- npm は、Cloudflare の workerd ランタイムを対象とするプロジェクトを構築するために必要な、コアの依存関係管理、バージョン管理、およびスクリプトを提供します。
- workd は、安全な Web 標準 API に重点を置いており、Node 固有のモジュールに互換性レイヤーを必要とする点で Node.js とは異なります。
- 新しい nodejs_compat_v2 モードは、ネイティブ C++ 実装、unenv ポリフィル、モックを組み合わせて、npm パッケージのサポートを大幅に改善します。
- モジュールのエイリアシングと選択的なポリフィルを使用すると、互換性のない依存関係の動作をカスタマイズし、Workers 上の npm エコシステムのさらなる活用が可能になります。
npmエコシステムとCloudflareのworkerdランタイムを組み合わせる 少し謎めいた響きに聞こえるかもしれませんが、その裏では、Node.jsスタイルのコードとパッケージをWeb中心のプラットフォーム上でスムーズに実行できるようにすることがすべてです。Cloudflare WorkersとPagesは、改良されたNode.js互換性レイヤーを提供するようになりました。これにより、ランタイム間の低レベルな差異に悩まされることなく、より多くのnpmパッケージをプルできるようになりました。
この記事では、npmパッケージがworkerdとどのように交差するか、そして新しい互換性フラグについて説明します。、一部のパッケージが以前は失敗していた理由と、 nodejs_compat_v2 モード。また、npm の動作(インストール、アップデート、スクリプト、依存関係の種類)が workrd をターゲットとするプロジェクトにどのように適合するかについても学習します。これにより、自信を持ってアプリを構築し、予期せぬ事態を回避できるようになります。
npmとは何か、そしてworkerdにとってなぜ重要なのか
npm Node.jsの事実上のパッケージマネージャーであり続けているは、サーバーサイドコードと今日のフロントエンドツールの大部分を支えています。当初はシンプルな依存関係管理ツールとして始まりましたが、瞬く間にユニバーサルレジストリとCLIへと進化し、ほぼすべてのJavaScript開発者が日常的に使用するようになりました。
npmレジストリには数百万のパッケージが含まれていますつまり、HTTPクライアント、認証、データベースドライバー、ビルドツール、テストフレームワークなど、ほぼあらゆる問題に対応するライブラリが存在する可能性が高いということです。workerdとCloudflare Workersにとって、このエコシステムは恩恵であると同時に課題でもあります。多くのツールにアクセスできる一方で、その多くはWeb標準環境ではなくNode.jsランタイムを想定して構築されています。
npmはフロントエンドのワークフローにおいても同様に中心的な役割を果たしているでは、バンドラ、トランスパイラ、リンターが開発時の依存関係としてインストールされます。React SPAを構築する場合でも、workerd上で実行されるWorkerスクリプトを構築する場合でも、依存関係とスクリプトの管理にはnpm(またはYarn/pnpm)を使用することになります。
npmはインストール、アップデート、依存関係の追跡を自動化します。モジュールを node_modules 記録要件 package.jsonworkerd ベースの Workers の場合、npm の設定は似ていますが、コードを実行するランタイムは Node.js 自体ではなく、workerd エンジンです。
Yarnやpnpmのような代替手段は、異なるCLIとパフォーマンス特性を提供します。ただし、workerd をターゲットとする場合の概念は同じです。パッケージ マネージャーがモジュールを解決し、Cloudflare のビルド ツールと互換性フラグによって、Worker ランタイムでそれらのモジュールを実行する方法が決まります。
npm による依存関係のインストールの仕組み

