Cloudflare Workers現(xiàn)已支持更多NPM包:結(jié)合polyfill和原生代碼以支持Node.js API

來源:Cloudflare
作者:Cloudflare
時間:2024-11-01
742
我們很高興地宣布為Workers和Pages推出改進的Node.js兼容性預覽。更廣泛的兼容性讓您可以使用更多NPM包,并在編寫Workers時充分利用JavaScript生態(tài)系統(tǒng)的優(yōu)勢。

CBD99BD1-CD0B-46B3-977C-75A48F9461B0.jpeg

我們很高興地宣布為Workers和Pages推出改進的Node.js兼容性預覽。更廣泛的兼容性讓您可以使用更多NPM包,并在編寫Workers時充分利用JavaScript生態(tài)系統(tǒng)的優(yōu)勢。

我們最新版本的Node.js兼容性結(jié)合了我們先前努力實現(xiàn)的最佳特征。Cloudflare Workers以某種形式支持Node.js已有相當長一段時間了。我們于2021年首次宣布對polyfill的支持,后來隨著時間的推移不斷擴展對部分Node.js API的內(nèi)置支持。

最新的改進將帶來更多便捷:

-您可在Workers上使用更多NPM包。

-您可以使用不是用node:prefix導入Node.js API的包

-您可以在Workers上使用更多Node.js API,包括async_hooks、Buffer、dns、os和events上的大多數(shù)方法。許多其他方法(例如fs或process)都可以使用模擬方法來導入。

如要嘗試,請將以下標志添加到wrangler.toml,并使用Wrangler部署您的Worker:

compatibility_flags=【"nodejs_compat_v2"】

無法使用nodejs_compat導入的包(即使是作為另一個包的依賴)現(xiàn)已可以加載。其中包括流行的包,例如body-parser、jsonwebtoken、{}Got、passport、md5、knex、mailparser、csv-stringify、cookie-signature、stream-slice等。

對于所有啟用了現(xiàn)有nodejs_compat兼容性標志且兼容性日期為2024-09-23或之后的Workers,此行為很快將成為默認。在您試用改進的Node.js兼容性過程中,歡迎通過在GitHub提交問題來分享您的反饋。

Workerd不是Node.js

要了解這些最新變化,我們先來簡單了解一下Workers運行時與Node.js的不同之處。

Node.js主要專為直接在主機操作系統(tǒng)上運行的服務而構(gòu)建,是服務器端JavaScript的先驅(qū)。因此,它包括與主機交互所需的功能(例如process或fs),以及各種實用模塊(例如crypto)。

Cloudflare Workers在一個名為workerd的開源JavaScript/Wasm運行時上運行。雖然Node.js和workerd都是在V8上構(gòu)建的,但workerd設計為在共享進程中運行不受信任的代碼,暴露綁定以便與其他Cloudflare服務進行互操作,包括JavaScript原生RPC,并盡可能使用Web標準API。

Cloudflare幫助建立了WinterCG(Web互操作運行時社區(qū)小組),其旨在提高JavaScript運行時之間以及運行時與Web平臺的互操作性。您可以僅使用Web標準API構(gòu)建許多應用,但是當您想從NPM導入依賴于Node.js API的依賴項時,該怎么辦呢?

例如,如果您在未開啟Node.js兼容性的情況下嘗試導入pg(一個PostgreSQL驅(qū)動程序)……

230B2236-66EA-4120-91B1-784B30D1DFED.jpeg

當運行wrangler dev以構(gòu)建您的Worker時,將看到如下錯誤:

5D1FF29D-187B-421B-A617-5625D36DE66B.jpeg

發(fā)生這種情況是因為pg包從Node.js導入events模塊,而workerd默認情況下不提供該模塊。

我們?nèi)绾螌崿F(xiàn)這一點?

我們的第一種方法——構(gòu)建時polyfills

Polyfill是為原生不支持某項功能的運行時添加功能的代碼。這些代碼通常用于為舊版瀏覽器提供現(xiàn)代JavaScript功能,但也可以用于服務器端運行時。

在2022年,我們?yōu)閃rangler添加了功能,如果您在wrangler.toml中設置node_compat=true,則可以將一些Node.js API的polyfill實現(xiàn)注入Worker中。以下代碼在開啟該標志時可以正常工作,但在關閉時則不行:

7C8C6822-740F-4F24-8D58-A4D1462AEB8E.jpeg

這些polyfill本質(zhì)上就是在部署Worker時由Wrangler添加到Worker的額外JavaScript代碼。這個行為由esbuild-plugins/node-globals-polyfill支持實現(xiàn),后者本身使用rollup-plugin-node-polyfills。

這允許您導入和使用一些NPM包,例如pg。然而,許多模塊無法用足夠快的代碼進行polyfill,或者根本無法被polyfill。

例如,Buffer是用于處理二進制數(shù)據(jù)的常見Node.js API。存在支持它的polyfill,但JavaScript通常并沒有針對它在內(nèi)部執(zhí)行的操作進行優(yōu)化,例如copy、concat、子字符串搜索或轉(zhuǎn)碼。雖然可以用純JavaScript實現(xiàn),但如果底層運行時可以使用來自不同語言的基元,那么速度還會更快。其他流行的API,如Crypto、AsyncLocalStorage和Stream,也存在類似的限制。

我們的第二種方法——在Workers運行時中原生支持一些Node.js API

2023年,我們開始將一部分Node.js API直接添加到Workers運行時中。您可以通過向Worker添加nodejs_compatcompatible標志來啟用這些API,但不能同時將polyfills與node_compat=true一起使用。

此外,在導入Node.js API時,必須使用node:prefix:

AAC6BF76-D926-4B50-8D9A-533F81DA86C8.jpeg

由于這些Node.js API直接內(nèi)置于Workers運行時中,因此可以用C++編寫,這使得它們比JavaScript polyfill更快。像AsyncLocalStorage這樣的API(不能在不影響安全性和性能的情況下進行polyfill)可以原生提供。

要求node:prefix使導入更加明確,并與現(xiàn)代Node.js約定保持一致。不幸的是,現(xiàn)有的NPM包可能不使用node:導入。例如,回顧一下上面的示例,如果您在帶有nodejs_compat標志的Worker中導入流行程序包pg,您仍然會看到以下錯誤:

3A1FA26B-2121-4682-80C0-5FF81D094E86.jpeg

即使您啟用了nodejs_compat兼容性標志,許多NPM包仍然不能在Workers中運行。您必須在較小的高性能API集(以許多NPM包無法訪問的方式暴露)之間進行選擇,亦或是在較大的不完整、性能較低的API集之間進行選擇。而在Node.js中暴露為全局變量的API,例如process,仍然只能通過將其作為模塊導入來訪問。

新方式:混合模型

如果我們可以做到兩全其美并能順利運行,那會如何?

-在Workers運行時中直接實現(xiàn)的Node.js API子集

-適用于其他大多數(shù)Node.js API的Polyfill

-不需要node:prefix

-一個簡單的選擇使用方式

改進后的Node.js兼容性就能做到這一點。

我們來看看兩行代碼,看起來相似,但在啟用nodejs_compat_v2后,內(nèi)部行為有所不同:

75094108-A36C-4793-86DF-F8DE3F6002D3.jpeg

第一行從workerd中的JavaScript模塊導入Buffer,該模塊由C++代碼支持。其他各種Node.js模塊也類似地以Typescript和C++的組合實現(xiàn),包括AsyncLocalStorage和Crypto。這樣允許編寫與Node.js行為相匹配的高性能代碼。

請注意,導入buffer時不需要node:prefix,即使用node:buffer代碼也能工作。

第二行導入net,Wrangler使用一個名為unenv的庫自動polyfill。Polyfill和內(nèi)置運行時API現(xiàn)在可以協(xié)同工作。

在以前的版本中,當您設置node_compat=true時,Wrangler會在能夠的情況下為每個Node.js API添加polyfill,即使您的Worker及其依賴項都沒有使用該API。當您啟用nodejs_compat_v2compatible_flag時,Wrangler只會為您的Worker或其依賴項實際使用的Node.js API添加polyfill。結(jié)果是,即使使用了polyfill,Worker也會很小。

對于某些Node.js API,Workers運行時中尚未提供原生支持,也沒有polyfill實現(xiàn)。在這些情況下,unenv會“模擬”接口。這意味著它會將該模塊及其方法添加到您的Worker,但調(diào)用該模塊的方法要么不執(zhí)行任何操作,要么拋出錯誤,并顯示類似以下的消息:

【unenv】is not implemented yet!

這比看起來更為重要。因為如果一個Node.js API被“模擬”,那么依賴它的NPM包仍然可以被導入。請考慮以下代碼:

