ESM / CJS 関連
CJS / CommonJS modules
- Node.js で使える
// 提供側
exports.foo = 0;
// 利用側
require('foo');
ESM / ECMAScript Modules
- Node.js、ブラウザで使える
// 提供側
export const foo = 0;
// 利用側
import { foo } from 'foo';
faux ESM
- バンドラーが解釈できる ESM ライクなもの
- 例えば ESM の中には本来は require は書けないが、faux ESM では書ける(よしなに解釈される)
- 混乱の元
import path from 'path';
// 書けちゃう、動いちゃう
const fs = require('fs');
package.json のエントリーポイント
- main
- ESM か CJS かの判定は以下で行う
- 指しているファイルの拡張子
- そのファイルの近くの package.json の type フィールド
- Node.js で使える
- この際、
exports
フィールドが存在すればそちらが優先
- この際、
- バンドラーでも使える
- この際、後述するほかのフィールドが存在すればそれらが優先
- ESM か CJS かの判定は以下で行う
- module / jsnext / jsnext:main
- ESM 用のエントリーポイント
- 非標準
- バンドラーで使える
- Node.js では使えない( バンドルしない限り)
- browser
- なんでもありのよくわからんフィールド
- exports
- 最新
- conditional exports が使える
モジュールで分ける例
{
"exports": {
".": {
"require": "./index.cjs.cjs",
"import": "./index.esm.mjs"
}
}
}
実行環境によって分けることも可
{
"exports": {
".": {
"deno": "./index.deno.js",
"browser": "./index.browser.js",
"node": "./index.node.js"
}
}
}
あるいはその両方も可
{
"exports": {
".": {
"browser": {
"require": "./index.browser.cjs.cjs",
"import": "./index.browser.esm.mjs"
},
"node": {
"require": "./index.node.cjs.cjs",
"import": "./index.node.esm.mjs"
}
}
}
}