自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

CommonJS 和 ES Module 終于能夠互相兼容了

開(kāi)發(fā) 前端
在 JavaScript 的世界里,模塊化是構(gòu)建大型應(yīng)用程序的基礎(chǔ)。模塊化幫助開(kāi)發(fā)者管理代碼而不影響全局命名空間,使得分離功能、重用代碼和管理依賴(lài)變得更加容易。在 Node.js 和瀏覽器環(huán)境中,有兩種主流的模塊系統(tǒng):CommonJS(CJS)和 ECMAScript Module(ESM)。

ECMAScript Module(ESM)逐漸成為現(xiàn)代 JavaScript 開(kāi)發(fā)中的公認(rèn)行業(yè)標(biāo)準(zhǔn)。自從 ESM 被引入到 Node.js 以來(lái),其異步加載特性和模塊解析邏輯受到了廣泛歡迎。

然而,由于歷史原因,許多現(xiàn)有代碼庫(kù)和第三方庫(kù)仍然依賴(lài)于 CommonJS(CJS)模塊系統(tǒng)。由于 ESM 的設(shè)計(jì)是異步加載的,這兩種模塊化方案一直無(wú)法共存,這成為了許多開(kāi)發(fā)者的一個(gè)主要痛點(diǎn)。

最近,開(kāi)發(fā)者 joyeecheung 提交了一個(gè)重要的 Pull Request 來(lái)解決這個(gè)問(wèn)題。

CJS 和 ESM 的過(guò)去與現(xiàn)在

在 JavaScript 的世界里,模塊化是構(gòu)建大型應(yīng)用程序的基礎(chǔ)。模塊化幫助開(kāi)發(fā)者管理代碼而不影響全局命名空間,使得分離功能、重用代碼和管理依賴(lài)變得更加容易。在 Node.js 和瀏覽器環(huán)境中,有兩種主流的模塊系統(tǒng):CommonJS(CJS)和 ECMAScript Module(ESM)。

CommonJS 是 Node.js 原生支持的模塊系統(tǒng),最初是為了滿(mǎn)足服務(wù)器端的模塊化需求。CJS 使用 require 函數(shù)來(lái)加載模塊,并使用 module.exports 或 exports 對(duì)象來(lái)暴露代碼。CJS 模塊的特點(diǎn)是同步加載,這意味著模塊加載完成后,代碼會(huì)立即執(zhí)行:

// math.js
function add(x, y) {
  return x + y;
}
module.exports = { add };

// app.js
const math = require('./math.js');
console.log(math.add(0, 17)); // 輸出 17

在服務(wù)器環(huán)境中,同步加載通常不是問(wèn)題,因?yàn)榇蠖鄶?shù)文件都是本地的。然而,在瀏覽器環(huán)境中,同步加載會(huì)導(dǎo)致性能問(wèn)題,因?yàn)樗鼤?huì)阻塞瀏覽器的事件循環(huán),直到腳本完全下載和解析完畢。

ESM 是現(xiàn)代 JavaScript 的官方標(biāo)準(zhǔn)模塊系統(tǒng),并且得到了最新版本瀏覽器的原生支持。與 CommonJS 不同,ESM 被設(shè)計(jì)為靜態(tài)的,這意味著不能在運(yùn)行時(shí)動(dòng)態(tài)加載或創(chuàng)建模塊。ESM 使用 import 和 export 語(yǔ)句進(jìn)行模塊的導(dǎo)入和導(dǎo)出,支持異步加載:

// math.js
export function add(x, y) {
  return x + y;
}

// app.js
import { add } from './math.js';
console.log(add(0, 17)); // 輸出 17

ESM 的設(shè)計(jì)允許瀏覽器優(yōu)化加載和解析過(guò)程,例如通過(guò) HTTP/2 高效并行加載和通過(guò)樹(shù)搖優(yōu)化去除未使用的代碼,從而提升性能和效率。然而,在 Node.js 中,ESM 的異步特性與大量現(xiàn)有的 CommonJS 模塊之間存在不兼容的問(wèn)題。

在 Node.js 中啟用 ESM 目前需要更復(fù)雜的方法,因?yàn)槟J(rèn)情況下,.js 文件擴(kuò)展名與 CommonJS 模塊關(guān)聯(lián)。為了解決這個(gè)問(wèn)題,Node.js 允許使用 .mjs 文件擴(kuò)展名或在 package.json 中顯式指定 "type": "module" 屬性來(lái)指示 ESM 模塊。

