はじめに
CommonJSとESModulesという言葉をこれまで何度か目にしてきて、
「詳しくはわからないけどJavaScriptのモジュールシステムらしい。CommonJSは古くて、ESModulesが新しいらしい。」という曖昧な理解のまま放置してしまっていました。
最近Viteを学習する機会があり、
「ViteはESModules前提の設計なので、CommonJS構文であるrequire()はブラウザで動くアプリのソースコード上では使えない。import/exportに書き換える必要がある。」
というのを知りました。
CommonJSとESModulesの理解が浅かったため、この説明がよくわからない!!
ということでこの機にまとめます。
そもそもCommonJSとESModulesとは
CommonJS と ES Modules は「JavaScriptでファイルを分割して使うための仕組み(モジュールシステム)」です。
モジュールシステムとは「コードを分割し、必要なものだけを共有する仕組み」です。
つまり、CommonJSやES Modulesによって、別ファイルのコードをどのように読み込むかというルールが定められています。
モジュールシステムの歴史
モジュールシステムが何なのか理解するため、モジュールシステムがなぜ生まれたのか調べました。
1. モジュールがなかった時代のJavaScript
昔のJavaScriptは下記のように1ファイル=1世界でした。
<script src="a.js"></script>
<script src="b.js"></script>
<script src="c.js"></script>
a.jsやb.jsというようにファイルは分けられていても、全ての変数・関数が同じグローバル空間に置かれます。
これでは、変数名が衝突する・ファイルの読み込み順に依存・依存関係が分からない・大規模開発ができないなどの問題がありました。
ここで生まれたのがモジュールです。
モジュールシステムは上記の問題を解決するために4つの目的を持っています。
- スコープを分離する
- 依存関係を明示する
- 再利用可能にする
- 安全に共有する
2. CommonJSの誕生
CommonJSは2009年に誕生しました。
2009年にNode.jsが登場し、サーバーサイドでJavaScriptを使いたいという背景がありました。
しかし、サーバーでJavaScriptを使う場合、大量のファイルを扱うためにモジュールが必須でした。
そこでCommonJSが採用され、Node.jsとともに普及しました。
CommonJSの特徴と問題
CommonJSはサーバー用途に最適な形で進化し、下記のような特徴があります。
・必要になったときにrequire()で読み込み
・実行時に同期読み込み
const fs = require("fs")
module.exports = function(){}
一方、ブラウザにはCommonJSが標準搭載されていないため、そのままでは動きません。
ブラウザで使用するときは、モジュールバンドラーを使ってCommonJSモジュールを一度バンドルしてから使う必要がありました。
当時、Node.jsではCommonJSが使用され、ブラウザではAMDというモジュールシステムが使用されるなどJavaScriptに統一使用がない状態になっていました。
3. ECMAScript Modules(ES Modules)の誕生
そこで、ESModulesが2015年に誕生しました(ES2015)。
ES2015はECMAScriptの2015年版の仕様のことを指します。
つまり、JavaScriptの標準言語仕様として新たなモジュールシステムが追加され、それがES Modulesということです。
ECMAScriptとはJavaScriptの標準仕様を定めた国際規格です。
ESModulesの特徴
ESModulesはJavaScript言語の正式仕様であり、以下の特徴があります。
・import/exportを構文にした
・静的解析が可能
・静的importは実行前に依存関係を確定
export const x = 1;
import { x } from "./x.js";
「はじめに」で述べた疑問
「ViteはESModules前提の設計なので、CommonJS構文であるrequire()はブラウザで動くアプリのソースコード上では使えない。import/exportに書き換える必要がある。」は、
Viteが下記のようなES Moduleの設計を前提とし、開発時に ES Modules をそのままブラウザに配信する設計であため、ブラウザにそのまま渡すアプリケーションコード上では扱えないということだと理解できました。
【Vite設計の前提】
- ブラウザはES Modulesをネイティブに理解できる
(2017〜2018 年ごろから主要ブラウザで import / export がそのまま使えるようになった) - (静的importでは)依存関係は実行前に確定できる
まとめ
今回はVite学習の中で引っかかった点を深掘りましたが、Viteの理解を超えてJavaScriptの思想を理解することができました。
深ぼっていくと、これまで点で散らばっていたものが「そういうことか!」と線で繋がる感覚があって気持ちいいですね!
今後は、ちょっと気になったことを放置しないで納得いくまで調べていきたいと思います!