vite-legacy-interop

raw JSON →
1.0.4 verified Mon Apr 27 auth: no javascript

A Vite 8 plugin that wraps legacy CJS subpath imports in ESM-compatible virtual modules to prevent runtime interop errors. Current version 1.0.4, actively maintained. Designed for Vite 8 and Rolldown, it intercepts imports like `legacy-lib/lib/Button` and replaces them with virtual ESM wrappers that handle CJS-to-ESM interop, solving `SyntaxError` and `ReferenceError` at runtime. Differentiators: targeted at Vite 8 with Rolldown, supports multiple libraries and nested subpaths, minimal configuration, includes debug logging.

error SyntaxError: The requested module 'legacy-lib/lib/Button' does not provide an export named 'default'
cause Rolldown does not perform CJS-to-ESM interop for subpath imports.
fix
Install and configure vite-legacy-interop with 'legacy-lib' in libs.
error ReferenceError: require is not defined
cause Legacy CJS module is emitted as-is in ESM bundle.
fix
Add vite-legacy-interop plugin with the legacy library name.
error Error: The plugin 'vite:legacy-interop' requires Vite >=8.0.0
cause Attempting to use with older Vite version.
fix
Upgrade Vite to 8.x or remove this plugin.
breaking Requires Vite 8.x; incompatible with Vite 7 or earlier.
fix Upgrade to Vite 8 or use alternative plugin for earlier Vite versions.
gotcha Plugin must be placed before other plugins that transform imports.
fix Ensure legacyInterop is first in the plugins array.
deprecated Option 'libDir' default is 'lib'; legacy packages with different directory must specify.
fix Explicitly set 'libDir' if your package uses 'dist' or other paths.
gotcha Virtual module IDs start with '\0legacy-interop:' which may conflict with other plugins.
fix Avoid other plugins using the same namespace prefix.
gotcha Does not handle dynamic imports (import()) or require() calls; only static import statements.
fix Use static imports for legacy CJS subpaths.
npm install vite-legacy-interop
yarn add vite-legacy-interop
pnpm add vite-legacy-interop

Configure vite-legacy-interop to wrap CJS subpath imports from 'legacy-lib' in ESM virtual modules.

// vite.config.ts
import { defineConfig } from 'vite';
import { legacyInterop } from 'vite-legacy-interop';

export default defineConfig({
  plugins: [
    legacyInterop({
      libs: ['legacy-lib'],
      showLog: true,
      apply: 'build',
    }),
  ],
});

// Now imports like:
// import Button from 'legacy-lib/lib/Button'
// are transparently wrapped in ESM interop modules.