Skip to content

Commit

Permalink
fix: try to detect global mixins adding meta info (#467)
Browse files Browse the repository at this point in the history
* feat: try to detect global mixins adding meta info

* fix: add find polyfill for ie

* fix: only detect global mixins when Vue.devtools: true
  • Loading branch information
pimlie committed Oct 9, 2019
1 parent 35b7099 commit 2231ec1
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 10 deletions.
36 changes: 27 additions & 9 deletions src/shared/mixin.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { triggerUpdate } from '../client/update'
import { isUndefined, isFunction } from '../utils/is-type'
import { find } from '../utils/array'
import { ensuredPush } from '../utils/ensure'
import { rootConfigKey } from './constants'
import { hasMetaInfo } from './meta-helpers'
Expand All @@ -18,12 +19,13 @@ export default function createMixin (Vue, options) {
const rootKey = '$root'
const $root = this[rootKey]
const $options = this.$options
const devtoolsEnabled = Vue.config.devtools

Object.defineProperty(this, '_hasMetaInfo', {
configurable: true,
get () {
// Show deprecation warning once when devtools enabled
if (Vue.config.devtools && !$root[rootConfigKey].deprecationWarningShown) {
if (devtoolsEnabled && !$root[rootConfigKey].deprecationWarningShown) {
warn('VueMeta DeprecationWarning: _hasMetaInfo has been deprecated and will be removed in a future version. Please use hasMetaInfo(vm) instead')
$root[rootConfigKey].deprecationWarningShown = true
}
Expand All @@ -41,6 +43,17 @@ export default function createMixin (Vue, options) {
if (!$root[rootConfigKey]) {
$root[rootConfigKey] = { appId }
appId++

if (devtoolsEnabled && $root.$options[options.keyName]) {
// use nextTick so the children should be added to $root
this.$nextTick(() => {
// find the first child that lists fnOptions
const child = find($root.$children, c => c.$vnode && c.$vnode.fnOptions)
if (child && child.$vnode.fnOptions[options.keyName]) {
warn(`VueMeta has detected a possible global mixin which adds a ${options.keyName} property to all Vue components on the page. This could cause severe performance issues. If possible, use $meta().addApp to add meta information instead`)
}
})
}
}

// to speed up updates we keep track of branches which have a component with vue-meta info defined
Expand Down Expand Up @@ -83,14 +96,18 @@ export default function createMixin (Vue, options) {
$root[rootConfigKey].initialized = this.$isServer

if (!$root[rootConfigKey].initialized) {
ensuredPush($options, 'beforeMount', function () {
const $root = this[rootKey]
// if this Vue-app was server rendered, set the appId to 'ssr'
// only one SSR app per page is supported
if ($root.$el && $root.$el.nodeType === 1 && $root.$el.hasAttribute('data-server-rendered')) {
$root[rootConfigKey].appId = options.ssrAppId
}
})
if (!$root[rootConfigKey].initializedSsr) {
$root[rootConfigKey].initializedSsr = true

ensuredPush($options, 'beforeMount', function () {
const $root = this
// if this Vue-app was server rendered, set the appId to 'ssr'
// only one SSR app per page is supported
if ($root.$el && $root.$el.nodeType === 1 && $root.$el.hasAttribute('data-server-rendered')) {
$root[rootConfigKey].appId = options.ssrAppId
}
})
}

// we use the mounted hook here as on page load
ensuredPush($options, 'mounted', function () {
Expand Down Expand Up @@ -155,6 +172,7 @@ export default function createMixin (Vue, options) {
if (!this.$parent || !hasMetaInfo(this)) {
return
}
delete this._hasMetaInfo

this.$nextTick(() => {
if (!options.waitOnDestroyed || !this.$el || !this.$el.offsetParent) {
Expand Down
13 changes: 13 additions & 0 deletions src/utils/array.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,19 @@
// which means the polyfills are removed for other build formats
const polyfill = process.env.NODE_ENV === 'test'

export function find (array, predicate, thisArg) {
if (polyfill && !Array.prototype.find) {
// idx needs to be a Number, for..in returns string
for (let idx = 0; idx < array.length; idx++) {
if (predicate.call(thisArg, array[idx], idx, array)) {
return array[idx]
}
}
return
}
return array.find(predicate, thisArg)
}

export function findIndex (array, predicate, thisArg) {
if (polyfill && !Array.prototype.findIndex) {
// idx needs to be a Number, for..in returns string
Expand Down
13 changes: 12 additions & 1 deletion test/unit/utils.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* @jest-environment node
*/
import { findIndex, includes, toArray } from '../../src/utils/array'
import { find, findIndex, includes, toArray } from '../../src/utils/array'
import { ensureIsArray } from '../../src/utils/ensure'
import { hasGlobalWindowFn } from '../../src/utils/window'

Expand Down Expand Up @@ -29,6 +29,17 @@ describe('shared', () => {
})

/* eslint-disable no-extend-native */
test('find polyfill', () => {
const _find = Array.prototype.find
Array.prototype.find = false

const arr = [1, 2, 3]
expect(find(arr, (v, i) => i === 0)).toBe(1)
expect(find(arr, (v, i) => i === 3)).toBe(undefined)

Array.prototype.find = _find
})

test('findIndex polyfill', () => {
const _findIndex = Array.prototype.findIndex
Array.prototype.findIndex = false
Expand Down

0 comments on commit 2231ec1

Please sign in to comment.