ECMAScript、ESM、CommonJSといった用語の理解が曖昧なので調べてみた。
はじめに
「ブラウザ側がESM(import)で、サーバーサイドがCommonJS(require)でしょ?」程度の曖昧な理解しかできていなかったので、今後もJSと関わっていく上である程度は理解しておいた方が良いと思い、簡単に調べてみました。
そもそもECMAScriptやCommonJSはJSの規格の一つ
ECMAScriptについて英語版のwikiを読むと、
ECMAScript (/ˈɛkməskrɪpt/) (or ES)[1] is a JavaScript standard meant to >ensure the interoperability of web pages across different web browsers.
(Google翻訳)さまざまなWebブラウザー間でのWebページの相互運用性を保証することを目的としたJavaScript標準です。
同様にCommonJSについてのwikiを読むと、
CommonJS is a project with the goal to establish conventions on the module >ecosystem for JavaScript outside of the web browser.
(Google翻訳) CommonJSは、Webブラウザーの外部でJavaScriptのモジュールエコシステムに関する規則を確立することを目的としたプロジェクトです。
よってどちらもJSの規格なのですが、ECMAScriptがモジュールシステム(ESM)以外の文法も定めている規格なのに対して、CommonJSはブラウザ外でのモジュールシステムに焦点を当てている規格のようです。
これらの規格はV8(JavaScriptエンジン)やNode(ランタイム)によって実装されています。
まとめ
以上を踏まえると、冒頭の「ブラウザ側がESM」という表現は、「ブラウザのJavaScriptエンジンが実装している言語仕様であるECMAScriptのモジュールシステムがESM」というとより正確な表現に近づくのではないかと思います。
また、「サーバーサイドがCommonJS」という表現に関しても、モジュールシステムに焦点を当てるのであれば、「サーバーサイドではCommonJSのモジュールシステムが使われている」という表現がより正確な気がします。実際に、NodeのドキュメントでもCommonJS modulesという用語が使われています。
補足1(エンジンとランタイムの違い)
ECMAScriptなどの言語仕様はV8(エンジン)やNode(ランタイム)によって実装されているという情報を読んで、エンジンとランタイムの違いが分からなかったので調べてみたところ、エンジンはコードを機械が実行可能な機械語に翻訳する役割を担当しているのに対して、ランタイムは外界とインタラクトするオブジェクトを提供しているそうです。(例えばChromeとNodeはV8という同じエンジンで動いているが、ランタイムが違うのでDOM APIはChromeのみで使用可能でFileSystem APIはNodeのみで使用可能。)
補足2(モジュールシステムの今後)
CommonJSが2009年に始まった一方で、2015年にはECMAScriptによりESMの仕様が策定されたことにより、ブラウザでもモジュールシステムが使えるようになりました。browserify等のパッケージを使わない限り、ブラウザではCommonJSのモジュールシステムを使うことができないので、ESMがJSのモジュールシステムの標準となりつつあります。
NodeではCommonJSのモジュールシステムがデフォルトですが、実はv14よりESMをフルサポートしています。様々な事情があり(https://redfin.engineering/node-modules-at-war-why-commonjs-and-es-modules-cant-get-along-9617135eeca1)、すぐにESMに移行することは難しいようですが、今後はサーバーサイドでもESMが標準となりそうです。
Discussion