mirror of
https://gitee.com/vuejs/vue.git
synced 2024-11-30 02:57:43 +08:00
optimize asset merging
This commit is contained in:
parent
c0d22e8cae
commit
a316dfe9a4
@ -69,8 +69,8 @@
|
||||
"src/util/env.js",
|
||||
"src/util/index.js",
|
||||
"src/util/lang.js",
|
||||
"src/util/merge-option.js",
|
||||
"src/util/misc.js",
|
||||
"src/util/options.js",
|
||||
"src/vue.js",
|
||||
"src/watcher.js"
|
||||
]
|
||||
|
@ -1,5 +1,5 @@
|
||||
var _ = require('../util')
|
||||
var mergeOptions = require('../util/merge-option')
|
||||
var config = require('../config')
|
||||
|
||||
/**
|
||||
* Expose useful internals
|
||||
@ -48,7 +48,7 @@ exports.extend = function (extendOptions) {
|
||||
Sub.prototype = Object.create(Super.prototype)
|
||||
Sub.prototype.constructor = Sub
|
||||
Sub.cid = cid++
|
||||
Sub.options = mergeOptions(
|
||||
Sub.options = _.mergeOptions(
|
||||
Super.options,
|
||||
extendOptions
|
||||
)
|
||||
@ -101,13 +101,6 @@ exports.use = function (plugin) {
|
||||
* @param {Function} Constructor
|
||||
*/
|
||||
|
||||
var assetTypes = [
|
||||
'directive',
|
||||
'elementDirective',
|
||||
'filter',
|
||||
'transition'
|
||||
]
|
||||
|
||||
function createAssetRegisters (Constructor) {
|
||||
|
||||
/* Asset registration methods share the same signature:
|
||||
@ -116,7 +109,7 @@ function createAssetRegisters (Constructor) {
|
||||
* @param {*} definition
|
||||
*/
|
||||
|
||||
assetTypes.forEach(function (type) {
|
||||
config._assetTypes.forEach(function (type) {
|
||||
Constructor[type] = function (id, definition) {
|
||||
if (!definition) {
|
||||
return this.options[type + 's'][id]
|
||||
|
@ -3,6 +3,7 @@ var config = require('../config')
|
||||
var textParser = require('../parsers/text')
|
||||
var dirParser = require('../parsers/directive')
|
||||
var templateParser = require('../parsers/template')
|
||||
var resolveAsset = _.resolveAsset
|
||||
|
||||
// internal directives
|
||||
var propDef = require('../directives/prop')
|
||||
@ -278,7 +279,7 @@ function processTextToken (token, options) {
|
||||
}
|
||||
function setTokenType (type) {
|
||||
token.type = type
|
||||
token.def = options.directives[type]
|
||||
token.def = resolveAsset(options, 'directives', type)
|
||||
token.descriptor = dirParser.parse(token.value)[0]
|
||||
}
|
||||
return el
|
||||
@ -469,7 +470,7 @@ function makePropsLinkFn (props) {
|
||||
|
||||
function checkElementDirectives (el, options) {
|
||||
var tag = el.tagName.toLowerCase()
|
||||
var def = options.elementDirectives[tag]
|
||||
var def = resolveAsset(options, 'elementDirectives', tag)
|
||||
if (def) {
|
||||
return makeTerminalNodeLinkFn(el, tag, '', options, def)
|
||||
}
|
||||
@ -539,6 +540,8 @@ skip.terminal = true
|
||||
|
||||
function makeTerminalNodeLinkFn (el, dirName, value, options, def) {
|
||||
var descriptor = dirParser.parse(value)[0]
|
||||
// no need to call resolveAsset since terminal directives
|
||||
// are always internal
|
||||
def = def || options.directives[dirName]
|
||||
var fn = function terminalNodeLinkFn (vm, el, host) {
|
||||
vm._bindDir(dirName, el, descriptor, def, host)
|
||||
@ -571,7 +574,7 @@ function compileDirectives (elOrAttrs, options) {
|
||||
if (value === null) continue
|
||||
if (name.indexOf(config.prefix) === 0) {
|
||||
dirName = name.slice(config.prefix.length)
|
||||
dirDef = options.directives[dirName]
|
||||
dirDef = resolveAsset(options, 'directives', dirName)
|
||||
_.assertAsset(dirDef, 'directive', dirName)
|
||||
if (dirDef) {
|
||||
dirs.push({
|
||||
|
@ -62,7 +62,20 @@ module.exports = {
|
||||
* @type {Boolean}
|
||||
*/
|
||||
|
||||
_delimitersChanged: true
|
||||
_delimitersChanged: true,
|
||||
|
||||
/**
|
||||
* List of asset types that a component can own.
|
||||
*
|
||||
* @type {Array}
|
||||
*/
|
||||
|
||||
_assetTypes: [
|
||||
'directive',
|
||||
'elementDirective',
|
||||
'filter',
|
||||
'transition'
|
||||
]
|
||||
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,6 @@ var expParser = require('../parsers/expression')
|
||||
var templateParser = require('../parsers/template')
|
||||
var compile = require('../compiler/compile')
|
||||
var transclude = require('../compiler/transclude')
|
||||
var mergeOptions = require('../util/merge-option')
|
||||
var uid = 0
|
||||
|
||||
// async component resolution states
|
||||
@ -133,7 +132,7 @@ module.exports = {
|
||||
return
|
||||
}
|
||||
this.Ctor = Ctor
|
||||
var merged = mergeOptions(Ctor.options, {}, {
|
||||
var merged = _.mergeOptions(Ctor.options, {}, {
|
||||
$parent: this.vm
|
||||
})
|
||||
merged.template = this.inlineTempalte || merged.template
|
||||
@ -175,7 +174,7 @@ module.exports = {
|
||||
_.define(context, key, meta[key])
|
||||
}
|
||||
var id = this.ctorGetter.call(context, context)
|
||||
var Ctor = this.vm.$options.components[id]
|
||||
var Ctor = _.resolveAsset(this.vm.$options, 'components', id)
|
||||
_.assertAsset(Ctor, 'component', id)
|
||||
if (!Ctor.options) {
|
||||
_.warn(
|
||||
|
@ -19,7 +19,7 @@ module.exports = {
|
||||
// so the transition module knows this is a
|
||||
// javascript transition without having to check
|
||||
// computed CSS.
|
||||
fns: vm.$options.transitions[id]
|
||||
fns: _.resolveAsset(vm.$options, 'transitions', id)
|
||||
}
|
||||
if (oldId) {
|
||||
_.removeClass(this.el, oldId + '-transition')
|
||||
|
@ -1,4 +1,4 @@
|
||||
var mergeOptions = require('../util/merge-option')
|
||||
var mergeOptions = require('../util').mergeOptions
|
||||
|
||||
/**
|
||||
* The main init sequence. This is called for every
|
||||
|
@ -11,8 +11,7 @@ var _ = require('../util')
|
||||
*/
|
||||
|
||||
exports._applyFilter = function (id, args) {
|
||||
var registry = this.$options.filters
|
||||
var filter = registry[id]
|
||||
var filter = _.resolveAsset(this.$options, 'filters', id)
|
||||
_.assertAsset(filter, 'filter', id)
|
||||
return (filter.read || filter).apply(this, args)
|
||||
}
|
||||
@ -29,8 +28,7 @@ exports._applyFilter = function (id, args) {
|
||||
*/
|
||||
|
||||
exports._resolveComponent = function (id, cb) {
|
||||
var registry = this.$options.components
|
||||
var factory = registry[id]
|
||||
var factory = _.resolveAsset(this.$options, 'components', id)
|
||||
_.assertAsset(factory, 'component', id)
|
||||
// async component factory
|
||||
if (!factory.options) {
|
||||
|
@ -6,3 +6,4 @@ extend(exports, require('./env'))
|
||||
extend(exports, require('./dom'))
|
||||
extend(exports, require('./misc'))
|
||||
extend(exports, require('./debug'))
|
||||
extend(exports, require('./options'))
|
@ -1,5 +1,6 @@
|
||||
var _ = require('./debug')
|
||||
var _ = require('./index')
|
||||
var config = require('../config')
|
||||
var commonTagRE = /^(div|p|span|img|a|br|ul|ol|li|h1|h2|h3|h4|h5|table|tbody|tr|td|pre)$/
|
||||
|
||||
/**
|
||||
* Check if an element is a component, if yes return its
|
||||
@ -17,7 +18,10 @@ exports.checkComponent = function (el, options) {
|
||||
var exp = el.getAttribute('is')
|
||||
el.removeAttribute('is')
|
||||
return exp
|
||||
} else if (options.components[tag]) {
|
||||
} else if (
|
||||
!commonTagRE.test(tag) &&
|
||||
_.resolveAsset(options, 'components', tag)
|
||||
) {
|
||||
return tag
|
||||
}
|
||||
}
|
||||
@ -66,7 +70,7 @@ exports.resolveFilters = function (vm, filters, target) {
|
||||
var res = target || {}
|
||||
// var registry = vm.$options.filters
|
||||
filters.forEach(function (f) {
|
||||
var def = vm.$options.filters[f.name]
|
||||
var def = _.resolveAsset(vm.$options, 'filters', f.name)
|
||||
_.assertAsset(def, 'filter', f.name)
|
||||
if (!def) return
|
||||
var args = f.args
|
||||
|
@ -135,23 +135,11 @@ strats.directives =
|
||||
strats.filters =
|
||||
strats.transitions =
|
||||
strats.components =
|
||||
strats.elementDirectives = function (parentVal, childVal, vm, key) {
|
||||
var ret = Object.create(
|
||||
vm && vm.$parent
|
||||
? vm.$parent.$options[key]
|
||||
: _.Vue.options[key]
|
||||
)
|
||||
if (parentVal) {
|
||||
var keys = Object.keys(parentVal)
|
||||
var i = keys.length
|
||||
var field
|
||||
while (i--) {
|
||||
field = keys[i]
|
||||
ret[field] = parentVal[field]
|
||||
}
|
||||
}
|
||||
if (childVal) extend(ret, childVal)
|
||||
return ret
|
||||
strats.elementDirectives = function (parentVal, childVal) {
|
||||
var res = Object.create(parentVal)
|
||||
return childVal
|
||||
? extend(res, childVal)
|
||||
: res
|
||||
}
|
||||
|
||||
/**
|
||||
@ -233,26 +221,45 @@ function guardComponents (components) {
|
||||
* an instantiation merge.
|
||||
*/
|
||||
|
||||
module.exports = function mergeOptions (parent, child, vm) {
|
||||
exports.mergeOptions = function merge (parent, child, vm) {
|
||||
guardComponents(child.components)
|
||||
var options = {}
|
||||
var key
|
||||
if (child.mixins) {
|
||||
for (var i = 0, l = child.mixins.length; i < l; i++) {
|
||||
parent = mergeOptions(parent, child.mixins[i], vm)
|
||||
parent = merge(parent, child.mixins[i], vm)
|
||||
}
|
||||
}
|
||||
for (key in parent) {
|
||||
merge(key)
|
||||
mergeField(key)
|
||||
}
|
||||
for (key in child) {
|
||||
if (!(parent.hasOwnProperty(key))) {
|
||||
merge(key)
|
||||
mergeField(key)
|
||||
}
|
||||
}
|
||||
function merge (key) {
|
||||
function mergeField (key) {
|
||||
var strat = strats[key] || defaultStrat
|
||||
options[key] = strat(parent[key], child[key], vm, key)
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve an asset.
|
||||
* This function is used because child instances need access
|
||||
* to assets defined in its ancestor chain.
|
||||
*
|
||||
* @param {Object} options
|
||||
* @param {String} type
|
||||
* @param {String} id
|
||||
* @return {Object|Function}
|
||||
*/
|
||||
|
||||
exports.resolveAsset = function resolve (options, type, id) {
|
||||
return options[type][id] || (
|
||||
options._parent
|
||||
? resolve(options._parent.$options, type, id)
|
||||
: null
|
||||
)
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
var Vue = require('../../../../src/vue')
|
||||
var _ = Vue.util
|
||||
|
||||
describe('Child API', function () {
|
||||
|
||||
@ -22,7 +23,7 @@ describe('Child API', function () {
|
||||
expect(child.$parent).toBe(vm)
|
||||
expect(child.$root).toBe(vm)
|
||||
expect(vm._children.indexOf(child)).toBe(0)
|
||||
expect(child.$options.directives.test).toBeTruthy()
|
||||
expect(_.resolveAsset(child.$options, 'directives', 'test')).toBeTruthy()
|
||||
})
|
||||
|
||||
it('inherit scope', function () {
|
||||
|
@ -1,7 +1,6 @@
|
||||
var Vue = require('../../../../src/vue')
|
||||
var _ = require('../../../../src/util')
|
||||
var dirParser = require('../../../../src/parsers/directive')
|
||||
var merge = require('../../../../src/util/merge-option')
|
||||
var compile = require('../../../../src/compiler/compile')
|
||||
var transclude = require('../../../../src/compiler/transclude')
|
||||
|
||||
@ -50,7 +49,7 @@ if (_.inBrowser) {
|
||||
var defB = { priority: 2 }
|
||||
var descriptorA = dirParser.parse('a')[0]
|
||||
var descriptorB = dirParser.parse('b')[0]
|
||||
var options = merge(Vue.options, {
|
||||
var options = _.mergeOptions(Vue.options, {
|
||||
directives: {
|
||||
a: defA,
|
||||
b: defB
|
||||
@ -120,7 +119,7 @@ if (_.inBrowser) {
|
||||
})
|
||||
|
||||
it('custom element components', function () {
|
||||
var options = merge(Vue.options, {
|
||||
var options = _.mergeOptions(Vue.options, {
|
||||
components: {
|
||||
'my-component': {}
|
||||
}
|
||||
@ -146,7 +145,7 @@ if (_.inBrowser) {
|
||||
})
|
||||
|
||||
it('props', function () {
|
||||
var options = merge(Vue.options, {
|
||||
var options = _.mergeOptions(Vue.options, {
|
||||
_asComponent: true,
|
||||
props: [
|
||||
'a',
|
||||
|
@ -26,7 +26,7 @@ if (_.inBrowser) {
|
||||
expect(dir.el.className === 'test-transition')
|
||||
dir.update('lol', 'test')
|
||||
expect(dir.el.__v_trans.id).toBe('lol')
|
||||
expect(dir.el.__v_trans.fns).toBeUndefined()
|
||||
expect(dir.el.__v_trans.fns).toBeNull()
|
||||
expect(dir.el.className === 'lol-transition')
|
||||
})
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
var _ = require('../../../../src/util')
|
||||
var Vue = require('../../../../src/vue')
|
||||
var merge = require('../../../../src/util/merge-option')
|
||||
var merge = _.mergeOptions
|
||||
|
||||
describe('Util - Option merging', function () {
|
||||
|
||||
@ -101,42 +101,18 @@ describe('Util - Option merging', function () {
|
||||
it('assets', function () {
|
||||
var asset1 = {}
|
||||
var asset2 = {}
|
||||
var asset3 = {}
|
||||
var asset4 = {}
|
||||
var asset5 = {}
|
||||
var res = merge(
|
||||
{ directives: { a: asset1 }},
|
||||
{ directives: { b: asset2 }}
|
||||
).directives
|
||||
expect(res.a).toBe(asset1)
|
||||
expect(res.b).toBe(asset2)
|
||||
// vm asset merge should do tree-way merge
|
||||
var proto = { d: asset5 }
|
||||
var parent = { directives: Object.create(proto) }
|
||||
parent.directives.a = asset1
|
||||
parent.directives.b = asset4
|
||||
res = merge(
|
||||
parent,
|
||||
{ directives: { b: asset2 }},
|
||||
{
|
||||
$parent: {
|
||||
$options: {
|
||||
directives: { c: asset3 }
|
||||
}
|
||||
}
|
||||
},
|
||||
'directives'
|
||||
).directives
|
||||
expect(res.a).toBe(asset1)
|
||||
// child should overwrite parent
|
||||
expect(res.b).toBe(asset2)
|
||||
expect(res.c).toBe(asset3)
|
||||
// should not copy parent prototype properties
|
||||
expect(res.d).toBeUndefined()
|
||||
})
|
||||
|
||||
it('guard components', function () {
|
||||
var res = merge({}, {
|
||||
var res = merge({
|
||||
components: null
|
||||
}, {
|
||||
components: {
|
||||
a: { template: 'hi' }
|
||||
}
|
Loading…
Reference in New Issue
Block a user