JavaScriptの新しい仕様には、モジュールという仕組みがあります。現時点では一部のブラウザしか対応していませんが、ECMAScript 2015のModulesの標準仕様として策定されているため、やがて全てのブラウザで使えるようになっていくでしょう。この機能は、ES2015 Modules、ES6 Modules、ES Modules、ESMなどと呼ばれています(以下、ES Modulesと記載します)。

webpack 2+やRollup.jsなどのモダンなフロントエンドのツールを通して、すでにES Modulesを使っているエンジニアも多いと思います。この記事では、ブラウザネイティブで使えるES Modulesに焦点をあて、ES Modulesの導入で解決できる課題と利点を紹介します

HTML+JSではモジュールの仕組みがなかった

JavaScript自体には他のJSファイルを取り込む標準的な仕様がいままではありませんでした。従来だと、外部JS(例えばjQueryのライブラリなど)を読み込みたい時に、HTMLファイルにscriptタグを書き込むことで別ファイルを読み込んでいました。例えば次のようなコードです。

<script src="js/vender/jquery.min.js"></script>
<script src="js/vender/jquery.cookie.js"></script>
<script src="js/vender/jquery.easing.1.3.js"></script>
<script src="js/common.js"></script>
<script src="js/utils.js"></script>
<script src="js/app.js"></script>

この方法だと扱いづらい点があります。

  • HTMLファイルと密結合となる
  • JSファイル単独で管理できない
  • 読み込みの順番を気にしなければならない

これを解決するための手段として、様々なアプローチが登場しました。有名なところだと、AMD(+RequireJS)やCommonJS(+Browserify)などの技術があります。これらは独自仕様だったため、これからはES Modulesが標準仕様として取って代わっていくと考えられます。

サンプルで理解するES Modules

ES Modulesをブラウザで使うにはいくつか手順があります。サンプルを通して、一つ一つ抑えていきましょう。

利用可能なブラウザ

まずは利用できるブラウザを用意ください。デフォルトでES Modulesを使えるのは次のブラウザです。ES Modulesの搭載はSafariが先行していました。

  • iOS Safari 10.1以上 (2017年3月リリース)
  • macOS Safari 10.3以上 (2017年3月リリース)
  • Chrome 61以上 (2017年8月リリース)

▼ES Modulesのブラウザサポート状況。「Can I Use…」より

EdgeやFirefoxはフラグ設定でES Modulesを利用できるため、将来的にフラグ設定無しで搭載されるかもしれません。

読み込まれる側の処理

まずはモジュールとしての外部JSファイルを用意しましょう。次のコードはブラウザでアラートを表示するだけのサンプルコードです。

▼sample-alert.js

export function sayMessage(message) {
  alert(message);
}

外部ファイルのJSファイルではexport文を使って定義します。exportで宣言されたものだけが他のJSファイルから参照できます。

読み込む側の処理

HTMLには次のコードを記述します。従来はtype="text/javascript"と記載していましたが、ES Modulesを使う時はtype="module"と書きます。moduleを指定しないと、importexportなどのJSコード内の宣言がエラーとなります。

▼パターン1

<html>
<head>
  <meta charset="UTF-8">
  <script type="module">
    import {sayMessage} from "./sample-alert.js";
    sayMessage("こんにちは世界");
  </script>
</head>
<body>
</body>
</html>

src属性で外部ファイルを指定できます。インラインでも外部ファイルでも、どちらでもES Modulesを読み込めます。

▼パターン2

<html>
<head>
  <meta charset="UTF-8">
  <script type="module" src="index.js"></script>
</head>
<body>
</body>
</html>
import {sayMessage} from "./sample-alert.js";
sayMessage("こんにちは世界");

import文のfromの中では必ず./..//、といったパスで記述しなければなりません。xxx.jsというように記述するのはNGで、./xxx.jsとファイルパスを明確に記載します。拡張子も必須です。Node.jsでは拡張子無しの記述ができましたが、ブラウザでは必ず拡張子を記載ください。

これをブラウザで開くとJSファイルで記載されたコードが実行されていることがわかります。

外部JSも扱える

もう一つ興味深いサンプルを紹介しましょう。import文にはURLも指定できます。ES Modulesに対応した外部JSであれば、CDNから読み込めるので次のように記載できます。

<html>
<head>
  <meta charset="UTF-8">
  <script type="module">
    import * as THREE from 'https://cdnjs.cloudflare.com/ajax/libs/three.js/87/three.module.js';
    
    // Three.jsの起動コード (略)
  </script>
</head>
<body>
</body>
</html>

次の作例はWebGL用のJSライブラリThree.jsを使ったサンプルです。

注意点として、どのJSライブラリでもES Modulesとして読み込めるわけではありません。Three.jsはES Modulesで設計された数少ないJSライブラリです。有名どころだとjQueryやReact、Vue.jsなどはES Modulesとして配布されていないため、現時点ではブラウザネイティブではES Modulesとして利用できません。

次のページではES Modulesの課題や、モジュールバンドラーとの棲み分けについて紹介します。