雖然 Node.js 支持導(dǎo)入 CommonJS 模塊,但卻無(wú)法通過(guò) require 加載 ESM 模塊。這種因 ERR_REQUIRE_ESM 錯(cuò)誤導(dǎo)致的挫敗感困擾了許多人,并且可能是 Node.js 生態(tài)系統(tǒng)內(nèi)時(shí)間浪費(fèi)的主要原因之一。

如果包作者希望確保 CJS 和 ESM 用戶(hù)都能使用他們的包,他們要么必須繼續(xù)發(fā)布 CJS 模塊,要么發(fā)布 CJS 和 ESM 版本的雙模塊(這可能會(huì)引發(fā)一些問(wèn)題,但現(xiàn)在已經(jīng)是一種非常普遍的做法)。

同時(shí),許多轉(zhuǎn)譯器(例如 TypeScript 編譯器)仍然配置為生成 CJS 代碼作為最終輸出。這些轉(zhuǎn)譯器的用戶(hù)使用 ESM 語(yǔ)法編寫(xiě)代碼,但他們可能不知道他們的代碼最終由 Node.js 作為 CJS 運(yùn)行。當(dāng)他們的代碼使用真正的 ESM 第三方模塊(無(wú)法被 require)時(shí),他們會(huì)看到 ERR_REQUIRE_ESM。這會(huì)非常令人困惑,因?yàn)樗麄兛赡苷J(rèn)為他們的代碼是作為真正的 ESM 運(yùn)行的。

為什么不能兼容?

自然,人們可能會(huì)問(wèn):為什么 require() 不支持加載 ESM?

長(zhǎng)時(shí)間以來(lái),Node.js 項(xiàng)目的回答一直是這樣的:

使用 require 加載 ES 模塊是不支持的,因?yàn)?ES 模塊是異步執(zhí)行的。

但是,這種情況中的文檔和其他形式的溝通可能會(huì)誤導(dǎo)人們——或許他們只是在談?wù)?Node.js 中的 ESM 發(fā)生了什么,而不是 ESM 本身的設(shè)計(jì)。去年,當(dāng) joyeecheung 在閱讀 V8 代碼以修復(fù)內(nèi)存泄漏問(wèn)題時(shí),他偶然發(fā)現(xiàn) ESM 本身并沒(méi)有被設(shè)計(jì)為無(wú)條件異步的。相反,它是有條件異步的——只有當(dāng)代碼中有頂級(jí) await 時(shí),它才會(huì)是異步的。

所以,支持 require() 加載不包含頂級(jí) await 的 ESM 并沒(méi)有什么問(wèn)題。雖然有些庫(kù)可能有正當(dāng)理由使用頂級(jí) await,但這可能并不常見(jiàn)。

事實(shí)上,當(dāng) joyeecheung 后來(lái)測(cè)試了 npm 注冊(cè)表上的大約 30 個(gè)僅通過(guò) ESM 提供支持的包時(shí),沒(méi)有一個(gè)包含頂級(jí) await——支持同步模塊的 require() 可能已經(jīng)解決了生態(tài)系統(tǒng)中的許多頭痛問(wèn)題。

早期探索和嘗試

對(duì) ESM 的支持經(jīng)歷了長(zhǎng)時(shí)間的討論、設(shè)計(jì)和實(shí)驗(yàn)。早在 2019 年,Node.js 社區(qū)就開(kāi)始探索如何支持 ESM 和 CommonJS 之間的互操作性。在此期間,許多開(kāi)發(fā)者提交了 Pull Requests,提出了不同的實(shí)現(xiàn)方案和改進(jìn)措施。

當(dāng)時(shí),一個(gè)里程碑式的 PR 討論集中在如何在 Node.js 中支持 .mjs 擴(kuò)展名的文件以及如何實(shí)現(xiàn)同時(shí)支持 CommonJS 和 ESM 的雙模塊系統(tǒng)。

該請(qǐng)求嘗試通過(guò)在加載器中循環(huán)事件來(lái)處理頂級(jí) await,但其方法不安全,這就是它被關(guān)閉的原因。

在規(guī)范方面,基于語(yǔ)法的 ESM 同步評(píng)估的理論基礎(chǔ)在 2019 年已經(jīng)確立。隨著時(shí)間的推移,在 Node.js 中似乎形成了一個(gè)關(guān)于“ESM 是異步的,CJS 是同步的,因此 CJS 不能加載 ESM”的神話(huà)。然而,在標(biāo)準(zhǔn)組織中,ES 規(guī)范特別確保 ESM 是有條件異步的。W3C 規(guī)范使用它來(lái)確保 Service Workers 只允許同步模塊評(píng)估。如果在 2019 年之后,規(guī)范中的語(yǔ)法同步性被更廣泛地認(rèn)識(shí)到,可能會(huì)有更多的嘗試,文檔也不會(huì)無(wú)條件地討論 ESM 作為異步的。

