Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

なぜJavaScriptには2つもモジュールシステムが混在しているのですか?(ES ModulesとCommonJS) #527

Closed
suin opened this issue Nov 25, 2022 · 0 comments · Fixed by #566

Comments

@suin
Copy link
Contributor

suin commented Nov 25, 2022

これをお読みの皆さんの中には、JavaScriptやTypeScript以外のプログラミング言語を経験したことがある人もいるかと思います。他の言語で、複数のモジュールシステムが共存している言語を使ったことはありますでしょうか。

JavaScriptには、系統が異なるモジュールシステムが、少なくとも2つ存在しています。ESモジュールとCommonJSです。こうした状況は、プログラミング言語としては、珍しいことです。JavaScriptのモジュールまわりを理解するのを難しくしている要因でもあります。

では、どうしてJavaScriptは2系統もモジュールシステムを持つようになったのでしょうか? ここでは、JavaScriptの現状に至る流れを歴史からひも解いていきます。

ひとつめのモジュールシステム

JavaScriptのモジュールシステムは、ブラウザよりも先んじて、サーバーサイドJavaScript、とりわけNode.jsの文脈で発展してきた経緯があります。

JavaScriptで広く普及しているモジュールシステムのひとつがCommonJSです。CommonJSの歴史をさかのぼると、2009年のServerJS発足に至ります。ServerJSはJavaScriptをサーバーサイドで使えるようにすることを目指し、サーバーサイドJavaScriptの共通APIを策定する標準化プロジェクトでした。のちに、CommonJSに改名されます。

サーバーサイドにJavaScriptを持ってくると一言で言っても、ブラウザのJavaScriptをそのまま持ち込んでもうまくいきません。たとえば、ブラウザには<script>タグがあるので、ひとつのページに複数の<script>タグを書くことで、複数のJavaScriptが実行できます。一方、サーバーサイドにはページという概念がありません。

また、当時のJavaScriptにはESモジュールのようなモジュールシステムもありませんでした。そのため、JavaScriptファイルを複数ロードできる仕組みを考えるところから始めなければなりませんでした。

そこで考え出された仕様がCommonJSのモジュールです。おなじみのrequire()module.exportsです。CommonJSは、モジュールシステムが存在しない当時のJavaScriptの文法や機能の枠を超えずに、関数や変数で工夫することで、モジュール的なものを成立させるものでした。

Node.jsはCommonJSと同時期にリリースされましたが、Node.jsに採用されたモジュールシステムがこのCommonJSでした。このおかげで、Node.jsにおいてはサーバーサイドJavaScriptでもファイルの分割と、複数ファイルのロードができるようになっていました。このモジュールシステムは、Node.jsユーザーに受け入れられはじめ、ライブラリを公開できるnpmなど、モジュールまわりのエコシステムも発展していきました。

ちなみに、CommonJSやNode.jsがスタートした2009年の前年には、ECMAScript 4草案破棄というショッキングな出来ごとがありました。ES4には、モジュールシステムをJavaScriptに追加する仕様も盛り込まれていました。もし、ES4が実現していたら、CommonJSは必要無かったかも知れません。現実はESの仕様を決めるブラウザベンダー間での意見と対立があり、JavaScriptを改善する動きは仲たがいで終わってしまいました。

Node.jsの登場時期がそんなバッドタイミングだったこともあり、JavaScript自体がモジュールシステムを改善するのはなかなか期待できない状況でした。そのため、Node.jsは既存のJavaScriptでできる範囲内の解決策として、モジュールシステムにCommonJSを採用したという見方もできます。

CommonJSはサーバーサイドで生まれ、発展してきました。CommonJSの土台に乗ったライブラリも数多く作られました。こうしたライブラリは、クライアントサイドでも需要がありました。そのため、webpackを筆頭にモジュールバンドラーはCommonJSをサポートしてきました。CommonJSの生い立ちはサーバーサイドではあったものの、モジュールバンドラーの対応によって、フロントエンドもCommonJSに頼る状況が醸成されました。

ふたつめのモジュールシステム

CommonJSの誕生から歴史は流れ、2015年になると、ES6という新しいJavaScriptの標準仕様が確定します。これはJavaScriptの10年数ぶりの大型アップデートです。そこには、ES6 Modulesというモジュールシステムを実現するための仕様も盛り込まれていました。皆さんご存知のimport文とexport文です。これは、JavaScript初のJavaScriptネイティブのモジュールシステムです。CommonJSが草の根活動で規格化されたモジュールシステムだとすると、ESモジュールは本家が発表した公式的・標準的なモジュールシステムだとも言えます。

JavaScript界は、サーバーサイドもクライアントサイドも関係なく、ES6に対応する中で、ES6 Modulesも導入する方向になり、2016年頃からESモジュール導入に向けて議論が始まりました。議論の中心は、やはり、在来のモジュールシステムであるCommonJSと新システムのESモジュールの共存についてです。

ESモジュールの仕様が確定する頃には、JavaScriptはCommonJS前提とした環境ができあがっていて、CommonJSに準拠したNPMパッケージも沢山あったため、CommonJSを切り捨てる選択肢はありませんでした。もしも、CommonJSを切り捨ててしまうと、過去の資産をほぼすべて失うことになるわけで、CommonJSとESモジュールの共存はNode.jsにとって重要なテーマだったのです。

例えば、サーバーサイドJavaScriptのNode.jsひとつとっても、長い議論のすえ、2017年にNode.js v8.5.0にて、ESモジュールが実験的な機能としてリリースされます。その後、2019年にv13.2.0にて、ESモジュールから「実験的な機能」というラベルが外れ、プロダクションで使われることを想定した機能に昇格しました。そして2020年には、CommonJSの名前付きエクスポートがESモジュールの名前付きインポートでロードできるようになり、次第にNode.jsでESモジュールを動かす環境が整ってきています。

ESモジュール環境が整備されてきたとは言っても、CommonJSは10年以上、JavaScriptを支えてきており、もはや切っても切れない関係になっています。そのため、今日現在においては、2つのモジュールシステムがJavaScriptに生きているわけです。

まとめ

  • JavaScriptにはCommonJSとESモジュールの2つのモジュールシステムがある。
  • CommonJSはJSと10年以上に及ぶ長く深いつながりがある。
  • JS界はCommonJSとESモジュールが共存する道を選んだ。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant