mirror of
https://github.com/tenrok/vue-meta.git
synced 2026-06-24 22:40:34 +03:00
fix: detect and apply changes triggered before or during initialization (#377)
This commit is contained in:
@@ -2,6 +2,13 @@
|
|||||||
let batchId = null
|
let batchId = null
|
||||||
|
|
||||||
export function triggerUpdate(vm, hookName) {
|
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) {
|
if (vm.$root._vueMeta.initialized && !vm.$root._vueMeta.paused) {
|
||||||
// batch potential DOM updates to prevent extraneous re-rendering
|
// batch potential DOM updates to prevent extraneous re-rendering
|
||||||
batchUpdate(() => vm.$meta().refresh())
|
batchUpdate(() => vm.$meta().refresh())
|
||||||
|
|||||||
+18
-1
@@ -72,12 +72,29 @@ export default function createMixin(Vue, options) {
|
|||||||
this.$root._vueMeta.initialized = this.$isServer
|
this.$root._vueMeta.initialized = this.$isServer
|
||||||
|
|
||||||
if (!this.$root._vueMeta.initialized) {
|
if (!this.$root._vueMeta.initialized) {
|
||||||
|
// we use the mounted hook here as on page load
|
||||||
ensuredPush(this.$options, 'mounted', () => {
|
ensuredPush(this.$options, 'mounted', () => {
|
||||||
if (!this.$root._vueMeta.initialized) {
|
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
|
// refresh meta in nextTick so all child components have loaded
|
||||||
this.$nextTick(function () {
|
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
|
this.$root._vueMeta.initialized = true
|
||||||
|
delete this.$root._vueMeta.initializing
|
||||||
|
|
||||||
// add the navigation guards if they havent been added yet
|
// add the navigation guards if they havent been added yet
|
||||||
// they are needed for the afterNavigation callback
|
// they are needed for the afterNavigation callback
|
||||||
|
|||||||
@@ -197,4 +197,80 @@ describe('client', () => {
|
|||||||
guards.after()
|
guards.after()
|
||||||
expect(afterNavigation).toHaveBeenCalled()
|
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')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user