From 9c80dab7b2e333a9c4b21a17b0adcf901702403c Mon Sep 17 00:00:00 2001 From: pimlie Date: Sat, 23 Feb 2019 13:49:37 +0100 Subject: [PATCH] fix: use single object prop on feat: provide hasMetaInfo export for other libraries to check if metaInfo has been defined chore: deprecate _hasMetaInfo --- src/browser.js | 3 ++- src/client/triggerUpdate.js | 2 +- src/index.js | 3 ++- src/shared/hasMetaInfo.js | 3 +++ src/shared/mixin.js | 31 ++++++++++++++++++++------- src/shared/pausing.js | 4 ++-- test/plugin-browser.test.js | 12 +++++------ test/plugin-server.test.js | 42 ++++++++++++++++++++++++++++++++++++- test/utils/index.js | 3 ++- 9 files changed, 83 insertions(+), 20 deletions(-) create mode 100644 src/shared/hasMetaInfo.js diff --git a/src/browser.js b/src/browser.js index abbda201..8839c059 100644 --- a/src/browser.js +++ b/src/browser.js @@ -3,6 +3,7 @@ import createMixin from './shared/mixin' import setOptions from './shared/options' import { isUndefined } from './shared/typeof' import $meta from './client/$meta' +export { hasMetaInfo } from './shared/hasMetaInfo' /** * Plugin install function. @@ -13,7 +14,7 @@ function VueMeta(Vue, options = {}) { Vue.prototype.$meta = $meta(options) - Vue.mixin(createMixin(options)) + Vue.mixin(createMixin(Vue, options)) } VueMeta.version = version diff --git a/src/client/triggerUpdate.js b/src/client/triggerUpdate.js index 19105bb2..b0e6903b 100644 --- a/src/client/triggerUpdate.js +++ b/src/client/triggerUpdate.js @@ -4,7 +4,7 @@ import batchUpdate from './batchUpdate' let batchId = null export default function triggerUpdate(vm, hookName) { - if (vm.$root._vueMetaInitialized && !vm.$root._vueMetaPaused) { + if (vm.$root._vueMeta.initialized && !vm.$root._vueMeta.paused) { // batch potential DOM updates to prevent extraneous re-rendering batchId = batchUpdate(batchId, () => { vm.$meta().refresh() diff --git a/src/index.js b/src/index.js index 0e1160f9..cb378840 100644 --- a/src/index.js +++ b/src/index.js @@ -2,6 +2,7 @@ import { version } from '../package.json' import createMixin from './shared/mixin' import setOptions from './shared/options' import $meta from './server/$meta' +export { hasMetaInfo } from './shared/hasMetaInfo' /** * Plugin install function. @@ -12,7 +13,7 @@ function VueMeta(Vue, options = {}) { Vue.prototype.$meta = $meta(options) - Vue.mixin(createMixin(options)) + Vue.mixin(createMixin(Vue, options)) } VueMeta.version = version diff --git a/src/shared/hasMetaInfo.js b/src/shared/hasMetaInfo.js new file mode 100644 index 00000000..975f7626 --- /dev/null +++ b/src/shared/hasMetaInfo.js @@ -0,0 +1,3 @@ +export function hasMetaInfo(vm = this) { + return vm && !!vm._vueMeta +} diff --git a/src/shared/mixin.js b/src/shared/mixin.js index bdacc29d..beece7ae 100644 --- a/src/shared/mixin.js +++ b/src/shared/mixin.js @@ -2,18 +2,35 @@ import triggerUpdate from '../client/triggerUpdate' import { isUndefined, isFunction } from './typeof' import { ensuredPush } from './ensure' -export default function createMixin(options) { +export default function createMixin(Vue, options) { // for which Vue lifecycle hooks should the metaInfo be refreshed const updateOnLifecycleHook = ['activated', 'deactivated', 'beforeMount'] // watch for client side component updates return { beforeCreate() { + Object.defineProperty(this, '_hasMetaInfo', { + get() { + // Show deprecation warning once when devtools enabled + if (Vue.config.devtools && !this.$root._vueMeta.hasMetaInfoDeprecationWarningShown) { + console.warn('VueMeta DeprecationWarning: _hasMetaInfo has been deprecated and will be removed in a future version. Please import hasMetaInfo and use hasMetaInfo(vm) instead') // eslint-disable-line no-console + this.$root._vueMeta.hasMetaInfoDeprecationWarningShown = true + } + return !!this._vueMeta + } + }) + // Add a marker to know if it uses metaInfo // _vnode is used to know that it's attached to a real component // useful if we use some mixin to add some meta tags (like nuxt-i18n) if (!isUndefined(this.$options[options.keyName]) && this.$options[options.keyName] !== null) { - this._hasMetaInfo = true + if (!this.$root._vueMeta) { + this.$root._vueMeta = {} + } + + if (!this._vueMeta) { + this._vueMeta = true + } // coerce function-style metaInfo to a computed prop so we can observe // it on creation @@ -39,18 +56,18 @@ export default function createMixin(options) { // to triggerUpdate until this initial refresh is finished // this is to make sure that when a page is opened in an inactive tab which // has throttled rAF/timers we still immeditately set the page title - if (isUndefined(this.$root._vueMetaInitialized)) { - this.$root._vueMetaInitialized = this.$isServer + if (isUndefined(this.$root._vueMeta.initialized)) { + this.$root._vueMeta.initialized = this.$isServer - if (!this.$root._vueMetaInitialized) { + if (!this.$root._vueMeta.initialized) { const $rootMeta = this.$root.$meta() ensuredPush(this.$options, 'mounted', () => { - if (!this.$root._vueMetaInitialized) { + if (!this.$root._vueMeta.initialized) { // refresh meta in nextTick so all child components have loaded this.$nextTick(function () { $rootMeta.refresh() - this.$root._vueMetaInitialized = true + this.$root._vueMeta.initialized = true }) } }) diff --git a/src/shared/pausing.js b/src/shared/pausing.js index afd7dfe5..65e5b456 100644 --- a/src/shared/pausing.js +++ b/src/shared/pausing.js @@ -1,11 +1,11 @@ export function pause(refresh = true) { - this.$root._vueMetaPaused = true + this.$root._vueMeta.paused = true return () => resume(refresh) } export function resume(refresh = true) { - this.$root._vueMetaPaused = false + this.$root._vueMeta.paused = false if (refresh) { return this.$root.$meta().refresh() diff --git a/test/plugin-browser.test.js b/test/plugin-browser.test.js index b8caedd9..67b114b2 100644 --- a/test/plugin-browser.test.js +++ b/test/plugin-browser.test.js @@ -72,8 +72,8 @@ describe('plugin', () => { }) // no batchUpdate on initialization - expect(wrapper.vm.$root._vueMetaInitialized).toBe(false) - expect(wrapper.vm.$root._vueMetaPaused).toBeFalsy() + expect(wrapper.vm.$root._vueMeta.initialized).toBe(false) + expect(wrapper.vm.$root._vueMeta.paused).toBeFalsy() expect(triggerUpdateSpy).toHaveBeenCalledTimes(1) expect(batchUpdateSpy).not.toHaveBeenCalled() jest.clearAllMocks() @@ -83,8 +83,8 @@ describe('plugin', () => { wrapper.setProps({ title }) // batchUpdate on normal update - expect(wrapper.vm.$root._vueMetaInitialized).toBe(true) - expect(wrapper.vm.$root._vueMetaPaused).toBeFalsy() + expect(wrapper.vm.$root._vueMeta.initialized).toBe(true) + expect(wrapper.vm.$root._vueMeta.paused).toBeFalsy() expect(triggerUpdateSpy).toHaveBeenCalledTimes(1) expect(batchUpdateSpy).toHaveBeenCalledTimes(1) jest.clearAllMocks() @@ -94,8 +94,8 @@ describe('plugin', () => { wrapper.setProps({ title }) // no batchUpdate when paused - expect(wrapper.vm.$root._vueMetaInitialized).toBe(true) - expect(wrapper.vm.$root._vueMetaPaused).toBe(true) + expect(wrapper.vm.$root._vueMeta.initialized).toBe(true) + expect(wrapper.vm.$root._vueMeta.paused).toBe(true) expect(triggerUpdateSpy).toHaveBeenCalledTimes(1) expect(batchUpdateSpy).not.toHaveBeenCalled() jest.clearAllMocks() diff --git a/test/plugin-server.test.js b/test/plugin-server.test.js index 60813c19..85c445ca 100644 --- a/test/plugin-server.test.js +++ b/test/plugin-server.test.js @@ -1,4 +1,4 @@ -import { mount, defaultOptions, VueMetaServerPlugin, loadVueMetaPlugin } from './utils' +import { mount, defaultOptions, hasMetaInfo, VueMetaServerPlugin, loadVueMetaPlugin } from './utils' jest.mock('../package.json', () => ({ version: 'test-version' @@ -7,6 +7,7 @@ jest.mock('../package.json', () => ({ describe('plugin', () => { let Vue + beforeEach(() => jest.clearAllMocks()) beforeAll(() => (Vue = loadVueMetaPlugin())) test('is loaded', () => { @@ -29,4 +30,43 @@ describe('plugin', () => { test('plugin sets package version', () => { expect(VueMetaServerPlugin.version).toBe('test-version') }) + + test('prints deprecation warning once when using _hasMetaInfo', () => { + const warn = jest.spyOn(console, 'warn').mockImplementation(() => {}) + + const Component = Vue.component('test-component', { + template: '
Test
', + [defaultOptions.keyName]: { + title: 'Hello World' + } + }) + + Vue.config.devtools = true + const { vm } = mount(Component, { localVue: Vue }) + + expect(vm._hasMetaInfo).toBe(true) + expect(warn).toHaveBeenCalledTimes(1) + + expect(vm._hasMetaInfo).toBe(true) + expect(warn).toHaveBeenCalledTimes(1) + warn.mockRestore() + }) + + test('can use hasMetaInfo export', () => { + const warn = jest.spyOn(console, 'warn').mockImplementation(() => {}) + + const Component = Vue.component('test-component', { + template: '
Test
', + [defaultOptions.keyName]: { + title: 'Hello World' + } + }) + + const { vm } = mount(Component, { localVue: Vue }) + + expect(hasMetaInfo(vm)).toBe(true) + expect(warn).not.toHaveBeenCalled() + + warn.mockRestore() + }) }) diff --git a/test/utils/index.js b/test/utils/index.js index fee4c7b7..b4f4fccf 100644 --- a/test/utils/index.js +++ b/test/utils/index.js @@ -1,7 +1,7 @@ import { mount, createLocalVue } from '@vue/test-utils' import { renderToString } from '@vue/server-test-utils' import VueMetaBrowserPlugin from '../../src/browser' -import VueMetaServerPlugin from '../../src' +import VueMetaServerPlugin, { hasMetaInfo } from '../../src' import { keyName, @@ -15,6 +15,7 @@ import { export { mount, renderToString, + hasMetaInfo, VueMetaBrowserPlugin, VueMetaServerPlugin }