Skip to content

experimental.bundledDev: hotUpdate runs without environment injection (this.environment undefined), leaving stale output until restart #23314

Description

@raphamorim

Describe the bug

Under experimental.bundledDev, a plugin's hotUpdate hook is invoked with this.environment undefined. Reading this.environment is the documented way to scope hotUpdate behavior (https://vite.dev/changes/hotupdate-hook), so plugins following the docs throw a TypeError on every file edit.

Mechanism, as far as we can tell from the source (checked on main and v8.1.5):

  • ROLLUP_HOOKS (packages/vite/src/node/constants.ts) includes watchChange but not hotUpdate.
  • injectEnvironmentToHooks (packages/vite/src/node/build.ts) wraps resolveId/load/transform explicitly and every other hook only if (ROLLUP_HOOKS.includes(hook)) — so no environment-bound wrapper exists for hotUpdate, and under bundled dev the hook executes with the engine's bare plugin context.

The consequence is worse than a crash: the throw is captured as a build error, the dev server keeps running, and it serves stale output on every subsequent edit until restart. (#23024 improved terminal printing for failed HMR updates, but the hook-contract violation and the stale serving remain.) For anyone running Vite behind a wrapper — hosted dev servers, CI preview environments — this presents as "HMR silently stopped working."

Real-world occurrence: @tanstack/start-plugin-core reads this.environment.name on the first line of its hotUpdate hook (plugin.ts) — deterministic breakage on @tanstack/start-plugin-core 1.171.17–1.171.34, tracked in TanStack/router#8062 (guard PR TanStack/router#8061). These versions are pulled transitively by current @tanstack/react-start releases, so the blast radius is every TanStack Start app trying bundled dev.

Related issues, which we believe are distinct facets of the same underlying gap:

Suggested behavior until #22956 lands (in order of preference)

  1. Bind the environment for hotUpdate when plugins are handed to the full-bundle dev engine, even while the Phase 2 semantics (Bundled dev mode design doc and Road Map #22746) are still being designed.
  2. Or skip hotUpdate hooks entirely under bundled dev, with a one-time warning naming the plugin — an explicitly unsupported hook should not run with a context that violates its documented contract.
  3. At minimum, make the failure loud and attributed, rather than degrading to stale serving.

Reproduction

https://github.com/TIMTOMTOP/tanstack-hotupdate-repro

Steps to reproduce

  1. npm install && npm run dev (repro pins vite@8.2.1, @tanstack/react-start@1.168.44@tanstack/start-plugin-core@1.171.34)
  2. Set experimental: { bundledDev: true } (already set in the repro config)
  3. Edit any source file
  4. hotUpdate throws TypeError: Cannot read properties of undefined (reading 'name'); the error is captured as a build error and the dev server serves stale output for all subsequent edits until restart

System Info

vite: 8.2.1 (also verified the ROLLUP_HOOKS omission on v8.1.5 and main)
@tanstack/react-start: 1.168.44 (→ @tanstack/start-plugin-core 1.171.34)
See reproduction repository for the full manifest.

Used Package Manager

npm

Validations

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions