ES Modules と CommonJS どちらで書くべきか?
ESM を使う動機
静的な import によるツリーシェーキングができる。
ESM でしか取り込めないライブラリがある。
動的 import で非同期処理(top-level await)ができる。(await import と書くか、import にコールバック関数を渡すことになる。)
これからの主流に合わせたい。
前提知識
大きく違うのはモジュールの export と import の方法
CommonJS (以下CJS)
module.exports で外に見せる。
require 関数で取り込む
const someModule = require("some-module");
動的に import するときにも require を使う。(つまり静的と動的の区別なしで常に同期的にロードされる。)
ES Modules (以下ESM)
export キーワードで外に見せる。
export class ...
export function ...
export { identifire, ... }
import キーワードで取り込む
import ... from "some-module";
動的に import する場合は const someModule = await import("some-module"); (非同期にロードされる。)
次に問題なのは、拡張子の取り扱い。
package.json に "type": "module" が付いている場合、どのような動作になるか?
ファイル名が *.js でも ESM だと認識される。
Node.js では、デフォルトの状態では、*.js のファイルは CJS と認識される。
*.cjs のファイルが CJS, *.mjs のファイルが ESM と認識される。
このため、*.js のファイルに ESM の書式で書こうとすると以下のようなエラーが出る。
SyntaxError: Cannot use import statement outside a module
import したファイルの方が CJS と認識されている場合
code:console
import { hello } from "./hello.js";
^^^^^
SyntaxError: Named export 'hello' not found. The requested module './hello.js' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:
import pkg from './hello.js';
const { hello } = pkg;
package.json に "type": "module" が付くと、*.js のファイルは ESM と認識される。
import に拡張子を書かないのは ES Modules としては本来は不正な書き方。
拡張子を書かないでも通るのは実装がそのように配慮しているから。
モジュールが呼び出せるかどうかの問題
CommonJS からは ES Modules を呼び出すことができない。
と言いながらも、実際には呼び出せてしまうらしい?
Native ESM
ESM のままで実行されるもの。
Fake ESM
各種トランスパイラで CJS に変換して実行されるもの。
一見すると、Fake ESM と Native ESM は区別が付かない。
Fake ESM で動いても、Native ESM では動かないケースがある。
Web 系では、実際には1つのファイルにバンドルすることでパフォーマンスを上げることが行われている。
このため、Webpack、Rollup などのバンドラが解釈できるかどうかが重要になる。
top-level await ができない。
async 関数の中でしか await が書けないため、最上位のコード(グローバルスコープ)では await を書くことは本質的にできない。このため、以下のように async 関数を即時実行関数で包むことでごまかすことが行われている。
code:js
(async() => {
const result = await func();
console.log(result);
})();
参考
実践 Node.js Native ESM — Wantedlyでのアプリケーション移行事例 https://www.wantedly.com/companies/wantedly/post_articles/410531