支持同步 require(esm)

去年底,joyeecheung 發(fā)現(xiàn)根據(jù)語(yǔ)法,ESM 可以是同步的,只有 Node.js 引入了異步到加載過(guò)程中。因此,joyeecheung 和 GeoffreyBooth 開(kāi)始討論重啟同步 require(esm)。

在 2024 年 2 月底,當(dāng) joyeecheung 在為 CJS 和 ESM 加載器做類(lèi)似緩存的工作并再次深入研究它們時(shí),他注意到似乎有一個(gè)更簡(jiǎn)單的實(shí)現(xiàn)方法——只需放棄“使 ESM 加載器成為 Node.js 中唯一加載器”的想法,并為 CJS 加載器實(shí)現(xiàn)一些專(zhuān)用程序以支持同步 require(esm)。使用的現(xiàn)有 ESM 加載器代碼越少,越容易實(shí)現(xiàn)。

于是,這個(gè) PR 誕生了。

https://github.com/nodejs/node/pull/51977。

與 2019 年的 PR 的主要區(qū)別在于,這次嘗試將 require(esm) 的范圍縮小,僅支持同步加載 ESM。事實(shí)證明,在技術(shù)指導(dǎo)委員會(huì)(TSC)中,這并不是一個(gè)有爭(zhēng)議的想法,并沒(méi)有引起太多爭(zhēng)議。

目前,該功能仍在通過(guò) --experimental-require-module 標(biāo)志進(jìn)行實(shí)驗(yàn),并且在退出實(shí)驗(yàn)階段之前需要完成一些工作。

目前,require(esm) 僅支持顯式標(biāo)記為 ESM 的 ESM 模塊——要么通過(guò) .mjs 擴(kuò)展名,要么通過(guò)使用 .js 擴(kuò)展名的 “type”: “module” 包字段。這足以支持 npm 中的 ESM-only 包。當(dāng)一個(gè) .js 文件包含 ESM 語(yǔ)法并且其最近的 package.json 中沒(méi)有 “type”: “module” 字段時(shí),它可以“回退”到 ESM 加載,但這是用戶(hù)應(yīng)該避免的事情——ESM 語(yǔ)法檢測(cè)會(huì)帶來(lái)開(kāi)銷(xiāo),一旦你的項(xiàng)目中有足夠的 ESM 模塊,你可能不希望 Node.js 浪費(fèi)時(shí)間猜測(cè)你的模塊類(lèi)型。特別是,只需在 package.json 中使用顯式的 “type”: “module” 字段,就可以節(jié)省這些開(kāi)銷(xiāo)。

最后

老實(shí)說(shuō),這個(gè)問(wèn)題困擾了我很長(zhǎng)時(shí)間。許多 NPM 包開(kāi)發(fā)者也深受其害。我希望 joyeecheung 的這次嘗試能夠盡快投入生產(chǎn)!

責(zé)任編輯:姜華 來(lái)源: 大遷世界
相關(guān)推薦

2021-08-11 07:54:47

Commonjs

2022-06-18 23:10:56

前端模塊循環(huán)依賴(lài)

2025-02-07 15:58:43

2023-11-08 08:40:35

JavaScriptS 模塊

2016-06-05 17:35:44

容器/虛擬化/東網(wǎng)科技

2023-10-31 07:40:15

EslintJSHint

2024-07-08 00:00:07

2013-01-22 10:54:51

HTML5App移動(dòng)應(yīng)用

2020-09-14 14:30:31

WindowsLinux命令

2020-02-23 16:33:02

GitHub印度子公司

2021-07-29 20:29:36

Linux c 代碼Java

2024-07-16 16:53:09

2022-05-03 20:48:17

Webpackcommonjsesmodule

2017-03-16 07:18:46

科技新聞早報(bào)

2022-08-18 20:44:34

HDFS架構(gòu)流程

2022-05-06 20:18:36

元宇宙Web 3.0網(wǎng)絡(luò)

2020-01-13 15:34:10

超融合邊緣計(jì)算架構(gòu)

2021-12-13 20:09:33

GoElasticsearJava

2024-05-07 16:19:33

以太全光園區(qū)網(wǎng)銳捷網(wǎng)絡(luò)

2021-07-26 05:00:16

算法DfsBfs
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)