一直以來(lái) Node.js 中存在一個(gè)問(wèn)題,CommonJS 與 ES Modules 如何更好的共存? 是令大多數(shù) Node.js 開發(fā)者頭疼的問(wèn)題。
當(dāng)在 ES Modules 模塊中引入 CommonJS 模塊代碼,一切是 Ok 的。如下代碼所示:
// c.jsmodule.exports = { moduleName: 'a'}
// m.mjsimport C_Module from './c.js'console.log(C_Module); // { moduleName: 'a' }
換一種方式,讓 CommonJS 引入 ES Modules,如下代碼所示:
// m.mjsexport default 'm'
// c.jsconst M_Module = require('./m.mjs')console.log(M_Module);
終端運(yùn)行 node c.js,會(huì)得到如下提示
圖片
ERR_REQUIRE_ESM 這個(gè)錯(cuò)誤太熟悉不過(guò)了,它困惑了很多的 Node.js 開發(fā)者,為什么換個(gè)順序就不行?
看到的很多答案是這樣的 “不支持使用 require 加載 ES 模塊,因?yàn)?ES 模塊是異步執(zhí)行的”,后面大家就默認(rèn)了 “CommonJS 是同步,ES Modules 是異步” 這樣的一個(gè)規(guī)則。
CommonJS 模塊如何加載 ES Modules 模塊,這個(gè)問(wèn)題 2019 年就已經(jīng)提出,參考 “Support requiring .mjs files” https://github.com/nodejs/node/pull/30891 這個(gè)問(wèn)題在當(dāng)時(shí)沒(méi)有被解決。
圖片
ES Modules 在文件頂層可以使用 Top-Level Await,該方法看之前的介紹,是在使用 esm 加載器加載的 .mjs 文件上使用 require 的功能時(shí),使用了與 esm Top-Level Await 相同的權(quán)衡。
這意味著:如果可能,所有執(zhí)行和評(píng)估都是同步進(jìn)行的,通過(guò)立即展開執(zhí)行的組件承諾。這意味著任何現(xiàn)有的代碼都不應(yīng)該有可觀察到的行為變化,因?yàn)榈侥壳盀橹惯€不存在任何異步模塊。問(wèn)題在于,一旦使用需要異步執(zhí)行的模塊,它必須讓出事件循環(huán)來(lái)執(zhí)行該操作,這反過(guò)來(lái)又允許其他代碼在異步操作之后的繼續(xù)執(zhí)行之前執(zhí)行,這對(duì)于現(xiàn)在變成了異步模塊的調(diào)用者是可觀察到的。如果這對(duì)你的調(diào)用者很重要,那么意味著將你的模塊執(zhí)行異步化可能被視為庫(kù)的破壞性更改,但實(shí)際上,對(duì)于大多數(shù)調(diào)用者來(lái)說(shuō),這并不重要。而且,由于當(dāng)前的生態(tài)系統(tǒng),零個(gè)模塊是異步執(zhí)行的,因此在有異步執(zhí)行的模塊之前,這種方法沒(méi)有任何缺點(diǎn),因?yàn)闆](méi)有執(zhí)行會(huì)改變?nèi)藗兘裉焖谕模ó?dāng)然,除了不再錯(cuò)誤地要求("./foo.mjs"))。
最后,問(wèn)題被關(guān)閉了,原因是 “因?yàn)榧兇鈴募夹g(shù)角度來(lái)看,目前嘗試在事件循環(huán)已經(jīng)運(yùn)行時(shí)旋轉(zhuǎn)它是行不通的”。
圖片
問(wèn)題是挺錯(cuò)綜復(fù)雜的,感興趣的可以去看看 2019 年提出的這個(gè) Issue。
2019 ~ 2024 這一令大多數(shù)開發(fā)者頭疼的問(wèn)題,由 Node.js 的維護(hù)者成員 “Joyee Cheung” 再次提出了解決方案。參考 Issue “module: support require()ing synchronous ESM graphs” https://github.com/nodejs/node/pull/51977
圖片
參考 Joyee Cheung 博客的介紹 https://joyeecheung.github.io/blog/2024/03/18/require-esm-in-node-js/
圖片
去年年底左右,Joyee Cheung 發(fā)現(xiàn)了 ESM 的求值可以基于語(yǔ)法同步,而只是 Node.js 將異步性扔到加載過(guò)程中后,便與 @GeoffreyBooth 開始討論重新啟動(dòng)同步 require(esm)。
因此,才有了這個(gè) PR。與 2019 年的 PR 相比主要區(qū)別在于它試圖將 require(esm) 的范圍保持小型,并且僅支持加載同步 ESM。
后續(xù)會(huì)通過(guò) --experimental-require-module 標(biāo)志啟用,則加載的 ECMAScript 模塊 require() 時(shí)要滿足以下要求:
有網(wǎng)友就在下面問(wèn)了,這能向后移至到 Node.js 18? 大家還是很喜歡這個(gè)功能的!Node.js v20 可能還有希望,這要取決于 Node.js 的發(fā)布團(tuán)隊(duì),期待下個(gè) Node.js 版本!
圖片
這一問(wèn)題的解決對(duì) Node.js 模塊來(lái)講是里程碑式的,很敬佩 Joyee Cheung 的才華!
本文鏈接:http://www.www897cc.com/showinfo-26-79450-0.html一個(gè)提出五年的 Node.js 模塊問(wèn)題,終被解決!
聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com
上一篇: 我們一起聊聊如何向文本添加漸變效果和圖案