- npm zapewnia podstawowe funkcje zarządzania zależnościami, kontroli wersji i tworzenia skryptów niezbędne do strukturyzowania projektów, które są przeznaczone dla środowiska wykonawczego Cloudflare.
- workerd różni się od Node.js tym, że koncentruje się na bezpiecznych, zgodnych ze standardami internetowymi interfejsach API i wymaga warstw kompatybilności dla modułów specyficznych dla Node.
- Nowy tryb nodejs_compat_v2 łączy natywne implementacje C++, polyfille unenv i mocki, co znacznie poprawia obsługę pakietów npm.
- Aliasowanie modułów i selektywne wypełniacze typu polyfill umożliwiają dostosowanie zachowania w przypadku niezgodnych zależności i odblokowanie większej części ekosystemu npm w ramach procesów roboczych.
Łączenie ekosystemu npm z roboczym środowiskiem wykonawczym Cloudflare Może to brzmieć nieco tajemniczo, ale tak naprawdę chodzi o to, aby kod i pakiety w stylu Node.js działały płynnie na platformie zorientowanej na internet. Cloudflare Workers i Pages oferują teraz ulepszoną warstwę kompatybilności z Node.js, która pozwala na pobieranie znacznie większej liczby pakietów npm bez konieczności radzenia sobie z różnicami niskiego poziomu między środowiskami wykonawczymi.
W tym artykule wyjaśniono, w jaki sposób pakiety npm łączą się z pakietem Worked i nowymi flagami zgodnościpokazując, dlaczego niektóre pakiety zawodziły i jakie zmiany wprowadza nodejs_compat_v2 Zobaczysz również, jak zachowania npm (instalacja, aktualizacje, skrypty i typy zależności) pasują do projektów ukierunkowanych na Worker, dzięki czemu możesz pewnie strukturyzować aplikacje i unikać niespodzianek.
Czym jest npm i dlaczego ma to znaczenie dla Worked
npm pozostaje faktycznym menedżerem pakietów dla Node.js, obsługujący zarówno kod po stronie serwera, jak i znaczną część dzisiejszych narzędzi front-endowych. Zaczęło się jako prosty menedżer zależności, ale szybko przekształciło się w uniwersalny rejestr i interfejs wiersza poleceń, z którymi praktycznie każdy programista JavaScript ma do czynienia na co dzień.
Rejestr npm zawiera miliony pakietów, co oznacza, że prawdopodobnie istnieje biblioteka dla niemal każdego problemu: klientów HTTP, uwierzytelniania, sterowników baz danych, narzędzi do kompilacji, frameworków testowych i wielu innych. Dla Workerów Workerów i Cloudflare Workerów ten ekosystem jest zarówno błogosławieństwem, jak i wyzwaniem: uzyskujesz dostęp do wielu narzędzi, ale wiele z nich zostało stworzonych z myślą o środowisku uruchomieniowym Node.js, a nie o standardowym środowisku internetowym.
npm jest równie istotny dla przepływów pracy front-end, gdzie bundlery, transpilery i lintery są instalowane jako zależności w czasie tworzenia. Niezależnie od tego, czy tworzysz React SPA, czy skrypt Worker działający na Worker, prawdopodobnie użyjesz npm (lub Yarn/pnpm) do zarządzania zależnościami i skryptami.
W swojej istocie npm automatyzuje instalację, aktualizacje i śledzenie zależności, utrzymując moduły w node_modules i wymagania dotyczące rejestrowania w package.jsonW przypadku Workerów opartych na mechanizmach roboczych konfiguracja npm wygląda znajomo, ale środowiskiem wykonawczym wykonującym kod jest silnik Workerów, a nie sam Node.js.
Alternatywy takie jak Yarn i pnpm oferują różne interfejsy wiersza poleceń i cechy wydajnościowe, ale w przypadku pakietu workerd koncepcja jest taka sama: menedżer pakietów rozwiązuje moduły, podczas gdy narzędzia do kompilacji i flagi zgodności Cloudflare decydują o sposobie wykonywania tych modułów w środowisku wykonawczym Worker.
Jak działa instalacja zależności z npm

