package.json ã® imports / exports ãã£ã¼ã«ã
ãã®è¨äºã¯ Node.js ãã®2 Advent Calendar 2020 ã® 2 æ¥ç®ã®è¨äºã§ããæ稿ãå¤§å¹ ã«é ãã¦ç³ã訳ãããã¾ããã
Node.js v15.3.0 ãã ES Modules ã experimental ãã stable ã«ãªãã¾ãã ð
ä»å¹´ã¯ã¢ã¸ã¥ã¼ã«å¨ãã大ããé£èºãã¾ãããå人çã«ä»äºã§æ¢æ±ãã¦ãããã¨ããã£ã¦ã¢ã¸ã¥ã¼ã«å¨ãã追ããã¨ãå¤ãã£ãã§ãã
ES Modules ã使ã£ã¦ import ã§ãã npm ããã±ã¼ã¸ãå¢ãã¦ãã¦ãã¾ãã
ããã§ä»åã¯ã¢ã¸ã¥ã¼ã«é¢é£ã§è¿½å ããã package.json ã®ãã£ã¼ã«ãã«ã¤ãã¦ã¾ã¨ãã¦ç´¹ä»ãã¾ãã
以åä¼ç¤¾ã®ããã°ã«æ¸ããå 容ã¨éè¤ããé¨åãããã¾ãããããã§ã¯ç´¹ä»ã§ããªãã£ãæ©è½ãç´¹ä»ãããã¨æãã¾ãã
ã¾ãããã®è¨äºã®å 容㯠Node.js ã®å ¬å¼ããã¥ã¡ã³ã Module: Packages ãèªãã°ããã¹ã¦æ¸ãã¦ããå 容ã§ãã
ä»åç´¹ä»ããæ©è½ã¯ Node.js v12.19 ã¾ã㯠v14.13.0 ããå©ç¨å¯è½ã§ãã
"exports"
㨠"imports"
ãã£ã¼ã«ãã¨é¢é£ããæ©è½ã«ã¤ãã¦ä»¥ä¸ã®å
容ãç´¹ä»ãã¾ãã
- exports ã«ãããã¹ã®æå®
- imports ã«ããã¢ã¸ã¥ã¼ã«åã¨ãã¡ã¤ã«ã®ãããã³ã°
- --conditions ã«ããå®è¡æã®æ¡ä»¶å¤æ´
- Self-referencing ã«ããèªããã±ã¼ã¸ã®ãã¼ã
- ã¾ã¨ã
exports ã«ãããã¹ã®æå®
"exports"
ã¯ããã±ã¼ã¸ã®ã¨ã³ããªãã¤ã³ãã®ãã¡ã¤ã«ããµããã¹ãæå®ãããã¨ãã«èªã¿è¾¼ã¾ãããã¡ã¤ã«ãå®ç¾©ãããã¨ãã§ãã¾ãã次ã®ããã«ãµããã¹ãè¤æ°æå®ãããã¨ãã§ãã¾ãã
// package.json { "name": "my-mod", "exports": { ".": "./path/to/index.js", "./lib": "./path/to/lib/index.js" } }
"exports"
ã§å®ç¾©ãããã¨ã§ã次ã®ããã« import ãããã¨ãã§ãã¾ãã
// node_modules/my-mod/path/to/lib/index.js ãèªã¿ãã import { somefunc } from "my-mod/lib";
ãã® "exports"
ã«ã¯ glob ãã¿ã¼ã³ã®ããã« *
ã§æå®ãããã¨ã§ãããã³ã°ãããã¡ã¤ã«ãèªã¿è¾¼ã¿å¯è½ã«ãããã¨ãã§ãã¾ãã
// package.json { "name": "my-mod", "exports": { ".": "./path/to/index.js", "./lib": "./path/to/lib/index.js", "./lib/*": "./path/to/lib/*.js", "./package.json": "./package.json" } }
ä¾ãã°ãpath/to/lib/string_util.js
ã¨ãããã¡ã¤ã«ããã£ãã¨ãã¾ãããã®å ´å次ã®ããã« import ãããã¨ãã§ãã¾ãã
import { somefunc } from "my-mod/lib/string_util";
ã¾ãã "."
ã§æå®ãããã¡ã¤ã«ã¯ããã±ã¼ã¸ã®ã¨ã³ããªãã¤ã³ãã¨ãªãã "main"
ããåªå
ããã¾ãã
// node_modules/path/to/index.js ãèªã¿ãã import { somefunc } from "my-mod";
ãã¨ããµããã¹ãå®ç¾©ããªãã¨ãã¦ãã "main"
㨠"exports"
両æ¹å®ç¾©ãã¦ãããã¨ãæ¨å¥¨ããã¦ãã¾ãã
// package.json { "main": "./main.js", "exports": "./main.js" }
**"exports"
ãå®ç¾©ãããã¨ã§ãããã±ã¼ã¸ã®ãµããã¹ã¯ãã¹ã¦é è½ããã¾ãã**"exports"
ã«è¨è¼ã®ãªããã¹ãæå®ã㦠import ãããã¨ããã¨ãERR_PACKAGE_PATH_NOT_EXPORTED
ã¨ã©ã¼ãçºçããããã«ãªãã¾ããããã¯ã¦ã¼ã¶ã¼ã«æ¬æ¥ä½¿ããããã¨ãæå³ãã¦ããªããã¡ã¤ã«ãé è½ããã®ã«å½¹ç«ã¡ã¾ãã
Conditional Exports ã«ããæ¡ä»¶ã«å¿ãããã¼ã
"exports"
ã¯æ¡ä»¶ã«å¿ãã¦å®è¡ãã¡ã¤ã«ãåãæ¿ããæ©è½ãåãã¦ãã¾ãããã¨ãã°ã次ã®ããã«å®ç¾©ãã¦ããå ´åãNode.js ã¨ãã©ã¦ã¶ã¨ãã以å¤ã§å®è¡ãããã¡ã¤ã«ãå¤æ´ã§ãã¾ãã
// package.json { "name": "my-mod", "exports": { "./feature": { "node": "./feature-node.js", "browser": "./feature-browser.js", "default": "./feature.js" } } }
ä¸è¨ã®å®ç¾©ãããã¦ãã npm ããã±ã¼ã¸ãå©ç¨ãã以ä¸ã®ã³ã¼ããããã¾ãã
import { somefunc } from "my-mod/feature";
ãã®ã³ã¼ããå®è¡ãããç°å¢ã«å¿ãã¦ãå®è¡ãããããã±ã¼ã¸å ã®ãã¡ã¤ã«ã¯ä»¥ä¸ã®ããã«å¤ããã¾ãã
- Node.js ã§å®è¡ããå ´å...
feature-node.js
ãå®è¡ããã - ãã©ã¦ã¶ã§å®è¡ããå ´å...
feature-browser.js
ãå®è¡ããã - ãã®ä»ã®å®è¡ç°å¢ï¼Electron ãªã©ï¼ã§å®è¡ããå ´å...
feature.js
ãå®è¡ããã
ãã®ããã«å®è¡ç°å¢ã«å¿ãã¦ãã¡ã¤ã«ãåãæ¿ããããããã«ãããã¨ã§ã1 ã¤ã®ããã±ã¼ã¸ã§è¤æ°ã®å®è¡ç°å¢ããµãã¼ããããã¨ãã§ãã¾ãã
ãã ããããã±ã¼ã¸ãèªã¿è¾¼ãå®è¡ç°å¢ããã® Conditional Exports ã«å¯¾å¿ãã¦ããå¿
è¦ãããã¾ãããã©ã¦ã¶èªä½ã¯å¯¾å¿ãã¦ãã¾ããããwebpack ã Rollup ã¯å¯¾å¿ãã¦ããã®ã§ãã³ãã«ããã¨ãã«ã¯ "browser"
ã«å®ç¾©ããããã¡ã¤ã«ããã³ãã«ããã¾ãã
Conditional Exports 㯠ES Modules 㨠CommonJS ã®ä¸¡æ¹ããµãã¼ããã npm ããã±ã¼ã¸ã®éçºã«ã便å©ã§ãã以åä¼ç¤¾ã®ããã°ã«æ¸ãã¾ããã®ã§ããã¡ãããèªã¿ãã ããã
Node.js Dual Packages (CommonJS/ES Modules) に対応した npm パッケージの開発 - Cybozu Inside Out | サイボウズエンジニアのブログ
imports ã«ããã¢ã¸ã¥ã¼ã«åã¨ãã¡ã¤ã«ã®ãããã³ã°
"imports"
ã¯ããã±ã¼ã¸ã使ã人ãå©ç¨ãããã£ã¼ã«ãã§ãã"imports"
ãå©ç¨ããã°ãimport ããã¢ã¸ã¥ã¼ã«ãä»»æã®å称ã«ãããã³ã°ã§ãã¾ãã
Web ã§ããã¨ããã® import-maps ã«ä¼¼ãæ©è½ã§ãã
次ã®ããã«ä½¿ãããã¢ã¸ã¥ã¼ã«ã #
ããã¯ãã¾ãååã«ãããã³ã°ãããã¨ã§ãimport æã®ç縮ãã§ãã¾ãã
// package.json { "imports": { "#math": "./path/to/lib/utils/math.js" } }
import ãã JS ã«ã¯æ¬¡ã®ããã«æ¸ããã¨ãã§ãã¾ãã
// path/to/lib/utils/math.js ãèªã¿è¾¼ã import { rand } from "#math";
ããã "exports"
ã¨åããã*
ã使ã£ããã¿ã¼ã³ãããã³ã°ã«ããæå®ãã§ãã¾ãã
// package.json { "imports": { "#utils/*": "./path/to/lib/utils/*.js" } }
// path/to/lib/utils/math.js ãèªã¿è¾¼ã import { rand } from "#utils/math";
"imports"
ã«é¢ãã¦ã "exports"
åæ§ã«æ¡ä»¶ã«å¿ãã¦å®è¡ãããã¡ã¤ã«ãåãæ¿ããæ©è½ãåãã¦ãã¾ãã
次ã®ããã«å®ç¾©ãããã¨ã§ import ããå®è¡ç°å¢ã«å¿ãã¦å®è¡ãããã¡ã¤ã«ãåãæ¿ãããã§ãã¾ãã
// package.json { "imports": { "#dep": { "node": "dep-node-native", "default": "./dep-polyfill.js" } }, "dependencies": { "dep-node-native": "^1.0.0" } }
import ããã³ã¼ãã¯æ¬¡ã®ããã«åãã§ãå®è¡ããç°å¢ã«ãã£ã¦å®è¡ãããã¡ã¤ã«ãå¤ããã¾ãã
import { somefunc } from "#dep";
ãã®ã³ã¼ããå®è¡ããã¨ã次ã®ããã«å®è¡ç°å¢ã«å¿ãã¦å®è¡ãããã¡ã¤ã«ãåãæ¿ããã¾ãã
- Node.js ã§å®è¡ããå ´å...
dep-node-native
ããã±ã¼ã¸ãå®è¡ããã - Node.js 以å¤ã®å®è¡ç°å¢ã§å®è¡ãããå ´å...
dep-polyfill.js
ãå®è¡ããã
ãã®æ©è½ã使ãã°ãã¢ããªã±ã¼ã·ã§ã³ãããã±ã¼ã¸ãéçºããã¨ãã«ãimport ããå´ã®ã³ã¼ããã㯠Node.js ããã©ã¦ã¶ãæèããã« import ãããã¨ãã§ãã¾ããNode.js ã¨ãã©ã¦ã¶ã®ä¸¡æ¹ããµãã¼ããã¦ãã isomorphic 㪠npm ããã±ã¼ã¸ã®éçºã«ã¨ã¦ã便å©ã§ãã
ãããããã®æ©è½ã Conditional Exports ã¨åãããã«å®è¡ç°å¢ã対å¿ãã¦ããªãã¨ä½¿ãã¾ãããç¾å¨ã¯ webpack ã Rollup ãªã© module bundler ã¯å¯¾å¿ãã¦ãã¾ããã
--conditions ã«ããå®è¡æã®æ¡ä»¶å¤æ´
ç´¹ä»ãã "exports"
ã "imports"
ã®æ¡ä»¶ã¯å®è¡ç°å¢ã«ããåãæ¿ããã¢ã¸ã¥ã¼ã«ã·ã¹ãã ã«ããåãæ¿ãã ãã§ãªããã¦ã¼ã¶ã¼ã®éçºæã«ãå¿ç¨ã§ãã¾ãã
ãã¨ãã°ãéçºæã¨æ¬çªã§å®è¡ãããã¡ã¤ã«ãå¤æ´ãããå ´åã¯ä»¥ä¸ã®ããã«å®ç¾©ãããã¨ãã§ãã¾ãã
{ "imports": { "#log": { "development": "./path/to/log-dev.js", "default": "./path/to/log.js" } } }
import ããã³ã¼ãã¯æ¬¡ã®ããã« log-dev.js
ã log.js
ããæèãã使ããã¨ãã§ãã¾ãã
// index.js import log from "#log";
å®è¡æã« Node.js ã®å®è¡ãªãã·ã§ã³ --conditions
ã使ãã° import ãããã¡ã¤ã«ãåãæ¿ãããã¨ãã§ãã¾ãããã¨ãã°éçºæ㯠"developmen"
ã§å®ç¾©ããã log-dev.js
ã使ãããå ´åã¯æ¬¡ã®ããã« --conditions
ãªãã·ã§ã³ãç¨ãã¦å®è¡ãã¾ãã
node --conditions=development index.js
"exports"
ã§ãåæ§ã®ãã¨ãã§ãã¾ãã次ã®ããã«å®ç¾©ãã¦ããã¨ããã±ã¼ã¸ã®ã¦ã¼ã¶ã¼ã®æå®ã«ãããã¡ã¤ã«ãåãæ¿ãããã¨ãã§ãã¾ãã
// package.json { "name": "my-mod", "exports": { ".": { "node": { "development": "./dev.js", "default": "./index.js" } } } }
ããã±ã¼ã¸ã使ãã¦ã¼ã¶ã¼ã¯æ¬¡ã®ããã« import ãã¦ä½¿ãã¾ãã
// index.js import { somefunc } from "my-mod";
å®è¡æã« --conditions
ãªãã·ã§ã³ãæå®ããã°ããã±ã¼ã¸å
ã® dev.js
ãå®è¡ãã¾ãã
node --conditions=development index.js
Self-referencing ã«ããèªããã±ã¼ã¸ã®ãã¼ã
"exports"
ã®å®ç¾©ã¯ããã±ã¼ã¸ã使ãã¦ã¼ã¶ã¼ã ãã§ãªããããã±ã¼ã¸èªèº«ã§ãå©ç¨ãããã¨ãã§ãã¾ãã
ãã¨ãã°ã次ã®ããã«å®ç¾©ãããããã±ã¼ã¸ããã£ãã¨ãã¾ãã
// package.json { "name": "my-mod", "exports": { ".": "./path/to/index.js", "./lib/*": "./path/to/lib/*.js" } }
次㫠my-mod
ããã±ã¼ã¸å
ã®ãã¡ã¤ã«ãã次ã®ããã«èªèº«ã import ãã¦ä½¿ããã¨ãã§ãã¾ãã
// ãã¨ãã°ãmy-mod/another-path/to/util.js ããèªã¿è¾¼ãã§ããã¨ãã // path/to/index.js ãèªã¿è¾¼ã import { somefunc } from "my-mod"; // path/to/lib/log.js ãèªã¿è¾¼ã import log from "my-mod/lib/log";
ãã®ããã«ã¦ã¼ã¶ã¼ã¨åãããã« import ãããã¨ãã§ããã®ã§ããã¹ãã§ä½¿ã£ãããµã³ãã«ã³ã¼ããªã©ã§ä½¿ãã°å®éã®ã¦ã¼ã¶ã¼ã®ä½¿ç¨ã«è¿ãã³ã¼ããæ¸ããã¨ãã§ãã¾ãã
ã¾ã¨ã
ä»å¹´ã¯ã¤ãã« Node.js ã§ã ES Modules ãæ¬æ ¼çã«ä½¿ããå¹´ã«ãªããããã«ä»éããå½¢ã§ã¢ã¸ã¥ã¼ã«å¨ãã«æ§ã
ãªæ©è½ã追å ããã¾ããã主è¦ãª npm ããã±ã¼ã¸ã¯ãã§ã« "exports"
ãã£ã¼ã«ãã使ã£ã¦ ES Modules å½¢å¼ã§ãé
ä¿¡ãå§ãã¦ãã¾ããä»å¾ãä»æ¥ç´¹ä»ããæ©è½ãç¨ãã ES Modules ã«å¯¾å¿ãã npm ããã±ã¼ã¸ãå¢ãã¦ããã¨äºæ³ããã¾ãã
ã¢ã¸ã¥ã¼ã«å¨ãã§ã¯ã¾ã Experimental ãªæ©è½ãããã¾ãããã¼ãºã«å¿ãã¦æ°æ©è½ã追å ããã¦ããã§ããããæ¥å¹´ãã¢ã¸ã¥ã¼ã«å¨ããé²åãã¦ããã¨æãã¾ããå人çã«ã¯ JSON modules ãªãã㯠WHATWG ã®ä»æ§ã import assertion ãªã©ãå«ãã¦ã©ããªãã®ã楽ãã¿ã§ãã
Node.js ã®ã¢ã¸ã¥ã¼ã«é¢é£ã«ã¤ãã¦ã¯ä»¥ä¸ã®ãªãã¸ããªã§ã¢ã¸ã¥ã¼ã«ãã¼ã ãè°è«ããã¦ããããã¾ããããèå³ãããã°ã¦ã©ãããã¦ã¿ã¦ãã ããã
æå¾ã¾ã§ãèªã¿ããã ããããã¨ããããã¾ãããä¸åã質å㯠@shisama_ã¾ã§ãé¡ããã¾ãã