better global mixin strategy

This commit is contained in:
Evan You 2016-06-25 10:43:19 -04:00
parent 1d88d9b8a0
commit 1d8f3a264e
6 changed files with 42 additions and 45 deletions

View File

@ -8,6 +8,9 @@ declare interface Component {
static options: Object;
// extend
static extend: (options: Object) => Function;
static superOptions: Object;
static extendOptions: Object;
static super: Class<Component>;
// assets
static directive: (id: string, def?: Function | Object) => Function | Object | void;
static component: (id: string, def?: Class<Component> | Object) => Class<Component>;

View File

@ -18,8 +18,7 @@ export type Config = {
_assetTypes: Array<string>,
_lifecycleHooks: Array<string>,
_maxUpdateCount: number,
_isServer: boolean,
_ctors: Array<Function>
_isServer: boolean
}
const config: Config = {
@ -105,14 +104,7 @@ const config: Config = {
/**
* Server rendering?
*/
_isServer: process.env.VUE_ENV === 'server',
/**
* Keeping track of all extended Component constructors
* so that we can update them in the case of global mixins being applied
* after their creation.
*/
_ctors: []
_isServer: process.env.VUE_ENV === 'server'
}
export default config

View File

@ -1,7 +1,7 @@
/* @flow */
import config from '../config'
import { warn, remove, mergeOptions } from '../util/index'
import { warn, mergeOptions } from '../util/index'
export function initExtend (Vue: GlobalAPI) {
/**
@ -54,12 +54,11 @@ export function initExtend (Vue: GlobalAPI) {
if (name) {
Sub.options.components[name] = Sub
}
// book-keeping for global mixin edge cases. also expose a way to remove it
// keep a reference to the super options at extension time.
// later at instantiation we can check if Super's options have
// been updated.
Sub.superOptions = Super.options
Sub.extendOptions = extendOptions
config._ctors.push(Sub)
Sub.release = () => {
remove(config._ctors, Sub)
}
// cache constructor
if (isFirstExtend) {
extendOptions._Ctor = Sub

View File

@ -1,17 +1,9 @@
/* @flow */
import config from '../config'
import { mergeOptions } from '../util/index'
export function initMixin (Vue: GlobalAPI) {
Vue.mixin = function (mixin: Object) {
Vue.options = mergeOptions(Vue.options, mixin)
// update constructors that are already created
config._ctors.forEach(Ctor => {
Ctor.options = mergeOptions(Ctor['super'].options, Ctor.extendOptions)
if (Ctor.options.name) {
Ctor.options.components[Ctor.options.name] = Ctor
}
})
}
}

View File

@ -24,7 +24,7 @@ export function initMixin (Vue: Class<Component>) {
initInternalComponent(vm, options)
} else {
vm.$options = mergeOptions(
vm.constructor.options,
resolveConstructorOptions(vm),
options || {},
vm
)
@ -44,19 +44,37 @@ export function initMixin (Vue: Class<Component>) {
callHook(vm, 'created')
initRender(vm)
}
}
function initInternalComponent (vm: Component, options: InternalComponentOptions) {
const opts = vm.$options = Object.create(vm.constructor.options)
// doing this because it's faster than dynamic enumeration.
opts.parent = options.parent
opts.propsData = options.propsData
opts._parentVnode = options._parentVnode
opts._parentListeners = options._parentListeners
opts._renderChildren = options._renderChildren
opts._componentTag = options._componentTag
if (options.render) {
opts.render = options.render
opts.staticRenderFns = options.staticRenderFns
function initInternalComponent (vm: Component, options: InternalComponentOptions) {
const opts = vm.$options = Object.create(resolveConstructorOptions(vm))
// doing this because it's faster than dynamic enumeration.
opts.parent = options.parent
opts.propsData = options.propsData
opts._parentVnode = options._parentVnode
opts._parentListeners = options._parentListeners
opts._renderChildren = options._renderChildren
opts._componentTag = options._componentTag
if (options.render) {
opts.render = options.render
opts.staticRenderFns = options.staticRenderFns
}
}
function resolveConstructorOptions (vm: Component) {
const Ctor = vm.constructor
let options = Ctor.options
if (Ctor.super) {
const superOptions = Ctor.super.options
const cachedSuperOptions = Ctor.superOptions
if (superOptions !== cachedSuperOptions) {
// super option changed
Ctor.superOptions = superOptions
options = Ctor.options = mergeOptions(superOptions, Ctor.extendOptions)
if (options.name) {
options.components[options.name] = Ctor
}
}
}
return options
}
}

View File

@ -35,11 +35,4 @@ describe('Global API: mixin', () => {
})
expect(calls).toEqual(['hello global', 'hello local'])
})
it('should allow releasing constructors', () => {
const Test = Vue.extend({})
expect(Vue.config._ctors.indexOf(Test) > -1).toBe(true)
Test.release()
expect(Vue.config._ctors.indexOf(Test) > -1).toBe(false)
})
})