Uruchomienie standardowego polecenia npm install powoduje wypełnienie node_modules odczytując listy zależności i pobierając każdy wymieniony pakiet wraz z jego zależnościami przechodnimi, dzięki czemu nie musisz ręcznie śledzić zagnieżdżonych wymagań.
Aby dodać nową bibliotekę, zazwyczaj uruchamiasz pojedyncze polecenie instalacyjnei od npm 5 jest automatycznie dodawany do dependencies odcinek package.json chyba że zmienisz to zachowanie.
npm obsługuje flagi klasyfikujące sposób wykorzystania pakietu w projekcie, co jest przydatne w przypadku środowisk wykonawczych, takich jak workered, w których można chcieć użyć różnych pakietów lub procesów kompilacji:
--save-devdodaje pakiet dodevDependencies, oznaczając je jako potrzebne wyłącznie na etapie rozwoju lub kompilacji, jak w przypadku programów uruchamiających testy lub pakietujących.--no-saveinstaluje się bez modyfikacjipackage.json, przydatne do szybkich eksperymentów lub jednorazowych poleceń.--save-optionalumieszcza pakiet woptionalDependencies, więc błędy instalacji nie przerywają całego procesu.--no-optionalzapobiega instalowaniu opcjonalnych zależności, zmniejszając w ten sposób zajmowaną przestrzeń lub zapobiegając problematycznym opcjonalnym pakietom na niektórych platformach.
Różnica pomiędzy dependencies oraz devDependencies sprawy przy budowaniu dla pracownikówponieważ zazwyczaj pakowanie i dostarczanie wymagają tylko zależności środowiska wykonawczego; zależności deweloperskie są usuwane podczas kompilacji, dzięki czemu wdrożenia są mniejsze.
Opcjonalne zależności zapewniają elastyczną obsługę błędów, ale Twój kod musi sprawdzić dostępność, zanim na nich skorzystasz. Jest to pomocne, gdy pakiet powinien używać innych implementacji w Node.js niż w Worked lub gdy moduł natywny nie jest obsługiwany.
Zarządzanie aktualizacjami i wersjami w projektach npm
Polecenie update npm aktualizuje pakiety zgodnie z zadeklarowanymi przez Ciebie zakresami semver, skanowanie zainstalowanych modułów i aktualizowanie ich do najnowszych dozwolonych wersji zarówno dla zależności bezpośrednich, jak i zagnieżdżonych.
W razie potrzeby można również aktualizować pojedynczy pakiet, przydatne, jeśli biblioteka wyda poprawkę błędu lub ulepszenie, które ma wpływ na Twojego Workera lub jego zgodność z środowiskami wykonawczymi innymi niż Node, takimi jak workerd.
npm stosuje wersjonowanie semantyczne, co pozwala na precyzyjną kontrolę granic aktualizacji, co jest szczególnie ważne, gdy Twój Worker zależy od biblioteki powiązanej z konkretną główną wersją lub gdy wprowadzane są zmiany powodujące przerwanie działania systemu.
Blokowanie wersji i używanie plików blokady pozwala na powtarzalność kompilacji, dzięki czemu zespoły i środowiska CI generują ten sam graf zależności dla lokalnych pracowników ds. rozwoju, przygotowania i produkcji.
skrypty npm i automatyzacja w przepływach pracy opartych na pracownikach
scripts pole w package.json służy jako Twój program uruchamiający skrypty, umożliwiając mapowanie krótkich nazw na dłuższe polecenia CLI i wykonywanie ich za pomocą npm run <script-name>.
Nowoczesne projekty wykorzystują skrypty npm do pakowania narzędzi do kompilacji, testów i pakietów, a projekty Worker przeznaczone dla pracowników zwykle udostępniają w ten sposób polecenia pakowania, sprawdzania typów i wdrażania.
Typowym wzorcem jest podłączanie pakietu lub programu uruchamiającego zadania za pomocą wpisu skryptu, zmieniając złożone wywołanie CLI w proste polecenie dostępne dla całego zespołu.
Skrypty stają się potężne, gdy połączy się je z flagami zgodności Node.js dla workd, ponieważ skrypty mogą kontrolować, które opcje zgodności są aktywne i jakie polyfille lub aliasy są stosowane przed dołączeniem końcowego Workera.
Worker kontra Node.js: zrozumienie luki w czasie wykonywania
workerd jest silnikiem JavaScript i WebAssembly o otwartym kodzie źródłowym, zoptymalizowanym pod kątem wykonywania na krawędzi, zbudowany na bazie V8 — tego samego silnika niskiego poziomu, z którego korzystają Node.js i Chromium — ale zaprojektowany z uwzględnieniem innych warunków operacyjnych i modeli zaufania.
Node.js został stworzony do uruchamiania JavaScript na systemie operacyjnym hosta i udostępnia potężne interfejsy API systemu jak na przykład process, fs i niskopoziomowych narzędzi kryptograficznych, dzięki czemu idealnie nadaje się do serwerów, interfejsów wiersza poleceń i infrastruktury zaplecza z bezpośrednim dostępem do maszyn.
workerd jest dostrojony do uruchamiania niezaufanego kodu w wielodostępnych procesach brzegowych, kładąc nacisk na izolację i interfejsy API zorientowane na sieć, takie jak fetch, strumienie i powiązania specyficzne dla Cloudflare (KV, obiekty trwałe, wewnętrzne RPC), a nie dostęp do systemu plików lub procesu.
Aby poprawić interoperacyjność, Cloudflare pomógł w utworzeniu WinterCG, którego celem jest dostosowanie środowisk uruchomieniowych JavaScript po stronie serwera i platformy internetowej do wspólnego zestawu interfejsów API, tak aby aplikacje zachowywały się podobnie we wszystkich środowiskach.
Jednak wiele pakietów npm zakłada środowisko Node.js i importuje wbudowane moduły lubić events, fs, net, crypto or bufferBez warstwy kompatybilności te importy mogą się nie powieść, ponieważ workerd nie dostarcza automatycznie modułów specyficznych dla węzła.
Od polyfillów do wbudowanych interfejsów API Node.js w Workers
Początkowo Cloudflare opierał się na polyfillach, aby połączyć Node.js i workflow, wykorzystując implementacje JavaScript do naśladowania interfejsów API Node. W 2021 roku Workers zyskał tryb zgodności oparty na polyfillach, a Wrangler zaczął wstrzykiwać te polyfille, gdy node_compat = true został ustawiony w wrangler.toml.
Wraz z node_compat = trueWrangler dołączył implementacje JS dla kilku podstawowych modułów Node, wykorzystując wtyczki takie jak @esbuild-plugins/node-globals-polyfill oraz rollup-plugin-node-polyfills więc importy takie jak import EventEmitter from 'events' mógłby pracować w Worker.
Polyfille umożliwiły uruchamianie wielu pakietów npm na serwerach roboczych, ale miały ograniczenia, szczególnie w przypadku modułów wykonujących intensywne operacje binarne lub kryptograficzne, w których natywne implementacje są znacznie szybsze i dokładniejsze niż czyste podkładki JS.
Buffer jest wyraźnym przykładem funkcji, którą trudno efektywnie emulować w środowisku użytkownika, ponieważ operacje takie jak kopiowanie i kodowanie konwersji korzystają ze zoptymalizowanych implementacji natywnych. To samo dotyczy interfejsów API, takich jak Crypto oraz AsyncLocalStorage.
Aby poprawić wydajność i kompletność, Cloudflare zaczął osadzać niektóre interfejsy API Node w środowisku wykonawczym w 2023 roku za pośrednictwem nodejs_compat flaga; te główne moduły są implementowane w C++ i udostępniane Workers dla zapewnienia większej wierności niż w przypadku wypełniaczy JS.
W przypadku korzystania z wbudowanych modułów Node w Workers należy je zaimportować za pomocą node: prefiks, Na przykład import { Buffer } from 'node:buffer', sygnalizując zależność od modułu dostarczonego przez środowisko wykonawcze, a nie od pakietu rejestru.
Dlaczego wiele pakietów npm nadal nie działa z wczesnym nodejs_compat
Wcześnie nodejs_compat nadal powodowało błędy, ponieważ wiele bibliotek używało importów bez prefiksunp. import { EventEmitter } from 'events', które pakiet traktował jako moduły systemu plików i nie był w stanie ich rozwiązać, gdy ich nie było.
Podczas importowania sterowników, takich jak pg które zależą od modułów rdzeniowych bez prefiksupowodując, że podczas kompilacji pojawia się komunikat informujący, że moduł nie został znaleziony, mimo że Node traktuje go jako wbudowany.
Deweloperzy stanęli przed wyborem pomiędzy małym natywnym wsparciem API a wolniejszym, niekompletnym zestawem polyfill, plus brakujące zmienne globalne, takie jak process że wiele bibliotek zakładało, że będzie istnieć w obiekcie globalnym.
To tarcie utrudniało niezawodne używanie złożonych pakietów npm w systemie Worked, szczególnie gdy zależności pośrednie oczekiwały określonych modułów węzła lub zmiennych globalnych, co prowadziło do błędów kompilacji przed uruchomieniem procesu roboczego.
Nowy nodejs_compat_v2: lepsza obsługa npm w workd
nodejs_compat_v2 łączy natywne implementacje z wypełnieniami na żądanie, dzięki czemu znacznie większa część ekosystemu npm staje się użyteczna w Workers, poprzez decydowanie, kiedy używać modułów opartych na C++, polyfillów JS lub lekkich stubów, które umożliwiają powodzenie importów.
Włącz ten tryb, dodając compatibility_flags = ["nodejs_compat_v2"] do wrangler.toml, która zmienia zarówno sposób, w jaki środowisko wykonawcze udostępnia interfejsy API Node, jak i sposób, w jaki Wrangler pakuje importy i zależności w stylu Node.
Wiele pakietów, których wcześniej nie dało się zaimportować, teraz ładuje się poprawnie w wersji 2, w tym biblioteki takie jak body-parser, jsonwebtoken, got, passport, knex i inne — zmniejszając liczbę błędów kompilacji na rzecz lokalnych informacji zwrotnych w czasie wykonywania dla nieobsługiwanych operacji.
W wersji 2 możesz zapisywać importy w następujący sposób: import { Buffer } from 'buffer' a środowisko wykonawcze skutecznie je kieruje do implementacji opartych na C++; w tym samym czasie moduły takie jak net może być wypełniony polifilem przez Wrangler przy użyciu unenv, umożliwiając natywnemu i polifilowanemu interfejsowi API współistnienie bez konfliktów.
Wrangler teraz wstrzykuje polyfille tylko do modułów Node, z których faktycznie korzysta Twój Worker, utrzymując rozmiary pakietów na niskim poziomie poprzez analizę kodu i zależności zamiast dostarczania domyślnie pełnego zestawu polyfillów.
polyfille unenv i mockowane interfejsy API Node.js
Jeśli natywna implementacja lub dojrzały polyfill jest niedostępny, unenv zapewnia wymuszone moduły które udostępniają te same interfejsy, ale albo wykonują operacje no-op, albo generują opisowe błędy czasu wykonania, gdy wywoływane są nieobsługiwane metody.
Błędy takie jak [unenv] <method name> is not implemented yet! są bardziej wyraźne i zlokalizowane, pozwalając, aby proces roboczy został uruchomiony i zakończył się niepowodzeniem tylko w miejscu wywołania, które wywołało niezgodność, zamiast przerywać go w czasie kompilacji.
Moduły wymuszone pozwalają na importowanie i używanie pakietów, które częściowo zależą od funkcji Node, o ile unikasz nieobsługiwanych części; bezpieczne części mogą być uruchamiane, natomiast operacje zależne od pliku wyzwalają błędy tylko w przypadku wykonania.
Wcześniej każdy import fs może sprawić, że pakiet stanie się bezużyteczny w Workers, ale z nodejs_compat_v2 unenv mocks umożliwia selektywne uwzględnianie i wywoływanie zależności.
To przejście od informacji zwrotnej z czasu kompilacji do czasu wykonania upraszcza debugowanie, ponieważ można dokładnie określić, która metoda i stos wywołań powodują niezgodność, a następnie przebudować kod lub dostarczyć ukierunkowane polyfille lub aliasy jako obejście problemu.
Aliasowanie modułów: dostosowywanie zachowania w przypadku problematycznych zależności
Aliasowanie modułów pozwala na przekierowywanie importów do własnych implementacji, skonfigurowany w wrangler.toml, więc problematyczna ścieżka modułu kieruje do pliku niestandardowego zamiast domyślnego zachowania.
Jeśli biblioteka jest zależna od fs.readFile ale nie potrzebujesz dostępu do systemu plików, alias "fs" do ./fs-polyfill i udostępnij niestandardowy readFile który rejestruje, wywołuje inne API lub odczytuje z KV.
Po aliasingu importy takie jak import { readFile } from 'fs' rozwiąż swój moduł i omiń domyślne ustawienia unenv, zapobiegając błędom „nie zaimplementowano jeszcze” przy jednoczesnym zachowaniu niezmienionego pakietu zużywającego.
Aliasowanie pomaga również, gdy zależność pobiera pakiety specyficzne dla Node, takie jak node-fetch, który może opierać się na nieobsługiwanych modułach Node; możesz mapować "node-fetch" do modułu, który ponownie eksportuje globalne fetch.
Narzędzia takie jak nolyfill uprościć wzorce reeksportu, co pozwala na ominięcie niekompatybilnych implementacji i utrzymanie zależnego działania pakietów na workd.
Aliasowanie modułów działa jako elastyczna warstwa kompatybilności na wierzchu nodejs_compat_v2, co pozwala na dostosowanie konkretnych pakietów bez konieczności ich ponownego przepisywania lub rozwidlania.
Wydajność, współpraca ekosystemowa i wdrażanie
Kluczowe interfejsy API Node.js zaimplementowane natywnie w języku C++ w ramach pakietu workerd zapewniają lepszą wydajność i poprawnośći moduły takie jak Buffer, AsyncLocalStorage oraz Crypto Skorzystaj z tych natywnych implementacji zawartych w podkładkach JS, które odzwierciedlają zachowanie Node.
Cloudflare przyczynia się do unenv, który zapewnia inteligentne, dostępne na żądanie wypełnienia i makietyponieważ jest przeznaczony do obsługi wielu środowisk uruchomieniowych i został przyjęty przez takie projekty, jak Nuxt i Nitro; dodawanie wyłącznie niezbędnych polyfillów sprawia, że aplikacje są lekkie i sprzyja konwergencji ekosystemów.
Szerszym celem jest przenośność kodu w stylu Node w różnych środowiskach wykonawczych, dzięki czemu programiści mogą napisać kod raz, a następnie uruchamiać go w Node.js, środowiskach Workplace lub innych środowiskach z minimalnym tarciem, automatycznie wybierając polyfille i natywne funkcje na podstawie sposobu użycia.
Poprawa zachowania w nodejs_compat_v2 oczekuje się, że z czasem stanie się to ustawieniem domyślnym gdy data kompatybilności Twojego Workera jest wystarczająco niedawna, dzięki czemu więcej Workerów będzie transparentnie korzystać z silniejszej kompatybilności npm bez konieczności dodatkowej konfiguracji.
Zachęcamy programistów do wypróbowania ulepszonej kompatybilności Node.js i aktualizacji wrangler.toml, zgłaszanie pozostałych niezgodności lub błędów poprzez kanały przesyłania opinii, tak aby można było usunąć luki.
Połączenie dojrzałego zarządzania zależnościami npm, bezpiecznego środowiska uruchomieniowego workend zorientowanego na sieć i rozwijającej się warstwy zgodności Node.js Daje Ci praktyczną możliwość ponownego wykorzystania ogromnej ilości istniejącego kodu JavaScript, jednocześnie wykorzystując wykonywanie brzegowe, izolację i funkcje platformy Cloudflare. Dzięki inteligentnym polyfillom, natywnym implementacjom, mockowaniu i aliasowaniu modułów, wprowadzanie zaawansowanych pakietów npm do projektów Workers staje się o wiele bardziej realistyczne bez ciągłej walki ze środowiskiem wykonawczym.