Skip to content

Commit a31303f

Browse files
committed
build: generate more treeshaking friendly code
1 parent a6e5f82 commit a31303f

File tree

2 files changed

+120
-113
lines changed

2 files changed

+120
-113
lines changed

packages/runtime-core/src/componentRenderUtils.ts

+108-107
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,13 @@ export function renderComponentRoot(
6060
} = instance
6161

6262
let result
63+
let fallthroughAttrs
6364
const prev = setCurrentRenderingInstance(instance)
6465
if (__DEV__) {
6566
accessedAttrs = false
6667
}
68+
6769
try {
68-
let fallthroughAttrs
6970
if (vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT) {
7071
// withProxy is a proxy with a different `has` trap only for
7172
// runtime-compiled render functions using `with` block.
@@ -110,127 +111,127 @@ export function renderComponentRoot(
110111
? attrs
111112
: getFunctionalFallthrough(attrs)
112113
}
114+
} catch (err) {
115+
blockStack.length = 0
116+
handleError(err, instance, ErrorCodes.RENDER_FUNCTION)
117+
result = createVNode(Comment)
118+
}
113119

114-
// attr merging
115-
// in dev mode, comments are preserved, and it's possible for a template
116-
// to have comments along side the root element which makes it a fragment
117-
let root = result
118-
let setRoot: ((root: VNode) => void) | undefined = undefined
119-
if (
120-
__DEV__ &&
121-
result.patchFlag > 0 &&
122-
result.patchFlag & PatchFlags.DEV_ROOT_FRAGMENT
123-
) {
124-
;[root, setRoot] = getChildRoot(result)
125-
}
120+
// attr merging
121+
// in dev mode, comments are preserved, and it's possible for a template
122+
// to have comments along side the root element which makes it a fragment
123+
let root = result
124+
let setRoot: ((root: VNode) => void) | undefined = undefined
125+
if (
126+
__DEV__ &&
127+
result.patchFlag > 0 &&
128+
result.patchFlag & PatchFlags.DEV_ROOT_FRAGMENT
129+
) {
130+
;[root, setRoot] = getChildRoot(result)
131+
}
126132

127-
if (fallthroughAttrs && inheritAttrs !== false) {
128-
const keys = Object.keys(fallthroughAttrs)
129-
const { shapeFlag } = root
130-
if (keys.length) {
131-
if (shapeFlag & (ShapeFlags.ELEMENT | ShapeFlags.COMPONENT)) {
132-
if (propsOptions && keys.some(isModelListener)) {
133-
// If a v-model listener (onUpdate:xxx) has a corresponding declared
134-
// prop, it indicates this component expects to handle v-model and
135-
// it should not fallthrough.
136-
// related: #1543, #1643, #1989
137-
fallthroughAttrs = filterModelListeners(
138-
fallthroughAttrs,
139-
propsOptions
140-
)
141-
}
142-
root = cloneVNode(root, fallthroughAttrs)
143-
} else if (__DEV__ && !accessedAttrs && root.type !== Comment) {
144-
const allAttrs = Object.keys(attrs)
145-
const eventAttrs: string[] = []
146-
const extraAttrs: string[] = []
147-
for (let i = 0, l = allAttrs.length; i < l; i++) {
148-
const key = allAttrs[i]
149-
if (isOn(key)) {
150-
// ignore v-model handlers when they fail to fallthrough
151-
if (!isModelListener(key)) {
152-
// remove `on`, lowercase first letter to reflect event casing
153-
// accurately
154-
eventAttrs.push(key[2].toLowerCase() + key.slice(3))
155-
}
156-
} else {
157-
extraAttrs.push(key)
133+
if (fallthroughAttrs && inheritAttrs !== false) {
134+
const keys = Object.keys(fallthroughAttrs)
135+
const { shapeFlag } = root
136+
if (keys.length) {
137+
if (shapeFlag & (ShapeFlags.ELEMENT | ShapeFlags.COMPONENT)) {
138+
if (propsOptions && keys.some(isModelListener)) {
139+
// If a v-model listener (onUpdate:xxx) has a corresponding declared
140+
// prop, it indicates this component expects to handle v-model and
141+
// it should not fallthrough.
142+
// related: #1543, #1643, #1989
143+
fallthroughAttrs = filterModelListeners(
144+
fallthroughAttrs,
145+
propsOptions
146+
)
147+
}
148+
root = cloneVNode(root, fallthroughAttrs)
149+
} else if (__DEV__ && !accessedAttrs && root.type !== Comment) {
150+
const allAttrs = Object.keys(attrs)
151+
const eventAttrs: string[] = []
152+
const extraAttrs: string[] = []
153+
for (let i = 0, l = allAttrs.length; i < l; i++) {
154+
const key = allAttrs[i]
155+
if (isOn(key)) {
156+
// ignore v-model handlers when they fail to fallthrough
157+
if (!isModelListener(key)) {
158+
// remove `on`, lowercase first letter to reflect event casing
159+
// accurately
160+
eventAttrs.push(key[2].toLowerCase() + key.slice(3))
158161
}
159-
}
160-
if (extraAttrs.length) {
161-
warn(
162-
`Extraneous non-props attributes (` +
163-
`${extraAttrs.join(', ')}) ` +
164-
`were passed to component but could not be automatically inherited ` +
165-
`because component renders fragment or text root nodes.`
166-
)
167-
}
168-
if (eventAttrs.length) {
169-
warn(
170-
`Extraneous non-emits event listeners (` +
171-
`${eventAttrs.join(', ')}) ` +
172-
`were passed to component but could not be automatically inherited ` +
173-
`because component renders fragment or text root nodes. ` +
174-
`If the listener is intended to be a component custom event listener only, ` +
175-
`declare it using the "emits" option.`
176-
)
162+
} else {
163+
extraAttrs.push(key)
177164
}
178165
}
179-
}
180-
}
181-
182-
if (
183-
__COMPAT__ &&
184-
isCompatEnabled(DeprecationTypes.INSTANCE_ATTRS_CLASS_STYLE, instance) &&
185-
vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT &&
186-
root.shapeFlag & (ShapeFlags.ELEMENT | ShapeFlags.COMPONENT)
187-
) {
188-
const { class: cls, style } = vnode.props || {}
189-
if (cls || style) {
190-
if (__DEV__ && inheritAttrs === false) {
191-
warnDeprecation(
192-
DeprecationTypes.INSTANCE_ATTRS_CLASS_STYLE,
193-
instance,
194-
getComponentName(instance.type)
166+
if (extraAttrs.length) {
167+
warn(
168+
`Extraneous non-props attributes (` +
169+
`${extraAttrs.join(', ')}) ` +
170+
`were passed to component but could not be automatically inherited ` +
171+
`because component renders fragment or text root nodes.`
172+
)
173+
}
174+
if (eventAttrs.length) {
175+
warn(
176+
`Extraneous non-emits event listeners (` +
177+
`${eventAttrs.join(', ')}) ` +
178+
`were passed to component but could not be automatically inherited ` +
179+
`because component renders fragment or text root nodes. ` +
180+
`If the listener is intended to be a component custom event listener only, ` +
181+
`declare it using the "emits" option.`
195182
)
196183
}
197-
root = cloneVNode(root, {
198-
class: cls,
199-
style: style
200-
})
201184
}
202185
}
186+
}
203187

204-
// inherit directives
205-
if (vnode.dirs) {
206-
if (__DEV__ && !isElementRoot(root)) {
207-
warn(
208-
`Runtime directive used on component with non-element root node. ` +
209-
`The directives will not function as intended.`
188+
if (
189+
__COMPAT__ &&
190+
isCompatEnabled(DeprecationTypes.INSTANCE_ATTRS_CLASS_STYLE, instance) &&
191+
vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT &&
192+
root.shapeFlag & (ShapeFlags.ELEMENT | ShapeFlags.COMPONENT)
193+
) {
194+
const { class: cls, style } = vnode.props || {}
195+
if (cls || style) {
196+
if (__DEV__ && inheritAttrs === false) {
197+
warnDeprecation(
198+
DeprecationTypes.INSTANCE_ATTRS_CLASS_STYLE,
199+
instance,
200+
getComponentName(instance.type)
210201
)
211202
}
212-
root.dirs = root.dirs ? root.dirs.concat(vnode.dirs) : vnode.dirs
213-
}
214-
// inherit transition data
215-
if (vnode.transition) {
216-
if (__DEV__ && !isElementRoot(root)) {
217-
warn(
218-
`Component inside <Transition> renders non-element root node ` +
219-
`that cannot be animated.`
220-
)
221-
}
222-
root.transition = vnode.transition
203+
root = cloneVNode(root, {
204+
class: cls,
205+
style: style
206+
})
223207
}
208+
}
224209

225-
if (__DEV__ && setRoot) {
226-
setRoot(root)
227-
} else {
228-
result = root
210+
// inherit directives
211+
if (vnode.dirs) {
212+
if (__DEV__ && !isElementRoot(root)) {
213+
warn(
214+
`Runtime directive used on component with non-element root node. ` +
215+
`The directives will not function as intended.`
216+
)
229217
}
230-
} catch (err) {
231-
blockStack.length = 0
232-
handleError(err, instance, ErrorCodes.RENDER_FUNCTION)
233-
result = createVNode(Comment)
218+
root.dirs = root.dirs ? root.dirs.concat(vnode.dirs) : vnode.dirs
219+
}
220+
// inherit transition data
221+
if (vnode.transition) {
222+
if (__DEV__ && !isElementRoot(root)) {
223+
warn(
224+
`Component inside <Transition> renders non-element root node ` +
225+
`that cannot be animated.`
226+
)
227+
}
228+
root.transition = vnode.transition
229+
}
230+
231+
if (__DEV__ && setRoot) {
232+
setRoot(root)
233+
} else {
234+
result = root
234235
}
235236

236237
setCurrentRenderingInstance(prev)

packages/runtime-core/src/scheduler.ts

+12-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ErrorCodes, callWithErrorHandling } from './errorHandling'
2-
import { isArray } from '@vue/shared'
2+
import { isArray, NOOP } from '@vue/shared'
33
import { ComponentInternalInstance, getComponentName } from './component'
44
import { warn } from './warning'
55

@@ -128,10 +128,7 @@ function queueCb(
128128
if (!isArray(cb)) {
129129
if (
130130
!activeQueue ||
131-
!activeQueue.includes(
132-
cb,
133-
cb.allowRecurse ? index + 1 : index
134-
)
131+
!activeQueue.includes(cb, cb.allowRecurse ? index + 1 : index)
135132
) {
136133
pendingQueue.push(cb)
137134
}
@@ -241,11 +238,20 @@ function flushJobs(seen?: CountMap) {
241238
// its update can be skipped.
242239
queue.sort((a, b) => getId(a) - getId(b))
243240

241+
// conditional usage of checkRecursiveUpdate must be determined out of
242+
// try ... catch block since Rollup by default de-optimizes treeshaking
243+
// inside try-catch. This can leave all warning code unshaked. Although
244+
// they would get eventually shaken by a minifier like terser, some minifiers
245+
// would fail to do that (e.g. https://github.com/evanw/esbuild/issues/1610)
246+
const check = __DEV__
247+
? (job: SchedulerJob) => checkRecursiveUpdates(seen!, job)
248+
: NOOP
249+
244250
try {
245251
for (flushIndex = 0; flushIndex < queue.length; flushIndex++) {
246252
const job = queue[flushIndex]
247253
if (job && job.active !== false) {
248-
if (__DEV__ && checkRecursiveUpdates(seen!, job)) {
254+
if (__DEV__ && check(job)) {
249255
continue
250256
}
251257
// console.log(`running:`, job.id)

0 commit comments

Comments
 (0)