feat(vue-app): context.beforeSerialize method (#9332)

Co-authored-by: Sébastien Chopin <seb@nuxtjs.com>
Co-authored-by: Daniel Roe <daniel@roe.dev>
Co-authored-by: pooya parsa <pyapar@gmail.com>
This commit is contained in:
David Ovčačík 2021-06-04 16:21:16 +02:00 committed by GitHub
parent fa12cf1e2d
commit 9f02e5dae7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 49 additions and 6 deletions

View File

@ -72,6 +72,7 @@ export interface Context {
redirected: boolean
next: NextFunction
beforeRenderFns: Array<() => any>
beforeSerializeFns: Array<() => any>
fetchCounters: Record<string, number>
nuxt: {
layout: string
@ -87,6 +88,7 @@ export interface Context {
error(params: NuxtError): void
nuxtState: NuxtState
beforeNuxtRender(fn: (params: { Components: VueRouter['getMatchedComponents'], nuxtState: NuxtState }) => void): void
beforeSerialize(fn: (nuxtState: NuxtState) => void): void
enablePreview?: (previewData?: Record<string, any>) => void
$preview?: Record<string, any>
}

View File

@ -183,6 +183,7 @@ async function createApp(ssrContext, config = {}) {
req: ssrContext ? ssrContext.req : undefined,
res: ssrContext ? ssrContext.res : undefined,
beforeRenderFns: ssrContext ? ssrContext.beforeRenderFns : undefined,
beforeSerializeFns: ssrContext ? ssrContext.beforeSerializeFns : undefined,
ssrContext
})

View File

@ -85,6 +85,8 @@ export default async (ssrContext) => {
ssrContext.next = createNext(ssrContext)
// Used for beforeNuxtRender({ Components, nuxtState })
ssrContext.beforeRenderFns = []
// for beforeSerialize(nuxtState)
ssrContext.beforeSerializeFns = []
// Nuxt object (window.{{globals.context}}, defaults to window.__NUXT__)
ssrContext.nuxt = { <% if (features.layouts) { %>layout: 'default', <% } %>data: [], <% if (features.fetch) { %>fetch: {}, <% } %>error: null<%= (store ? ', state: null' : '') %>, serverRendered: true, routePath: '' }
<% if (features.fetch) { %>
@ -120,16 +122,21 @@ export default async (ssrContext) => {
const beforeRender = async () => {
// Call beforeNuxtRender() methods
await Promise.all(ssrContext.beforeRenderFns.map(fn => promisify(fn, { Components, nuxtState: ssrContext.nuxt })))
<% if (store) { %>
ssrContext.rendered = () => {
// Call beforeSerialize() hooks
ssrContext.beforeSerializeFns.forEach(fn => fn(ssrContext.nuxt))
<% if (store) { %>
// Add the state from the vuex store
ssrContext.nuxt.state = store.state
<% } %>
<% if (isFullStatic && store) { %>
// Stop recording store mutations
ssrContext.unsetMutationObserver()
<% } %>
}
<% } %>
}
const renderErrorPage = async () => {

View File

@ -259,6 +259,7 @@ export async function setContext (app, context) {
}
if (process.server) {
app.context.beforeNuxtRender = fn => context.beforeRenderFns.push(fn)
app.context.beforeSerialize = fn => context.beforeSerializeFns.push(fn)
}
if (process.client) {
app.context.nuxtState = window.<%= globals.context %>

View File

@ -201,10 +201,16 @@ describe('basic ssr', () => {
})
})
test('/special-state -> check window.__NUXT__.test = true', async () => {
const window = await nuxt.server.renderAndGetWindow(url('/special-state'))
test('/before-nuxt-render -> check window.__NUXT__.beforeNuxtRender = true', async () => {
const window = await nuxt.server.renderAndGetWindow(url('/before-nuxt-render'))
expect(window.document.title).toBe('Nuxt')
expect(window.__NUXT__.test).toBe(true)
expect(window.__NUXT__.beforeNuxtRender).toBe(true)
})
test('/before-serialize -> check window.__NUXT__.beforeSerialize = true', async () => {
const window = await nuxt.server.renderAndGetWindow(url('/before-serialize'))
expect(window.document.title).toBe('Nuxt')
expect(window.__NUXT__.beforeSerialize).toBe(true)
})
test('/error', async () => {

View File

@ -7,7 +7,7 @@ export default {
middleware ({ beforeNuxtRender }) {
if (process.server) {
beforeNuxtRender(({ nuxtState }) => {
nuxtState.test = true
nuxtState.beforeNuxtRender = true
})
}
}

View File

@ -0,0 +1,26 @@
<template>
<div>
<h1>Special state in `window.__NUXT__`</h1>
<client-only><pre>{{ nuxtState }}</pre></client-only>
</div>
</template>
<script>
export default {
data () {
return {
nuxtState: null
}
},
fetch () {
if (process.server) {
this.$root.context.beforeSerialize((nuxtState) => {
nuxtState.beforeSerialize = true
})
}
},
beforeMount () {
this.nuxtState = window.__NUXT__
}
}
</script>