fix(nuxt): render user-inserted links in island responses (#25219)

This commit is contained in:
Daniel Roe 2024-01-16 12:36:26 +00:00 committed by GitHub
parent 84eaf7ba2e
commit 20e88bb171
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 29 additions and 25 deletions

View File

@ -229,9 +229,8 @@ export default defineRenderHandler(async (event): Promise<Partial<RenderResponse
}
// Check for island component rendering
const islandContext = (process.env.NUXT_COMPONENT_ISLANDS && event.path.startsWith('/__nuxt_island'))
? await getIslandContext(event)
: undefined
const isRenderingIsland = (process.env.NUXT_COMPONENT_ISLANDS as unknown as boolean && event.path.startsWith('/__nuxt_island'))
const islandContext = isRenderingIsland ? await getIslandContext(event) : undefined
if (import.meta.prerender && islandContext && event.path && await islandCache!.hasItem(event.path)) {
return islandCache!.getItem(event.path) as Promise<Partial<RenderResponse>>
@ -241,7 +240,7 @@ export default defineRenderHandler(async (event): Promise<Partial<RenderResponse
let url = ssrError?.url as string || islandContext?.url || event.path
// Whether we are rendering payload route
const isRenderingPayload = PAYLOAD_URL_RE.test(url) && !islandContext
const isRenderingPayload = PAYLOAD_URL_RE.test(url) && !isRenderingIsland
if (isRenderingPayload) {
url = url.substring(0, url.lastIndexOf('/')) || '/'
@ -260,7 +259,9 @@ export default defineRenderHandler(async (event): Promise<Partial<RenderResponse
})
// needed for hash hydration plugin to work
const headEntryOptions: HeadEntryOptions = { mode: 'server' }
if (!isRenderingIsland) {
head.push(appHead, headEntryOptions)
}
// Initialize ssr context
const ssrContext: NuxtSSRContext = {
@ -270,7 +271,7 @@ export default defineRenderHandler(async (event): Promise<Partial<RenderResponse
noSSR:
!!(process.env.NUXT_NO_SSR) ||
event.context.nuxt?.noSSR ||
(routeOptions.ssr === false && !islandContext) ||
(routeOptions.ssr === false && !isRenderingIsland) ||
(import.meta.prerender ? PRERENDER_NO_SSR_ROUTES.has(url) : false),
head,
error: !!ssrError,
@ -281,7 +282,7 @@ export default defineRenderHandler(async (event): Promise<Partial<RenderResponse
}
// Whether we are prerendering route
const _PAYLOAD_EXTRACTION = import.meta.prerender && process.env.NUXT_PAYLOAD_EXTRACTION && !ssrContext.noSSR && !islandContext
const _PAYLOAD_EXTRACTION = import.meta.prerender && process.env.NUXT_PAYLOAD_EXTRACTION && !ssrContext.noSSR && !isRenderingIsland
const payloadURL = _PAYLOAD_EXTRACTION ? joinURL(useRuntimeConfig().app.baseURL, url, process.env.NUXT_JSON_PAYLOADS ? '_payload.json' : '_payload.js') : undefined
if (import.meta.prerender) {
ssrContext.payload.prerenderedAt = Date.now()
@ -330,7 +331,7 @@ export default defineRenderHandler(async (event): Promise<Partial<RenderResponse
await payloadCache!.setItem(withoutTrailingSlash(url), renderPayloadResponse(ssrContext))
}
if (process.env.NUXT_INLINE_STYLES && !islandContext) {
if (process.env.NUXT_INLINE_STYLES && !isRenderingIsland) {
const source = ssrContext.modules ?? ssrContext._registeredComponents
if (source) {
for (const id of await getEntryIds()) {
@ -340,7 +341,7 @@ export default defineRenderHandler(async (event): Promise<Partial<RenderResponse
}
// Render inline styles
const inlinedStyles = (process.env.NUXT_INLINE_STYLES || Boolean(islandContext))
const inlinedStyles = (process.env.NUXT_INLINE_STYLES || isRenderingIsland)
? await renderInlineStyles(ssrContext.modules ?? ssrContext._registeredComponents ?? [])
: []
@ -349,7 +350,7 @@ export default defineRenderHandler(async (event): Promise<Partial<RenderResponse
// Setup head
const { styles, scripts } = getRequestDependencies(ssrContext, renderer.rendererContext)
// 1.Extracted payload preloading
if (_PAYLOAD_EXTRACTION) {
if (_PAYLOAD_EXTRACTION && !isRenderingIsland) {
head.push({
link: [
process.env.NUXT_JSON_PAYLOADS
@ -361,14 +362,18 @@ export default defineRenderHandler(async (event): Promise<Partial<RenderResponse
// 2. Styles
head.push({ style: inlinedStyles })
head.push({
link: Object.values(styles)
.map(resource =>
({ rel: 'stylesheet', href: renderer.rendererContext.buildAssetsURL(resource.file) })
)
}, headEntryOptions)
if (!isRenderingIsland || import.meta.dev) {
const link = []
for (const style in styles) {
const resource = styles[style]
if (!import.meta.dev || (resource.file.includes('scoped') && !resource.file.includes('pages/'))) {
link.push({ rel: 'stylesheet', href: renderer.rendererContext.buildAssetsURL(resource.file) })
}
}
head.push({ link }, headEntryOptions)
}
if (!NO_SCRIPTS) {
if (!NO_SCRIPTS && !isRenderingIsland) {
// 3. Resource Hints
// TODO: add priorities based on Capo
head.push({
@ -395,7 +400,7 @@ export default defineRenderHandler(async (event): Promise<Partial<RenderResponse
}
// 5. Scripts
if (!routeOptions.experimentalNoScripts) {
if (!routeOptions.experimentalNoScripts && !isRenderingIsland) {
head.push({
script: Object.values(scripts).map(resource => (<Script> {
type: resource.module ? 'module' : null,
@ -411,7 +416,7 @@ export default defineRenderHandler(async (event): Promise<Partial<RenderResponse
// Create render context
const htmlContext: NuxtRenderHTMLContext = {
island: Boolean(islandContext),
island: isRenderingIsland,
htmlAttrs: htmlAttrs ? [htmlAttrs] : [],
head: normalizeChunks([headTags, ssrContext.styles]),
bodyAttrs: bodyAttrs ? [bodyAttrs] : [],
@ -424,16 +429,15 @@ export default defineRenderHandler(async (event): Promise<Partial<RenderResponse
await nitroApp.hooks.callHook('render:html', htmlContext, { event })
// Response for component islands
if (process.env.NUXT_COMPONENT_ISLANDS && islandContext) {
if (isRenderingIsland && islandContext) {
const islandHead: NuxtIslandResponse['head'] = {
link: [],
style: []
}
for (const tag of await head.resolveTags()) {
if (tag.tag === 'link' && tag.props.rel === 'stylesheet' && tag.props.href.includes('scoped') && !tag.props.href.includes('pages/')) {
islandHead.link.push({ ...tag.props, key: 'island-link-' + hash(tag.props.href) })
}
if (tag.tag === 'style' && tag.innerHTML) {
if (tag.tag === 'link') {
islandHead.link.push({ key: 'island-link-' + hash(tag.props), ...tag.props })
} else if (tag.tag === 'style' && tag.innerHTML) {
islandHead.style.push({ key: 'island-style-' + hash(tag.innerHTML), innerHTML: tag.innerHTML })
}
}

View File

@ -32,7 +32,7 @@ describe.skipIf(process.env.SKIP_BUNDLE_SIZE === 'true' || process.env.ECOSYSTEM
const serverDir = join(rootDir, '.output/server')
const serverStats = await analyzeSizes(['**/*.mjs', '!node_modules'], serverDir)
expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot(`"200k"`)
expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot(`"201k"`)
const modules = await analyzeSizes('node_modules/**/*', serverDir)
expect.soft(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot(`"1335k"`)