feat: store and replay vuex mutations for static target (#7350)

* feat: store and replay vuex mutations for static target

* test: add full-static fixture

* perf: clean store subscription before render

* fix: record mutations after nuxtServerInit and middleware
This commit is contained in:
Pooya Parsa 2020-05-12 13:05:24 +02:00 committed by GitHub
parent 498f408d9a
commit 42406d6075
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 120 additions and 10 deletions

View File

@ -491,13 +491,9 @@ async function render (to, from, next) {
if (this.isPreview) {
promise = promisify(Component.options.asyncData, app.context)
} else {
try {
const payload = await this.fetchPayload(to.path).then((payloadData) => payloadData.data[i])
promise = Promise.resolve(payload)
} catch (err) {
// fallback
promise = promisify(Component.options.asyncData, app.context)
}
promise = this.fetchPayload(to.path)
.then(payload => payload.data[i])
.catch(_err => promisify(Component.options.asyncData, app.context)) // Fallback
}
<% } else { %>
const promise = promisify(Component.options.asyncData, app.context)
@ -514,6 +510,13 @@ async function render (to, from, next) {
}
<% } %>
<% if (isFullStatic && store) { %>
// Replay store mutations
promises.push(this.fetchPayload(to.path).then(payload => {
payload.mutations.forEach(m => { this.$store.commit(m[0], m[1]) })
}))
<% } %>
// Check disabled page loading
this.$loading.manual = Component.options.loading === false
@ -523,7 +526,7 @@ async function render (to, from, next) {
// Catching the error here for letting the SPA fallback and normal fetch behaviour
promises.push(this.fetchPayload(to.path).catch(err => null))
}
<% } %>
<% } %>
// Call fetch(context)
if (hasFetch) {
let p = Component.options.fetch(app.context)

View File

@ -100,6 +100,10 @@ export default async (ssrContext) => {
ssrContext.rendered = () => {
// Add the state from the vuex store
ssrContext.nuxt.state = store.state
<% if (isFullStatic && store) { %>
// Stop recording store mutations
ssrContext.unsetMutationObserver()
<% } %>
}
<% } %>
}
@ -175,6 +179,12 @@ export default async (ssrContext) => {
}
<% } %>
<% if (isFullStatic && store) { %>
// Record store mutations for full-static after nuxtServerInit and Middleware
ssrContext.nuxt.mutations =[]
ssrContext.unsetMutationObserver = store.subscribe(m => { ssrContext.nuxt.mutations.push([m.type, m.payload]) })
<% } %>
<% if (features.layouts) { %>
/*
** Set layout

View File

@ -163,7 +163,7 @@ export default class SSRRenderer extends BaseRenderer {
const preloadScripts = []
renderContext.staticAssets = []
const { staticAssetsBase, url, nuxt, staticAssets } = renderContext
const { data, fetch, ...state } = nuxt
const { data, fetch, mutations, ...state } = nuxt
// Initial state
const nuxtStaticScript = `window.__NUXT_STATIC__='${staticAssetsBase}';`
@ -186,7 +186,7 @@ export default class SSRRenderer extends BaseRenderer {
const payloadPath = urlJoin(url, 'payload.js')
const payloadUrl = urlJoin(staticAssetsBase, payloadPath)
const routePath = (url.replace(/\/+$/, '') || '/').split('?')[0] // remove trailing slah and query params
const payloadScript = `__NUXT_JSONP__("${routePath}", ${devalue({ data, fetch })});`
const payloadScript = `__NUXT_JSONP__("${routePath}", ${devalue({ data, fetch, mutations })});`
staticAssets.push({ path: payloadPath, src: payloadScript })
preloadScripts.push(payloadUrl)

View File

@ -0,0 +1,3 @@
import { buildFixture } from '../../utils/build'
buildFixture('full-static')

View File

@ -0,0 +1,21 @@
<template>
<div>
<NLink to="/">
Home
</NLink>
<NLink to="/store">
Store
</NLink>
<NLink to="/pagination/1">
Pagination
</NLink>
<br>
<Nuxt />
</div>
</template>
<style scoped>
a {
margin: 0 1em;
}
</style>

View File

@ -0,0 +1,3 @@
export default {
target: 'static'
}

View File

@ -0,0 +1,5 @@
<template>
<div>
<h1>Full Static Playground!</h1>
</div>
</template>

View File

@ -0,0 +1,21 @@
<template>
<div>
<NLink v-if="i>0" :to="`./${i-1}`">
Previous
</NLink>
Page {{ i }}
<NLink v-if="i<5" :to="`./${i+1}`">
Next
</NLink>
</div>
</template>
<script>
export default {
computed: {
i () {
return parseInt(this.$route.params.i) || 0
}
}
}
</script>

View File

@ -0,0 +1,18 @@
<template>
<div>
<h3>Welcome {{ $store.state.auth.user.name }}!</h3>
<br>
You visited this page <strong>{{ $store.state.counter }}</strong> times.
</div>
</template>
<script>
export default {
fetch () {
this.$store.commit('COUNT')
},
async asyncData ({ store }) {
await store.dispatch('auth/FETCH_USER')
}
}
</script>

17
test/fixtures/full-static/store/auth.js vendored Normal file
View File

@ -0,0 +1,17 @@
export const state = () => ({
user: null
})
export const mutations = {
SET_USER (state, user) {
state.user = user
}
}
export const actions = {
FETCH_USER ({ commit }) {
commit('SET_USER', {
name: (process.client ? 'C' : 'S') + ' Æ A-' + (10 + Math.round(Math.random() * 10))
})
}
}

View File

@ -0,0 +1,9 @@
export const state = () => ({
counter: 0
})
export const mutations = {
COUNT (state) {
state.counter += 1
}
}