這是正常的補丁日。我在沒有更改程式碼的情況下修補併升級了我的 npm 依賴項,突然間,我的一些單元測試失敗了。
臥槽!
我的測試失敗了,因為 Jest 遇到了意外的令牌;他們失敗了,因為 Jest 無法處理開箱即用的僅 ESM 套件。事實上,Jest 是用 CommonJS 寫的。
但這意味著什麼?為此,我們需要了解 CommonJS 和 ESM 存在的原因。
在 Web 開發的早期,JavaScript 主要用於透過 jQuery 等函式庫來操作文件物件模型 (DOM)。然而,Node.js 的引入也導致 JavaScript 被用於伺服器端程式設計。這種轉變增加了 JavaScript 程式碼庫的複雜性和大小。因此,需要一種結構化方法來組織和管理 JavaScript 程式碼。模組系統的引入就是為了滿足這種需求,使開發人員能夠將程式碼劃分為可管理、可重複使用的單元1.
CommonJS 成立於 2009 年,原名為 ServerJS2。它是為伺服器端 JavaScript 設計的,提供了定義模組的約定。 Node.js 採用 CommonJS 作為其預設模組系統,使其在後端 JavaScript 開發人員中流行。 CommonJS 使用 require 導入,使用 module.exports 導出模組。 CommonJS 中的所有操作都是同步的,這表示每個模組都是單獨載入的。
2015 年,ECMAScript 引進了一個名為 ECMAScript Modules (ESM) 的新模組系統,主要針對客戶端開發。 ESM使用導入和導出語句,其操作是非同步的,允許並行載入模組3。最初,ESM 是為瀏覽器設計的,而 CommonJS 是為伺服器設計的。它越來越成為 JS 生態系統的標準。如今,現代 JavaScript 運行時支援這兩種模組系統。瀏覽器從 2017 年開始原生支援 ESM。甚至 Typescript 也適配了 ESM 文法,每當你學習它時,你也在潛意識中學習 ESM。
事實是,僅 CommonJS (CJS) 的軟體包比僅 ESM 的軟體包多得多4.
然而,有一個明顯的趨勢。僅 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-Client,因為它有雙模組支援。這裡我們實例化客戶端,然後用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。使用 esbuild 因為它能夠捆綁到 CJS 和 ESM。 現在,讓我們使用捆綁版本來執行相同的基準測試。
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 檔案更快,因為由於有效的樹搖動(刪除未使用的程式碼的過程),它會導致更小的檔案大小和更快的載入時間。
JavaScript 模組的未來無疑傾向於 ESM。這在創建新的 NodeJS 專案甚至 React 專案時開始。每個教學和文章都使用 import 語句,這就是 ESM。儘管已有許多 CommonJS 包,但隨著越來越多的開發人員和維護人員因其效能優勢和現代語法而採用 ESM,這種趨勢正在改變。另一個問題是還有多少這些僅 CJS 的項目仍在維護中。
ESM 是一個可以在任何運行時(例如 NodeJS、Bun 或 Deno)以及瀏覽器中運行的標準,無需在伺服器上運行。沒有必要透過 Babel 轉換為 CommonJS,因為瀏覽器可以理解 ESM。您仍然可以使用 Babel 轉換為不同的 ECMAScript 版本,但不應轉換為 CJS。
您應該只使用 ESM 進行開發,因為現在的每個運行時間和 2017 年更新的瀏覽器都可以理解 ESM。
如果您的程式碼損壞,您可能會遇到遺留問題。考慮使用不同的工具或套件。例如,您可以從 Jest 遷移到 vitest,或從 ExpressJS 遷移到 h3。語法保持不變;唯一的差異是 import 語句。
關鍵要點:
要開始使用,您可以遵循此要點或在這裡獲得啟發性學習。
為了更好的 JavaScript 未來,擁抱 ESM!
示範
https://www.freecodecamp.org/news/javascript-es-modules-and-module-bundlers/#why-use-modules ↩
https://deno.com/blog/commonjs-is-hurting-javascript ↩
https://tc39.es/ecma262/#sec-overview ↩
https://twitter.com/wooorm/status/1759918205928194443 ↩
以上是噢,CommonJS!為什麼跟我聊天?放棄 CommonJS 的原因的詳細內容。更多資訊請關注PHP中文網其他相關文章!