標準のnpm installコマンドを実行すると、 node_modules 依存関係リストを読み取り、リストされているすべてのパッケージをその推移的な依存関係とともに取り込むことで、ネストされた要件を手動で追跡する必要がなくなります。
新しいライブラリを追加するには、通常、単一のインストールコマンドを実行します。npm 5以降では自動的に dependencies のセクション package.json その動作を上書きしない限り。
npmは、プロジェクト内でパッケージがどのように使用されるかを分類するフラグをサポートしています。これは、異なるバンドルやビルド プロセスが必要な workrd などのランタイムをターゲットにする場合に便利です。
--save-devパッケージをdevDependenciesテスト ランナーやバンドラーなどの開発またはビルド ステップでのみ必要であるとマークします。--no-save変更せずにインストールpackage.json簡単な実験や 1 回限りのコマンドに便利です。--save-optionalパッケージをoptionalDependencies、インストールの失敗によってプロセス全体が中止されることはありません。--no-optionalオプションの依存関係がインストールされるのを防ぎ、フットプリントを削減したり、一部のプラットフォームで問題となるオプション パッケージを回避したりします。
違い dependencies および devDependencies 労働者のために建設する場合の問題通常、バンドルと出荷が必要なのは実行時の依存関係のみであり、開発時の依存関係はビルド中に削除されるため、デプロイメントは小さく抑えられます。
オプションの依存関係により、柔軟な障害処理が可能になりますただし、コードではそれらを利用する前に可用性を確認する必要があります。これは、パッケージがNode.jsとworkerdで異なる実装を使用する必要がある場合や、ネイティブモジュールがサポートされていない場合にフォールバックする必要がある場合に役立ちます。
npm プロジェクトの更新とバージョンの管理
npmのupdateコマンドは、宣言したsemver範囲に従ってパッケージをアップグレードします。インストールされたモジュールをスキャンし、直接の依存関係とネストされた依存関係の両方について、許可された最新バージョンに更新します。
必要に応じて単一のパッケージを更新することもできますライブラリが、Worker や、workerd などの非 Node ランタイムとの互換性に影響するバグ修正や改善をリリースする場合に役立ちます。
npmはセマンティックバージョニングに従うため、アップグレードの境界を正確に制御できます。これは、Worker が特定のメジャー バージョンに関連付けられたライブラリに依存している場合や、アップストリームで重大な変更が導入された場合に重要です。
バージョンをロックし、ロックファイルを使用することでビルドの再現性を維持できます、チームと CI 環境は、ローカルの開発、ステージング、および本番環境のワーカー全体で同じ依存関係グラフを生成します。
Workerdベースのワークフローにおけるnpmスクリプトと自動化
当学校区の scripts フィールドイン package.json スクリプトランナーとして機能します短い名前を長いCLIコマンドにマッピングして実行することができます。 npm run <script-name>.
現代のプロジェクトでは、ビルドツール、テスト、バンドラーをラップするためにnpmスクリプトを使用しています。、および workerd をターゲットとする Worker プロジェクトでは、通常、バンドル、型チェック、およびデプロイメント コマンドがこのように公開されます。
一般的なパターンは、スクリプトエントリを介してバンドラまたはタスクランナーを接続することです。複雑な CLI 呼び出しを、チーム全体がアクセスできる単純なコマンドに変換します。
スクリプトは、workerdのNode.js互換性フラグと組み合わせると強力になります。スクリプトでは、最終的な Worker をバンドルする前に、どの互換性オプションがアクティブになるか、どのポリフィルまたはエイリアスが適用されるかなどを制御できるためです。
workerd vs Node.js: ランタイムギャップを理解する
workerd エッジ実行に最適化されたオープンソースのJavaScriptおよびWebAssemblyエンジンです。は、Node.js や Chromium で使用されるものと同じ低レベル エンジンである V8 上に構築されていますが、異なる動作条件と信頼モデルで設計されています。
Node.jsはホストOS上でJavaScriptを実行するために作成され、強力なシステムAPIを公開しています。 など process, fs 低レベルの暗号化ユーティリティも備えているため、マシンに直接アクセスできるサーバー、CLI、バックエンド インフラストラクチャに最適です。
workrd は、マルチテナント エッジ プロセスで信頼できないコードを実行するように調整されています。分離とWeb中心のAPIを強調し、 fetch、ストリーム、および Cloudflare 固有のバインディング (KV、Durable Objects、内部 RPC) ではなく、ファイルシステムまたはプロセス アクセスを使用します。
相互運用性を向上させるために、CloudflareはWinterCGの設立を支援しましたは、サーバー側の JavaScript ランタイムと Web プラットフォームを共通の API セットに合わせて調整し、アプリが環境間で同じように動作するようにすることを目指しています。
しかし、多くのnpmパッケージはNode.js環境を想定しており、組み込みモジュールをインポートします。 ような events, fs, net, crypto or buffer互換性レイヤーがないと、workerd はノード固有のモジュールを自動的に提供しないため、これらのインポートは失敗する可能性があります。
ポリフィルからWorkersの組み込みNode.js APIまで
Cloudflareは当初、Node.jsとworkerdを橋渡しするためにポリフィルに依存していました。JavaScript実装を使用してNode APIを模倣しています。2021年にWorkersはポリフィルベースの互換モードを獲得し、Wranglerはこれらのポリフィルを注入し始めました。 node_compat = true に設定されました wrangler.toml.
自律的AI node_compat = trueWranglerはいくつかのコアNodeモジュールのJS実装をバンドルしましたのようなプラグインを活用して @esbuild-plugins/node-globals-polyfill および rollup-plugin-node-polyfills 例えば、 import EventEmitter from 'events' 労働者として働くことができます。
ポリフィルにより多くのnpmパッケージをWorkers上で実行できるようになりましたが、制限がありました。特に、大量のバイナリや暗号化の作業を実行するモジュールの場合、ネイティブ実装は純粋な JS シムよりもはるかに高速かつ正確です。
Buffer これは、ユーザーランドで効率的にエミュレートするのが難しい機能の明確な例です。コピーやエンコード変換などの操作は、最適化されたネイティブ実装の恩恵を受けるからです。同じことは、次のようなAPIにも当てはまります。 Crypto および AsyncLocalStorage.
パフォーマンスと完全性を向上させるために、CloudflareはいくつかのNode APIをランタイムに埋め込み始めました。 2023年に nodejs_compat フラグ。これらのコア モジュールは C++ で実装され、JS ポリフィルよりも忠実度を高めるためにワーカーに公開されます。
Workersで組み込みのNodeモジュールを使用する場合は、 node: 接頭辞例えば、 import { Buffer } from 'node:buffer'レジストリ パッケージではなく、ランタイム提供のモジュールへの依存関係を示します。
多くのnpmパッケージが初期のnodejs_compatで失敗する理由
早い nodejs_compat 多くのライブラリがプレフィックスなしのインポートを使用していたため、依然として失敗が発生しました例えば import { EventEmitter } from 'events'バンドラーはこれをファイルシステムモジュールとして扱い、存在しない場合は解決できませんでした。
次のようなドライバーをインポートするときによくあるエラーが発生しました pg プレフィックスのないコアモジュールに依存するこれによって、Node が組み込みであると認識しているにもかかわらず、ビルド ステップでモジュールが見つからないというエラーが発生します。
開発者は、ネイティブAPIサポートの少なさと、遅くて不完全なポリフィルセットの間でトレードオフに直面していた。、そして以下のようなグローバルが欠落している process 多くのライブラリがグローバル オブジェクト上に存在すると想定していました。
この摩擦により、workerd上で複雑なnpmパッケージを信頼性を持って使用することが困難になりました。特に間接的な依存関係が特定のノード モジュールまたはグローバルを期待している場合、ワーカーが実行される前にビルド時の障害が発生します。
新しい nodejs_compat_v2: workrd での npm サポートが向上
nodejs_compat_v2 ネイティブ実装とオンデマンドポリフィルを融合、C++ ベースのモジュール、JS ポリフィル、またはインポートを成功させる軽量スタブをいつ使用するかを決定することで、Workers でより多くの npm エコシステムを利用できるようになります。
このモードを有効にするには、 compatibility_flags = ["nodejs_compat_v2"] 〜へ wrangler.tomlこれにより、ランタイムが Node API を公開する方法と、Wrangler が Node スタイルのインポートと依存関係をバンドルする方法の両方が変更されます。
以前はインポートに失敗した多くのパッケージが、v2 では正しく読み込まれるようになりました。、以下のような図書館を含む body-parser, jsonwebtoken, got, passport, knex その他、サポートされていない操作に対するローカライズされた実行時フィードバックを優先してビルド時のエラーを削減します。
v2では次のようにインポートできます import { Buffer } from 'buffer' ランタイムはそれらを効率的にルーティングします C++ベースの実装に。同時に、次のようなモジュールは net Wranglerでポリフィルできる unenvネイティブ API とポリフィル API が競合することなく共存できるようになります。
Wrangler は、Worker が実際に使用する Node モジュールに対してのみポリフィルを挿入するようになりました。デフォルトでポリフィルの完全なスイートを出荷するのではなく、コードと依存関係を分析することでバンドル サイズを小さく保ちます。
unenv ポリフィルとモックされた Node.js API
ネイティブ実装や成熟したポリフィルが利用できない場合、 unenv モックモジュールを提供する 同じインターフェースを公開しますが、サポートされていないメソッドが呼び出されると、何も実行しないか、説明的なランタイム エラーをスローします。
次のようなエラー [unenv] <method name> is not implemented yet! より明確かつローカライズされたビルド時に中止するのではなく、非互換性をトリガーする呼び出しサイトでのみワーカーを開始して失敗できるようにします。
モックモジュールを使用すると、Nodeの機能に部分的に依存するパッケージをインポートして使用できます。サポートされていない部分を避けていれば、安全な部分は実行できますが、ファイル依存の操作は実行された場合にのみエラーが発生します。
これまで、 fs Workersでパッケージが使用できなくなる可能性があるしかし、と nodejs_compat_v2 unenv は依存関係をモックし、選択的に含めたり呼び出したりできます。
ビルド時フィードバックから実行時フィードバックへの移行によりデバッグが簡素化されるなぜなら、どのメソッドとコールスタックが非互換性を引き起こすのかを正確に特定し、コードを再構築したり、回避策として対象となるポリフィルやエイリアスを提供したりできるからです。
モジュールエイリアシング: 問題のある依存関係の動作をカスタマイズする
モジュールエイリアシングを使用すると、インポートを独自の実装にリダイレクトできます。、構成 wrangler.tomlそのため、問題のあるモジュール パスは、デフォルトの動作ではなく、カスタム ファイルに解決されます。
ライブラリが依存している場合 fs.readFile ただし、ファイルシステムへのアクセスは必要ありません。 "fs" 〜へ ./fs-polyfill カスタムを公開する readFile ログに記録したり、別の API を呼び出したり、KV から読み取ったりします。
エイリアシング後、次のようなインポート import { readFile } from 'fs' モジュールを解決し、unenvのデフォルトをバイパスします消費パッケージを変更せずに、「まだ実装されていません」というエラーを防止します。
エイリアシングは、依存関係がNode.js固有のパッケージをプルする場合にも役立ちます。 node-fetchはサポートされていないNodeモジュールに依存している可能性があります。 "node-fetch" グローバルを再エクスポートするモジュールに fetch.
のようなツール nolyfill 再エクスポートパターンを簡単にするこれにより、互換性のない実装を省略し、依存パッケージを workrd 上で機能させ続けることができます。
モジュールエイリアシングは、柔軟な互換性レイヤーとして機能します。 nodejs_compat_v2特定のパッケージを書き換えたりフォークしたりせずに適応させることができます。
パフォーマンス、エコシステムのコラボレーションと展開
重要なNode.js APIはworkerd内でC++でネイティブに実装されており、パフォーマンスと正確性が向上します。、および次のようなモジュール Buffer, AsyncLocalStorage および Crypto Node の動作を反映する JS シムにラップされたこれらのネイティブ実装のメリットを享受できます。
Cloudflareは unenvスマートなオンデマンドのポリフィルとモックを提供するこれは複数のランタイムを対象としており、Nuxt や Nitro などのプロジェクトで採用されているためです。必要なポリフィルのみを追加することで、アプリの軽量化が維持され、エコシステムの収束が促進されます。
より広い目的は、異なるランタイム間でのNodeスタイルのコードの移植性です。、開発者は一度記述すれば、使用状況に基づいてポリフィルとネイティブ機能を自動的に選択することで、最小限の摩擦で Node.js、workerd、またはその他の環境で実行できます。
改善された行動は nodejs_compat_v2 時間の経過とともにデフォルトになると予想される Worker の互換性日付が十分に新しい場合、追加の構成を行わなくても、より多くの Worker が強化された npm 互換性の恩恵を透過的に受けられるようになります。
開発者は改善されたNode.jsの互換性を試し、 wrangler.toml残っている非互換性やバグをフィードバック チャネルを通じて報告し、ギャップを埋めます。
npmの成熟した依存関係管理、workerdの安全なWeb中心のランタイム、進化するNode.js互換性レイヤーの組み合わせ エッジ実行、分離、そしてCloudflareのプラットフォーム機能を活用しながら、膨大な量の既存のJavaScriptコードを再利用するための実用的な方法を提供します。スマートなポリフィル、ネイティブ実装、モック、モジュールエイリアシングを活用すれば、ランタイムと常に格闘することなく、洗練されたnpmパッケージをWorkersプロジェクトに導入することがはるかに現実的になります。