Skip to content

refactor: iterate viteConfig.environments directly instead of re-invoking plugin config hook#442

Merged
onlywei merged 5 commits into
fastify:mainfrom
teneburu:feat/vite-env-discovery
Jul 2, 2026
Merged

refactor: iterate viteConfig.environments directly instead of re-invoking plugin config hook#442
onlywei merged 5 commits into
fastify:mainfrom
teneburu:feat/vite-env-discovery

Conversation

@teneburu

@teneburu teneburu commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Refactor environment discovery to iterate viteConfig.environments directly

Removes the fragile findPlugin / hasPlugin pattern that re-invoked the plugin's config hook to discover environment entry paths. Instead, reads viteConfig.environments directly — the same source of truth Vite already provides.

Why

The old approach called the plugin's config hook a second time at runtime to reconstruct environment configuration. This broke when another plugin (like @vitejs/plugin-rsc) modified the same environments during its own config hook — the re-invocation could produce a different result or fail outright.

The new approach iterates viteConfig.environments directly, which is always available after Vite resolves its config. No plugin introspection needed.

Changes

  • development.ts (environment config)loadEntryModulePaths() now walks viteConfig.environments directly, instead of re-invoking the plugin's config hook on a synthetic object. Removes the findPlugin/hasPlugin introspection helpers and the ViteEnvironmentsConfig interface. Because the new path reads already-resolved config, it also strips Vite's internal \0 null-byte prefix from virtual module IDs. The file deletes ~90 lines total. Returns null (not {}) when no environments match — the caller handles both identically.

  • development.ts (runner reuse)loadEntries() uses isRunnableDevEnvironment(envConfig).runner where available, falling back to createServerModuleRunner(). Avoids creating a duplicate ModuleRunner when @vitejs/plugin-rsc later accesses envConfig.runner via its lazy getter for cross-environment imports.

  • plugin.ts — Generalizes rollupOptions.input from { index?: string } to Record<string, string>. Iterates all input entries, not just the one named index. Required when Vite environments register entries under non-standard names.

  • development.test.ts — Adds environments field to the mock config so loadEntryModulePaths is exercised as intended.

Verification

  • All 86 tests pass (78 runtime + 8 typecheck)
  • tsc build produces no errors
  • No breaking changes — iterates environments that always exist in Vite 8, falls back gracefully (returns null) when none match

teneburu added 4 commits July 2, 2026 17:19
Replace the ViteEnvironmentsConfig/findPlugin/hasPlugin pattern with
direct iteration over viteConfig.environments. This supports the RSC
environment without requiring manual plugin config hook invocation.
The development.ts refactor (iterating viteConfig.environments directly
instead of re-invoking the plugin config hook) changed the contract:
loadEntryModulePaths now reads viteConfig.environments.ssr.build.rollupOptions.input
to discover entry paths. Add the environments field to the test mock
so createServerModuleRunner is exercised as intended.
…double SSR ModuleRunner

loadEntries() called createServerModuleRunner(envConfig) unconditionally,
creating a separate ModuleRunner. When @vitejs/plugin-rsc later performed
cross-environment imports via import.meta.viteRsc.import('ssr', ...),
RunnableDevEnvironment.runner lazy getter created a second independent
ModuleRunner — causing duplicate '(ssr) connected' logs and duplicate
HMR connections.

For RunnableDevEnvironment instances, use envConfig.runner (the same
cached getter the RSC plugin uses) instead of createServerModuleRunner.
Generalize the rollupOptions.input type from { index?: string } to
Record<string, string> and iterate over all entries instead of only
the 'index' key. This is required when vite environments use
non-standard entry names (e.g., when @vitejs/plugin-rsc registers
its own build environments).
@changeset-bot

changeset-bot Bot commented Jul 2, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 6098208

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@fastify/vite Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@teneburu teneburu changed the title Refactor environment discovery to iterate viteConfig.environments directly refactor: iterate viteConfig.environments directly instead of re-invoking plugin config hook Jul 2, 2026
@onlywei
onlywei merged commit e70066c into fastify:main Jul 2, 2026
4 checks passed
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.

2 participants