Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 14 commits into from Jun 4, 2021
2 changes: 2 additions & 0 deletions packages/types/app/index.d.ts
Expand Up @@ -72,6 +72,7 @@ export interface Context {
redirected: boolean
next: NextFunction
beforeRenderFns: Array<() => any>
beforeSerializeFns: Array<() => any>
fetchCounters: Record<string, number>
nuxt: {
layout: string
Expand All @@ -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>
}
Expand Down
1 change: 1 addition & 0 deletions packages/vue-app/template/index.js
Expand Up @@ -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
})

Expand Down
11 changes: 9 additions & 2 deletions packages/vue-app/template/server.js
Expand Up @@ -85,6 +85,8 @@ export default async (ssrContext) => {
ssrContext.next = createNext(ssrContext)
// Used for beforeNuxtRender({ Components, nuxtState })
ssrContext.beforeRenderFns = []
// for beforeSerialize({ Components, 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) { %>
Expand Down Expand Up @@ -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 () => {
Expand Down
1 change: 1 addition & 0 deletions packages/vue-app/template/utils.js
Expand Up @@ -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 %>
Expand Down
12 changes: 9 additions & 3 deletions test/dev/basic.ssr.test.js
Expand Up @@ -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 () => {
Expand Down
Expand Up @@ -7,7 +7,7 @@ export default {
middleware ({ beforeNuxtRender }) {
if (process.server) {
beforeNuxtRender(({ nuxtState }) => {
nuxtState.test = true
nuxtState.beforeNuxtRender = true
})
}
}
Expand Down
26 changes: 26 additions & 0 deletions test/fixtures/basic/pages/before-serialize.vue
@@ -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>