Skip to content

Commit 1d8f3a2

Browse files
committed
better global mixin strategy
1 parent 1d88d9b commit 1d8f3a2

File tree

6 files changed

+42
-45
lines changed

6 files changed

+42
-45
lines changed

flow/component.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ declare interface Component {
88
static options: Object;
99
// extend
1010
static extend: (options: Object) => Function;
11+
static superOptions: Object;
12+
static extendOptions: Object;
13+
static super: Class<Component>;
1114
// assets
1215
static directive: (id: string, def?: Function | Object) => Function | Object | void;
1316
static component: (id: string, def?: Class<Component> | Object) => Class<Component>;

src/core/config.js

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ export type Config = {
1818
_assetTypes: Array<string>,
1919
_lifecycleHooks: Array<string>,
2020
_maxUpdateCount: number,
21-
_isServer: boolean,
22-
_ctors: Array<Function>
21+
_isServer: boolean
2322
}
2423

2524
const config: Config = {
@@ -105,14 +104,7 @@ const config: Config = {
105104
/**
106105
* Server rendering?
107106
*/
108-
_isServer: process.env.VUE_ENV === 'server',
109-
110-
/**
111-
* Keeping track of all extended Component constructors
112-
* so that we can update them in the case of global mixins being applied
113-
* after their creation.
114-
*/
115-
_ctors: []
107+
_isServer: process.env.VUE_ENV === 'server'
116108
}
117109

118110
export default config

src/core/global-api/extend.js

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* @flow */
22

33
import config from '../config'
4-
import { warn, remove, mergeOptions } from '../util/index'
4+
import { warn, mergeOptions } from '../util/index'
55

66
export function initExtend (Vue: GlobalAPI) {
77
/**
@@ -54,12 +54,11 @@ export function initExtend (Vue: GlobalAPI) {
5454
if (name) {
5555
Sub.options.components[name] = Sub
5656
}
57-
// book-keeping for global mixin edge cases. also expose a way to remove it
57+
// keep a reference to the super options at extension time.
58+
// later at instantiation we can check if Super's options have
59+
// been updated.
60+
Sub.superOptions = Super.options
5861
Sub.extendOptions = extendOptions
59-
config._ctors.push(Sub)
60-
Sub.release = () => {
61-
remove(config._ctors, Sub)
62-
}
6362
// cache constructor
6463
if (isFirstExtend) {
6564
extendOptions._Ctor = Sub

src/core/global-api/mixin.js

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,9 @@
11
/* @flow */
22

3-
import config from '../config'
43
import { mergeOptions } from '../util/index'
54

65
export function initMixin (Vue: GlobalAPI) {
76
Vue.mixin = function (mixin: Object) {
87
Vue.options = mergeOptions(Vue.options, mixin)
9-
// update constructors that are already created
10-
config._ctors.forEach(Ctor => {
11-
Ctor.options = mergeOptions(Ctor['super'].options, Ctor.extendOptions)
12-
if (Ctor.options.name) {
13-
Ctor.options.components[Ctor.options.name] = Ctor
14-
}
15-
})
168
}
179
}

src/core/instance/init.js

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export function initMixin (Vue: Class<Component>) {
2424
initInternalComponent(vm, options)
2525
} else {
2626
vm.$options = mergeOptions(
27-
vm.constructor.options,
27+
resolveConstructorOptions(vm),
2828
options || {},
2929
vm
3030
)
@@ -44,19 +44,37 @@ export function initMixin (Vue: Class<Component>) {
4444
callHook(vm, 'created')
4545
initRender(vm)
4646
}
47-
}
4847

49-
function initInternalComponent (vm: Component, options: InternalComponentOptions) {
50-
const opts = vm.$options = Object.create(vm.constructor.options)
51-
// doing this because it's faster than dynamic enumeration.
52-
opts.parent = options.parent
53-
opts.propsData = options.propsData
54-
opts._parentVnode = options._parentVnode
55-
opts._parentListeners = options._parentListeners
56-
opts._renderChildren = options._renderChildren
57-
opts._componentTag = options._componentTag
58-
if (options.render) {
59-
opts.render = options.render
60-
opts.staticRenderFns = options.staticRenderFns
48+
function initInternalComponent (vm: Component, options: InternalComponentOptions) {
49+
const opts = vm.$options = Object.create(resolveConstructorOptions(vm))
50+
// doing this because it's faster than dynamic enumeration.
51+
opts.parent = options.parent
52+
opts.propsData = options.propsData
53+
opts._parentVnode = options._parentVnode
54+
opts._parentListeners = options._parentListeners
55+
opts._renderChildren = options._renderChildren
56+
opts._componentTag = options._componentTag
57+
if (options.render) {
58+
opts.render = options.render
59+
opts.staticRenderFns = options.staticRenderFns
60+
}
61+
}
62+
63+
function resolveConstructorOptions (vm: Component) {
64+
const Ctor = vm.constructor
65+
let options = Ctor.options
66+
if (Ctor.super) {
67+
const superOptions = Ctor.super.options
68+
const cachedSuperOptions = Ctor.superOptions
69+
if (superOptions !== cachedSuperOptions) {
70+
// super option changed
71+
Ctor.superOptions = superOptions
72+
options = Ctor.options = mergeOptions(superOptions, Ctor.extendOptions)
73+
if (options.name) {
74+
options.components[options.name] = Ctor
75+
}
76+
}
77+
}
78+
return options
6179
}
6280
}

test/unit/features/global-api/mixin.spec.js

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,4 @@ describe('Global API: mixin', () => {
3535
})
3636
expect(calls).toEqual(['hello global', 'hello local'])
3737
})
38-
39-
it('should allow releasing constructors', () => {
40-
const Test = Vue.extend({})
41-
expect(Vue.config._ctors.indexOf(Test) > -1).toBe(true)
42-
Test.release()
43-
expect(Vue.config._ctors.indexOf(Test) > -1).toBe(false)
44-
})
4538
})

0 commit comments

Comments
 (0)