はじめに
現在「プロを目指す人のためのTypeScript入門」の学習を進めています。第1章の環境構築の段階で、生成されたpackage.jsonに"type": "module"を追加するように、という記述がありました。(実際にはデフォルトでcommonjsが指定されていたので、それをmoduleに書き換えました)
そこで、typeにcommonjsを指定した時とmoduleを指定した時の違いについて疑問を持ちました。調べたことを整理して書いていきたいと思います。
typeとは
Node.jsは、拡張子が.jsのファイルをどのモジュールシステムで解釈するかをpackage.jsonのtypeで指定します。
この記事では詳しくは説明しませんが、モジュールとは機能を再利用しやすいように分割したものを指し、モジュールシステムとは複数のモジュールからなるプログラムを作るための仕組みを指します。
-
commonjsを指定した・またはtypeを省略した場合:プロジェクト内のファイルはCommonJSとして扱われる -
moduleを指定した場合:プロジェクト内のファイルはES Modulesとして扱われる
これらは拡張子で上書きすることも可能で、.cjsはCommonJSとして、.mjsはES Modulesとして扱われます。
CommonJSについて
Node.jsが長く使ってきたモジュールシステムです。そのままではWebブラウザでの動作には対応しておらず、バンドラを使って変換を行う必要があります。
構文の特徴は以下の通りです。
-
module.exports/exportsでモジュールをエクスポートする
例①(module.exports):
function add(a, b) {
return a + b;
}
module.exports = { add };
例②(exports):
exports.add = (a, b) => a + b;
-
require("...")で他のモジュールをインポートする
例:
const math = require("./math");
console.log(math.add(2, 3));
requireは通常の関数呼び出しとして実行時に評価されるため、条件分岐の中で呼び出すといった書き方が可能です。
CommonJSではモジュールの読み込みが同期的に行われ、読み込みが完了するまではそのほかの処理はブロックされます。
ES Modulesについて
ES2015で追加されたモジュールシステムです。Node.js・Webブラウザ両方に対応しています。
構文の特徴は以下の通りです。
-
exportでモジュールのエクスポートを宣言する
例:
export const add = (a, b) => a + b;
export const sub = (a, b) => a - b;
-
importでモジュールのインポートを宣言する
例:
import { add } from "./math.js";
console.log(add(2, 3));
-
import()で動的にモジュールをインポートする
例:
const math = await import("./math.js");
console.log(math.add(2, 3));
import宣言はモジュールのトップレベルにしか書くことができません。CommonJSのrequireのように実行時に動的にモジュールを読み込みたい場合にはimport()を使います。
また、ES Modulesではモジュールの読み込みが非同期的に行われます。
以下の形でES ModulesからCommonJSをインポートすることも可能です。
import math from "./math.cjs";
console.log(math.add(2, 3));
対応関係の整理
| 観点 | CommonJS | ES Modules |
|---|---|---|
| インポート | require |
import / import()
|
| エクスポート |
module.exports, exports
|
export |
| package.json |
type 未指定または "type": "commonjs"
|
"type": "module" |
| 拡張子 | .cjs |
.mjs |
おわりに
普段はES Modulesしか使う機会がなく、モジュールシステムについて意識することも特になかったため、CommonJSの構文は見慣れず新鮮に感じました。
最近はES Modulesを使うのが主流になってきているとのことですが、CommonJSについてもJavaScriptの基本知識として押さえておきたいと思います。