やりたいこと
Webアプリのbuild時にクライアントサイドの設定定義ファイル (ECMAScript Module形式) をビルドスクリプト (Node.jsのスクリプト、CommonJS) 内で読み込み、定義内容に応じた事前処理を実行したい。
フォルダ構成
project
+- src <- Reactのsrcフォルダ
| `- commons
| `- index.js <- このファイルが設定定義
|
`- scripts
`- build.js <- ビルド時の処理が書かれた Node.jsのスクリプト
問題点
- 通常の方法 (
require
) では CommonJS形式のスクリプトからECMAScript Module形式のファイルを呼び出すことはできない - CommonJS形式のスクリプトではECMAScript Module形式の
import/export
は使用できない
CommonJSからECMAScript Moduleを取り込む方法
以下の手順を踏むと、 CommonJS から ECMAScript Module を取り込める
(1) ECMAScript Moduleの拡張子を .mjs
とする
common.mjs
// ECMAScript Module
export const VERSION = '1.0.0';
export const config = {
hoge: 'fuga',
foo: 'bar',
};
(2) dynamic import を使用してimportする
index.js
// CommonJS
async function main() {
// dynamic import
const { config } = await import('./common.mjs');
console.log(config);
}
main()
.then(() => { console.log('done!'); })
.catch((err) => { console.error(err); });
(3) nodeコマンドに --experimental-modules
フラグを指定する
$ node --experimental-modules index.js
(node:22431) ExperimentalWarning: The ESM module loader is experimental.
{ hoge: 'fuga', foo: 'bar' }
done!
まとめ
build.js
の冒頭で src/commons/index.js
を scripts/common.mjs
にコピーし、そのファイルをimportすることでやりたいことが実現できた。
build.js
const path = require('path');
const fs = require('fs-extra');
async function main() {
// 設定定義ファイル
const commonFile = path.resolve(__dirname, '../src/commons/index.js');
// .mjsファイル
const commonMjs = path.resolve(__dirname, './common.mjs');
// ファイルをコピー
await fs.copyFile(commonFile, commonMjs);
// dynamic import
const { config } = await import(commonMjs);
// ...以降ビルド処理をゴニョゴニョ...
}
main()
.then(() => { console.log('done!'); })
.catch((err) => { console.error(err); });
参考
Node.jsとECMAScript Modules - 技術探し
https://blog.hiroppy.me/entry/nodejs-esm
ECMAScript Modules | Node.js v11.0.0 Documentation
https://nodejs.org/api/esm.html