Skip to content

Commit

Permalink
fix: use single object prop on
Browse files Browse the repository at this point in the history
feat: provide hasMetaInfo export for other libraries to check if metaInfo has been defined

chore: deprecate _hasMetaInfo
  • Loading branch information
pimlie committed Feb 23, 2019
1 parent 5935cf3 commit 9c80dab
Show file tree
Hide file tree
Showing 9 changed files with 83 additions and 20 deletions.
3 changes: 2 additions & 1 deletion src/browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/client/triggerUpdate.js
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
3 changes: 2 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand Down
3 changes: 3 additions & 0 deletions src/shared/hasMetaInfo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function hasMetaInfo(vm = this) {
return vm && !!vm._vueMeta
}
31 changes: 24 additions & 7 deletions src/shared/mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
})
}
})
Expand Down
4 changes: 2 additions & 2 deletions src/shared/pausing.js
Original file line number Diff line number Diff line change
@@ -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()
Expand Down
12 changes: 6 additions & 6 deletions test/plugin-browser.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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()
Expand All @@ -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()
Expand Down
42 changes: 41 additions & 1 deletion test/plugin-server.test.js
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -7,6 +7,7 @@ jest.mock('../package.json', () => ({
describe('plugin', () => {
let Vue

beforeEach(() => jest.clearAllMocks())
beforeAll(() => (Vue = loadVueMetaPlugin()))

test('is loaded', () => {
Expand All @@ -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: '<div>Test</div>',
[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: '<div>Test</div>',
[defaultOptions.keyName]: {
title: 'Hello World'
}
})

const { vm } = mount(Component, { localVue: Vue })

expect(hasMetaInfo(vm)).toBe(true)
expect(warn).not.toHaveBeenCalled()

warn.mockRestore()
})
})
3 changes: 2 additions & 1 deletion test/utils/index.js
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -15,6 +15,7 @@ import {
export {
mount,
renderToString,
hasMetaInfo,
VueMetaBrowserPlugin,
VueMetaServerPlugin
}
Expand Down

0 comments on commit 9c80dab

Please sign in to comment.