ホームページ  >  記事  >  ウェブフロントエンド  >  ああ、CommonJS!なぜ私と一緒にESMするのですか?! CommonJS を廃止する理由

ああ、CommonJS!なぜ私と一緒にESMするのですか?! CommonJS を廃止する理由

PHPz
PHPzオリジナル
2024-07-17 21:56:18701ブラウズ

それは通常のパッチ適用の日でした。コードを変更せずに npm の依存関係にパッチを適用してアップグレードしたところ、突然単体テストの一部が失敗しました。
Oh CommonJS! Why are you mESMing with me?! Reasons to ditch CommonJS

なんと!

Oh CommonJS! Why are you mESMing with me?! Reasons to ditch CommonJS

Jest が予期しないトークンに遭遇したため、テストは失敗しました。 Jest はそのままでは ESM のみのパッケージを処理できないため、失敗しました。実際、Jest は CommonJS で書かれています。
しかし、それは何を意味するのでしょうか?そのためには、CommonJS と ESM が存在する理由を理解する必要があります。

なぜモジュールシステムが必要なのでしょうか?

Web 開発の初期の頃、JavaScript は主に、jQuery などのライブラリを使用してドキュメント オブジェクト モデル (DOM) を操作するために使用されていました。ただし、Node.js の導入により、サーバーサイド プログラミングにも JavaScript が使用されるようになりました。この変化により、JavaScript コードベースの複雑さとサイズが増大しました。その結果、JavaScript コードを編成および管理するための構造化された方法の必要性が生じました。このニーズを満たすためにモジュール システムが導入され、開発者がコードを管理可能で再利用可能な単位に分割できるようになりました1.

CommonJS の登場

CommonJS は 2009 年に設立され、当初は ServerJS2 という名前でした。これはサーバーサイド JavaScript 用に設計されており、モジュールを定義するための規則を提供します。 Node.js は CommonJS をデフォルトのモジュール システムとして採用し、バックエンド JavaScript 開発者の間で普及しました。 CommonJS はモジュールのインポートに require を使用し、モジュールのエクスポートに module.exports を使用します。 CommonJS のすべての操作は同期的です。つまり、各モジュールは個別にロードされます。

ESM (ECMAScript モジュール) の台頭

2015 年、ECMAScript は、主にクライアント側の開発を対象とした、ECMAScript Modules (ESM) と呼ばれる新しいモジュール システムを導入しました。 ESM はインポートおよびエクスポート ステートメントを使用し、その操作は非同期であるため、モジュールを並行してロードできます3。当初、ESM はブラウザー向けに設計されていましたが、CommonJS はサーバー向けに設計されました。これはますます JS エコシステムの標準になりました。現在、最新の JavaScript ランタイムは両方のモジュール システムをサポートしています。ブラウザは 2017 年に ESM をネイティブにサポートし始めました。Typescript でさえ ESM 構文を採用しており、ESM 構文を学習するたびに、無意識のうちに ESM も学習することになります。

How Are you not dead.jpg

CommonJS は今後も存続します

実際には、ESM のみのパッケージよりも CommonJS (CJS) のみのパッケージの方がはるかに多く存在します4
Oh CommonJS! Why are you mESMing with me?! Reasons to ditch CommonJS
ただし、明らかな傾向があります。 ESM 専用パッケージまたはデュアル モジュール パッケージの数は増加傾向にありますが、CJS 専用パッケージの作成数は減少しています。この傾向は、ESM への関心が高まっていることを強調しており、CJS 専用パッケージのうちのどれくらいが積極的に保守されているのかという疑問を引き起こしています。

比較

CommonJS と ESM の興味深い比較には、パフォーマンス ベンチマークが含まれます。 CommonJS は同期的な性質があるため、require ステートメントと import ステートメントを直接使用すると高速になります。次の例を考えてみましょう:

// CommonJS -> s3-get-files.cjs
const s3 = require('@aws-sdk/client-s3');
new s3.S3Client({ region: 'eu-central-1' });

// ESM -> s3-get-files.mjs
import { S3Client } from '@aws-sdk/client-s3';

new S3Client({ region: 'eu-central-1' });

デュアル モジュール サポートがあるため、aws-sdk S3 クライアントを使用しました。ここではクライアントをインスタンス化し、node:
で実行します。

hyperfine --warmup 10 --style color 'node s3-get-files.cjs' 'node s3-get-files.mjs'

Benchmark 1: node s3-get-files.cjs
Time (mean ± σ): 82.6 ms ± 3.7 ms [User: 78.5 ms, System: 16.7 ms]
Range (min … max): 78.0 ms … 93.6 ms 37 runs
Benchmark 2: node s3-get-files.mjs
Time (mean ± σ): 93.9 ms ± 4.0 ms [User: 98.3 ms, System: 18.1 ms]
Range (min … max): 88.1 ms … 104.8 ms 32 runs

