<script type="module">を試してみる

2018-01-06 #javascript  #es_modules  #html 

script type=“module”

scriptタグのtype属性に指定する値と言えば “text/javascript” が一般的だと思う。自分の使っているエディタ(Atom)でもスニペットでscriptタグを出力するとデフォルトで指定されている。

<script type="text/javascript"></script>

このtype属性はタグの中身(もしくはsrcで指定するファイル)がどのようなスクリプトで書かれているかをブラウザに教えるためのものなのだが、「scriptと言えば普通JavaScriptだよねー」ということでHTML5からはわざわざ書かなくても良くなっている。

ということで存在感の薄かったtype属性だが現在は module という値を指定することができるようになっている。これでscriptタグにES Moduleを書くことができる。

<script type="module">
// ES Module here!
</script>

type=“module”を指定せずにES Moduleを書くとSyntaxErrorになる。

<!-- Uncaught SyntaxError: Unexpected token import -->
<script>
import '/dummy.js';
</script>

ブラウザの対応状況はこんな感じ。主要なモダンブラウザでは軒並み使用可能になっている。(IE対応については後述)

デスクトップブラウザ 対応有無
Chrome 61
Edge 16
Firefox Yes
Internet Explorer No
Safari 10.1
モバイルブラウザ 対応有無
Android webview 61
Chrome for Android 61
Edge mobile 16
Firefox for Android Yes
iOS Safari 10.3

実際に使ってみる

単純なfunctionをexportするだけのES Moduleで試してみる。

// demo.js
export default () => {
  return "type=moduleでロードしました。";
}

このファイルをscriptタグで読み込んで使用する。

<script type="module">
import demo from '/js/post/20180106-script-type-module/demo.js';
document.querySelector('#moduleResult').innerHTML = demo();
</script>

実際にこのページで使っているので対応ブラウザで見ているなら↓に「type=moduleで実行されました。」と表示されるはず。



FireFoxなら about:config にアクセスして dom.moduleScripts.enabled の値を切り替えれば両方の挙動を確認することができるのでとても便利だ。

レガシーブラウザ対応

type=“module”は例によってIEが対応していないが、ちゃんと回避策が用意されている。

知らないtypeは無視される

そもそもブラウザが知らない値がtypeに指定されているとその内容は無視されるようになっている。 このページにも以下のscriptを仕込んでいるが実行はされないはずだ。

<script type="foo">
alert('実行されないはず');
</script>

だからtype=“module”を指定しても知らないブラウザはそれを無視してくれるので後方互換性が保たれるという仕組み。

“nomodule”を付加する

逆にtype=“module”を知らないブラウザ用にはscriptタグに nomodule を指定すれば良い。
これによって、type=“module”を…

  • 知っているブラウザ→実行しない
  • 知らないブラウザ→実行する

という挙動になる。

例によってこのページにも以下のscriptを仕込んでいる。

<script nomodule>
document.querySelector('#nomoduleResult').innerHTML = 'nomoduleで実行されました。';
</script>

type=“module”に対応していないブラウザなら↓にメッセージが表示されるはずだ。



これで何が嬉しいかというと、モダンブラウザ向けとレガシーブラウザ向けのjsファイルを切り替えることができる。

<!-- どちらかしかロードされない -->
<script type="module" src="for-modern-browser.js"></script>
<script nomodule src="for-legacy-browser.js"></script>

こちらのブログでは「モダンブラウザ向けにBabelを通したjsファイル」に対して、「レガシーブラウザ向けにBabelを通したjsファイル」はファイルサイズ、ブラウザが内容を評価する時間ともに倍になるという結果が示されている。パフォーマンスが重要なら利用する価値があるかもしれない。


References

  1. https://blog.whatwg.org/js-modules
  2. https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script
  3. https://jakearchibald.com/2017/es-modules-in-browsers/
  4. https://philipwalton.com/articles/deploying-es2015-code-in-production-today/