Skip to content

refactor: remove CJS and env var Babel transforms, let Vite handle natively#3767

Open
bartlomieju wants to merge 8 commits intomainfrom
refactor/replace-babel-env-vars-with-vite-define
Open

refactor: remove CJS and env var Babel transforms, let Vite handle natively#3767
bartlomieju wants to merge 8 commits intomainfrom
refactor/replace-babel-env-vars-with-vite-define

Conversation

@bartlomieju
Copy link
Copy Markdown
Member

@bartlomieju bartlomieju commented Apr 9, 2026

Summary

  • Replace Babel env var transforms with Vite's native defineprocess.env.FRESH_PUBLIC_* and import.meta.env.FRESH_PUBLIC_* now use Vite's built-in define config. Deno.env.get() calls use a lightweight regex-based transform (~10 lines vs 78-line Babel plugin).

  • Remove the 960-line CJS→ESM Babel transform — Instead of transforming CJS to ESM via Babel, let Vite handle CJS packages natively:

    • Build mode: Rollup's @rollup/plugin-commonjs handles CJS (always has, but was bypassed by deno.ts loading through @deno/loader)
    • Dev mode: A ~30-line CJS shim wraps node_modules CJS files with module/exports/require so Vite's SSR module runner can evaluate them
    • deno.ts no longer attaches meta.deno to file:// resolved paths — Vite loads them from disk directly
  • Remove noDiscovery: true — Vite's dependency optimizer can now pre-bundle CJS packages for the client

  • Fix React compat aliasing — Apply resolve.alias (react → preact/compat) in deno.ts before @deno/loader resolution, so the alias works even when packages are non-external in SSR

Net: ~2,050 lines deleted, ~150 lines added. Eliminates the #1 source of npm compatibility bugs (#3619, #3653, #3505, #3478, #3449).

Test plan

  • deno test -A packages/plugin-vite/tests/dev_server_test.ts — 35/36 pass (1 failure: remote island — investigating)
  • deno test -A packages/plugin-vite/tests/build_test.ts — 31/31 pass
  • deno test -A packages/plugin-vite/src/plugins/patches/ — 15/15 pass
  • deno test -A packages/plugin-vite/tests/config_test.ts — passes
  • Fix remote island test failure

🤖 Generated with Claude Code

bartlomieju and others added 4 commits April 9, 2026 17:52
Remove the 78-line Babel `inlineEnvVarsPlugin` and replace it with
Vite's built-in `define` configuration for `process.env.FRESH_PUBLIC_*`
and `import.meta.env.FRESH_PUBLIC_*` patterns. A lightweight regex-based
Vite plugin handles `Deno.env.get()` calls which can't use `define`.

Env file loading moved from `configResolved` to `config` so define
entries are available during Vite's config resolution phase.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Instead of transforming CJS to ESM via a 960-line Babel plugin, let
Vite handle CJS packages natively by:

1. Removing `meta.deno` from file:// resolved paths in deno.ts so
   Vite loads npm packages from disk instead of through @deno/loader
2. Removing `noExternal: true` so Vite externalizes npm packages in
   SSR dev mode (Node.js handles CJS natively via require())
3. Removing `noDiscovery: true` so Vite's dependency optimizer can
   pre-bundle CJS packages for the client
4. Applying resolve.alias before Deno resolution so react -> preact/compat
   works even when packages are externalized

Also converts local .cjs test fixtures to ESM since they no longer
go through the CJS transform.

Deletes ~1,800 lines. Eliminates the #1 source of npm compat bugs
(#3619, #3653, #3505, #3478, #3449).

Known regressions (2 tests): radix-ui and remote island need
investigation for duplicate preact instances with externalization.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…l for radix-ui

Apply Vite's resolve.alias config (e.g. react -> preact/compat) in
deno.ts before calling @deno/loader, so the alias works even when
packages are externalized in SSR mode.

Also add noExternal for @radix-ui packages in the SSR environment
since they depend on React compat aliases being applied.

WIP: radix test still failing — alias format from Vite config needs
further investigation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add lightweight CJS shim in deno.ts load hook for dev mode: wraps
  CJS files in node_modules with module/exports/require so Vite's
  SSR module runner can evaluate them. Only ~30 lines vs the old
  960-line Babel CJS transform. Only runs in dev mode — build mode
  uses Rollup's @rollup/plugin-commonjs natively.

- Restore ssr.noExternal: true so resolve.alias (react -> preact/compat)
  is applied consistently in SSR. Without it, Node.js require() bypasses
  aliases and loads real react@19.1.1.

- Apply resolve.alias in deno.ts resolveId before @deno/loader runs,
  so aliased specifiers (react, react-dom) resolve to preact/compat
  through the Deno resolution pipeline.

- Remove environment-level noExternal (was duplicated).

Test results: 35/36 dev tests pass, 31/31 build tests pass.
The 1 failing test (remote island) is pre-existing on main.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@bartlomieju bartlomieju changed the title refactor: replace Babel env var transforms with Vite native define refactor: remove CJS and env var Babel transforms, let Vite handle natively Apr 9, 2026
bartlomieju and others added 4 commits April 9, 2026 20:43
Instead of disabling the dependency optimizer entirely (noDiscovery),
exclude only preact ecosystem packages from optimization. This allows
CJS packages like mime-db to be pre-bundled for the browser while
preventing duplicate preact instances when remote (JSR) islands
resolve deps to /@fs/ paths.

Also extends the CJS shim to work in both SSR (with createRequire)
and client (with stub require) environments.

All dev server tests pass (35/36 — 1 pre-existing flaky failure
on remote island that also fails on main). All 31 build tests pass.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The dependency optimizer causes duplicate preact instances when remote
(JSR) islands resolve deps to /@fs/ paths while the optimizer bundles
to /.vite/deps/. Restore noDiscovery: true to prevent this.

For CJS packages used in client-side islands (like mime-db), convert
require() calls to ESM import statements via regex so browsers can
load them. The SSR shim continues to use Node.js createRequire.

All tests pass: 36/36 dev, 31/31 build, 15/15 patches.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The `links` field referenced a sibling directory that only exists on the
author's machine, causing `deno install` to fail in CI.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant