3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[TS/JS]ESMとCJS

Posted at

ESMだのCJSだので詰まることが多すぎるので、いい加減情報をまとめる。

概要

ざっくりいうと、「modulesをどのように扱うか?」に係る2種の系統。

  • import, exportするほうがESM
  • require, modules.exportするほうがCJS

ESM; ES Modules

importの方。

ECMA Script2015(ES6)で策定されたモジュール仕様。
V8などは当然こちらに準拠している。

ECMAScript - Wikipedia

CJS; CommonJS

requireのほう

立ち上げは2009なので、ESMより古参。
ServerSideJavascriptというコンセプトを出発点とするため、Node.jsではデフォルトである一方、ブラウザでは非対応となっている。

CommonJS - Wikipedia

趨勢

メインストリームはESMである
ことフロントエンド開発においてはそもそもブラウザがCJSに非対応であるため、必然的にESM環境になる。
しかし、Node.js環境上においても、npmの開発者であるIsaac氏自ら「CJSは時代遅れになりつつある」とコメントしている模様。

Breaking the CommonJS standardization impasse · Issue #5132 · nodejs/node-v0.x-archive · GitHub

こうした状況を反映してか、最近のサードパーティモジュールの中にはCJSに対応していない(ESMのみ提供)ものが増えつつある。
……とされていたが、Node.js v22からそうでも無くなった模様。
CJSからESMをrequireで呼び出せるようになった。
Node.js — Node.js 22 is now available!

ただし、Pure ESM packageという観点からは、importの使用を強く推奨されている

Node.js + ESM + TypeScript

プロジェクト単位の手続き

一方、先述の通り、Node.jsにおいてはCJSをデフォルトとしている都合、Node.js環境を想定したプロジェクトをESM環境として扱うためにはボイラープレートな手続きが必要。

再掲・引用。
Pure ESM package · GitHub

  • Add "type": "module" to your package.json.
  • Replace "main": "index.js" with "exports": "./index.js" in your package.json.
  • Update the "engines" field in package.json to Node.js 18: "node": ">=18".
  • Remove 'use strict'; from all JavaScript files.
  • Replace all require()/module.export with import/export.
  • Use only full relative file paths for imports: import x from '.'; → import x from './index.js';.
  • If you have a TypeScript type definition (for example, index.d.ts), update it to use ESM imports/exports.
  • Use the node: protocol for Node.js built-in imports.

拡張子の明示と、TypeScriptでの都合

大きな違いとして、ESMでimportを行う際は拡張子を明示するのが原則。

import modules from "./modules.js"

ここまではまだ良いとして、TypeScriptでESM環境を想定する場合に留意点がある。
それは、.tsファイルをimportする場合でも、拡張子を.jsにする必要があるということ。
つまり、上記でimportするファイルがmodules.tsであろうとも、上のように.js拡張子で書かないといけない。

これは、tscのコンパイル方針に起因する。
tscimport内の文字列の書き換えや読み替えを行わないという方針がTypeScript開発チームから示されている。
Design Meeting Notes, 11/22/2019 · Issue #35589 · microsoft/TypeScript

そのため、import内にはトランスパイル後の.js拡張子を記載する必要がある。
一応、このあたりはtscなどがIDE上でサポートしてくれるのでエラーになったりすることはない。気持ちは悪い。

一応、tsconfigの設定次第で.tsを扱えるとされているようだが……なんだか情報が錯綜している。

参考・外部リンク

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?