fix(nuxt): add VNode reviver & don't deduplicate dev logs (#27309)

This commit is contained in:
Daniel Roe 2024-05-23 16:25:06 +01:00 committed by GitHub
parent c054ca084c
commit 47c47c9b42
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 23 additions and 34 deletions

View File

@ -1,13 +1,20 @@
import { consola, createConsola } from 'consola'
import { createConsola } from 'consola'
import type { LogObject } from 'consola'
import { parse } from 'devalue'
import { h } from 'vue'
import { defineNuxtPlugin } from '../nuxt'
// @ts-expect-error virtual file
import { devLogs, devRootDir } from '#build/nuxt.config.mjs'
export default defineNuxtPlugin((nuxtApp) => {
const devRevivers: Record<string, (data: any) => any> = import.meta.server
? {}
: {
VNode: data => h(data.type, data.props),
}
export default defineNuxtPlugin(async (nuxtApp) => {
if (import.meta.test) { return }
if (import.meta.server) {
@ -23,42 +30,18 @@ export default defineNuxtPlugin((nuxtApp) => {
date: true,
},
})
const hydrationLogs = new Set<string>()
consola.wrapConsole()
consola.addReporter({
log (logObj) {
try {
hydrationLogs.add(JSON.stringify(logObj.args))
} catch {
// silently ignore - the worst case is a user gets log twice
}
},
})
nuxtApp.hook('dev:ssr-logs', (logs) => {
for (const log of logs) {
// deduplicate so we don't print out things that are logged on client
try {
if (!hydrationLogs.size || !hydrationLogs.has(JSON.stringify(log.args))) {
logger.log(normalizeServerLog({ ...log }))
}
} catch {
logger.log(normalizeServerLog({ ...log }))
}
logger.log(normalizeServerLog({ ...log }))
}
})
nuxtApp.hooks.hook('app:suspense:resolve', () => consola.restoreAll())
nuxtApp.hooks.hookOnce('dev:ssr-logs', () => hydrationLogs.clear())
}
// pass SSR logs after hydration
nuxtApp.hooks.hook('app:suspense:resolve', async () => {
if (typeof window !== 'undefined') {
const content = document.getElementById('__NUXT_LOGS__')?.textContent
const logs = content ? parse(content, nuxtApp._payloadRevivers) as LogObject[] : []
await nuxtApp.hooks.callHook('dev:ssr-logs', logs)
}
})
if (typeof window !== 'undefined') {
const content = document.getElementById('__NUXT_LOGS__')?.textContent
const logs = content ? parse(content, { ...devRevivers, ...nuxtApp._payloadRevivers }) as LogObject[] : []
await nuxtApp.hooks.callHook('dev:ssr-logs', logs)
}
})
function normalizeFilenames (stack?: string) {

View File

@ -6,11 +6,16 @@ import type { H3Event } from 'h3'
import { withTrailingSlash } from 'ufo'
import { getContext } from 'unctx'
import { isVNode } from 'vue'
import type { NitroApp } from '#internal/nitro/app'
// @ts-expect-error virtual file
import { rootDir } from '#internal/dev-server-logs-options'
const devReducers: Record<string, (data: any) => any> = {
VNode: data => isVNode(data) ? { type: data.type, props: data.props } : undefined,
}
interface NuxtDevAsyncContext {
logs: LogObject[]
event: H3Event
@ -54,9 +59,10 @@ export default (nitroApp: NitroApp) => {
const ctx = asyncContext.tryUse()
if (!ctx) { return }
try {
htmlContext.bodyAppend.unshift(`<script type="application/json" id="__NUXT_LOGS__">${stringify(ctx.logs, ctx.event.context._payloadReducers)}</script>`)
htmlContext.bodyAppend.unshift(`<script type="application/json" id="__NUXT_LOGS__">${stringify(ctx.logs, { ...devReducers, ...ctx.event.context._payloadReducers })}</script>`)
} catch (e) {
console.warn('[nuxt] Failed to stringify dev server logs. You can define your own reducer/reviver for rich types following the instructions in https://nuxt.com/docs/api/composables/use-nuxt-app#payload.', 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.`)
}
})
}