mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-11 08:33:53 +00:00
perf(nuxt): use LRU prerender cache and limit cached items (#22465)
This commit is contained in:
parent
2f065184d2
commit
3722325220
@ -273,6 +273,12 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
|
||||
// Init nitro
|
||||
const nitro = await createNitro(nitroConfig)
|
||||
|
||||
// Set prerender-only options
|
||||
nitro.options._config.storage ||= {}
|
||||
nitro.options._config.storage['internal:nitro:prerender'] = { driver: 'memory' }
|
||||
nitro.options._config.storage['internal:nitro:prerender:island'] = { driver: 'lruCache', max: 1000 }
|
||||
nitro.options._config.storage['internal:nitro:prerender:payload'] = { driver: 'lruCache', max: 1000 }
|
||||
|
||||
// Expose nitro to modules and kit
|
||||
nuxt._nitro = nitro
|
||||
await nuxt.callHook('nitro:init', nitro)
|
||||
|
@ -17,7 +17,7 @@ import { renderToString as _renderToString } from 'vue/server-renderer'
|
||||
import { hash } from 'ohash'
|
||||
import { renderSSRHead } from '@unhead/ssr'
|
||||
|
||||
import { defineRenderHandler, getRouteRules, useRuntimeConfig } from '#internal/nitro'
|
||||
import { defineRenderHandler, getRouteRules, useRuntimeConfig, useStorage } from '#internal/nitro'
|
||||
import { useNitroApp } from '#internal/nitro/app'
|
||||
|
||||
import type { Link, Script } from '@unhead/vue'
|
||||
@ -155,9 +155,18 @@ const getSPARenderer = lazyCachedFunction(async () => {
|
||||
}
|
||||
})
|
||||
|
||||
const payloadCache = process.env.prerender ? useStorage('internal:nuxt:prerender:payload') : null
|
||||
const islandCache = process.env.prerender ? useStorage('internal:nuxt:prerender:island') : null
|
||||
const islandPropCache = process.env.prerender ? useStorage('internal:nuxt:prerender:island-props') : null
|
||||
|
||||
async function getIslandContext (event: H3Event): Promise<NuxtIslandContext> {
|
||||
// TODO: Strict validation for url
|
||||
const url = event.node.req.url?.substring('/__nuxt_island'.length + 1) || ''
|
||||
let url = event.node.req.url || ''
|
||||
if (process.env.prerender && event.node.req.url && await islandPropCache!.hasItem(event.node.req.url)) {
|
||||
// rehydrate props from cache so we can rerender island if cache does not have it any more
|
||||
url = await islandPropCache!.getItem(event.node.req.url) as string
|
||||
}
|
||||
url = url.substring('/__nuxt_island'.length + 1) || ''
|
||||
const [componentName, hashId] = url.split('?')[0].split('_')
|
||||
|
||||
// TODO: Validate context
|
||||
@ -175,8 +184,6 @@ async function getIslandContext (event: H3Event): Promise<NuxtIslandContext> {
|
||||
return ctx
|
||||
}
|
||||
|
||||
const PAYLOAD_CACHE = (process.env.NUXT_PAYLOAD_EXTRACTION && process.env.prerender) ? new Map() : null // TODO: Use LRU cache
|
||||
const ISLAND_CACHE = (process.env.NUXT_COMPONENT_ISLANDS && process.env.prerender) ? new Map() : null // TODO: Use LRU cache
|
||||
const PAYLOAD_URL_RE = process.env.NUXT_JSON_PAYLOADS ? /\/_payload(\.[a-zA-Z0-9]+)?.json(\?.*)?$/ : /\/_payload(\.[a-zA-Z0-9]+)?.js(\?.*)?$/
|
||||
const ROOT_NODE_REGEX = new RegExp(`^<${appRootTag} id="${appRootId}">([\\s\\S]*)</${appRootTag}>$`)
|
||||
|
||||
@ -206,8 +213,8 @@ export default defineRenderHandler(async (event): Promise<Partial<RenderResponse
|
||||
? await getIslandContext(event)
|
||||
: undefined
|
||||
|
||||
if (process.env.prerender && islandContext && ISLAND_CACHE!.has(event.node.req.url)) {
|
||||
return ISLAND_CACHE!.get(event.node.req.url)
|
||||
if (process.env.prerender && islandContext && event.node.req.url && await islandCache!.hasItem(event.node.req.url)) {
|
||||
return islandCache!.getItem(event.node.req.url) as Promise<Partial<RenderResponse>>
|
||||
}
|
||||
|
||||
// Request url
|
||||
@ -218,8 +225,8 @@ export default defineRenderHandler(async (event): Promise<Partial<RenderResponse
|
||||
if (isRenderingPayload) {
|
||||
url = url.substring(0, url.lastIndexOf('/')) || '/'
|
||||
event.node.req.url = url
|
||||
if (process.env.prerender && PAYLOAD_CACHE!.has(url)) {
|
||||
return PAYLOAD_CACHE!.get(url)
|
||||
if (process.env.prerender && await payloadCache!.hasItem(url)) {
|
||||
return payloadCache!.getItem(url) as Promise<Partial<RenderResponse>>
|
||||
}
|
||||
}
|
||||
|
||||
@ -285,7 +292,7 @@ export default defineRenderHandler(async (event): Promise<Partial<RenderResponse
|
||||
if (isRenderingPayload) {
|
||||
const response = renderPayloadResponse(ssrContext)
|
||||
if (process.env.prerender) {
|
||||
PAYLOAD_CACHE!.set(url, response)
|
||||
await payloadCache!.setItem(url, response)
|
||||
}
|
||||
return response
|
||||
}
|
||||
@ -294,7 +301,7 @@ export default defineRenderHandler(async (event): Promise<Partial<RenderResponse
|
||||
// Hint nitro to prerender payload for this route
|
||||
appendResponseHeader(event, 'x-nitro-prerender', joinURL(url, process.env.NUXT_JSON_PAYLOADS ? '_payload.json' : '_payload.js'))
|
||||
// Use same ssr context to generate payload for this route
|
||||
PAYLOAD_CACHE!.set(withoutTrailingSlash(url), renderPayloadResponse(ssrContext))
|
||||
await payloadCache!.setItem(withoutTrailingSlash(url), renderPayloadResponse(ssrContext))
|
||||
}
|
||||
|
||||
if (process.env.NUXT_INLINE_STYLES && !islandContext) {
|
||||
@ -422,7 +429,8 @@ export default defineRenderHandler(async (event): Promise<Partial<RenderResponse
|
||||
}
|
||||
} satisfies RenderResponse
|
||||
if (process.env.prerender) {
|
||||
ISLAND_CACHE!.set(`/__nuxt_island/${islandContext!.name}_${islandContext!.id}`, response)
|
||||
await islandCache!.setItem(`/__nuxt_island/${islandContext!.name}_${islandContext!.id}`, response)
|
||||
await islandPropCache!.setItem(`/__nuxt_island/${islandContext!.name}_${islandContext!.id}`, event.node.req.url!)
|
||||
}
|
||||
return response
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user