Fix asyncData on hot reloading

This commit is contained in:
Sébastien Chopin 2017-03-02 17:31:37 +01:00
parent 8253f5e75b
commit b8727b8d51
3 changed files with 41 additions and 41 deletions

View File

@ -8,6 +8,7 @@ Tasks for `0.9.10`:
- [ ] Fork preload-webpack-plugin and use it in package.json
- [ ] Test + Coverage performance, cache, filenames
- [ ] Manual tests on router.base & publicPath
- [ ] asyncData, fetch, transition, validate, scrollToTop can be in mixins and extend (super)
-> Not possible to have custom layout for a page, it should do the condition inside the layout itself (because of the middleware strategy)

View File

@ -216,7 +216,7 @@ function fixPrepatch (to, ___) {
// Set layout
this.setLayout(this.$options._nuxt.err ? NuxtError.layout : to.matched[0].components.default.options.layout)
// hot reloading
hotReloadAPI(this)
Vue.nextTick(() => hotReloadAPI(this))
})
}
@ -224,6 +224,8 @@ function fixPrepatch (to, ___) {
function hotReloadAPI (_app) {
if (!module.hot) return
const $nuxt = _app.$nuxt
if ($nuxt._hasHotReload) return
$nuxt._hasHotReload = true
var _forceUpdate = $nuxt.$forceUpdate.bind($nuxt)
$nuxt.$forceUpdate = function () {
let Component = getMatchedComponents(router.currentRoute)[0]
@ -233,13 +235,15 @@ function hotReloadAPI (_app) {
Component = Vue.extend(Component)
Component._Ctor = Component
}
_app.error()
let promises = []
// If layout changed
Component.options.layout = Component.options.layout || 'default'
if (_app.layoutName !== Component.options.layout) {
let promise = _app.loadLayout(Component.options.layout)
promise.then(() => {
_app.setLayout(Component.options.layout)
hotReloadAPI(_app)
Vue.nextTick(() => hotReloadAPI(_app))
})
promises.push(promise)
}
@ -248,37 +252,22 @@ function hotReloadAPI (_app) {
router.push(path)
}
const context = getContext({ route: router.currentRoute<%= (store ? ', store' : '') %>, isClient: true, next: next.bind(this), error: _app.error })
// Check if data has been updated
const originalDataFn = (Component._data || noopData).toString().replace(/\s/g, '')
const newDataFn = (Component._Ctor.options.data || noopData).toString().replace(/\s/g, '')
if (originalDataFn !== newDataFn) {
Component._data = Component._Ctor.options.data || noopData
let p = promisify(Component._data, context)
p.then((data) => {
Component._cData = () => data || {}
Component.options.data = Component._cData
Component._dataFn = Component.options.data.toString().replace(/\s/g, '')
Component._Ctor.options.data = Component.options.data
<%= (loading ? 'this.$loading.increase && this.$loading.increase(30)' : '') %>
})
promises.push(p)
} else if (Component._cData) {
Component._data = Component.options.data
Component.options.data = Component._cData
// Call asyncData()
let pAsyncData = promisify(Component.options.asyncData || noopData, context)
pAsyncData.then((asyncDataResult) => {
let data = (typeof Component.options.data === 'function' ? Component.options.data() : noopData())
data = Object.assign(data, asyncDataResult)
Component.options.data = () => data
Component._Ctor.options.data = Component.options.data
}
// Check if fetch has been updated
const originalFetchFn = (Component.options.fetch || noopFetch).toString().replace(/\s/g, '')
const newFetchFn = (Component._Ctor.options.fetch || noopFetch).toString().replace(/\s/g, '')
// Fetch has been updated, we call it to update the store
if (originalFetchFn !== newFetchFn) {
Component.options.fetch = Component._Ctor.options.fetch || noopFetch
let p = Component.options.fetch(context)
if (!(p instanceof Promise)) { p = Promise.resolve(p) }
<%= (loading ? 'p.then(() => this.$loading.increase && this.$loading.increase(30))' : '') %>
promises.push(p)
}
if (!promises.length) return;
<%= (loading ? 'this.$loading.increase && this.$loading.increase(30)' : '') %>
})
promises.push(pAsyncData)
// Call fetch()
Component.options.fetch = Component.options.fetch || noopFetch
let pFetch = Component.options.fetch(context)
if (!(pFetch instanceof Promise)) { pFetch = Promise.resolve(pFetch) }
<%= (loading ? 'pFetch.then(() => this.$loading.increase && this.$loading.increase(30))' : '') %>
promises.push(pFetch)
<%= (loading ? 'this.$loading.start && this.$loading.start()' : '') %>
return Promise.all(promises).then(() => {
<%= (loading ? 'this.$loading.finish && this.$loading.finish()' : '') %>
@ -306,7 +295,13 @@ const resolveComponents = flatMapComponents(router.match(path), (Component, _, m
Component.extendOptions = Component.options
}
if (NUXT.serverRendered) {
Component.options.data = () => NUXT.data[index]
let data = {}
if (Component.options.data && typeof Component.options.data === 'function') {
data = Component.options.data()
}
// Merge data() and asyncData() results
data = Object.assign(data, NUXT.data[index])
Component.options.data = () => data
if (Component._Ctor && Component._Ctor.options) {
Component._Ctor.options.data = Component.options.data
}
@ -346,10 +341,12 @@ Promise.all(resolveComponents)
.then(({ _app, Components }) => {
const mountApp = () => {
_app.$mount('#__nuxt')
// Hot reloading
hotReloadAPI(_app)
// Call window.onNuxtReady callbacks
Vue.nextTick(() => nuxtReady(_app))
Vue.nextTick(() => {
// Hot reloading
hotReloadAPI(_app)
// Call window.onNuxtReady callbacks
nuxtReady(_app)
})
}
<% if (store) { %>
// Replace store state

View File

@ -133,14 +133,18 @@ export default context => {
Component._Ctor.options.data = Component.options.data
})
promises.push(promise)
} else {
promises.push(null)
}
if (Component.options.fetch) {
promises.push(Component.options.fetch(ctx))
} else {
promises.push(null)
}
return Promise.all(promises)
}))
})
.then(() => {
.then((res) => {
if (!Components.length) {
context.nuxt.error = context.error({ statusCode: 404, message: 'This page could not be found.' })
<%= (store ? 'context.nuxt.state = store.state' : '') %>
@ -150,9 +154,7 @@ export default context => {
debug('Data fetching ' + context.req.url + ': ' + (Date.now() - s) + 'ms')
<% } %>
// datas are the first row of each
context.nuxt.data = Components.map((Component) => {
return (typeof Component.options.data === 'function' ? Component.options.data() : {})
})
context.nuxt.data = res.map((r) => (r[0] || {}))
context.nuxt.error = _app.$options._nuxt.err
<%= (store ? '// Add the state from the vuex store' : '') %>
<%= (store ? 'context.nuxt.state = store.state' : '') %>