node.js の require(CommonJS) と import(ESModule) について、理解が曖昧だったため、調べ直してみました。
※2022年2月の 最新バージョン v17.6.0 のドキュメントをもとに記述しています。あらかじめご了承ください。
require と import の違い
簡単にいうと、nodeモジュールの読み込み形式の違い。
require は 「CommonJS」 形式によるモジュールの読み込み方法。
import は 「ECMAScript」 形式によるモジュールの読み込み方法。
requireを定めたCommonJSは 2009年に始まったプロジェクト で、歴史が長い。nodeの公式ドキュメントを見ると、2011年の記事に利用方法の記載が行われている。
importによるモジュール読み込みが定義されたのは ES2015(ES6) から。 このため、import形式の方が新しい読み込み方法となる。
GitHub で node.js のコードを眺めていると、「ESM」とか「ESModule」という略語を目にすることがある。これは「ECMAScript Module」の略称を指す。
require を利用したモジュールの読み込み
require形式で、外部のJSファイルを読み込む。
const foo = require('bar.js')
import を利用したモジュールの読み込み
import形式で、外部のJSファイルを読み込む。
import { bar } from 'bar.js'
require, import を使ったサンプル
サンプルコードを利用して違いを見てみる。仕様は以下の通り。
- 指定した値に「2」を加算する関数ファイル「addTwo」
- addTwo をロードして、再利用するJSファイル「index」
の2つを準備する。
require(CommonJS) のサンプル
まずは require形式。ファイル構成は以下の通り。
.
├── addTwo.js
└── index.js
addTwo.js
module.exports = function addTwo(num) {
return num + 2;
}
index.js
const addTwo = require("./addTwo.js");
console.log(addTwo(4));
// 「6」が表示される
import(ESModule) のサンプル
続いてimportを利用したサンプル。
構成は以下のとおり。
.
├── addTwo.mjs
└── index.mjs
addTwo.mjs のコード
function addTwo(num) {
return num + 2;
}
export { addTwo };
index.mjs
import { addTwo } from './addTwo.mjs';
console.log(addTwo(4));
// 「6」が表示される
CommonJS (require) の有効化
以下の場合、CommonJSモジュールを利用するものとして扱われる。
- 拡張子が .cjsのファイル
- package.json のフィールド "type" に "commonjs" という値を含んでおり、拡張子 .js を持つファイル
- package.json にフィールド "type" が存在しない場合、拡張子が .js のファイル
何も宣言をしないで node.js のコードを書くと、暗黙的にCommonJSを利用する。
ESModule (import) の有効化
以下の場合、ESModuleを利用するものとして扱われる。
- 拡張子が.mjsのファイル
- package.json ファイルの "type" フィールドに "module" という値を含んでおり、拡張子が .js のファイル
- evalの引数として渡された文字列、またはSTDIN経由でnodeにパイプされた文字列で、 --input-type=moduleのフラグがあるもの
ESModuleの利用を前提とする場合、package.json もしくは拡張子に設定を加える必要がある。
参考文献
node.js のドキュメント各種および Wikipediaう, MDN を参照しました。