⛳
ESModuleとCommonJS
ESModuleとCommonJSを理解するのに実用例を出すとわかりやすいので、以下にそれぞれの最小構成を出します。
ES Modulesの使用例
ES Modulesは、モダンなJavaScriptアプリケーションにおけるコードのモジュール化、再利用を容易にする仕組みです。ここでは、ブラウザでHTMLファイルからJavaScriptのES Moduleを読み込む最小構成を示します。2017年以降のバージョンのブラウザは対応しています。
index.html
HTMLファイルからJavaScriptのES Moduleを読み込み、ボタンクリックでメッセージを表示します。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>ESModule</title>
</head>
<body>
<h1>ESModule</h1>
<button id="messageButton">Show Message</button>
<p id="messageDisplay"></p>
<script type="module">
import { showMessage } from "./main.js";
showMessage();
</script>
</body>
</html>
main.js
showMessage関数をエクスポートし、ボタンクリックイベントを設定します。
export function showMessage() {
document.getElementById("messageButton").addEventListener("click", () => {
document.getElementById("messageDisplay").textContent = "Hello World!";
});
}
CommonJSの使用例
サーバサイドのNodejsのデフォルトで使用されるモジュールシステム。
index.js
greet.jsモジュールを読み込み、その関数を実行します。
const { greet } = require("./main");
greet();
greet.js
greet関数を定義し、module.exportsを通じてエクスポートします。
function greet() {
console.log("Hello, World!");
}
module.exports = { greet };
よくハマるポイントと解決策
CommonJSからES Modulesをrequire()構文で読み込むことができない。
例えば、CommonJSのindex.jsからnanoidを使おうとすると以下のようにエラーが発生します。
const nanoid = require("nanoid");
console.log("nanoid", nanoid());
// error message
onst nanoid = require("nanoid");
^
ReferenceError: require is not defined in ES module scope, you can use import instead
解決策
1. Dynamic Importsを使う。
// index.js
(async () => {
const { nanoid } = await import("nanoid");
console.log(nanoid());
})();
Dynamic ImportsはPromiseオブジェクトを返すので、トップレベルスコープ以外で使用する必要があります。2回目以降に読み込む時は、メモリにキャッシュされた以前に読み込んだときのエクスポートを返します。
2. アプリケーションをESMとして扱う。
// package.jsonに追加
{
"type": "module",
}
// index.js
import { nanoid } from "nanoid";
console.log(nanoid());
package.jsonのtypeをmoduleに変更します。
つまりどちらを使えば良い?
基本的には、ES Modulesを使用することを推奨します。CommonJSを採用する場合はDynamic Importsを活用することでES Modulesのライブラリを読み込むことができます。
Discussion