Skip to content

fix: flush class manifest on SSR renderStart/generateBundle#43

Open
jrmybtlr wants to merge 6 commits into
mainfrom
cursor/ssr-manifest-robustness-184b
Open

fix: flush class manifest on SSR renderStart/generateBundle#43
jrmybtlr wants to merge 6 commits into
mainfrom
cursor/ssr-manifest-robustness-184b

Conversation

@jrmybtlr

@jrmybtlr jrmybtlr commented Jul 17, 2026

Copy link
Copy Markdown
Owner

Summary

manifestRoot already handles Nuxt srcDir, but there was no SSR-aware flush path. Builds could leave .classy/output.classy.html stale, and dual client+SSR environments could overwrite a shared manifest with a smaller server-side class set.

Changes

  • Add flushManifest() and call it from renderStart, generateBundle, and buildEnd
  • During builds, skip per-module writes in scheduleManifestWrite (flush hooks own the final write)
  • Skip all manifest writes from Vite Environment API server instances (consumer === 'server' / name === 'ssr') so only the client owns the shared file
  • Classic build.ssr without an Environment API server consumer still flushes
  • Detect SSR via config.build.ssr and the Environment API for logging / gating

Why these hooks

Hook Client Classic SSR (build.ssr) Env API server
renderStart flush skipped (client owns file)
generateBundle flush skipped
buildEnd flush skipped

Review follow-ups

Addressed Copilot review plus dual-env overwrite hardening:

  1. No per-module sync writes during build transforms
  2. Flush tests assert via mocked fs (static index import is not replaced by vi.doMock)
  3. Typed generateBundle(outputOptions, bundle, isWrite) test call
  4. Environment API server instances never write the shared manifest

Test plan

  • Classic SSR renderStart flush
  • Environment API server skips flush / scan writes
  • Dev no-op + no per-module write during build transform
  • Full suite: 202 passed
Open in Web Open in Cursor 

transformIndexHtml is client-only, so SSR builds could keep a stale
.classy manifest through the first server render. Flush after transforms
via renderStart and generateBundle, and write immediately during builds
instead of relying on the debounced path.

Co-authored-by: Jeremy Butler <jrmybtlr@users.noreply.github.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 17, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
useclassy-com 7aac889 Commit Preview URL

Branch Preview URL
Jul 21 2026, 09:58 PM

@jrmybtlr

Copy link
Copy Markdown
Owner Author

@copilot resolve the merge conflicts in this pull request

Copilot AI commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

Merged origin/main into this branch. The only conflict was tasks/todo.md (deleted in main, kept in this branch) — resolved by accepting the deletion. All 200 tests pass.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR makes the useClassy Vite plugin SSR-build aware by adding explicit manifest flush points during the Rollup/Vite build pipeline so .classy/output.classy.html can’t remain stale for SSR/server output.

Changes:

  • Add flushManifest() and invoke it from renderStart, generateBundle, and buildEnd to cover SSR builds that don’t run transformIndexHtml.
  • Change write scheduling so builds use immediate writes (vs. the existing debounced path in dev).
  • Add unit tests covering the new hooks and SSR/dev behavior; update lockfile for dependency/tooling changes.

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated 3 comments.

File Description
src/index.ts Adds SSR/build flush hooks and refactors manifest writing into helper functions.
src/tests/index.test.ts Adds tests intended to validate the new flush hooks and dev no-op behavior.
package-lock.json Updates lockfile for version/dependency/tooling changes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/index.ts Outdated
Comment on lines +154 to +172
/** Prefer an immediate write during builds so debounce cannot leave the file stale. */
function scheduleManifestWrite(): void {
if (isBuild) {
writeDirect(
allClassesSet,
outputDir,
outputFileName,
manifestRoot,
)
return
}

writeDebounced(
allClassesSet,
outputDir,
outputFileName,
manifestRoot,
)
}
Comment thread src/tests/index.test.ts Outdated
Comment on lines +625 to +631
it('should flush the manifest on renderStart during SSR builds', async () => {
const fs = await import('fs')
const writeSpy = vi.spyOn(fs.default, 'writeFileSync').mockImplementation(() => undefined)
const renameSpy = vi.spyOn(fs.default, 'renameSync').mockImplementation(() => undefined)
;(fs.default.existsSync as unknown as ReturnType<typeof vi.fn>).mockReturnValue(false)
;(fs.default.mkdirSync as unknown as ReturnType<typeof vi.fn>).mockImplementation(() => undefined)

Comment thread src/tests/index.test.ts
Comment on lines +713 to +720
if (typeof plugin.generateBundle === 'function') {
await plugin.generateBundle.call(
{} as never,
{} as never,
{} as never,
false,
)
}
cursoragent and others added 2 commits July 21, 2026 17:16
Defer build-time manifest writes to renderStart/generateBundle/buildEnd
instead of sync-writing on every transform. Clarify flush tests around
the real writer (via fs) and generateBundle's Rollup signature.

Co-authored-by: Jeremy Butler <jrmybtlr@users.noreply.github.com>
In dual client+SSR setups, only the client instance writes the shared
manifest so a smaller server class set cannot overwrite it. Classic
build.ssr without an Environment API server consumer still flushes.

Co-authored-by: Jeremy Butler <jrmybtlr@users.noreply.github.com>
@jrmybtlr

Copy link
Copy Markdown
Owner Author

@copilot resolve the merge conflicts in this pull request

@jrmybtlr
jrmybtlr marked this pull request as ready for review July 21, 2026 21:54
@cursor

cursor Bot commented Jul 21, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

Copilot AI commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

Merged origin/main into this branch. The only conflict was package-lock.json (deleted in main, modified in this branch) — resolved by accepting the deletion. All 202 tests pass.

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.

4 participants