perf(nuxt): use reducer array + handle modified proto (#28768)

This commit is contained in:
Daniel Roe 2024-09-02 12:14:18 +01:00
parent 3c4949acfb
commit 90f4447b37
No known key found for this signature in database
GPG Key ID: 3714AB03996F442B
4 changed files with 30 additions and 37 deletions

View File

@ -272,6 +272,7 @@ export function createNuxtApp (options: CreateOptions) {
get vue () { return nuxtApp.vueApp.version },
},
payload: shallowReactive({
...options.ssrContext?.payload || {},
data: shallowReactive({}),
state: reactive({}),
once: new Set<string>(),
@ -315,6 +316,20 @@ export function createNuxtApp (options: CreateOptions) {
nuxtApp.payload.serverRendered = true
}
if (import.meta.server && nuxtApp.ssrContext) {
nuxtApp.payload.path = nuxtApp.ssrContext.url
// Expose nuxt to the renderContext
nuxtApp.ssrContext.nuxt = nuxtApp
nuxtApp.ssrContext.payload = nuxtApp.payload
// Expose client runtime-config to the payload
nuxtApp.ssrContext.config = {
public: nuxtApp.ssrContext.runtimeConfig.public,
app: nuxtApp.ssrContext.runtimeConfig.app,
}
}
if (import.meta.client) {
const __NUXT__ = multiApp ? window.__NUXT__?.[nuxtApp._id] : window.__NUXT__
// TODO: remove/refactor in https://github.com/nuxt/nuxt/issues/25336
@ -361,29 +376,6 @@ export function createNuxtApp (options: CreateOptions) {
defineGetter(nuxtApp.vueApp, '$nuxt', nuxtApp)
defineGetter(nuxtApp.vueApp.config.globalProperties, '$nuxt', nuxtApp)
if (import.meta.server) {
if (nuxtApp.ssrContext) {
// Expose nuxt to the renderContext
nuxtApp.ssrContext.nuxt = nuxtApp
// Expose payload types
nuxtApp.ssrContext._payloadReducers = {}
// Expose current path
nuxtApp.payload.path = nuxtApp.ssrContext.url
}
// Expose to server renderer to create payload
nuxtApp.ssrContext = nuxtApp.ssrContext || {} as any
if (nuxtApp.ssrContext!.payload) {
Object.assign(nuxtApp.payload, nuxtApp.ssrContext!.payload)
}
nuxtApp.ssrContext!.payload = nuxtApp.payload
// Expose client runtime-config to the payload
nuxtApp.ssrContext!.config = {
public: options.ssrContext!.runtimeConfig.public,
app: options.ssrContext!.runtimeConfig.app,
}
}
// Listen to chunk load errors
if (import.meta.client) {
window.addEventListener('nuxt.preloadError', (event) => {

View File

@ -6,25 +6,25 @@ import { defineNuxtPlugin } from '../nuxt'
// @ts-expect-error Virtual file.
import { componentIslands } from '#build/nuxt.config.mjs'
const reducers: Record<string, (data: any) => any> = {
NuxtError: data => isNuxtError(data) && data.toJSON(),
EmptyShallowRef: data => isRef(data) && isShallow(data) && !data.value && (typeof data.value === 'bigint' ? '0n' : (JSON.stringify(data.value) || '_')),
EmptyRef: data => isRef(data) && !data.value && (typeof data.value === 'bigint' ? '0n' : (JSON.stringify(data.value) || '_')),
ShallowRef: data => isRef(data) && isShallow(data) && data.value,
ShallowReactive: data => isReactive(data) && isShallow(data) && toRaw(data),
Ref: data => isRef(data) && data.value,
Reactive: data => isReactive(data) && toRaw(data),
}
const reducers: [string, (data: any) => any][] = [
['NuxtError', data => isNuxtError(data) && data.toJSON()],
['EmptyShallowRef', data => isRef(data) && isShallow(data) && !data.value && (typeof data.value === 'bigint' ? '0n' : (JSON.stringify(data.value) || '_'))],
['EmptyRef', data => isRef(data) && !data.value && (typeof data.value === 'bigint' ? '0n' : (JSON.stringify(data.value) || '_'))],
['ShallowRef', data => isRef(data) && isShallow(data) && data.value],
['ShallowReactive', data => isReactive(data) && isShallow(data) && toRaw(data)],
['Ref', data => isRef(data) && data.value],
['Reactive', data => isReactive(data) && toRaw(data)],
]
if (componentIslands) {
reducers.Island = data => data && data?.__nuxt_island
reducers.push(['Island', data => data && data?.__nuxt_island])
}
export default defineNuxtPlugin({
name: 'nuxt:revive-payload:server',
setup () {
for (const reducer in reducers) {
definePayloadReducer(reducer, reducers[reducer as keyof typeof reducers])
for (const [reducer, fn] of reducers) {
definePayloadReducer(reducer, fn)
}
},
})

View File

@ -77,7 +77,8 @@ export default (nitroApp: NitroApp) => {
const ctx = asyncContext.tryUse()
if (!ctx) { return }
try {
htmlContext.bodyAppend.unshift(`<script type="application/json" data-nuxt-logs="${appId}">${stringify(ctx.logs, { ...devReducers, ...ctx.event.context._payloadReducers })}</script>`)
const reducers = Object.assign(Object.create(null), devReducers, ctx.event.context._payloadReducers)
htmlContext.bodyAppend.unshift(`<script type="application/json" data-nuxt-logs="${appId}">${stringify(ctx.logs, reducers)}</script>`)
} catch (e) {
const shortError = e instanceof Error && 'toString' in e ? ` Received \`${e.toString()}\`.` : ''
console.warn(`[nuxt] Failed to stringify dev server logs.${shortError} You can define your own reducer/reviver for rich types following the instructions in https://nuxt.com/docs/api/composables/use-nuxt-app#payload.`)

View File

@ -306,7 +306,7 @@ export default defineRenderHandler(async (event): Promise<Partial<RenderResponse
error: !!ssrError,
nuxt: undefined!, /* NuxtApp */
payload: (ssrError ? { error: ssrError } : {}) as NuxtPayload,
_payloadReducers: {},
_payloadReducers: Object.create(null),
modules: new Set(),
islandContext,
}