-
Notifications
You must be signed in to change notification settings - Fork 0
ES Modules Runtime support
このエントリでは、ES Modules のランタイム側のサポート状況について説明しています。
This entry is will be continually updated.
以下は、執筆当時(2018/03)の各ランタイムの ES Modules 関連仕様のサポート状況になります。
Browser / Runtime | ES Modules import / export
|
import() |
import.meta |
---|---|---|---|
Chrome | 61 | 63 | 64 |
Chrome for Android | 61 | 63 | 64 |
Mac Safari | 10.1 | 11 | |
Mobile Safari | 10.3 | 11 | |
Firefox | 54 + flag | ❌ (no signal) | |
Edge | 16 | ❌ (no signal) | |
Node.js | 9.3 + flag | WIP | WIP |
Babel | ⭕ | plugin | |
Rollup | ⭕ | 0.56 + flag | |
Webpack | ⭕ | ⭕ | |
TypeScript | ⭕ | 2.4 |
HTML関連仕様の状況です。
Browser | <script type="module"> |
<script nomodule> |
<link rel="modulepreload"> |
---|---|---|---|
Chrome | 61 | 61 | 64 + flag |
Chrome for Android | 61 | 61 | 64 + flag |
Mac Safari | 10.1 | 10.3 | |
Mobile Safari | 10.3 | 11.0 | |
Firefox | 55 | 55 | |
Edge | 16 | 16 |
ES Modules は ECMAScript の範囲内で振る舞いを定義しています。 モジュールとは何であり、どうやって解釈されるべきか… といった重要な部分は ES Modules で標準化されましたが、 モジュールの読み込み方などは、例により各実装にまかされています。
ブラウザや Node.js などのランタイム, トランスパイラなどのツールは、それぞれでバックエンドや状況が異なるといった事情を抱えています。
ES Modules をサポートするブラウザは <script type="module">
をサポートします。
<script type="module" src="..."></script>
<script type="module"> inline module </script>
<script type="module">
は ES Modules のために追加された仕様です。
ES Modules をサポートするブラウザは type="module"
属性が設定されている <script>
を読み込み実行します。
-
<script type="nomodule">
は defer 属性が設定されているものとして動作します -
<script>
はどこからでもファイルを読み込めますが、<script type="module">
はCORSの影響を受けます -
<script>
は cookie 付きでサーバにアクセスしますが、<script type="module">
は cookie を付与しません(No credentials) - 適切なMimeTypeがレスポンスヘッダで与えられない場合は実行に失敗します
また、ES Modules では <script type="modue">
が利用できない古いブラウザにむけたフォールバックの仕組みが用意されています。それが nomodule です。
<script type="module" src="main.js"></script>
<script nomodule src="bundle.js"></script>
<script nomodule> inline script </script>
- ES Modules をサポートしているブラウザは
<script type="module">
を読み込みますが、<script nomodule>
は無視します。 - ES Modules をサポートしていない古いブラウザは
<script type="module">
を恐らく無視します。そして<script nomodule>
を読み込み実行します。
<script type="module">
と <script nomodule>
の実行タイミングをあわせる場合は、<script nomodule>
に defer 属性を追加し、以下のようにすると良いでしょう。
<script type="module" src="main.js"></script>
<script nomodule defer src="bundle.js"></script>
読み込むモジュールが明らかな場合は、プリロードする仕組みが欲しくなります。
それが <link rel="modulepreload" href="module.js">
です。
<link rel="modulepreload" href="module.js" onload="onloaded()">
とすると、module.js 読み込み後に onloaded() がコールバックされます。
TypeScript は JavaScript のスーパーセット(上位互換)であり、ES Modules (import / export) をそのまま利用できます。
また、import()
も利用できます。
https://www.typescriptlang.org/docs/handbook/modules.html
Node.js v9.3.0 から以下の条件付きで ES Modules のサポートが入りました。
https://nodejs.org/api/esm.html
- Node.js v9.3.0 の時点では
node --experimental-modules index.mjs
のようにフラグ付きで起動する必要があります。- v10.0.0 で
--experimental-modules
が廃止され、ES Modules がデフォルトで利用可能になる予定です。
- v10.0.0 で
- Node.js の import / export で使用するモジュールの拡張子を
.mjs
にする必要があります。.js
は動作しません。 - Node.js v9.3.0 では
import()
やimport.meta
は利用できません。これらは将来の実装を待つ必要があります。 - 2020年ごろに
--experimental-modules
フラグを就けなくても動作するようになるとの情報もあります
require() で読み込まれるスクリプトと import で読み込まれるモジュールには以下の相違点があります。
- モジュールでは
NODE_PATH
を使用できません。 - モジュールでは Node.js 固有のキーワード(
require
,module
,exports
,__filename
,__dirname
)は利用できません。 - モジュールのパスは、URL のルールに基づいている必要があります。URLで使用できない記号はエスケープする必要があります。
- モジュールとして、CommonJS で書かれたコード、拡張子がJSONのテキストファイル、C++で書かれたアドオンを読み込む事ができます。
- モジュールを読み込む際のフックを設定できます。フックの詳細は https://nodejs.org/api/esm.html#esm_loader_hooks を参照してください。
__filename
や __dirname
が利用できないと困ってしまう状況もあるため、
環境依存のメタ情報を格納するためのプロパティ import.meta
以下に import.meta.url
を用意するなどの代替案も検討されています。
拡張子 .mjs
については注意すべきでしょう。
単に .js
を .mjs
にリネームするだけでは既存のツールが利用できなくなります。
- サーバ側に MimeType の設定を追加しないと、ブラウザ側では利用できないファイルになります。 ES Modules Path rule を参照してください。
- 既存のシンタックスハイライトツールは
.mjs
を JavaScript のコードとして認識しません。 -
/\.js$/.test(path)
という既存のjsにマッチする正規表現はそのままでは.mjs
にマッチしません。
/\.(js|mjs)$/.test(path)
に変更する必要があります。
以下は古い情報です
Node.js では require 構文が長年利用されてきた関係で、import へのスムーズな移行が難しい状況にあります。 2018/Q1 頃までになんらかの方向性を提案する予定とありますが、現在有力視されているのは、 従来の CommonJS(requre/module.exports)スタイルのコードの拡張子を
*.js
とし、 ES Modules スタイルで書かれたコードの拡張子を*.mjs
にする方法です。https://medium.com/the-node-js-collection/an-update-on-es6-modules-in-node-js-42c958b890c
このmjs拡張子(マイケルジャクソン拡張子)は、npm に蓄積された資産的な都合から提案されているのですが、 どちらかと言うと否定的な反応が多く観測されており、どうなるか揺れているようです。
実用上の課題が残っているブラウザも存在します。
- Firefox
- Firefox では
<script type="module" async>
を利用できません
- Firefox では
- Edge
- Edge 16 には同じモジュールを複数回実行するバグがあります。この不具合は Edge 17 で解消される見込みです
- Edge 16 にはMimeTypeを無視して実行するバグがあります
ES Modules に関するフラグの一覧です。
- Chrome
- Enable experimental features
- chrome://flags/#enable-experimental-web-platform-features
- Enable/Disable
<script type="module">
<script nomodule>
,import
,export
- chrome://flags/#enable-module-scripts
- Chrome 60 で追加、 63 で廃止になり disable 不能に
- Enable/Disable
import()
- chrome://flags/#enable-module-scripts-dynamic-import
- Chrome 63 で追加
- Enable/Disable
import.meta.url
- chrome://flags/#enable-module-scripts-import-meta-url
- Chrome 63 で追加
- Enable experimental features
- Node.js
- ES Modules
node --experimental-modules
- v9.3.0 で追加
- ES Modules
- Rollup.js
- Dynamic import
rollup --experimentalDynamicImport
- v0.56.0 で追加
- Dynamic import