build: generate more treeshaking friendly code
This commit is contained in:
parent
a6e5f82d8e
commit
a31303f835
@ -60,12 +60,13 @@ export function renderComponentRoot(
|
|||||||
} = instance
|
} = instance
|
||||||
|
|
||||||
let result
|
let result
|
||||||
|
let fallthroughAttrs
|
||||||
const prev = setCurrentRenderingInstance(instance)
|
const prev = setCurrentRenderingInstance(instance)
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
accessedAttrs = false
|
accessedAttrs = false
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let fallthroughAttrs
|
|
||||||
if (vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT) {
|
if (vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT) {
|
||||||
// withProxy is a proxy with a different `has` trap only for
|
// withProxy is a proxy with a different `has` trap only for
|
||||||
// runtime-compiled render functions using `with` block.
|
// runtime-compiled render functions using `with` block.
|
||||||
@ -110,129 +111,129 @@ export function renderComponentRoot(
|
|||||||
? attrs
|
? attrs
|
||||||
: getFunctionalFallthrough(attrs)
|
: getFunctionalFallthrough(attrs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// attr merging
|
|
||||||
// in dev mode, comments are preserved, and it's possible for a template
|
|
||||||
// to have comments along side the root element which makes it a fragment
|
|
||||||
let root = result
|
|
||||||
let setRoot: ((root: VNode) => void) | undefined = undefined
|
|
||||||
if (
|
|
||||||
__DEV__ &&
|
|
||||||
result.patchFlag > 0 &&
|
|
||||||
result.patchFlag & PatchFlags.DEV_ROOT_FRAGMENT
|
|
||||||
) {
|
|
||||||
;[root, setRoot] = getChildRoot(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fallthroughAttrs && inheritAttrs !== false) {
|
|
||||||
const keys = Object.keys(fallthroughAttrs)
|
|
||||||
const { shapeFlag } = root
|
|
||||||
if (keys.length) {
|
|
||||||
if (shapeFlag & (ShapeFlags.ELEMENT | ShapeFlags.COMPONENT)) {
|
|
||||||
if (propsOptions && keys.some(isModelListener)) {
|
|
||||||
// If a v-model listener (onUpdate:xxx) has a corresponding declared
|
|
||||||
// prop, it indicates this component expects to handle v-model and
|
|
||||||
// it should not fallthrough.
|
|
||||||
// related: #1543, #1643, #1989
|
|
||||||
fallthroughAttrs = filterModelListeners(
|
|
||||||
fallthroughAttrs,
|
|
||||||
propsOptions
|
|
||||||
)
|
|
||||||
}
|
|
||||||
root = cloneVNode(root, fallthroughAttrs)
|
|
||||||
} else if (__DEV__ && !accessedAttrs && root.type !== Comment) {
|
|
||||||
const allAttrs = Object.keys(attrs)
|
|
||||||
const eventAttrs: string[] = []
|
|
||||||
const extraAttrs: string[] = []
|
|
||||||
for (let i = 0, l = allAttrs.length; i < l; i++) {
|
|
||||||
const key = allAttrs[i]
|
|
||||||
if (isOn(key)) {
|
|
||||||
// ignore v-model handlers when they fail to fallthrough
|
|
||||||
if (!isModelListener(key)) {
|
|
||||||
// remove `on`, lowercase first letter to reflect event casing
|
|
||||||
// accurately
|
|
||||||
eventAttrs.push(key[2].toLowerCase() + key.slice(3))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
extraAttrs.push(key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (extraAttrs.length) {
|
|
||||||
warn(
|
|
||||||
`Extraneous non-props attributes (` +
|
|
||||||
`${extraAttrs.join(', ')}) ` +
|
|
||||||
`were passed to component but could not be automatically inherited ` +
|
|
||||||
`because component renders fragment or text root nodes.`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (eventAttrs.length) {
|
|
||||||
warn(
|
|
||||||
`Extraneous non-emits event listeners (` +
|
|
||||||
`${eventAttrs.join(', ')}) ` +
|
|
||||||
`were passed to component but could not be automatically inherited ` +
|
|
||||||
`because component renders fragment or text root nodes. ` +
|
|
||||||
`If the listener is intended to be a component custom event listener only, ` +
|
|
||||||
`declare it using the "emits" option.`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
__COMPAT__ &&
|
|
||||||
isCompatEnabled(DeprecationTypes.INSTANCE_ATTRS_CLASS_STYLE, instance) &&
|
|
||||||
vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT &&
|
|
||||||
root.shapeFlag & (ShapeFlags.ELEMENT | ShapeFlags.COMPONENT)
|
|
||||||
) {
|
|
||||||
const { class: cls, style } = vnode.props || {}
|
|
||||||
if (cls || style) {
|
|
||||||
if (__DEV__ && inheritAttrs === false) {
|
|
||||||
warnDeprecation(
|
|
||||||
DeprecationTypes.INSTANCE_ATTRS_CLASS_STYLE,
|
|
||||||
instance,
|
|
||||||
getComponentName(instance.type)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
root = cloneVNode(root, {
|
|
||||||
class: cls,
|
|
||||||
style: style
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// inherit directives
|
|
||||||
if (vnode.dirs) {
|
|
||||||
if (__DEV__ && !isElementRoot(root)) {
|
|
||||||
warn(
|
|
||||||
`Runtime directive used on component with non-element root node. ` +
|
|
||||||
`The directives will not function as intended.`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
root.dirs = root.dirs ? root.dirs.concat(vnode.dirs) : vnode.dirs
|
|
||||||
}
|
|
||||||
// inherit transition data
|
|
||||||
if (vnode.transition) {
|
|
||||||
if (__DEV__ && !isElementRoot(root)) {
|
|
||||||
warn(
|
|
||||||
`Component inside <Transition> renders non-element root node ` +
|
|
||||||
`that cannot be animated.`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
root.transition = vnode.transition
|
|
||||||
}
|
|
||||||
|
|
||||||
if (__DEV__ && setRoot) {
|
|
||||||
setRoot(root)
|
|
||||||
} else {
|
|
||||||
result = root
|
|
||||||
}
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
blockStack.length = 0
|
blockStack.length = 0
|
||||||
handleError(err, instance, ErrorCodes.RENDER_FUNCTION)
|
handleError(err, instance, ErrorCodes.RENDER_FUNCTION)
|
||||||
result = createVNode(Comment)
|
result = createVNode(Comment)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// attr merging
|
||||||
|
// in dev mode, comments are preserved, and it's possible for a template
|
||||||
|
// to have comments along side the root element which makes it a fragment
|
||||||
|
let root = result
|
||||||
|
let setRoot: ((root: VNode) => void) | undefined = undefined
|
||||||
|
if (
|
||||||
|
__DEV__ &&
|
||||||
|
result.patchFlag > 0 &&
|
||||||
|
result.patchFlag & PatchFlags.DEV_ROOT_FRAGMENT
|
||||||
|
) {
|
||||||
|
;[root, setRoot] = getChildRoot(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fallthroughAttrs && inheritAttrs !== false) {
|
||||||
|
const keys = Object.keys(fallthroughAttrs)
|
||||||
|
const { shapeFlag } = root
|
||||||
|
if (keys.length) {
|
||||||
|
if (shapeFlag & (ShapeFlags.ELEMENT | ShapeFlags.COMPONENT)) {
|
||||||
|
if (propsOptions && keys.some(isModelListener)) {
|
||||||
|
// If a v-model listener (onUpdate:xxx) has a corresponding declared
|
||||||
|
// prop, it indicates this component expects to handle v-model and
|
||||||
|
// it should not fallthrough.
|
||||||
|
// related: #1543, #1643, #1989
|
||||||
|
fallthroughAttrs = filterModelListeners(
|
||||||
|
fallthroughAttrs,
|
||||||
|
propsOptions
|
||||||
|
)
|
||||||
|
}
|
||||||
|
root = cloneVNode(root, fallthroughAttrs)
|
||||||
|
} else if (__DEV__ && !accessedAttrs && root.type !== Comment) {
|
||||||
|
const allAttrs = Object.keys(attrs)
|
||||||
|
const eventAttrs: string[] = []
|
||||||
|
const extraAttrs: string[] = []
|
||||||
|
for (let i = 0, l = allAttrs.length; i < l; i++) {
|
||||||
|
const key = allAttrs[i]
|
||||||
|
if (isOn(key)) {
|
||||||
|
// ignore v-model handlers when they fail to fallthrough
|
||||||
|
if (!isModelListener(key)) {
|
||||||
|
// remove `on`, lowercase first letter to reflect event casing
|
||||||
|
// accurately
|
||||||
|
eventAttrs.push(key[2].toLowerCase() + key.slice(3))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
extraAttrs.push(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (extraAttrs.length) {
|
||||||
|
warn(
|
||||||
|
`Extraneous non-props attributes (` +
|
||||||
|
`${extraAttrs.join(', ')}) ` +
|
||||||
|
`were passed to component but could not be automatically inherited ` +
|
||||||
|
`because component renders fragment or text root nodes.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (eventAttrs.length) {
|
||||||
|
warn(
|
||||||
|
`Extraneous non-emits event listeners (` +
|
||||||
|
`${eventAttrs.join(', ')}) ` +
|
||||||
|
`were passed to component but could not be automatically inherited ` +
|
||||||
|
`because component renders fragment or text root nodes. ` +
|
||||||
|
`If the listener is intended to be a component custom event listener only, ` +
|
||||||
|
`declare it using the "emits" option.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
__COMPAT__ &&
|
||||||
|
isCompatEnabled(DeprecationTypes.INSTANCE_ATTRS_CLASS_STYLE, instance) &&
|
||||||
|
vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT &&
|
||||||
|
root.shapeFlag & (ShapeFlags.ELEMENT | ShapeFlags.COMPONENT)
|
||||||
|
) {
|
||||||
|
const { class: cls, style } = vnode.props || {}
|
||||||
|
if (cls || style) {
|
||||||
|
if (__DEV__ && inheritAttrs === false) {
|
||||||
|
warnDeprecation(
|
||||||
|
DeprecationTypes.INSTANCE_ATTRS_CLASS_STYLE,
|
||||||
|
instance,
|
||||||
|
getComponentName(instance.type)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
root = cloneVNode(root, {
|
||||||
|
class: cls,
|
||||||
|
style: style
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// inherit directives
|
||||||
|
if (vnode.dirs) {
|
||||||
|
if (__DEV__ && !isElementRoot(root)) {
|
||||||
|
warn(
|
||||||
|
`Runtime directive used on component with non-element root node. ` +
|
||||||
|
`The directives will not function as intended.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
root.dirs = root.dirs ? root.dirs.concat(vnode.dirs) : vnode.dirs
|
||||||
|
}
|
||||||
|
// inherit transition data
|
||||||
|
if (vnode.transition) {
|
||||||
|
if (__DEV__ && !isElementRoot(root)) {
|
||||||
|
warn(
|
||||||
|
`Component inside <Transition> renders non-element root node ` +
|
||||||
|
`that cannot be animated.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
root.transition = vnode.transition
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__DEV__ && setRoot) {
|
||||||
|
setRoot(root)
|
||||||
|
} else {
|
||||||
|
result = root
|
||||||
|
}
|
||||||
|
|
||||||
setCurrentRenderingInstance(prev)
|
setCurrentRenderingInstance(prev)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { ErrorCodes, callWithErrorHandling } from './errorHandling'
|
import { ErrorCodes, callWithErrorHandling } from './errorHandling'
|
||||||
import { isArray } from '@vue/shared'
|
import { isArray, NOOP } from '@vue/shared'
|
||||||
import { ComponentInternalInstance, getComponentName } from './component'
|
import { ComponentInternalInstance, getComponentName } from './component'
|
||||||
import { warn } from './warning'
|
import { warn } from './warning'
|
||||||
|
|
||||||
@ -128,10 +128,7 @@ function queueCb(
|
|||||||
if (!isArray(cb)) {
|
if (!isArray(cb)) {
|
||||||
if (
|
if (
|
||||||
!activeQueue ||
|
!activeQueue ||
|
||||||
!activeQueue.includes(
|
!activeQueue.includes(cb, cb.allowRecurse ? index + 1 : index)
|
||||||
cb,
|
|
||||||
cb.allowRecurse ? index + 1 : index
|
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
pendingQueue.push(cb)
|
pendingQueue.push(cb)
|
||||||
}
|
}
|
||||||
@ -241,11 +238,20 @@ function flushJobs(seen?: CountMap) {
|
|||||||
// its update can be skipped.
|
// its update can be skipped.
|
||||||
queue.sort((a, b) => getId(a) - getId(b))
|
queue.sort((a, b) => getId(a) - getId(b))
|
||||||
|
|
||||||
|
// conditional usage of checkRecursiveUpdate must be determined out of
|
||||||
|
// try ... catch block since Rollup by default de-optimizes treeshaking
|
||||||
|
// inside try-catch. This can leave all warning code unshaked. Although
|
||||||
|
// they would get eventually shaken by a minifier like terser, some minifiers
|
||||||
|
// would fail to do that (e.g. https://github.com/evanw/esbuild/issues/1610)
|
||||||
|
const check = __DEV__
|
||||||
|
? (job: SchedulerJob) => checkRecursiveUpdates(seen!, job)
|
||||||
|
: NOOP
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (flushIndex = 0; flushIndex < queue.length; flushIndex++) {
|
for (flushIndex = 0; flushIndex < queue.length; flushIndex++) {
|
||||||
const job = queue[flushIndex]
|
const job = queue[flushIndex]
|
||||||
if (job && job.active !== false) {
|
if (job && job.active !== false) {
|
||||||
if (__DEV__ && checkRecursiveUpdates(seen!, job)) {
|
if (__DEV__ && check(job)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// console.log(`running:`, job.id)
|
// console.log(`running:`, job.id)
|
||||||
|
Loading…
Reference in New Issue
Block a user