Help us understand the problem. What is going on with this article?

Node.js(CommonJS)からECMAScript Moduleを読み込む

More than 1 year has passed since last update.

やりたいこと

Webアプリのbuild時にクライアントサイドの設定定義ファイル (ECMAScript Module形式) をビルドスクリプト (Node.jsのスクリプト、CommonJS) 内で読み込み、定義内容に応じた事前処理を実行したい。

フォルダ構成
project
  +- src               <- Reactのsrcフォルダ
  |   `- commons
  |        `- index.js <- このファイルが設定定義
  |
  `- scripts
      `- build.js      <- ビルド時の処理が書かれた Node.jsのスクリプト

問題点

  1. 通常の方法 (require) では CommonJS形式のスクリプトからECMAScript Module形式のファイルを呼び出すことはできない
  2. 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.jsscripts/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

Kazunori-Kimura
フリーランスのプログラマーです。JavaScript好き。 C#, Javaもやれます。 お仕事ください。
https://kazunori-kimura.github.io/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした