Skip to content

Vite+ CLI cannot start in StackBlitz because its WASI binding is unavailable #2598

Description

@ueberBrot

Describe the bug

The Vite+ CLI cannot start in a StackBlitz WebContainer.

A minimal project containing only vite-plus@0.3.0 fails when it runs vp --version or vp env current. Both commands exit while loading vite-plus/binding/index.cjs, before Vite+ processes the command.

The platform-specific native binding cannot load in the WebContainer. The generated loader then checks for these WASI bindings:

  • ./vite-plus.wasi.cjs
  • @voidzero-dev/vite-plus-wasm32-wasi

Neither option is available:

  • The published vite-plus@0.3.0 package contains no local WASI loader or .wasm artifact.
  • The npm registry returns 404 for @voidzero-dev/vite-plus-wasm32-wasi.

Expected: Vite+ loads a compatible WASI binding and runs vp commands in the WebContainer.

Actual: Vite+ exits with Cannot find native binding.

The missing WASI distribution can also be reproduced deterministically on macOS:

NAPI_RS_FORCE_WASI=error ./node_modules/.bin/vp --version

That command reports both missing WASI options:

Error: WASI binding not found and NAPI_RS_FORCE_WASI is set to error

Cause 1:
Error: Cannot find module '@voidzero-dev/vite-plus-wasm32-wasi'

Cause 2:
Error: Cannot find module './vite-plus.wasi.cjs'

Normal macOS execution succeeds with the native binding. The forced command isolates the unavailable WASI distribution; it does not indicate a problem with the macOS native binding.

Source references

The current generated loader documents WASI as its fallback:

// NAPI_RS_FORCE_WASI is a tri-state flag:
// unset / any other value → native binding preferred, WASI is only a fallback
// 'true' → prefer WASI, but retain native as a lazy fallback
// 'error' → require WASI without initializing a native fallback
// Treating any non-empty string as truthy (the historical behavior) meant
// NAPI_RS_FORCE_WASI=false, NAPI_RS_FORCE_WASI=0, etc. inadvertently triggered
// the WASI path, causing ENOENT for packages shipped without a .wasi.cjs file.
//
// NAPI_RS_WASI_FLAVOR selects one exact generated flavor and implies strict
// WASI loading. It never crosses into another flavor or falls back to native.

It first tries the bundled ./vite-plus.wasi.cjs loader and its .wasm artifacts:

if (!wasiBindingLoaded && (!__napiWasiFlavorRequested || __napiWasiFlavor === 'wasm32-wasi')) {
let candidateError = null;
let candidateFailed = false;
try {
candidateError = __napiWasiResolveCandidate('./vite-plus.wasi.cjs', false, [
'./vite-plus.wasm32-wasi.debug.wasm',
'./vite-plus.wasm32-wasi.wasm',
]);
candidateFailed = candidateError !== null;
if (!candidateFailed) {
wasiBinding = require('./vite-plus.wasi.cjs');
nativeBinding = wasiBinding;
wasiBindingLoaded = true;
}
} catch (err) {
candidateError = err;
candidateFailed = true;
}
if (candidateFailed) {
wasiBindingErrors.push(candidateError);
loadErrors.push(candidateError);
}
}

It then tries @voidzero-dev/vite-plus-wasm32-wasi:

if (!wasiBindingLoaded && (!__napiWasiFlavorRequested || __napiWasiFlavor === 'wasm32-wasi')) {
let candidateError = null;
let candidateFailed = false;
try {
candidateError = __napiWasiResolveCandidate(
'@voidzero-dev/vite-plus-wasm32-wasi',
true,
undefined,
);
candidateFailed = candidateError !== null;
if (!candidateFailed) {
if (
process.env.NAPI_RS_ENFORCE_VERSION_CHECK &&
process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0'
) {
const bindingPackageVersion =
require('@voidzero-dev/vite-plus-wasm32-wasi/package.json').version;
if (bindingPackageVersion !== '0.3.0') {
throw new Error(
`WASI binding package version mismatch, expected 0.3.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`,
);
}
}
wasiBinding = require('@voidzero-dev/vite-plus-wasm32-wasi');
nativeBinding = wasiBinding;
wasiBindingLoaded = true;
}
} catch (err) {
candidateError = err;
candidateFailed = true;
}
if (candidateFailed) {
wasiBindingErrors.push(candidateError);
loadErrors.push(candidateError);
}
}

When WASI is required and neither option can load, it throws the forced-WASI error:

if ((forceWasiError || __napiWasiFlavorRequested) && !wasiBindingLoaded) {
const error = new Error(
__napiWasiFlavorRequested
? 'WASI binding for flavor "' + __napiWasiFlavor + '" not found'
: 'WASI binding not found and NAPI_RS_FORCE_WASI is set to error',
);
error.cause = createLoadErrorChain(wasiBindingErrors);
throw error;

Related findings

This prevents projects that use Vite+ commands from running in StackBlitz WebContainers. The reproduction contains no application code and fails with vp --version alone.

I am not currently planning a PR.

Reproduction

https://stackblitz.com/~/github.com/ueberBrot/vite-plus-webcontainer-repro?file=package.json&terminal=dev

Steps to reproduce

  1. Open the StackBlitz reproduction.
  2. Wait for StackBlitz to install the dependencies.
  3. StackBlitz automatically runs pnpm run reproduce, which invokes vp --version.
  4. Observe that Vite+ exits while loading its native binding.
  5. Run pnpm run environment in the terminal.
  6. Observe that vp env current fails during the same binding-loading step.

To isolate the unavailable WASI distribution on macOS:

  1. Clone https://github.com/ueberBrot/vite-plus-webcontainer-repro.
  2. Run pnpm install.
  3. Run pnpm run reproduce:wasi.
  4. Observe that Vite+ cannot find either ./vite-plus.wasi.cjs or @voidzero-dev/vite-plus-wasm32-wasi.

System Info

StackBlitz WebContainer

$ node --version
v22.22.3

$ pnpm --version
8.15.6

$ pnpm run environment

> vite-plus-webcontainer-repro@0.0.0 environment /home/ueberBrot/vite-plus-webcontainer-repro
> vp env current

ELIFECYCLE Command failed with exit code 1.
Error: Cannot find native binding. npm has a bug related to optional dependencies (https://github.com/npm/cli/issues/4828). Please try `npm i` again after removing both package-lock.json and node_modules directory.
    at Object.eval (/home/ueberBrot/vite-plus-webcontainer-repro/node_modules/.pnpm/vite-plus@0.3.0_vite@8.2.2/node_modules/vite-plus/binding/index.cjs:882:19)
    at Module._compile (node:internal/modules/cjs/loader:160:19302)
    at Module._extensions..js (node:internal/modules/cjs/loader:160:20043)
    at Module.load (node:internal/modules/cjs/loader:160:17661)
    at Module._load (node:internal/modules/cjs/loader:160:15179)
    at wrapModuleLoad (node:internal/modules/cjs/loader:160:4199)
    at loadCJSModuleWithModuleLoad (node:internal/modules/esm/translators:174:3866)
    at _0x504db8.evaluationFunction (node:internal/modules/esm/translators:174:3603)

Node.js v22.22.3

$ pnpm run reproduce

> vite-plus-webcontainer-repro@0.0.0 reproduce /home/ueberBrot/vite-plus-webcontainer-repro
> vp --version

ELIFECYCLE Command failed with exit code 1.
Error: Cannot find native binding. npm has a bug related to optional dependencies (https://github.com/npm/cli/issues/4828). Please try `npm i` again after removing both package-lock.json and node_modules directory.
    at Object.eval (/home/ueberBrot/vite-plus-webcontainer-repro/node_modules/.pnpm/vite-plus@0.3.0_vite@8.2.2/node_modules/vite-plus/binding/index.cjs:882:19)
    at Module._compile (node:internal/modules/cjs/loader:160:19302)
    at Module._extensions..js (node:internal/modules/cjs/loader:160:20043)
    at Module.load (node:internal/modules/cjs/loader:160:17661)
    at Module._load (node:internal/modules/cjs/loader:160:15179)
    at wrapModuleLoad (node:internal/modules/cjs/loader:160:4199)
    at loadCJSModuleWithModuleLoad (node:internal/modules/esm/translators:174:3866)
    at _0x504db8.evaluationFunction (node:internal/modules/esm/translators:174:3603)

Node.js v22.22.3

Used Package Manager

pnpm

Logs

Local diagnostic environment:

macOS 26.6.2
Architecture: arm64
Node.js v24.18.0
vite-plus v0.3.0

$ NAPI_RS_FORCE_WASI=error node -e 'try { require("./node_modules/vite-plus/binding/index.cjs") } catch (error) { let current = error; let index = 0; while (current) { console.error("Cause " + index + ":"); console.error(current.stack || String(current)); current = current.cause; index += 1; } process.exit(1); }'

Cause 0:
Error: WASI binding not found and NAPI_RS_FORCE_WASI is set to error
    at Object.<anonymous> (/private/tmp/vite-plus-webcontainer-repro.9X28Wk/node_modules/.pnpm/vite-plus@0.3.0_vite@8.2.2/node_modules/vite-plus/binding/index.cjs:870:19)
    at Module._compile (node:internal/modules/cjs/loader:1871:14)
    at Object..js (node:internal/modules/cjs/loader:2002:10)
    at Module.load (node:internal/modules/cjs/loader:1594:32)
    at Module._load (node:internal/modules/cjs/loader:1396:12)
    at wrapModuleLoad (node:internal/modules/cjs/loader:255:19)
    at Module.require (node:internal/modules/cjs/loader:1617:12)
    at require (node:internal/modules/helpers:153:16)
    at [eval]:1:7
    at runScriptInThisContext (node:internal/vm:219:10)

Cause 1:
Error: Cannot find module '@voidzero-dev/vite-plus-wasm32-wasi'
Require stack:
- /private/tmp/vite-plus-webcontainer-repro.9X28Wk/node_modules/.pnpm/vite-plus@0.3.0_vite@8.2.2/node_modules/vite-plus/binding/index.cjs
- /private/tmp/vite-plus-webcontainer-repro.9X28Wk/[eval]
    at /private/tmp/vite-plus-webcontainer-repro.9X28Wk/node_modules/.pnpm/vite-plus@0.3.0_vite@8.2.2/node_modules/vite-plus/binding/index.cjs:727:19
    at Array.reduce (<anonymous>)
    at createLoadErrorChain (/private/tmp/vite-plus-webcontainer-repro.9X28Wk/node_modules/.pnpm/vite-plus@0.3.0_vite@8.2.2/node_modules/vite-plus/binding/index.cjs:720:17)
    at Object.<anonymous> (/private/tmp/vite-plus-webcontainer-repro.9X28Wk/node_modules/.pnpm/vite-plus@0.3.0_vite@8.2.2/node_modules/vite-plus/binding/index.cjs:875:19)
    at Module._compile (node:internal/modules/cjs/loader:1871:14)
    at Object..js (node:internal/modules/cjs/loader:2002:10)
    at Module.load (node:internal/modules/cjs/loader:1594:32)
    at Module._load (node:internal/modules/cjs/loader:1396:12)
    at wrapModuleLoad (node:internal/modules/cjs/loader:255:19)
    at Module.require (node:internal/modules/cjs/loader:1617:12)

Cause 2:
Error: Cannot find module './vite-plus.wasi.cjs'
Require stack:
- /private/tmp/vite-plus-webcontainer-repro.9X28Wk/node_modules/.pnpm/vite-plus@0.3.0_vite@8.2.2/node_modules/vite-plus/binding/index.cjs
- /private/tmp/vite-plus-webcontainer-repro.9X28Wk/[eval]
    at /private/tmp/vite-plus-webcontainer-repro.9X28Wk/node_modules/.pnpm/vite-plus@0.3.0_vite@8.2.2/node_modules/vite-plus/binding/index.cjs:727:19
    at Array.reduce (<anonymous>)
    at createLoadErrorChain (/private/tmp/vite-plus-webcontainer-repro.9X28Wk/node_modules/.pnpm/vite-plus@0.3.0_vite@8.2.2/node_modules/vite-plus/binding/index.cjs:720:17)
    at Object.<anonymous> (/private/tmp/vite-plus-webcontainer-repro.9X28Wk/node_modules/.pnpm/vite-plus@0.3.0_vite@8.2.2/node_modules/vite-plus/binding/index.cjs:875:19)
    at Module._compile (node:internal/modules/cjs/loader:1871:14)
    at Object..js (node:internal/modules/cjs/loader:2002:10)
    at Module.load (node:internal/modules/cjs/loader:1594:32)
    at Module._load (node:internal/modules/cjs/loader:1396:12)
    at wrapModuleLoad (node:internal/modules/cjs/loader:255:19)
    at Module.require (node:internal/modules/cjs/loader:1617:12)

Validations

Metadata

Metadata

Assignees

No one assigned

    Type

    Fields

    Priority

    None yet

    Effort

    None yet

    Target date

    None yet

    Start date

    None yet

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions