Skip to content

Migrate to Vite 8 and improve the codebase by introducing roles#31

Merged
thetutlage merged 8 commits into5.xfrom
refactor/runtime-strategy
May 9, 2026
Merged

Migrate to Vite 8 and improve the codebase by introducing roles#31
thetutlage merged 8 commits into5.xfrom
refactor/runtime-strategy

Conversation

@thetutlage
Copy link
Copy Markdown
Member

No description provided.

thetutlage added 6 commits May 3, 2026 10:41
Bump peerDep + devDep to vite ^8.0.0. Rename build.rollupOptions to
build.rolldownOptions in plugin config, with fallback chain that
honors user-provided rolldownOptions.input then legacy rollupOptions.input
for backwards compat.

Add npm overrides to allow vite-plugin-restart 2.0.0 (peer pinned to
^7.0.0) to resolve against vite 8 — plugin internals only use stable
Vite plugin API.

Smoke tests added to cover Vite 8 touchpoints: config defaults,
manifest shape, CSS chunk emission, dynamic imports, build error
shape, createBuilder().buildApp(), plugin compat, outDir override.

Existing CSS-collection tests updated to use rolldownOptions.

BREAKING CHANGE: requires vite ^8.0.0 as peer dependency.
Drop the vite-plugin-restart dependency in favor of a local plugin
implementation at src/client/reload.ts. The upstream package is
unmaintained and pins its peer to vite ^7, blocking clean installs
on vite 8.

Only the browser-reload feature was used (server.restart was never
exposed via defineConfig), so the new plugin is reload-only: it
debounces watcher events that match the user-supplied glob patterns
and emits a full-reload WS message.

Implementation details:
- Uses picomatch for matching (Vite's bundled glob engine).
- Watches the longest non-glob prefix of each pattern so newly
  created files inside watched dirs trigger reloads under chokidar 4
  (which removed glob support entirely).
- 100ms default debounce, configurable via { delay }.

Plugin is internal — not exported from package.json. Test helpers
(bootDevServer, waitForReload) added to tests/backend/helpers.ts.
Replaces the import.meta.glob pattern that was used by app authors to
register static assets (images, fonts) into the build output. Vite 8
no longer emits non-JS modules through import.meta.glob, breaking
that pattern.

The new assets option on the AdonisJS plugin accepts:

- string[]: shorthand for { chunks }, glob-expanded and emitted via
  emitFile({ type: 'chunk' }).
- { chunks?, assets? }: chunks behave as above; assets are exact file
  paths (no glob — throws on glob chars) emitted as raw type: 'asset'.
  The manifest is rewritten post-write so the manifest key matches
  the original source path, letting templates resolve via
  vite.assetPath('resources/images/logo.png').

Implemented as a pair of plugins (emit + manifest rewrite) in
src/client/resolve_assets.ts. tinyglobby is added as a direct dep
(was already transitive via @adonisjs/assembler).
Cover the runtime touchpoints between AdonisJS and Vite that were not
exercised by the existing suite — surfaces that could silently regress
on a future Vite upgrade.

- dev_server.spec.ts: createDevServer middlewareMode contract,
  useDevServer flag, VITE_HMR_PORT env wiring, moduleGraph
  getModuleById/idToModuleMap after warmupRequest, environments.ssr
  and environments.client presence, middlewares Connect API,
  stopDevServer cleanup, adonisjs plugin integration.
- module_runner.spec.ts: createModuleRunner returns ModuleRunner,
  runner.import loads a fixture module via the SSR environment, the
  vite/module-runner subpath export resolves.
- middleware.spec.ts: extended with three proxy cases — /@vite/client,
  a .ts entrypoint (asserts type stripping), and a CSS file.
- vite.spec.ts: re-skipped the recursive CSS collection test with an
  accurate reason (server-side warmupRequest does not transitively
  load nested imports the way a browser would).
Vite was a 519-line class mixing config, manifest reading, dev server
lifecycle, tag generation, manifest chunk walking, dev module graph
walking, and URL resolution — all branching on `useDevServer` at every
mode-aware method.

Split into a thin facade plus single-role collaborators:

  - TagBuilder            HTML element factory (link/script/preload)
  - ManifestLoader        lazy load + chunk lookup
  - AssetUrlBuilder       (Dev|Build) URL resolution strategy
  - EntrypointWalker      (DevCssGraph|ManifestChunk) traversal strategy
  - EntrypointTagRenderer shared walker + tagBuilder composition
  - ViteRuntime           (Dev|Build) mode-specific behavior bundle

Polymorphism point is the walker; renderer + tag builder are mode-free
and shared. Every `if (this.useDevServer)` branch in Vite is gone.

New seam: vite.useRuntime(runtime). Provider builds DevRuntime via
DevRuntime.create() and installs it explicitly in ready(). The
existing vite.createDevServer() is kept as a backward-compat wrapper.

Public API unchanged. All 101 tests pass; lint + typecheck clean.
@thetutlage thetutlage changed the title Improving the codebase by introducing roles Migrate to Vite 8 and improve the codebase by introducing roles May 4, 2026
@FlorianV85 FlorianV85 mentioned this pull request May 9, 2026
6 tasks
thetutlage added 2 commits May 9, 2026 20:00
picomatch and tinyglobby expect POSIX paths, but Vite's config root and
chokidar events use native separators. On Windows this caused the reload
plugin to never match changed files and the resolve_assets glob to skip
all chunk patterns, leaving asset manifest keys with backslashes.
`path.join` returns native separators, so on Windows the entrypoint
inputs forwarded to rolldown carried backslashes. That diverged from
the POSIX-style paths Vite uses everywhere else (manifest keys, module
IDs), which broke asset lookups built around forward-slash keys.
@thetutlage thetutlage merged commit e4601a6 into 5.x May 9, 2026
8 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.

1 participant