Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: try to detect global mixins adding meta info #467

Merged
merged 3 commits into from
Oct 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -154,6 +171,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