Skip to content

コードをESMとして解釈させるために.mjs拡張子を使うのではなく、package.json"type": "module"と書くように変更する #926

@chvmvd

Description

@chvmvd

背景

現在は.mjs拡張子を使用することで、コードをESMとしてNode.jsに解釈させるようにしています。cf.

Node.jsでは、ファイルの拡張子が`.mjs`の場合、`export`文や`import`文を用いて他の<Term>モジュール</Term>とのやりとりを行います。
```javascript title="sub.mjs"
export default function add(a, b) {
return a + b;
}
```
```javascript title="main.mjs"
import add from "./sub.mjs";
console.log(add(3, 4));
```

しかし、現在ではpackage.json"type": "module"と書くことでコードをESMとして解釈させることが多く、.mjs拡張子を使用することによる問題が顕在化してきたため、package.json"type": "module"とする方法に変更することを考えています。

コードをESMとしてNode.jsに解釈させる方法について

2026年2月現在Node.jsは以下のようにして、ESMとして解釈するかCJSとして解釈するかを決定しています。cf. https://nodejs.org/api/esm.html#enabling https://nodejs.org/api/packages.html#determining-module-system

Authors can tell Node.js to interpret JavaScript as an ES module via the .mjs file extension, the package.json "type" field with a value "module", or the --input-type flag with a value of "module". These are explicit markers of code being intended to run as an ES module.
次の3つの方法でコードをESMとして解釈するように伝えることができる。

  • .mjs拡張子を使う
  • package.json"type": "module"と記載する
  • --input-typeフラグを使用する

When code lacks explicit markers for either module system, Node.js will inspect the source code of a module to look for ES module syntax. If such syntax is found, Node.js will run the code as an ES module; otherwise it will run the module as CommonJS. See Determining module system for more details.
明示していない場合はESMのみの構文があれば、ESMとして解釈する。

それぞれの方法の良し悪し

  • .mjs拡張子を使う
    • シンプルなためわかりやすく明示することを忘れにくい 👍
    • package.jsonがない場合でも明示可能 👍
    • ブラウザで動くJSの拡張子は.jsでありそれと拡張子が異なるため混乱を招く 👎
    • あまり一般的ではない 👎
      例えば、Prismaが自動生成するファイルの拡張子は.mtsではなく.tsになっており、後から自分で変更する必要が出てくる。
  • package.json"type": "module"と記載する
    • 一般的 👍
    • package.jsonがない場合には使えない 👎
    • 明示することを忘れやすい 👎
  • --input-typeフラグを使用する
    • package.jsonがない場合でも明示可能 👍
    • 毎回指定することはあまり現実的ではない 👎
    • あまり一般的ではない 👎

方針

package.json"type": "module"と記載する方法を採用します。これは、一般的に採用されている方法であり、問題が起きにくいからです。また、前述したようにNode.js 22.7.0以降では明示していなくてもESM構文があればESMとして解釈されるためpackage.jsonがない場合などにESMとして解釈されるように明示していなくてもそれほど問題がなくなったことも大きな理由となります。さらに、npm 11からnpm initをする際にtypeの値が聞かれるようになったため、そこで指定するだけでよくなったことも理由の1つです。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions