前回までのあらすじ
この記事は続編となっています。前回の記事はこちら:
Part 1 では JavaScript のモジュール機能の代表的な2つの仕様を紹介しました。
- ECMAScript のモジュール機能 (通称 ES Modules)
- ES6(ES2015) で追加された
-
export
とimport
を使う
- CommonJS のモジュール機能
- 2009年ごろから存在する
-
exports
とrequire
を使う
今回は、それぞれの仕様を実際に使う方法として、以下を紹介します。
- ブラウザでモジュール機能を使う方法
- Node.js でモジュール機能を使う方法
ブラウザでモジュール機能を使う方法
ブラウザには様々な種類がありますが、HTML Living Standard という HTML の仕様に従っているブラウザがほとんどです。
HTML Living Standard では HTML 内に <script>
タグを記載することで JavaScript を実行できるようになっていて、さらに type="module"
属性を指定することで、ECMAScript のモジュール機能 (ES Modules) が使えます。
例として、以下のように変数を export するコードを main.js
に保存して、ブラウザ (HTML) で import してみます。
export const foo = 1
index.html
を作成し <script type="module">
内で import
してみます。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>タイトル</title>
</head>
<body>
<script type="module">
import { foo } from './main.js'
console.log("foo =", foo)
</script>
</body>
</html>
ブラウザで読み込めるか試してみましょう!
index.html
をそのままブラウザで開くと CORS の都合でエラーになるので、 http-server を使ってローカルサーバーを立てます。
適当なディレクトリの中に main.js
と index.html
を置いて、その中に移動しコマンドを実行します。
$ npx http-server
Starting up http-server, serving ./
(省略)
Available on:
http://127.0.0.1:8082
上記の例だと http://127.0.0.1:8082
にアクセスすればOKです。
真っ白なページが表示されますが、開発者ツールを開くと foo = 1
が表示されているはずです。
より詳しい使い方やインポートマップなどについても知りたい方は mdn のモジュールのページも参照してみてください。
ES Modules 以前は、どうやって複数の JS を読み込んでいたの?
ES Modules 登場以前は type="module"
なしで単に複数の <script>
タグを記載して、主にグローバルスコープで変数や関数を定義し参照していました。
const foo = 1
console.log("foo =", foo)
(省略)
<script src="main.js"></script>
<script src="index.js"></script>
(省略)
この方法ではグローバルスコープの汚染などの問題があったので、IIFE (即時実行関数式) などを駆使していましたが、ES Modules の登場により安全にモジュール化ができるようになりました。
Node.js でモジュール機能を使う方法
Node.js は JavaScript 実行環境の一つです。Node.js がリリースされた当初は ES Modules がなかったので、 CommonJS のモジュール機能 が長い間使用されてきました。ES2015 で ES Modules が登場した後は、 Node.js でも ECMAScript のモジュール機能 が使用できるようになりました。
Node.js で CommonJS のモジュール機能を使う
まずは CommonJS のモジュール機能を Node.js で使ってみましょう。
まずは CommonJS の module.exports
で変数をエクスポートする main.js を用意します。
const foo = 1
module.exports = { foo }
次に、それを require
でインポートする index.js を作成しましょう。
const { foo } = require('./main.js')
console.log("foo =", foo)
node をインストールした環境で、 index.js
を実行してみましょう。
$ node index.js
foo = 1
無事にインポートできました。
Node.js で ECMAScript のモジュール機能を使う
上で記載の通り、 Node.js は CommonJS のモジュール機能 が長い間使用されてきたため、そのままでは ECMAScript のモジュール機能が使えません。方法はいくつかありますが、ここではファイルの拡張子を .mjs
にする方法を紹介します。
ES Modules の記法でインポート/エクスポートを記載した、拡張子 .mjs
のファイルを用意します。
export const foo = 1
import { foo } from './main.mjs'
console.log("foo =", foo)
先程と同様に index.mjs
を実行してみましょう。
$ node index.mjs
foo = 1
ES Modules でもインポートできました
ES Modules で CommonJS のインポート、またはその逆はできるの?
ES Modules で CommonJS のインポート
できます。普通に import するだけです。
↓ CommonJS のモジュール
const foo = 1
module.exports = { foo }
↓ ES Modules のモジュール
import { foo } from './main.js'
console.log("foo =", foo)
CommonJS で ES Modules のインポート
逆に、CommonJS のモジュール内で ES Modules のモジュールもインポートできますが、こちらは Node.js のバージョンによって異なるので注意が必要です。
以前は Dynamic import でのみ CommonJS で ES Modules のインポートが可能でした。
(async () => {
const { foo } = await import('./main.mjs')
console.log("foo =", foo)
})()
Node.js v22 では --experimental-require-module
オプション指定時のみ require
による ES Module のインポートができるようになりました。
const { foo } = require('./main.mjs')
console.log("foo =", foo)
そして2024年12月にリリースされた Node.js v22.12.0 では、デフォルトで require
による ES Module のインポートがサポートされました
ここまでのまとめ
- ブラウザ
- ECMAScript のモジュール機能 (通称 ES Modules) が使用可能
-
<script type="module">
を指定する
-
- ECMAScript のモジュール機能 (通称 ES Modules) が使用可能
- Node.js
- CommonJS のモジュール機能が使用可能
- ECMAScript のモジュール機能も使用可能
- 拡張子を
.mjs
にするなど工夫が必要
- 拡張子を
- CommonJS <-> ECMAScript で互いにインポート可能
- CommonJS で ECMAScript のモジュールをインポートする場合は Node.js のバージョンに注意
Part 2 はここまでです。Part 3 以降では以下について書こうと思います。
- npm パッケージのインポート・エクスポート
- TypeScript のモジュール機能
- Webpack や Babel でモジュールはどのように扱われるか