perf(nuxt): skip island-renderer chunk when no islands used - #35456
#35456perf(nuxt): skip island-renderer chunk when no islands used#35456danielroe merged 4 commits intomainnuxt/nuxt:mainfrom perf/skip-inactive-island-renderernuxt/nuxt:perf/skip-inactive-island-rendererCopy head branch name to clipboard
Conversation
Route the root component's island renderer through a generated `#build/island-renderer.mjs` template. In default `auto` mode with no server components or server pages, the template exports a null component, so Vite never pulls `app/components/island-renderer` and its async chunk into the SSR build. Active islands (server components/pages, explicit `componentIslands`, or dev) resolve to the real renderer unchanged.
@nuxt/kit
@nuxt/nitro-server
nuxt
@nuxt/rspack-builder
@nuxt/schema
@nuxt/vite-builder
@nuxt/webpack-builder
commit: |
This comment has been minimized.
This comment has been minimized.
|
|
||
| const serverStats = await analyzeSizes(['**/*.mjs', '!_libs'], serverDir, rootDir) | ||
| expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot(`"70.2k"`) | ||
| expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot(`"70.3k"`) |
There was a problem hiding this comment.
I wonder why this is happening - shouldn't it go the other way, if anything?
There was a problem hiding this comment.
Already investigating why!
There was a problem hiding this comment.
This might be correct.
We get +23B through that change which pushes us over the limit for rounding 🙈
Before we could skip the whole declaration, but through the no-op we get const IslandRenderer = () => null. So, no "real increase" here
There was a problem hiding this comment.
reworked this so we don't rely on a named fn that gets mangled.
danielroe
left a comment
There was a problem hiding this comment.
I think we should add an assertion to bundle.test.ts about the number of client-side chunks - wdyt?
Merging this PR will not alter performance
Comparing Footnotes
|
Use knitwork's genDynamicImport helper instead of manual JSON.stringify interpolation, matching the convention used by the other templates (e.g. testComponentWrapperTemplate) and resolving the CodeQL 'improper code sanitization' alert.
Why client-side? In this case the chunks of the server built are reduced. |
Emit a named `IslandRenderer` binding from the template instead of an anonymous default export. This lets rolldown reuse the short name in the server entry rather than a verbose module-path-derived one; the server bundle ends up ~37 bytes smaller than before (the no-op is retained as it is referenced, but the island chunk's re-exports are dropped). Reverts the autofix snapshot bump as the size returns to its prior bucket.
|
ah! |
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
🔗 Linked issue
None (perf gainzzz)
📚 Description
This PR uses a generated
#build/island-renderer.mjstemplate for the island renderer.In default
automode with no server components or server pages, the template exports anullcomponent, so Vite never pullsapp/components/island-rendererand its async chunk into the SSR build.Bench
Local stats (15 interleaved runs):
This can vary by app of course and will only applied w/o islands.