10月17日、Denoは「CommonJSからESMへの変換方法」というブログ記事を公開した。
ECMAScriptモジュール(ESM)は、最新かつ公式なJavaScriptの記述・共有方法であり、多くの環境(ブラウザ、エッジ、Denoのような最新のランタイム)でサポートされており、非同期ローディングやグローバル変数を使わずにエクスポートできるなど、開発体験も向上する。一方、CommonJSは長年にわたって標準とされてきたが、現在ではJavaScriptコミュニティにとって障害となっている。
JavaScriptを将来的に見据えて開発するには、すべての新しいコードはESMで記述するべきである。しかし、互換性の理由から、レガシーコードベースを最新のパッケージに対応させるためにモダン化する必要がある場合もある。今回の公開内容では、レガシーなCommonJSプロジェクトをESMに対応させるための構文移行方法と、そのプロセスを円滑にするためのツールが紹介されている。
以下はその要点である。
モジュールのインポートとエクスポート
CommonJSではmodule.exportsを使って関数や変数をエクスポートしていたが、ESMではexportを使う。インポート側でも、requireをimportに変更する必要がある。また、ESMではファイル拡張子を含めたモジュールパスが必要であり、これにより曖昧さがなくなり、ブラウザでのモジュール処理と整合性が取れる。
// CommonJS
const addNumbers = require("./add_numbers");
console.log(addNumbers(2, 2));
// ESM
import { addNumbers } from "./add_numbers.js";
console.log(addNumbers(2, 2));
package.jsonの更新
ESMをサポートするためには、package.jsonにいくつかの変更を加える必要がある。typeをmoduleに変更し、mainフィールドをexportsに置き換える。これにより、複数のエントリーポイントを定義できるほか、環境間での条件付きエントリ解決をサポートできる。
{
"name": "my-project",
"type": "module",
"exports": {
".": "./index.js",
"./other": "./other.js"
}
}
その他の変更
ESMではデフォルトでJavaScriptが「strict mode」で実行されるため、"use strict";の記述を削除できる。また、CommonJSでサポートされていたグローバル変数(__dirnameや__filename)はESMでは存在しないため、それらを埋め込むためのシンプルなシムを使うことが推奨される。
const __dirname = new URL(".", import.meta.url).pathname;
import { fileURLToPath } from "node:url";
const __filename = fileURLToPath(import.meta.url);
移行ツール
VSCodeやDenoのlintツールを活用することで、CommonJSからESMへの変換をスムーズに行える。特に、VSCodeではrequireに対して「クイックフィックス」機能を利用して、インポート/エクスポートの変換が可能である。
また、deno lint --fixを使って、ファイル拡張子の追加やコードスタイルの修正が自動化される。
これらの変更により、レガシーなJavaScriptコードをESMを標準としたモダンなコードに書き換えることができる。ESMのサポートは、新しいJavaScriptプロジェクトにおいて必須であり、可能な限り移行を行うことをおすすめする。
詳細はHow to convert CommonJS to ESMを参照していただきたい。
I love these topics. It has been very beneficial to me in particular. Head Soccer