Skip to content

chore: migrate from Vite v7 to v8 (Rolldown/Oxc)#919

Merged
sirtimid merged 12 commits intomainfrom
sirtimid/vite-v8-migration
Apr 8, 2026
Merged

chore: migrate from Vite v7 to v8 (Rolldown/Oxc)#919
sirtimid merged 12 commits intomainfrom
sirtimid/vite-v8-migration

Conversation

@sirtimid
Copy link
Copy Markdown
Contributor

@sirtimid sirtimid commented Apr 7, 2026

Summary

Vite 8 replaces Rollup+esbuild with Rolldown+Oxc as its bundler and transformer. This PR adapts the codebase to all relevant breaking changes.

Config changes (all packages)

  • Rename build.rollupOptionsbuild.rolldownOptions in every vite.config.ts and vitest.config.ts
  • Remove the _commonjsHelpers chunk-name special-case — Rolldown handles CJS natively and this chunk no longer appears
  • Update vite-plugin-static-copy targets with rename: { stripBase: true } to match v4's new directory-structure-preserving behaviour
  • Replace vite-tsconfig-paths plugin with the native resolve.tsconfigPaths: true option (Vite 8 built-in)
  • Replace deprecated customResolver alias with a resolveId plugin hook for the @metamask/kernel-shims/endoify redirect
  • Update js-trusted-prelude.ts plugin to read config.build.rolldownOptions?.input

