2
0
mirror of https://github.com/tenrok/vue-meta.git synced 2026-06-18 17:00:35 +03:00

fix: detect and apply changes triggered before or during initialization (#377)

This commit is contained in:
Pim
2019-06-06 10:01:11 +02:00
committed by GitHub
parent 011a71d905
commit 34c6ad957d
3 changed files with 101 additions and 1 deletions
+7
View File
@@ -2,6 +2,13 @@
let batchId = null
export function triggerUpdate(vm, hookName) {
// if an update was triggered during initialization or when an update was triggered by the
// metaInfo watcher, set initialized to null
// then we keep falsy value but know we need to run a triggerUpdate after initialization
if (!vm.$root._vueMeta.initialized && (vm.$root._vueMeta.initializing || hookName === 'watcher')) {
vm.$root._vueMeta.initialized = null
}
if (vm.$root._vueMeta.initialized && !vm.$root._vueMeta.paused) {
// batch potential DOM updates to prevent extraneous re-rendering
batchUpdate(() => vm.$meta().refresh())
+18 -1
View File
@@ -72,12 +72,29 @@ export default function createMixin(Vue, options) {
this.$root._vueMeta.initialized = this.$isServer
if (!this.$root._vueMeta.initialized) {
// we use the mounted hook here as on page load
ensuredPush(this.$options, 'mounted', () => {
if (!this.$root._vueMeta.initialized) {
// used in triggerUpdate to check if a change was triggered
// during initialization
this.$root._vueMeta.initializing = true
// refresh meta in nextTick so all child components have loaded
this.$nextTick(function () {
const { metaInfo } = this.$root.$meta().refresh()
const { tags, metaInfo } = this.$root.$meta().refresh()
// After ssr hydration (identifier by tags === false) check
// if initialized was set to null in triggerUpdate. That'd mean
// that during initilazation changes where triggered which need
// to be applied OR a metaInfo watcher was triggered before the
// current hook was called
// (during initialization all changes are blocked)
if (tags === false && this.$root._vueMeta.initialized === null) {
this.$nextTick(() => triggerUpdate(this, 'initializing'))
}
this.$root._vueMeta.initialized = true
delete this.$root._vueMeta.initializing
// add the navigation guards if they havent been added yet
// they are needed for the afterNavigation callback
+76
View File
@@ -197,4 +197,80 @@ describe('client', () => {
guards.after()
expect(afterNavigation).toHaveBeenCalled()
})
test('changes before hydration initialization trigger an update', async () => {
html.setAttribute(defaultOptions.ssrAttribute, 'true')
// this component uses a computed prop to simulate a non-synchronous
// metaInfo update like you would have with a Vuex mutation
const component = Vue.component('test-component', {
data() {
return {
hiddenTheme: 'light'
}
},
computed: {
theme() {
return this.hiddenTheme
}
},
beforeMount() {
this.hiddenTheme = 'dark'
},
render: h => h('div'),
metaInfo() {
return {
htmlAttrs: {
theme: this.theme
}
}
}
})
const wrapper = mount(component, { localVue: Vue })
expect(html.getAttribute('theme')).not.toBe('dark')
await vmTick(wrapper.vm)
jest.runAllTimers()
expect(html.getAttribute('theme')).toBe('dark')
html.removeAttribute('theme')
})
test('changes during hydration initialization trigger an update', async () => {
html.setAttribute(defaultOptions.ssrAttribute, 'true')
const component = Vue.component('test-component', {
data() {
return {
hiddenTheme: 'light'
}
},
computed: {
theme() {
return this.hiddenTheme
}
},
mounted() {
this.hiddenTheme = 'dark'
},
render: h => h('div'),
metaInfo() {
return {
htmlAttrs: {
theme: this.theme
}
}
}
})
const wrapper = mount(component, { localVue: Vue })
expect(html.getAttribute('theme')).not.toBe('dark')
await vmTick(wrapper.vm)
jest.runAllTimers()
expect(html.getAttribute('theme')).toBe('dark')
html.removeAttribute('theme')
})
})