モジュールの背景
JavaScript のプログラムはとても小さいものから始まりました。初期の用途は、必要に応じてウェブページにちょっとした対話的な機能を追加する独立したスクリプト処理がほとんどであったため、大きなスクリプトは通常必要ありませんでした。そして何年かが過ぎ、今や大量の JavaScript を持つ完全なアプリケーションをブラウザーで実行することはもちろん、JavaScript を他のコンテキスト(例えば Node.js)で使うこともあります。
複雑なプロジェクトでは、必要に応じて JavaScript プログラムを別個のモジュールに分割し、インポートできる仕組みが必要です。 Node.js は長年この機能を提供しており、モジュールの利用を可能にする JavaScript ライブラリーやフレームワークも数多くあります(例えば、他の CommonJS や、AMD ベースのモジュールシステムである RequireJS、 webpack や Babel)。
現行のブラウザーはすべて、トランスパイルを必要とせずにモジュール機能にネイティブで対応しています。これは良いことであるに違いありません。ブラウザーはモジュールの読み込みを最適化することができ、ライブラリーを使用してクライアント側で余分な処理や余分なラウンドトリップを行うよりも効率的です。しかし、 webpack のようなバンドラーが不要になるわけではありません。バンドラーは、コードを合理的なサイズの塊に分割する作業に依然として優れており、また、ミニファイ、デッドコードの排除、ツリーシェイクなどの最適化も可能です。
例の紹介
モジュールの使い方を紹介するために、GitHub 上に一連の例を作りました。これらは、ウェブページに <canvas> 要素を追加し、そのキャンバス上にいくつかの異なる図形(と、それに関するレポート)を描画するモジュールの例です。
このような機能はあまり役に立ちませんが、モジュールの説明が明確になるように意図的に単純にしています。
メモ: 使用例をダウンロードしてローカル実行する場合、ローカルのウェブサーバー上で実行する必要があります。
基本的な構造の例
最初の例 (basic-modules を参照) は、次のようなファイル構造になっています。
index.html
main.js
modules/
canvas.js
square.js
メモ: このガイドの使用例のファイル構造は、全て基本的に同一ですので、上記のファイル構造をよく見ることになるでしょう。
modules ディレクトリーには、次の 2 つのモジュールがあります。
-
canvas.js— キャンバスの設定に関する次の関数を持ちます。create()— 指定されたwidthとheightを持つキャンバスを、指定された ID を持つラッパー<div>の中に作成し、そのラッパー div 自体を指定された親要素の中に追加します。返値は、キャンバスの 2D コンテキストとラッパーの ID を持つオブジェクトです。createReportList()— 順序なしリストを指定されたラッパー要素の中に作成し、これをレポートデータを出力するために使うことができます。返値は、リストの ID です。
-
square.js— 次のものを持ちます。name—文字列 'square' を内容とする定数です。draw()— 正方形を、指定されたキャンバス上に、指定された辺の長さ、位置、色を使って描画します。返値は、正方形の辺の長さ、位置、色を持つオブジェクトです。reportArea()— 指定された辺の長さを持つ正方形の面積を、指定されたレポート用のリストに書き出します。reportPerimeter()— 指定された辺の長さを持つ正方形の周囲の長さを、指定されたレポート用のリストに書き出します。
余談 — .mjs と .js
この記事ではモジュールファイルに .js の拡張子を使用していますが、他の記事では .mjs という拡張子が使用されているのを目にすることがあるかもしれません。例えば、V8 のドキュメントではこれを推奨しています。理由は以下の通りです。
- どのファイルがモジュールで、どのファイルが通常の JavaScript であるかを明確にすることができます。
- これにより、Node.js のようなランタイムや Babel のようなビルドツールで、モジュールファイルがモジュールとして解析されるようになります。
しかし、少なくとも今のところは .js を使い続けることにしました。ブラウザーでモジュールを正しく動作させるためには、サーバーが Content-Type ヘッダーで JavaScript の MIME タイプ、例えば text/javascript などを含めて提供していることを確認する必要があります。そうしないと、"The server responded with a non-JavaScript MIME type" のような厳格な MIME タイプチェックエラーが表示され、ブラウザーは JavaScript を実行しません。ほとんどのサーバーでは、.js ファイルにはすでに正しい MIME タイプが設定されていますが、.mjs ファイルにはまだ設定されていません。すでに .mjs ファイルを正しく提供しているサーバーには、GitHub Pages や Node.js の http-server などがあります。
これは、すでにそのような環境を使用している場合や、今はまだ使用していないが、何をしているか知っていてアクセスできる場合には問題ありません(つまり、.mjs ファイルに正しい Content-Type を設定するようにサーバーを設定することができます)。しかし、あなたがファイルを提供しているサーバーを制御できない場合には、混乱を引き起こす可能性があります。
この記事では学習と移植性を考慮して、.js を使用することにしました。
通常の JavaScript ファイルに .js を使用するのと比較して、モジュールに .mjs を使用することの明確さを本当に重視しているが、上記の問題に直面したくない場合は、開発中に .mjs を使用し、ビルドステップで .js に変換することをおすすめします。
また、次の点にも注意してください。
- 一部のツールは
.mjsに対応していないことがあります。 - モジュールが指し示されているとき、それを示すために
<script type="module">属性を使用してください。
モジュール機能のエクスポート
モジュールが持つ機能にアクセスするために最初に必要なことは、そのような機能をエクスポートすることです。これは export 文を使って行います。
最も簡単な使い方は、モジュール外部に公開したい項目の前に export をつけることです。
export const name = "square";
export function draw(ctx, length, x, y, color) {
ctx.fillStyle = color;
ctx.fillRect(x, y, length, length);
return { length, x, y, color };
}
エクスポートできるものは、関数、var、