Skip to content

Commit 19480ca

Browse files
committed
perf: use new Empty() instead of Object.create(null) for performance
1 parent 828d4a4 commit 19480ca

File tree

23 files changed

+66
-52
lines changed

23 files changed

+66
-52
lines changed

packages/compiler-core/src/babelUtils.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import type {
1111
ObjectProperty,
1212
Program,
1313
} from '@babel/types'
14+
import { Empty } from '@vue/shared'
1415
import { walk } from 'estree-walker'
1516

1617
/**
@@ -27,7 +28,7 @@ export function walkIdentifiers(
2728
) => void,
2829
includeAll = false,
2930
parentStack: Node[] = [],
30-
knownIds: Record<string, number> = Object.create(null),
31+
knownIds: Record<string, number> = new Empty(),
3132
): void {
3233
if (__BROWSER__) {
3334
return

packages/compiler-core/src/transform.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
} from './ast'
2323
import {
2424
EMPTY_OBJ,
25+
Empty,
2526
NOOP,
2627
PatchFlags,
2728
camelize,
@@ -187,7 +188,7 @@ export function createTransformContext(
187188
cached: [],
188189
constantCache: new WeakMap(),
189190
temps: 0,
190-
identifiers: Object.create(null),
191+
identifiers: new Empty(),
191192
scopes: {
192193
vFor: 0,
193194
vSlot: 0,

packages/compiler-sfc/src/compileScript.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
type SFCScriptBlock,
1212
} from './parse'
1313
import type { ParserPlugin } from '@babel/parser'
14-
import { generateCodeFrame } from '@vue/shared'
14+
import { Empty, generateCodeFrame } from '@vue/shared'
1515
import type {
1616
ArrayPattern,
1717
CallExpression,
@@ -194,8 +194,8 @@ export function compileScript(
194194

195195
// metadata that needs to be returned
196196
// const ctx.bindingMetadata: BindingMetadata = {}
197-
const scriptBindings: Record<string, BindingTypes> = Object.create(null)
198-
const setupBindings: Record<string, BindingTypes> = Object.create(null)
197+
const scriptBindings: Record<string, BindingTypes> = new Empty()
198+
const setupBindings: Record<string, BindingTypes> = new Empty()
199199

200200
let defaultExport: Node | undefined
201201
let hasAwait = false

packages/compiler-sfc/src/script/context.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { CallExpression, Node, ObjectPattern, Program } from '@babel/types'
22
import type { SFCDescriptor } from '../parse'
3-
import { generateCodeFrame, isArray } from '@vue/shared'
3+
import { Empty, generateCodeFrame, isArray } from '@vue/shared'
44
import { type ParserPlugin, parse as babelParse } from '@babel/parser'
55
import type { ImportBinding, SFCScriptCompileOptions } from '../compileScript'
66
import type { PropsDestructureBindings } from './defineProps'
@@ -28,7 +28,7 @@ export class ScriptCompileContext {
2828
// import / type analysis
2929
scope?: TypeScope
3030
globalScopes?: TypeScope[]
31-
userImports: Record<string, ImportBinding> = Object.create(null)
31+
userImports: Record<string, ImportBinding> = new Empty()
3232

3333
// macros presence check
3434
hasDefinePropsCall = false
@@ -46,7 +46,7 @@ export class ScriptCompileContext {
4646
propsRuntimeDecl: Node | undefined
4747
propsTypeDecl: Node | undefined
4848
propsDestructureDecl: ObjectPattern | undefined
49-
propsDestructuredBindings: PropsDestructureBindings = Object.create(null)
49+
propsDestructuredBindings: PropsDestructureBindings = new Empty()
5050
propsDestructureRestId: string | undefined
5151
propsRuntimeDefaults: Node | undefined
5252

@@ -56,7 +56,7 @@ export class ScriptCompileContext {
5656
emitDecl: Node | undefined
5757

5858
// defineModel
59-
modelDecls: Record<string, ModelDecl> = Object.create(null)
59+
modelDecls: Record<string, ModelDecl> = new Empty()
6060

6161
// defineOptions
6262
optionsRuntimeDecl: Node | undefined

packages/compiler-sfc/src/script/definePropsDestructure.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919
unwrapTSNode,
2020
walkFunctionParams,
2121
} from '@vue/compiler-dom'
22-
import { genPropsAccessExp } from '@vue/shared'
22+
import { Empty, genPropsAccessExp } from '@vue/shared'
2323
import { isCallOf, resolveObjectKey } from './utils'
2424
import type { ScriptCompileContext } from './context'
2525
import { DEFINE_PROPS } from './defineProps'
@@ -103,12 +103,12 @@ export function transformDestructuredProps(
103103
return
104104
}
105105

106-
const rootScope: Scope = Object.create(null)
106+
const rootScope: Scope = new Empty()
107107
const scopeStack: Scope[] = [rootScope]
108108
let currentScope: Scope = rootScope
109109
const excludedIds = new WeakSet<Identifier>()
110110
const parentStack: Node[] = []
111-
const propsLocalToPublicMap: Record<string, string> = Object.create(null)
111+
const propsLocalToPublicMap: Record<string, string> = new Empty()
112112

113113
for (const key in ctx.propsDestructuredBindings) {
114114
const { local } = ctx.propsDestructuredBindings[key]

packages/compiler-sfc/src/script/resolveType.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import {
3434
} from './utils'
3535
import { type ScriptCompileContext, resolveParserPlugins } from './context'
3636
import type { ImportBinding, SFCScriptCompileOptions } from '../compileScript'
37-
import { capitalize, hasOwn } from '@vue/shared'
37+
import { Empty, capitalize, hasOwn } from '@vue/shared'
3838
import { parse as babelParse } from '@babel/parser'
3939
import { parse } from '../parse'
4040
import { createCache } from '../cache'
@@ -111,14 +111,14 @@ export class TypeScope {
111111
public filename: string,
112112
public source: string,
113113
public offset: number = 0,
114-
public imports: Record<string, Import> = Object.create(null),
115-
public types: Record<string, ScopeTypeNode> = Object.create(null),
116-
public declares: Record<string, ScopeTypeNode> = Object.create(null),
114+
public imports: Record<string, Import> = new Empty(),
115+
public types: Record<string, ScopeTypeNode> = new Empty(),
116+
public declares: Record<string, ScopeTypeNode> = new Empty(),
117117
) {}
118118
isGenericScope = false
119-
resolvedImportSources: Record<string, string> = Object.create(null)
120-
exportedTypes: Record<string, ScopeTypeNode> = Object.create(null)
121-
exportedDeclares: Record<string, ScopeTypeNode> = Object.create(null)
119+
resolvedImportSources: Record<string, string> = new Empty()
120+
exportedTypes: Record<string, ScopeTypeNode> = new Empty()
121+
exportedDeclares: Record<string, ScopeTypeNode> = new Empty()
122122
}
123123

124124
export interface MaybeWithScope {
@@ -231,7 +231,7 @@ function innerResolveTypeElements(
231231
resolved.typeParameters &&
232232
node.typeParameters
233233
) {
234-
typeParams = Object.create(null)
234+
typeParams = new Empty()
235235
resolved.typeParameters.params.forEach((p, i) => {
236236
let param = typeParameters && typeParameters[p.name]
237237
if (!param) param = node.typeParameters!.params[i]
@@ -1442,7 +1442,7 @@ function attachNamespace(
14421442
}
14431443

14441444
export function recordImports(body: Statement[]): Record<string, Import> {
1445-
const imports: TypeScope['imports'] = Object.create(null)
1445+
const imports: TypeScope['imports'] = new Empty()
14461446
for (const s of body) {
14471447
recordImport(s, imports)
14481448
}

packages/compiler-sfc/src/style/pluginScoped.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@ import {
77
} from 'postcss'
88
import selectorParser from 'postcss-selector-parser'
99
import { warn } from '../warn'
10+
import { Empty } from '@vue/shared'
1011

1112
const animationNameRE = /^(-\w+-)?animation-name$/
1213
const animationRE = /^(-\w+-)?animation$/
1314

1415
const scopedPlugin: PluginCreator<string> = (id = '') => {
15-
const keyframes = Object.create(null)
16+
const keyframes = new Empty()
1617
const shortId = id.replace(/^data-v-/, '')
1718

1819
return {

packages/runtime-core/src/apiCreateApp.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import { warn } from './warning'
2222
import { type VNode, cloneVNode, createVNode } from './vnode'
2323
import type { RootHydrateFunction } from './hydration'
2424
import { devtoolsInitApp, devtoolsUnmountApp } from './devtools'
25-
import { NO, extend, isFunction, isObject } from '@vue/shared'
25+
import { Empty, NO, extend, isFunction, isObject } from '@vue/shared'
2626
import { version } from '.'
2727
import { installAppCompatProperties } from './compat/global'
2828
import type { NormalizedPropsOptions } from './componentProps'
@@ -234,7 +234,7 @@ export function createAppContext(): AppContext {
234234
mixins: [],
235235
components: {},
236236
directives: {},
237-
provides: Object.create(null),
237+
provides: new Empty(),
238238
optionsCache: new WeakMap(),
239239
propsCache: new WeakMap(),
240240
emitsCache: new WeakMap(),

packages/runtime-core/src/compat/compatConfig.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { extend, hasOwn, isArray, isFunction } from '@vue/shared'
1+
import { Empty, extend, hasOwn, isArray, isFunction } from '@vue/shared'
22
import {
33
type Component,
44
type ComponentInternalInstance,
@@ -425,8 +425,8 @@ export const deprecationData: Record<DeprecationTypes, DeprecationData> = {
425425
},
426426
}
427427

428-
const instanceWarned: Record<string, true> = Object.create(null)
429-
const warnCount: Record<string, number> = Object.create(null)
428+
const instanceWarned: Record<string, true> = new Empty()
429+
const warnCount: Record<string, number> = new Empty()
430430

431431
// test only
432432
let warningEnabled = true

packages/runtime-core/src/compat/global.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
trigger,
88
} from '@vue/reactivity'
99
import {
10+
Empty,
1011
NOOP,
1112
extend,
1213
invokeArrayFns,
@@ -259,7 +260,7 @@ export function createCompatVue(
259260
mergeBase[key] = isArray(superValue)
260261
? superValue.slice()
261262
: isObject(superValue)
262-
? extend(Object.create(null), superValue)
263+
? extend(new Empty(), superValue)
263264
: superValue
264265
}
265266

@@ -640,7 +641,7 @@ function defineReactive(obj: any, key: string, val: any) {
640641
if (i && obj === i.proxy) {
641642
// target is a Vue instance - define on instance.ctx
642643
defineReactiveSimple(i.ctx, key, val)
643-
i.accessCache = Object.create(null)
644+
i.accessCache = new Empty()
644645
} else if (isReactive(obj)) {
645646
obj[key] = val
646647
} else {

packages/runtime-core/src/compat/instanceEventEmitter.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { isArray } from '@vue/shared'
1+
import { Empty, isArray } from '@vue/shared'
22
import type { ComponentInternalInstance } from '../component'
33
import { ErrorCodes, callWithAsyncErrorHandling } from '../errorHandling'
44
import { DeprecationTypes, assertCompatEnabled } from './compatConfig'
@@ -18,7 +18,7 @@ export function getRegistry(
1818
): EventRegistry {
1919
let events = eventRegistryMap.get(instance)
2020
if (!events) {
21-
eventRegistryMap.set(instance, (events = Object.create(null)))
21+
eventRegistryMap.set(instance, (events = new Empty()))
2222
}
2323
return events!
2424
}
@@ -69,7 +69,7 @@ export function off(
6969
const vm = instance.proxy
7070
// all
7171
if (!event) {
72-
eventRegistryMap.set(instance, Object.create(null))
72+
eventRegistryMap.set(instance, new Empty())
7373
return vm
7474
}
7575
// array of events

packages/runtime-core/src/component.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ import {
6161
} from './componentEmits'
6262
import {
6363
EMPTY_OBJ,
64+
Empty,
6465
type IfAny,
6566
NOOP,
6667
ShapeFlags,
@@ -847,7 +848,7 @@ function setupStatefulComponent(
847848
}
848849
}
849850
// 0. create render proxy property access cache
850-
instance.accessCache = Object.create(null)
851+
instance.accessCache = new Empty()
851852
// 1. create public instance / render proxy
852853
instance.proxy = new Proxy(instance.ctx, PublicInstanceProxyHandlers)
853854
if (__DEV__) {

packages/runtime-core/src/componentOptions.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
currentInstance,
1010
} from './component'
1111
import {
12+
Empty,
1213
type LooseRequired,
1314
NOOP,
1415
type Prettify,
@@ -503,7 +504,7 @@ enum OptionTypes {
503504
}
504505

505506
function createDuplicateChecker() {
506-
const cache = Object.create(null)
507+
const cache = new Empty()
507508
return (type: OptionTypes, key: string) => {
508509
if (cache[key]) {
509510
warn(`${type} property "${key}" is already defined in ${cache[key]}.`)
@@ -1079,7 +1080,7 @@ function mergeAsArray<T = Function>(to: T[] | T | undefined, from: T | T[]) {
10791080
}
10801081

10811082
function mergeObjectOptions(to: Object | undefined, from: Object | undefined) {
1082-
return to ? extend(Object.create(null), to, from) : from
1083+
return to ? extend(new Empty(), to, from) : from
10831084
}
10841085

10851086
function mergeEmitsOrPropsOptions(
@@ -1099,7 +1100,7 @@ function mergeEmitsOrPropsOptions(
10991100
return [...new Set([...to, ...from])]
11001101
}
11011102
return extend(
1102-
Object.create(null),
1103+
new Empty(),
11031104
normalizePropsOrEmits(to),
11041105
normalizePropsOrEmits(from ?? {}),
11051106
)
@@ -1114,7 +1115,7 @@ function mergeWatchOptions(
11141115
) {
11151116
if (!to) return from
11161117
if (!from) return to
1117-
const merged = extend(Object.create(null), to)
1118+
const merged = extend(new Empty(), to)
11181119
for (const key in from) {
11191120
merged[key] = mergeAsArray(to[key], from[key])
11201121
}

packages/runtime-core/src/componentProps.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
import {
99
EMPTY_ARR,
1010
EMPTY_OBJ,
11+
Empty,
1112
type IfAny,
1213
PatchFlags,
1314
camelize,
@@ -197,7 +198,7 @@ export function initProps(
197198
const props: Data = {}
198199
const attrs: Data = createInternalObject()
199200

200-
instance.propsDefaults = Object.create(null)
201+
instance.propsDefaults = new Empty()
201202

202203
setFullProps(instance, rawProps, props, attrs)
203204

packages/runtime-core/src/componentPublicInstance.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
} from './apiWatch'
1515
import {
1616
EMPTY_OBJ,
17+
Empty,
1718
type IfAny,
1819
NOOP,
1920
type Prettify,
@@ -365,7 +366,7 @@ const getPublicInstance = (
365366
export const publicPropertiesMap: PublicPropertiesMap =
366367
// Move PURE marker to new line to workaround compiler discarding it
367368
// due to type annotation
368-
/*@__PURE__*/ extend(Object.create(null), {
369+
/*@__PURE__*/ extend(new Empty(), {
369370
$: i => i,
370371
$el: i => i.vnode.el,
371372
$data: i => i.data,

packages/runtime-core/src/components/BaseTransition.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { warn } from '../warning'
1616
import { isKeepAlive } from './KeepAlive'
1717
import { toRaw } from '@vue/reactivity'
1818
import { ErrorCodes, callWithAsyncErrorHandling } from '../errorHandling'
19-
import { PatchFlags, ShapeFlags, isArray, isFunction } from '@vue/shared'
19+
import { Empty, PatchFlags, ShapeFlags, isArray, isFunction } from '@vue/shared'
2020
import { onBeforeUnmount, onMounted } from '../apiLifecycle'
2121
import { isTeleport } from './Teleport'
2222
import type { RendererElement } from '../renderer'
@@ -303,7 +303,7 @@ function getLeavingNodesForType(
303303
const { leavingVNodes } = state
304304
let leavingVNodesCache = leavingVNodes.get(vnode.type)!
305305
if (!leavingVNodesCache) {
306-
leavingVNodesCache = Object.create(null)
306+
leavingVNodesCache = new Empty()
307307
leavingVNodes.set(vnode.type, leavingVNodesCache)
308308
}
309309
return leavingVNodesCache

packages/runtime-dom/src/apiCustomElement.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import {
3333
warn,
3434
} from '@vue/runtime-core'
3535
import {
36+
Empty,
3637
camelize,
3738
extend,
3839
hasOwn,
@@ -373,9 +374,7 @@ export class VueElement
373374
if (key in this._props) {
374375
this._props[key] = toNumber(this._props[key])
375376
}
376-
;(numberProps || (numberProps = Object.create(null)))[
377-
camelize(key)
378-
] = true
377+
;(numberProps || (numberProps = new Empty()))[camelize(key)] = true
379378
}
380379
}
381380
}

0 commit comments

Comments
 (0)