8B45EAE8-F3F4-4517-825A-5D68927386D2.jpeg

以前,即使啟用了現(xiàn)有的nodejs_compat兼容性標志,嘗試導入my-module也會在構(gòu)建時失敗,因為無法解析fs模塊。現(xiàn)在,fs模塊可以解析,不依賴于未實現(xiàn)的Node.js API的方法可以奏效,而那些確實拋出錯誤的方法會給出更具體的錯誤信息——一個運行時錯誤,表明某個特定的Node.js API方法尚不支持,而不是構(gòu)建時錯誤,指明模塊無法被解析。

這就是為什么某些包從“在Workers上甚至不加載”轉(zhuǎn)變?yōu)椤翱梢约虞d,但有一些不受支持的方法”。

依然缺少Node.js的某個API?模塊別名來幫忙

假設您需要一個NPM包在Workers上工作,其依賴于尚未在Workers運行時中實現(xiàn)的Node.js API,或作為unenv中的polyfill。您可以使用模塊別名來實現(xiàn)剛好足夠正常工作的API。

例如,假設您需要工作的NPM包調(diào)用fs.readFile。您可以通過將以下內(nèi)容添加到Worker的wrangler.toml來為fs模塊起別名:

53369474-B0ED-4672-BF51-E36FB9D17154.jpeg

然后,在fs-polyfill.js文件中,您可以定義自己對fs模塊的任何方法的實現(xiàn):

CCCB5B2F-67FB-4FDB-B0FA-B2D663381722.jpeg

以下代碼之前拋出錯誤信息“【unenv】readFile is not implemented yet!”,現(xiàn)在則可以正常運行:

A2ABBB54-250B-48F4-B854-BBFCF982A95B.jpeg

您還可以使用模塊別名來提供一個在Workers上不起作用的NPM包的實現(xiàn),即使您只是間接依賴該NPM包(作為您的Worker的某個依賴項的依賴項)。

例如,cross-fetch等一些NPM包依賴于node-fetch,后者在fetch()API在內(nèi)置到Node.js之前提供其polyfill。Workers中不需要node-fetch包,因為fetch()API由Workers運行時提供。node-fetch在Workers不能工作,因為它依賴的http和https模塊中的Node.js API目前不受支持。

您可以為node-fetch的所有導入設置別名,使其直接指向使用流行的nolyfill包內(nèi)置于Workers運行時的fetch()API:

0D7F713F-9D53-43F8-93C1-1356CF23C68A.jpeg

在這種情況下,您的替代模塊只需重新導出Workers運行時內(nèi)置的fetch API即可:

FA2448FF-2B8E-4AA7-8C5E-9D7032939164.jpeg

向unenv回報貢獻

Cloudflare正在為unenv積極做貢獻。我們認為unenv正在以正確的方式解決跨運行時兼容性問題——它會根據(jù)您使用的API和針對的運行時,僅向您的應用程序添加必要的polyfill。該項目支持也workerd之外的各種運行時,并且已經(jīng)被包括Nuxt和Nitro在內(nèi)的其他流行項目使用。我們要感謝Pooya Parsa和unenv的維護者,并鼓勵生態(tài)系統(tǒng)中的更多人采用或貢獻。

下一步

目前,您可以通過在wrangler.toml中設置nodejs_compat_v2標志來啟用改進的Node.js兼容性。我們從9月23日起使該新行為成為使用nodejs_compat標志時的默認行為。這將需要更新compatibility_date。

我們對即將到來的Node.js兼容性變化感到興奮,同時也十分鼓勵您即刻就進行嘗試。查看文檔,了解如何為你的Workers選擇加入。如果有任何反饋或錯誤,請通過提交問題告知我們。這樣可以幫助我們識別支持中的任何錯漏,確保盡可能多的Node.js生態(tài)系統(tǒng)能夠在Workers上運行。

立即登錄,閱讀全文
原文鏈接:點擊前往 >
文章來源:Cloudflare
版權說明:本文內(nèi)容來自于Cloudflare,本站不擁有所有權,不承擔相關法律責任。文章內(nèi)容系作者個人觀點,不代表快出海對觀點贊同或支持。如有侵權,請聯(lián)系管理員(zzx@kchuhai.com)刪除!
優(yōu)質(zhì)服務商推薦
更多
個人VIP