bundle-vat.ts (kernel-utils)

  • Use RolldownOutput / OutputChunk types from rolldown instead of Rollup.* from vite
  • Replace output.inlineDynamicImports: true (Rollup-only) with output.codeSplitting: false
  • Add removeDynamicImportsPlugin: Rolldown rejects IIFE format whenever the bundle graph contains any import() expression, even with codeSplitting: false. Some third-party packages (viem, @endo/*) use lazy await import(x) for utilities that vats never call; the plugin replaces all string-literal dynamic imports with Promise.resolve({}) to satisfy Rolldown's constraint
  • Add a module-level promise-queue mutex to serialize concurrent bundleVat() calls — Rolldown has global state that is corrupted when multiple IIFE builds run concurrently via Promise.all (as kernel-cli does when bundling a directory of vats)
  • Add rolldown as a peer dependency and update the vite peer dep range to ^8.0.6

bundle-loader.ts (ocap-kernel)

  • Add exports: {} to the SES Compartment endowments — Rolldown unconditionally emits Object.defineProperty(exports, Symbol.toStringTag, ...) in every IIFE bundle preamble, even for modules with no exports; without an exports endowment this throws inside the Compartment

stringify.test.ts (kernel-utils)

  • Oxc serialises function declarations with tabs instead of spaces, so the whitespace-sensitive string comparison is replaced with String(fn) to stay bundler-agnostic

Testing

All 24 build tasks and all 45 test tasks pass (yarn build + yarn test:dev:quiet from the monorepo root, both cached and uncached).

The key non-obvious behaviour changes are covered by the existing vat integration tests in @ocap/kernel-test (which build real vat bundles via bundleVat and execute them in SES Compartments) and by the evm-wallet-experiment build (which exercises the 4-vat Promise.all path through kernel-cli).

🤖 Generated with Claude Code


Note

Medium Risk
Medium risk because this upgrades the build/test toolchain (Vite/Vitest/Rolldown) and changes bundling semantics for vats and extension builds, which can cause subtle runtime or packaging regressions.

Overview
Upgrades the monorepo to Vite 8 / Vitest 4.1 (plus related tool bumps like Playwright, jsdom, and static-copy/checker plugins) and updates package configs accordingly.

Migrates build/test configs from build.rollupOptions to build.rolldownOptions, adjusts static asset copy behavior (adds rename.stripBase), and replaces vite-tsconfig-paths with Vite’s native resolve.tsconfigPaths plus a custom resolveId hook for the @metamask/kernel-shims/endoify test redirect.

Updates vat bundling to Rolldown by switching types/output options, adding a removeDynamicImportsPlugin() workaround for IIFE constraints, and serializing bundleVat() builds to avoid Rolldown concurrency issues; loadBundle() is hardened to support Rolldown-generated IIFE preambles (exports, globalThis, global). Minor follow-ups include exporting register from the OpenClaw plugin entrypoint and making stringify function tests bundler-output-agnostic.

Reviewed by Cursor Bugbot for commit 3fc36bd. Bugbot is set up for automated code reviews on this repo. Configure here.

@socket-security
Copy link
Copy Markdown

socket-security bot commented Apr 7, 2026

All alerts resolved. Learn more about Socket for GitHub.

This PR previously contained dependency changes with security issues that have been resolved, removed, or ignored.

Ignoring alerts on:

  • lightningcss@1.32.0
  • rolldown@1.0.0-rc.13
  • @bramus/specificity@2.4.2
  • lightningcss-android-arm64@1.32.0
  • lightningcss-darwin-arm64@1.32.0
  • lightningcss-darwin-x64@1.32.0
  • lightningcss-freebsd-x64@1.32.0
  • lightningcss-linux-arm-gnueabihf@1.32.0
  • lightningcss-linux-arm64-gnu@1.32.0
  • lightningcss-linux-arm64-musl@1.32.0
  • lightningcss-linux-x64-gnu@1.32.0
  • lightningcss-linux-x64-musl@1.32.0
  • lightningcss-win32-arm64-msvc@1.32.0
  • lightningcss-win32-x64-msvc@1.32.0
  • @oxc-project/types@0.123.0
  • @rolldown/binding-android-arm64@1.0.0-rc.13
  • @rolldown/binding-darwin-arm64@1.0.0-rc.13
  • @rolldown/binding-darwin-x64@1.0.0-rc.13
  • @rolldown/binding-freebsd-x64@1.0.0-rc.13
  • @rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.13
  • @rolldown/binding-linux-arm64-gnu@1.0.0-rc.13
  • @rolldown/binding-linux-arm64-musl@1.0.0-rc.13
  • @rolldown/binding-linux-ppc64-gnu@1.0.0-rc.13
  • @rolldown/binding-linux-s390x-gnu@1.0.0-rc.13
  • @rolldown/binding-linux-x64-gnu@1.0.0-rc.13
  • @rolldown/binding-linux-x64-musl@1.0.0-rc.13
  • @rolldown/binding-openharmony-arm64@1.0.0-rc.13
  • @rolldown/binding-wasm32-wasi@1.0.0-rc.13
  • @rolldown/binding-win32-arm64-msvc@1.0.0-rc.13
  • @rolldown/binding-win32-x64-msvc@1.0.0-rc.13
  • @blazediff/core@1.9.1
  • brace-expansion@5.0.5
  • eslint-visitor-keys@5.0.1
  • balanced-match@4.0.4
  • whatwg-mimetype@5.0.0
  • ws@8.20.0
  • @rolldown/pluginutils@1.0.0-rc.13
  • undici@7.24.7
  • @napi-rs/wasm-runtime@1.1.2
  • @typescript-eslint/scope-manager@8.58.0
  • @typescript-eslint/types@8.58.0
  • @typescript-eslint/visitor-keys@8.58.0
  • minimatch@10.2.5
  • lru-cache@11.3.2
  • @typescript-eslint/utils@8.58.0
  • picomatch@4.0.4
  • @babel/parser@7.29.2
  • @babel/types@7.29.0
  • semver@7.7.4
  • @typescript-eslint/typescript-estree@8.58.0
  • @typescript-eslint/project-service@8.58.0
  • @vitest/coverage-v8@4.1.3
  • @vitest/eslint-plugin@1.6.14
  • playwright@1.59.1
  • vite@8.0.6
  • vitest@4.1.3
  • jsdom@29.0.2
  • ts-api-utils@2.5.0
  • @eslint-community/eslint-utils@4.9.1
  • @typescript-eslint/tsconfig-utils@8.58.0
  • @vitest/utils@4.1.3
  • ast-v8-to-istanbul@1.0.0
  • js-tokens@10.0.0
  • magicast@0.5.2
  • std-env@4.0.0
  • tinyrainbow@3.1.0
  • playwright-core@1.59.1
  • postcss@8.5.8
  • @vitest/expect@4.1.3
  • @vitest/mocker@4.1.3
  • @vitest/pretty-format@4.1.3
  • @vitest/runner@4.1.3
  • @vitest/snapshot@4.1.3
  • @vitest/spy@4.1.3
  • es-module-lexer@2.0.0
  • @playwright/test@1.59.1
  • vite-plugin-checker@0.12.0
  • vite-plugin-static-copy@4.0.1
  • @vitest/browser@4.1.3
  • @vitest/browser-playwright@4.1.3
  • @asamuzakjp/dom-selector@7.0.7
  • @exodus/bytes@1.15.0
  • data-urls@7.0.0
  • tough-cookie@6.0.1
  • whatwg-url@16.0.1
  • p-map@7.0.4
  • detect-libc@2.1.2
  • css-tree@3.2.1
  • @asamuzakjp/css-color@5.1.6
  • @csstools/css-syntax-patches-for-csstree@1.1.2
  • mdn-data@2.27.1
  • @csstools/css-calc@3.1.1
  • @csstools/css-color-parser@4.0.2
  • @csstools/css-parser-algorithms@4.0.0
  • @csstools/css-tokenizer@4.0.0
  • @emnapi/core@1.9.1
  • @emnapi/runtime@1.9.1
  • @tybys/wasm-util@0.10.1
  • @csstools/color-helpers@6.0.2
  • @emnapi/wasi-threads@1.2.0

View full report

@sirtimid sirtimid requested a review from a team as a code owner April 7, 2026 18:10
@sirtimid sirtimid force-pushed the sirtimid/vite-v8-migration branch from 7cadb23 to aec2e3c Compare April 7, 2026 19:34
@sirtimid
Copy link
Copy Markdown
Contributor Author

sirtimid commented Apr 7, 2026

@SocketSecurity ignore-all

sirtimid and others added 4 commits April 7, 2026 22:56
Vite 8 replaces Rollup+esbuild with Rolldown+Oxc. This commit adapts
the codebase to the breaking changes in the migration guide.

Key changes:
- Rename `rollupOptions` → `rolldownOptions` across all vite/vitest configs
- Update `bundle-vat.ts` to use `RolldownOutput`/`OutputChunk` types from
  `rolldown` and `output.codeSplitting: false` instead of
  `inlineDynamicImports: true`
- Add `removeDynamicImportsPlugin` in `bundle-vat.ts` to replace runtime
  `import()` calls (viem lazy-loads crypto/WebSocket/CCIP utilities) with
  `Promise.resolve({})` so Rolldown accepts the IIFE output format
- Serialize concurrent `bundleVat()` calls via a module-level promise
  queue to prevent Rolldown global-state corruption under `Promise.all`
- Add `exports: {}` endowment to `bundle-loader.ts` Compartment so that
  Rolldown's unconditional `Object.defineProperty(exports, Symbol.toStringTag)`
  preamble does not throw in SES compartments
- Replace `vite-tsconfig-paths` plugin with `resolve.tsconfigPaths: true`
  (native Vite 8 feature) in root `vitest.config.ts`
- Replace deprecated `customResolver` alias with a `resolveId` plugin hook
  for the `@metamask/kernel-shims/endoify` redirect
- Update `vite-plugin-static-copy` targets with `rename: { stripBase: true }`
  to suppress the directory-structure-preserving behavior introduced in v4
- Remove `_commonjsHelpers` chunk-name special-case — Rolldown handles CJS
  natively, this chunk no longer appears
- Fix `stringify.test.ts` whitespace: Oxc serialises functions with tabs,
  so compare to `String(fn)` rather than a hardcoded string literal
- Update `js-trusted-prelude.ts` to read `rolldownOptions?.input` instead
  of `rollupOptions.input`
- Add `rolldown` and update `vite` peer dep in `kernel-utils/package.json`

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…s regex

The early-return guard `code.includes('import(')` required the token
`import` and `(` to be adjacent, but the replacement regex allows
optional whitespace (`\bimport\s*\(`).  A source file containing
`import ('specifier')` (space before the paren) would have been skipped
by the guard and left untransformed, causing Rolldown to reject the
IIFE build despite the plugin's purpose being to prevent that.

Replace the string fast-path with the equivalent regex test so both
paths agree on which files contain dynamic imports.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…olldown CJS compat

Rolldown-generated IIFE bundles include CJS helper code that uses
`var localThis = globalThis` to access intrinsics, and some bundled
libraries (e.g. lodash) detect the global object via
`typeof global == "object" && global` or `Function("return this")()`.

In a SES Compartment:
- `global` and `self` are not named bindings
- `Function("return this")()` returns undefined in strict mode

Inject `globalThis` and `global` on the compartment's own global after
construction so these patterns resolve to the compartment's global object
(which exposes all the hardened intrinsics).

Also fix the openclaw-plugin integration test to call `register.register()`
rather than treating the PluginEntry object itself as a function.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@sirtimid sirtimid force-pushed the sirtimid/vite-v8-migration branch from b5a15c4 to 59f8fcc Compare April 7, 2026 20:56
sirtimid and others added 4 commits April 7, 2026 23:27
- Export and add unit tests for removeDynamicImportsPlugin (16 tests)
- Add this.warn() when dynamic imports cannot be replaced
- Replace definite-assignment mutex with makePromiseKit
- Move exports: {} after endowment spreads to prevent accidental override
- Fix inaccurate comments (remove self, clarify ESM interop trigger)
- Add bundle-loader endowment tests for exports, globalThis, global

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… SES lockdown

The build tooling in bundle-vat.ts runs outside lockdown (e.g. during
`vite build`), so importing @endo/promise-kit fails with
"harden is not defined". Revert to the manual promise pattern.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The build tsconfig (with strict mode) requires the `!` assertion on
`releaseLock` since TypeScript cannot verify that the Promise constructor
callback runs synchronously.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…in static copy

Aligns the dead-code string-target branch with the object entries and
with extension/omnium-gatherum configs, preventing a subtle breakage
if a string target is re-added later.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 7, 2026

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 78.59%
⬆️ +0.01%
8630 / 10981
🔵 Statements 78.4%
⬆️ +0.01%
8766 / 11181
🔵 Functions 76.13%
⬆️ +0.01%
2019 / 2652
🔵 Branches 76.27%
⬆️ +0.03%
3714 / 4869
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
packages/kernel-utils/src/vite-plugins/bundle-vat.ts 41.66%
⬆️ +41.66%
50%
⬆️ +50.00%
40%
⬆️ +40.00%
41.66%
⬆️ +41.66%
75-135
packages/kernel-utils/src/vite-plugins/index.ts 100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
packages/ocap-kernel/src/vats/bundle-loader.ts 100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
packages/repo-tools/src/vite-plugins/js-trusted-prelude.ts 0%
🟰 ±0%
0%
🟰 ±0%
0%
🟰 ±0%
0%
🟰 ±0%
23-129
Generated in workflow #4249 for commit 3fc36bd by the Vitest Coverage Report Action

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit d2ee212. Configure here.

grypez
grypez previously requested changes Apr 8, 2026
Copy link
Copy Markdown
Contributor

@grypez grypez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall a good change. I didn't like the build queue promises until I couldn't think of any better solution. Some tiny changes suggested.

@sirtimid sirtimid added the no-changelog Indicates that no changelog updates are required, and that related CI checks should be skipped. label Apr 8, 2026
Export `register` as a named export from the openclaw-plugin to avoid
`register.register()` pattern, and improve the dynamic import warning in
`removeDynamicImportsPlugin` to also fire when mixed literal/computed
imports exist.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@sirtimid sirtimid requested a review from grypez April 8, 2026 19:02
@grypez grypez dismissed their stale review April 8, 2026 19:04

addressed

@sirtimid sirtimid enabled auto-merge April 8, 2026 19:04
Copy link
Copy Markdown
Contributor

@grypez grypez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. /bugbot 🤫

@sirtimid sirtimid added this pull request to the merge queue Apr 8, 2026
Merged via the queue into main with commit 882fd94 Apr 8, 2026
56 of 59 checks passed
@sirtimid sirtimid deleted the sirtimid/vite-v8-migration branch April 8, 2026 19:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-changelog Indicates that no changelog updates are required, and that related CI checks should be skipped.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants