From 51714ba32a6c464370f638fc4b3d029ec0611d45 Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Tue, 27 Oct 2026 10:23:19 -0400 Subject: [PATCH] fix(@angular/build): include the oxc-parser WASI binding as an optional dependency When running inside a WebContainer environment, such as StackBlitz or the angular.dev playground, native Node.js addons cannot be loaded. The `oxc-parser` package only lists its platform-specific native bindings as optional dependencies and does not include the WebAssembly-based `@oxc-parser/binding-wasm32-wasi` binding. As a result, package managers never install the WASI binding and `oxc-parser` falls back to downloading it on demand at runtime by shelling out to `pnpm` inside a temporary directory. This fallback is executed synchronously while the module graph is being evaluated, from within a worker thread, and via a synchronous `require()` of an ES module. Any failure along that path surfaces as a misleading `ERR_REQUIRE_CYCLE_MODULE` error rather than the underlying cause, which breaks `ng serve` and `ng build` entirely. The binding loader generated by napi-rs checks whether the WASI binding is already resolvable from `node_modules` before attempting the on-demand download. Declaring `@oxc-parser/binding-wasm32-wasi` as an optional dependency of `@angular/build` ensures that package managers install it alongside the package up front. This allows `oxc-parser` to load the WASI binding directly in WebContainer environments and avoids the fragile runtime installation path. The version is pinned to match `oxc-parser` exactly, since the loader rejects bindings whose version does not match the version of the main package. The two dependencies must therefore be kept in lockstep when updating. This mirrors the existing approach used for `lmdb`, which is also declared as an optional dependency to avoid hard failures on platforms where it is unavailable. Note that at the time of this change, the currently published WASI bindings for `oxc-parser` depend on an `@napi-rs/wasm-runtime` version range that resolves to a release incompatible with the `@emnapi` alpha runtime those bindings were built against. Until a compatible `oxc-parser` release is available, the pre-installed binding will fail to initialize in the same way the on-demand download does. This change is nonetheless a prerequisite for a durable fix and will take effect once `oxc-parser` is updated to a release with compatible WASI bindings. Related to #34524 --- packages/angular/build/package.json | 1 + pnpm-lock.yaml | 61 +++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/packages/angular/build/package.json b/packages/angular/build/package.json index 26cbbc89105f..7bcd33b3eff7 100644 --- a/packages/angular/build/package.json +++ b/packages/angular/build/package.json @@ -48,6 +48,7 @@ "xxhash-wasm": "1.1.0" }, "optionalDependencies": { + "@oxc-parser/binding-wasm32-wasi": "0.155.0", "lmdb": "3.5.8" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3580f903a6be..84b4d3b6cf42 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -596,6 +596,9 @@ importers: specifier: 5.0.5 version: 5.0.5(@opentelemetry/api@1.10.0)(@types/node@22.20.5)(@vitest/coverage-v8@5.0.5)(jsdom@30.1.3(@noble/hashes@1.8.0))(vite@8.3.5(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(less@4.9.1(supports-color@11.0.0))(sass-embedded@1.106.0)(sass@1.106.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)) optionalDependencies: + '@oxc-parser/binding-wasm32-wasi': + specifier: 0.155.0 + version: 0.155.0 lmdb: specifier: 3.5.8 version: 3.5.8 @@ -1803,6 +1806,15 @@ packages: resolution: {integrity: sha512-Xc3VhU02wqZ1HvHRJUwL09HkZSTvidqY5Ya0NXBSYOxAp+Ln9dcJr9fySI+CkONzP3PekQo9WdzCv0PGER/mOA==} engines: {node: '>=14.17.0'} + '@emnapi/core@2.0.0-alpha.6': + resolution: {integrity: sha512-MNVvMV7WtEJMgqaWJMvCyupK7Oi8sZctUIgPRZTsiS3cVvefk8DXPflOU3MSBddtj/rrYHygpYgpHDgwXnI3+w==} + + '@emnapi/runtime@2.0.0-alpha.6': + resolution: {integrity: sha512-5ZR49ZsZ3cLvu5lkrVj6CMpHRgZjYz7XSlqK23GYYpyEqp749RVuIH0bEUKaGNghMh2pXRhIC3cnVrH28Y1j1Q==} + + '@emnapi/wasi-threads@2.2.0': + resolution: {integrity: sha512-JP7OYH38Q7+pyTAe14raZHLQIK7BDKbdwji+Xi3pcd/6QkJYQH3SX4wu6EplGrGJWRepoNzedfm0G3B9Z4e9Rw==} + '@esbuild/aix-ppc64@0.28.2': resolution: {integrity: sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==} engines: {node: '>=18'} @@ -2835,6 +2847,13 @@ packages: resolution: {integrity: sha512-xJIPs+bYuc9ASBl+cvGsKbGrJmS6fAKaSZCnT0lhahT5rhA2VVy9/EcIgd2JhtEuFOJNx7UHNn/qiTPTY4nrQw==} engines: {node: '>= 10'} + '@napi-rs/wasm-runtime@1.2.6': + resolution: {integrity: sha512-mRyDmEw9/fCDXCGfL1sbgIw/GUK0PVxRW4YwgPN61F3LQ+fSyoBFarJVzgGyhF6kRzEQZ0FejDqm4WLXSeqQmw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} + peerDependencies: + '@emnapi/core': ^1.7.1 || 2.0.0-beta.2 + '@emnapi/runtime': ^1.7.1 || 2.0.0-beta.2 + '@noble/hashes@1.8.0': resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} engines: {node: ^14.21.3 || >=16} @@ -3075,6 +3094,10 @@ packages: cpu: [arm64] os: [openharmony] + '@oxc-parser/binding-wasm32-wasi@0.155.0': + resolution: {integrity: sha512-tqOJaG8vXTgIy1f2K06ZZoN4g0z5X0yuDsoFaLb2Jfn5vZlGUgrYWFqIUsDpz8gnK2QLMIIQIwgYRTq6p/Ts0g==} + engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} + '@oxc-parser/binding-win32-arm64-msvc@0.155.0': resolution: {integrity: sha512-alAb9TzjatUEsOeoncAziUnfdTDxfyswhalFZ9sC6plUgATIUx2NIZ0+bMn6aJ28AduS1OpG/OAisr/YISn4Ig==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3597,6 +3620,9 @@ packages: peerDependencies: eslint: '>=7.7.0' + '@tybys/wasm-util@0.10.4': + resolution: {integrity: sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A==} + '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -9494,6 +9520,22 @@ snapshots: '@discoveryjs/json-ext@1.1.0': {} + '@emnapi/core@2.0.0-alpha.6': + dependencies: + '@emnapi/wasi-threads': 2.2.0 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@2.0.0-alpha.6': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@2.2.0': + dependencies: + tslib: 2.8.1 + optional: true + '@esbuild/aix-ppc64@0.28.2': optional: true @@ -10621,6 +10663,13 @@ snapshots: '@napi-rs/nice-win32-x64-msvc': 1.1.1 optional: true + '@napi-rs/wasm-runtime@1.2.6(@emnapi/core@2.0.0-alpha.6)(@emnapi/runtime@2.0.0-alpha.6)': + dependencies: + '@emnapi/core': 2.0.0-alpha.6 + '@emnapi/runtime': 2.0.0-alpha.6 + '@tybys/wasm-util': 0.10.4 + optional: true + '@noble/hashes@1.8.0': {} '@nodelib/fs.scandir@2.1.5': @@ -10826,6 +10875,13 @@ snapshots: '@oxc-parser/binding-openharmony-arm64@0.155.0': optional: true + '@oxc-parser/binding-wasm32-wasi@0.155.0': + dependencies: + '@emnapi/core': 2.0.0-alpha.6 + '@emnapi/runtime': 2.0.0-alpha.6 + '@napi-rs/wasm-runtime': 1.2.6(@emnapi/core@2.0.0-alpha.6)(@emnapi/runtime@2.0.0-alpha.6) + optional: true + '@oxc-parser/binding-win32-arm64-msvc@0.155.0': optional: true @@ -11222,6 +11278,11 @@ snapshots: dependencies: eslint: 10.13.0(jiti@2.7.0)(supports-color@11.0.0) + '@tybys/wasm-util@0.10.4': + dependencies: + tslib: 2.8.1 + optional: true + '@types/babel__core@7.20.5': dependencies: '@babel/parser': 7.29.11