Summary
node s3-get-files.cjs ran
  1.14 ± 0.07 times faster than node s3-get-files.mjs

ご覧のとおり、s3-get-files.cjs と CommonJS はより高速に実行されます。
Buns のブログ投稿からインスピレーションを得ました。

ただし、JS ライブラリを製品化する場合は、それをバンドルする必要があります。それ以外の場合は、すべてのnode_modulesを出荷することになります。 CJSとESMにバンドルできるためesbuildを使用します。 次に、バンドルされたバージョンで同じベンチマークを実行してみましょう。

hyperfine --warmup 10 --style color 'node s3-bundle.cjs' 'node s3-bundle.mjs'

Benchmark 1: node s3-bundle.cjs
Time (mean ± σ): 62.1 ms ± 2.5 ms [User: 53.8 ms, System: 6.7 ms]
Range (min … max): 59.5 ms … 74.5 ms 45 runs

Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet system without any interferences from other programs. It might help to use the '--warmup' or '--prepare' options.

Benchmark 2: node s3-bundle.mjs
Time (mean ± σ): 45.3 ms ± 2.2 ms [User: 38.1 ms, System: 5.6 ms]
Range (min … max): 43.0 ms … 59.2 ms 62 runs

Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet system without any interferences from other programs. It might help to use the '--warmup' or '--prepare' options.

Summary

  node s3-bundle.mjs ran
    1.37 ± 0.09 times faster than node s3-bundle.cjs

ご覧のとおり、s3-bundle.mjs は s3-bundle.cjs よりも高速になりました。 ESM ファイルは、バンドルされていない CommonJS ファイルよりもさらに高速になりました。これは、効率的なツリーシェーキング (未使用のコードを削除するプロセス) によってファイル サイズが小さくなり、ロード時間が短縮されるためです。

ESMを受け入れましょう!

JavaScript モジュールの将来は間違いなく ESM に傾いています。これは、新しい NodeJS プロジェクト、または React プロジェクトを作成するときに始まります。すべてのチュートリアルと記事では import ステートメントが使用されており、これが ESM です。多くの CommonJS パッケージが既存しているにもかかわらず、パフォーマンス上の利点と最新の構文を求めて ESM を採用する開発者や保守者が増えるにつれて、傾向は変わりつつあります。もう 1 つの疑問は、これらの CJS のみのプロジェクトがどれだけまだ維持されているかということです。

ESM は、NodeJS、Bun、Deno などのあらゆるランタイムで、サーバー上で実行せずにブラウザーで動作する標準です。ブラウザは ESM を理解するため、Babel 経由で CommonJS に変換する必要はありません。 Babel を使用して別の ECMAScript バージョンに変換することはできますが、CJS に変換しないでください。

現在のすべてのランタイムと 2017 年以降のブラウザは ESM を理解するため、ESM のみで開発する必要があります。

コードが壊れた場合、従来の問題が発生している可能性があります。別のツールやパッケージの使用を検討してください。たとえば、Jest から vitest に移行したり、ExpressJS から h3 に移行したりできます。構文は同じままです。唯一の違いは import ステートメントです。

重要なポイント:

  • 小さいバンドル: ESM はツリーシェイキングを通じて小さいバンドルを生成し、読み込み時間の短縮につながります。
  • ユニバーサル サポート: ESM は、ブラウザーと JavaScript ランタイム (Node.js、Bun、Deno) によってネイティブにサポートされています。
  • 将来性: 継続的な採用により、ESM は最新の JavaScript モジュールの標準として位置付けられています。

始めるには、この要点に従うか、ここでインスピレーションを与える学習を得ることができます。

JavaScript のより良い未来のために、ESM を活用してください!

プレゼンテーション

その他のリソース

  • https://dev.to/logto/maigrate-a-60k-loc-typescript-nodejs-repo-to-esm-and-testing-become-4x-faster-22-4a4k
  • https://jakearchibald.com/2017/es-modules-in-browsers/
  • https://gist.github.com/joepie91/bca2fda868c1e8b2c2caf76af7dfcad3
  • https://gist.github.com/joepie91/bca2fda868c1e8b2c2caf76af7dfcad3

  1. https://www.freecodecamp.org/news/javascript-es-modules-and-module-bundlers/#why-use-modules ↩

  2. https://deno.com/blog/commonjs-is-hurting-javascript ↩

  3. https://tc39.es/ecma262/#sec-overview ↩

  4. https://twitter.com/wooorm/status/1759918205928194443 ↩

以上がああ、CommonJS!なぜ私と一緒にESMするのですか?! CommonJS を廃止する理由の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。