Closes #10635
---
.../compileScript/resolveType.spec.ts | 21 +++++++++++++++++++
.../compiler-sfc/src/script/resolveType.ts | 2 ++
2 files changed, 23 insertions(+)
diff --git a/packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts b/packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts
index 0c5c95cd17f..f3be58a301c 100644
--- a/packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts
+++ b/packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts
@@ -561,6 +561,27 @@ describe('resolveType', () => {
expect(deps && [...deps]).toStrictEqual(Object.keys(files))
})
+ // #10635
+ test('relative tsx', () => {
+ const files = {
+ '/foo.tsx': 'export type P = { foo: number }',
+ '/bar/index.tsx': 'export type PP = { bar: string }',
+ }
+ const { props, deps } = resolve(
+ `
+ import { P } from './foo'
+ import { PP } from './bar'
+ defineProps()
+ `,
+ files,
+ )
+ expect(props).toStrictEqual({
+ foo: ['Number'],
+ bar: ['String'],
+ })
+ expect(deps && [...deps]).toStrictEqual(Object.keys(files))
+ })
+
test.runIf(process.platform === 'win32')('relative ts on Windows', () => {
const files = {
'C:\\Test\\FolderA\\foo.ts': 'export type P = { foo: number }',
diff --git a/packages/compiler-sfc/src/script/resolveType.ts b/packages/compiler-sfc/src/script/resolveType.ts
index 968c168ddb9..f6e291791a8 100644
--- a/packages/compiler-sfc/src/script/resolveType.ts
+++ b/packages/compiler-sfc/src/script/resolveType.ts
@@ -956,8 +956,10 @@ function resolveExt(filename: string, fs: FS) {
return (
tryResolve(filename) ||
tryResolve(filename + `.ts`) ||
+ tryResolve(filename + `.tsx`) ||
tryResolve(filename + `.d.ts`) ||
tryResolve(joinPaths(filename, `index.ts`)) ||
+ tryResolve(joinPaths(filename, `index.tsx`)) ||
tryResolve(joinPaths(filename, `index.d.ts`))
)
}
From 4bc9f39f028af7313e5cf24c16915a1985d27bf8 Mon Sep 17 00:00:00 2001
From: Evan You
Date: Fri, 12 Apr 2024 11:49:31 +0800
Subject: [PATCH 39/67] perf(ssr): avoid calling markRaw on component instance
proxy
The previous behavior invokes the definePropery proxy trap on the
instance proxy and has massive overhead. This change improves Vue
ops/sec by 40% in https://github.com/eknkc/ssr-benchmark
---
packages/runtime-core/src/component.ts | 3 +--
packages/runtime-core/src/componentPublicInstance.ts | 5 +++++
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts
index 2ad0a66f188..4cabdad0d44 100644
--- a/packages/runtime-core/src/component.ts
+++ b/packages/runtime-core/src/component.ts
@@ -775,8 +775,7 @@ function setupStatefulComponent(
// 0. create render proxy property access cache
instance.accessCache = Object.create(null)
// 1. create public instance / render proxy
- // also mark it raw so it's never observed
- instance.proxy = markRaw(new Proxy(instance.ctx, PublicInstanceProxyHandlers))
+ instance.proxy = new Proxy(instance.ctx, PublicInstanceProxyHandlers)
if (__DEV__) {
exposePropsOnRenderContext(instance)
}
diff --git a/packages/runtime-core/src/componentPublicInstance.ts b/packages/runtime-core/src/componentPublicInstance.ts
index 5b2b4f2303d..a1b45e4f9cc 100644
--- a/packages/runtime-core/src/componentPublicInstance.ts
+++ b/packages/runtime-core/src/componentPublicInstance.ts
@@ -23,6 +23,7 @@ import {
isString,
} from '@vue/shared'
import {
+ ReactiveFlags,
type ShallowUnwrapRef,
TrackOpTypes,
type UnwrapNestedRefs,
@@ -307,6 +308,10 @@ const hasSetupBinding = (state: Data, key: string) =>
export const PublicInstanceProxyHandlers: ProxyHandler = {
get({ _: instance }: ComponentRenderContext, key: string) {
+ if (key === ReactiveFlags.SKIP) {
+ return true
+ }
+
const { ctx, setupState, data, props, accessCache, type, appContext } =
instance
From 6af733d68eb400a3d2c5ef5f465fff32b72a324e Mon Sep 17 00:00:00 2001
From: Evan You
Date: Fri, 12 Apr 2024 14:41:03 +0800
Subject: [PATCH 40/67] perf: optimize component props/slots internal object
checks
---
packages/runtime-core/src/componentProps.ts | 12 ++++++++----
packages/runtime-core/src/componentSlots.ts | 4 +---
packages/runtime-core/src/vnode.ts | 7 +++----
3 files changed, 12 insertions(+), 11 deletions(-)
diff --git a/packages/runtime-core/src/componentProps.ts b/packages/runtime-core/src/componentProps.ts
index 2d91affe082..c0cef2f0901 100644
--- a/packages/runtime-core/src/componentProps.ts
+++ b/packages/runtime-core/src/componentProps.ts
@@ -12,7 +12,6 @@ import {
PatchFlags,
camelize,
capitalize,
- def,
extend,
hasOwn,
hyphenate,
@@ -34,7 +33,6 @@ import {
setCurrentInstance,
} from './component'
import { isEmitListener } from './componentEmits'
-import { InternalObjectKey } from './vnode'
import type { AppContext } from './apiCreateApp'
import { createPropsDefaultThis } from './compat/props'
import { isCompatEnabled, softAssertCompatEnabled } from './compat/compatConfig'
@@ -187,6 +185,13 @@ type NormalizedProp =
export type NormalizedProps = Record
export type NormalizedPropsOptions = [NormalizedProps, string[]] | []
+/**
+ * Used during vnode props normalization to check if the vnode props is the
+ * attrs object of a component via `Object.getPrototypeOf`. This is more
+ * performant than defining a non-enumerable property.
+ */
+export const attrsProto = {}
+
export function initProps(
instance: ComponentInternalInstance,
rawProps: Data | null,
@@ -194,8 +199,7 @@ export function initProps(
isSSR = false,
) {
const props: Data = {}
- const attrs: Data = {}
- def(attrs, InternalObjectKey, 1)
+ const attrs: Data = Object.create(attrsProto)
instance.propsDefaults = Object.create(null)
diff --git a/packages/runtime-core/src/componentSlots.ts b/packages/runtime-core/src/componentSlots.ts
index 61e1ecc072c..e0f051b3984 100644
--- a/packages/runtime-core/src/componentSlots.ts
+++ b/packages/runtime-core/src/componentSlots.ts
@@ -1,6 +1,5 @@
import { type ComponentInternalInstance, currentInstance } from './component'
import {
- InternalObjectKey,
type VNode,
type VNodeChild,
type VNodeNormalizedChildren,
@@ -174,7 +173,7 @@ export const initSlots = (
// we should avoid the proxy object polluting the slots of the internal instance
instance.slots = toRaw(children as InternalSlots)
// make compiler marker non-enumerable
- def(children as InternalSlots, '_', type)
+ def(instance.slots, '_', type)
} else {
normalizeObjectSlots(
children as RawSlots,
@@ -188,7 +187,6 @@ export const initSlots = (
normalizeVNodeSlots(instance, children)
}
}
- def(instance.slots, InternalObjectKey, 1)
}
export const updateSlots = (
diff --git a/packages/runtime-core/src/vnode.ts b/packages/runtime-core/src/vnode.ts
index daa9413d2ee..28b60be78f2 100644
--- a/packages/runtime-core/src/vnode.ts
+++ b/packages/runtime-core/src/vnode.ts
@@ -55,6 +55,7 @@ import { convertLegacyVModelProps } from './compat/componentVModel'
import { defineLegacyVNodeProperties } from './compat/renderFn'
import { ErrorCodes, callWithAsyncErrorHandling } from './errorHandling'
import type { ComponentPublicInstance } from './componentPublicInstance'
+import { attrsProto } from './componentProps'
export const Fragment = Symbol.for('v-fgt') as any as {
__isFragment: true
@@ -404,8 +405,6 @@ const createVNodeWithArgsTransform = (
)
}
-export const InternalObjectKey = `__vInternal`
-
const normalizeKey = ({ key }: VNodeProps): VNode['key'] =>
key != null ? key : null
@@ -618,7 +617,7 @@ function _createVNode(
export function guardReactiveProps(props: (Data & VNodeProps) | null) {
if (!props) return null
- return isProxy(props) || InternalObjectKey in props
+ return isProxy(props) || Object.getPrototypeOf(props) === attrsProto
? extend({}, props)
: props
}
@@ -792,7 +791,7 @@ export function normalizeChildren(vnode: VNode, children: unknown) {
} else {
type = ShapeFlags.SLOTS_CHILDREN
const slotFlag = (children as RawSlots)._
- if (!slotFlag && !(InternalObjectKey in children!)) {
+ if (!slotFlag) {
// if slots are not normalized, attach context instance
// (compiled / normalized slots already have context)
;(children as RawSlots)._ctx = currentRenderingInstance
From ca84316bfb3410efe21333670a6ad5cd21857396 Mon Sep 17 00:00:00 2001
From: Evan You
Date: Fri, 12 Apr 2024 16:02:52 +0800
Subject: [PATCH 41/67] perf(ssr): optimize setup context creation for ssr in
v8
---
packages/runtime-core/src/component.ts | 62 ++++++++++-----------
packages/runtime-core/src/componentProps.ts | 2 +-
2 files changed, 29 insertions(+), 35 deletions(-)
diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts
index 4cabdad0d44..a551529e667 100644
--- a/packages/runtime-core/src/component.ts
+++ b/packages/runtime-core/src/component.ts
@@ -1004,36 +1004,28 @@ export function finishComponentSetup(
}
}
-function getAttrsProxy(instance: ComponentInternalInstance): Data {
- return (
- instance.attrsProxy ||
- (instance.attrsProxy = new Proxy(
- instance.attrs,
- __DEV__
- ? {
- get(target, key: string) {
- markAttrsAccessed()
- track(instance, TrackOpTypes.GET, '$attrs')
- return target[key]
- },
- set() {
- warn(`setupContext.attrs is readonly.`)
- return false
- },
- deleteProperty() {
- warn(`setupContext.attrs is readonly.`)
- return false
- },
- }
- : {
- get(target, key: string) {
- track(instance, TrackOpTypes.GET, '$attrs')
- return target[key]
- },
- },
- ))
- )
-}
+const attrsProxyHandlers = __DEV__
+ ? {
+ get(target: Data, key: string) {
+ markAttrsAccessed()
+ track(target, TrackOpTypes.GET, '')
+ return target[key]
+ },
+ set() {
+ warn(`setupContext.attrs is readonly.`)
+ return false
+ },
+ deleteProperty() {
+ warn(`setupContext.attrs is readonly.`)
+ return false
+ },
+ }
+ : {
+ get(target: Data, key: string) {
+ track(target, TrackOpTypes.GET, '')
+ return target[key]
+ },
+ }
/**
* Dev-only
@@ -1080,9 +1072,13 @@ export function createSetupContext(
if (__DEV__) {
// We use getters in dev in case libs like test-utils overwrite instance
// properties (overwrites should not be done in prod)
+ let attrsProxy: Data
return Object.freeze({
get attrs() {
- return getAttrsProxy(instance)
+ return (
+ attrsProxy ||
+ (attrsProxy = new Proxy(instance.attrs, attrsProxyHandlers))
+ )
},
get slots() {
return getSlotsProxy(instance)
@@ -1094,9 +1090,7 @@ export function createSetupContext(
})
} else {
return {
- get attrs() {
- return getAttrsProxy(instance)
- },
+ attrs: new Proxy(instance.attrs, attrsProxyHandlers),
slots: instance.slots,
emit: instance.emit,
expose,
diff --git a/packages/runtime-core/src/componentProps.ts b/packages/runtime-core/src/componentProps.ts
index c0cef2f0901..1c87304185c 100644
--- a/packages/runtime-core/src/componentProps.ts
+++ b/packages/runtime-core/src/componentProps.ts
@@ -365,7 +365,7 @@ export function updateProps(
// trigger updates for $attrs in case it's used in component slots
if (hasAttrsChanged) {
- trigger(instance, TriggerOpTypes.SET, '$attrs')
+ trigger(instance.attrs, TriggerOpTypes.SET, '')
}
if (__DEV__) {
From c3c5dc93fbccc196771458f0b43cd5b7ad1863f4 Mon Sep 17 00:00:00 2001
From: Evan You
Date: Sun, 14 Apr 2024 22:46:48 +0800
Subject: [PATCH 42/67] fix(reactivity): fix tracking when hasOwnProperty is
called with non-string value
close #10455
close #10464
---
.../reactivity/__tests__/reactiveArray.spec.ts | 15 +++++++++++++++
packages/reactivity/src/baseHandlers.ts | 6 ++++--
2 files changed, 19 insertions(+), 2 deletions(-)
diff --git a/packages/reactivity/__tests__/reactiveArray.spec.ts b/packages/reactivity/__tests__/reactiveArray.spec.ts
index 1c6fcefd592..d405608f8c4 100644
--- a/packages/reactivity/__tests__/reactiveArray.spec.ts
+++ b/packages/reactivity/__tests__/reactiveArray.spec.ts
@@ -99,6 +99,21 @@ describe('reactivity/reactive/Array', () => {
expect(fn).toHaveBeenCalledTimes(1)
})
+ test("should reactive when mutate array's index", () => {
+ const original = [1, 2, 3]
+ const observed = reactive(original)
+
+ let dummy
+ effect(() => {
+ dummy = observed.hasOwnProperty(0)
+ })
+
+ expect(dummy).toBe(true)
+
+ delete observed[0]
+ expect(dummy).toBe(false)
+ })
+
test('shift on Array should trigger dependency once', () => {
const arr = reactive([1, 2, 3])
const fn = vi.fn()
diff --git a/packages/reactivity/src/baseHandlers.ts b/packages/reactivity/src/baseHandlers.ts
index 7cee7aa9bd5..36707aa9138 100644
--- a/packages/reactivity/src/baseHandlers.ts
+++ b/packages/reactivity/src/baseHandlers.ts
@@ -80,10 +80,12 @@ function createArrayInstrumentations() {
return instrumentations
}
-function hasOwnProperty(this: object, key: string) {
+function hasOwnProperty(this: object, key: unknown) {
+ // #10455 hasOwnProperty may be called with non-string values
+ key = '' + key
const obj = toRaw(this)
track(obj, TrackOpTypes.HAS, key)
- return obj.hasOwnProperty(key)
+ return obj.hasOwnProperty(key as string)
}
class BaseReactiveHandler implements ProxyHandler {
From c4684d3161505d15c585a5dd0f095cdd527d45b5 Mon Sep 17 00:00:00 2001
From: Evan You
Date: Sun, 14 Apr 2024 22:49:16 +0800
Subject: [PATCH 43/67] chore: amend test case name [ci skip]
---
packages/reactivity/__tests__/reactiveArray.spec.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/reactivity/__tests__/reactiveArray.spec.ts b/packages/reactivity/__tests__/reactiveArray.spec.ts
index d405608f8c4..e32b5deeb6d 100644
--- a/packages/reactivity/__tests__/reactiveArray.spec.ts
+++ b/packages/reactivity/__tests__/reactiveArray.spec.ts
@@ -99,7 +99,7 @@ describe('reactivity/reactive/Array', () => {
expect(fn).toHaveBeenCalledTimes(1)
})
- test("should reactive when mutate array's index", () => {
+ test('should track hasOwnProperty call with index', () => {
const original = [1, 2, 3]
const observed = reactive(original)
From 140a7681cc3bba22f55d97fd85a5eafe97a1230f Mon Sep 17 00:00:00 2001
From: edison
Date: Sun, 14 Apr 2024 23:16:01 +0800
Subject: [PATCH 44/67] fix(TransitionGroup): avoid set transition hooks for
comment nodes and text nodes (#9421)
close #4621
close #4622
close #5153
close #5168
close #7898
close #9067
---
.../src/components/TransitionGroup.ts | 35 +++--
.../vue/__tests__/e2e/TransitionGroup.spec.ts | 122 ++++++++++++++++++
2 files changed, 145 insertions(+), 12 deletions(-)
diff --git a/packages/runtime-dom/src/components/TransitionGroup.ts b/packages/runtime-dom/src/components/TransitionGroup.ts
index f98e82b2734..763b7a98b24 100644
--- a/packages/runtime-dom/src/components/TransitionGroup.ts
+++ b/packages/runtime-dom/src/components/TransitionGroup.ts
@@ -112,7 +112,29 @@ const TransitionGroupImpl: ComponentOptions = {
tag = 'span'
}
- prevChildren = children
+ prevChildren = []
+ if (children) {
+ for (let i = 0; i < children.length; i++) {
+ const child = children[i]
+ if (child.el && child.el instanceof Element) {
+ prevChildren.push(child)
+ setTransitionHooks(
+ child,
+ resolveTransitionHooks(
+ child,
+ cssTransitionProps,
+ state,
+ instance,
+ ),
+ )
+ positionMap.set(
+ child,
+ (child.el as Element).getBoundingClientRect(),
+ )
+ }
+ }
+ }
+
children = slots.default ? getTransitionRawChildren(slots.default()) : []
for (let i = 0; i < children.length; i++) {
@@ -127,17 +149,6 @@ const TransitionGroupImpl: ComponentOptions = {
}
}
- if (prevChildren) {
- for (let i = 0; i < prevChildren.length; i++) {
- const child = prevChildren[i]
- setTransitionHooks(
- child,
- resolveTransitionHooks(child, cssTransitionProps, state, instance),
- )
- positionMap.set(child, (child.el as Element).getBoundingClientRect())
- }
- }
-
return createVNode(tag, null, children)
}
},
diff --git a/packages/vue/__tests__/e2e/TransitionGroup.spec.ts b/packages/vue/__tests__/e2e/TransitionGroup.spec.ts
index febc9d3c20a..da3f4a42de9 100644
--- a/packages/vue/__tests__/e2e/TransitionGroup.spec.ts
+++ b/packages/vue/__tests__/e2e/TransitionGroup.spec.ts
@@ -508,4 +508,126 @@ describe('e2e: TransitionGroup', () => {
expect(` children must be keyed`).toHaveBeenWarned()
})
+
+ // #5168, #7898, #9067
+ test(
+ 'avoid set transition hooks for comment node',
+ async () => {
+ await page().evaluate(duration => {
+ const { createApp, ref, h, createCommentVNode } = (window as any).Vue
+
+ const show = ref(false)
+ createApp({
+ template: `
+
+ button
+ `,
+ components: {
+ Child: {
+ setup() {
+ return () =>
+ show.value
+ ? h('div', { class: 'test' }, 'child')
+ : createCommentVNode('v-if', true)
+ },
+ },
+ },
+ setup: () => {
+ const items = ref([])
+ const click = () => {
+ items.value = ['a', 'b', 'c']
+ setTimeout(() => {
+ show.value = true
+ }, duration)
+ }
+ return { click, items }
+ },
+ }).mount('#app')
+ }, duration)
+
+ expect(await html('#container')).toBe(``)
+
+ expect(await htmlWhenTransitionStart()).toBe(
+ `a
` +
+ `b
` +
+ `c
` +
+ ``,
+ )
+
+ await transitionFinish(duration)
+ await nextFrame()
+ expect(await html('#container')).toBe(
+ `a
` +
+ `b
` +
+ `c
` +
+ `child
`,
+ )
+
+ await transitionFinish(duration)
+ expect(await html('#container')).toBe(
+ `a
` +
+ `b
` +
+ `c
` +
+ `child
`,
+ )
+ },
+ E2E_TIMEOUT,
+ )
+
+ // #4621, #4622, #5153
+ test(
+ 'avoid set transition hooks for text node',
+ async () => {
+ await page().evaluate(() => {
+ const { createApp, ref } = (window as any).Vue
+ const app = createApp({
+ template: `
+
+ button
+ `,
+ setup: () => {
+ const show = ref(false)
+ const click = () => {
+ show.value = true
+ }
+ return { show, click }
+ },
+ })
+
+ app.config.compilerOptions.whitespace = 'preserve'
+ app.mount('#app')
+ })
+
+ expect(await html('#container')).toBe(`foo
` + ` `)
+
+ expect(await htmlWhenTransitionStart()).toBe(
+ `foo
` +
+ ` ` +
+ `bar
`,
+ )
+
+ await nextFrame()
+ expect(await html('#container')).toBe(
+ `foo
` +
+ ` ` +
+ `bar
`,
+ )
+
+ await transitionFinish(duration)
+ expect(await html('#container')).toBe(
+ `foo
` + ` ` + `bar
`,
+ )
+ },
+ E2E_TIMEOUT,
+ )
})
From f709238c30e49bd7589c04d371b3038bd56c7757 Mon Sep 17 00:00:00 2001
From: Evan You
Date: Mon, 15 Apr 2024 11:35:05 +0800
Subject: [PATCH 45/67] chore: use correct parse in parser tests for
whitespace: condense
---
packages/compiler-core/__tests__/parse.spec.ts | 8 ++++----
packages/compiler-core/src/options.ts | 1 +
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/packages/compiler-core/__tests__/parse.spec.ts b/packages/compiler-core/__tests__/parse.spec.ts
index d5bdb4bc5fd..882133a5387 100644
--- a/packages/compiler-core/__tests__/parse.spec.ts
+++ b/packages/compiler-core/__tests__/parse.spec.ts
@@ -2166,7 +2166,7 @@ describe('compiler: parse', () => {
})
test('should remove leading newline character immediately following the pre element start tag', () => {
- const ast = baseParse(`\n foo bar `, {
+ const ast = parse(`\n foo bar `, {
isPreTag: tag => tag === 'pre',
})
expect(ast.children).toHaveLength(1)
@@ -2176,7 +2176,7 @@ describe('compiler: parse', () => {
})
test('should NOT remove leading newline character immediately following child-tag of pre element', () => {
- const ast = baseParse(` \n foo bar `, {
+ const ast = parse(` \n foo bar `, {
isPreTag: tag => tag === 'pre',
})
const preElement = ast.children[0] as ElementNode
@@ -2187,7 +2187,7 @@ describe('compiler: parse', () => {
})
test('self-closing pre tag', () => {
- const ast = baseParse(`\n foo bar `, {
+ const ast = parse(`\n foo bar `, {
isPreTag: tag => tag === 'pre',
})
const elementAfterPre = ast.children[1] as ElementNode
@@ -2196,7 +2196,7 @@ describe('compiler: parse', () => {
})
test('should NOT condense whitespaces in RCDATA text mode', () => {
- const ast = baseParse(``, {
+ const ast = parse(``, {
parseMode: 'html',
})
const preElement = ast.children[0] as ElementNode
diff --git a/packages/compiler-core/src/options.ts b/packages/compiler-core/src/options.ts
index 8a989a8c659..5a8cd0079b9 100644
--- a/packages/compiler-core/src/options.ts
+++ b/packages/compiler-core/src/options.ts
@@ -74,6 +74,7 @@ export interface ParserOptions
delimiters?: [string, string]
/**
* Whitespace handling strategy
+ * @default 'condense'
*/
whitespace?: 'preserve' | 'condense'
/**
From 16174da21d6c8ac0aae027dd964fc35e221ded0a Mon Sep 17 00:00:00 2001
From: Evan You
Date: Mon, 15 Apr 2024 11:50:57 +0800
Subject: [PATCH 46/67] fix(compiler-core): fix loc.source for end tags with
whitespace before >
close #10694
close #10695
---
packages/compiler-core/__tests__/parse.spec.ts | 10 ++++++++++
packages/compiler-core/src/parser.ts | 8 +++++++-
2 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/packages/compiler-core/__tests__/parse.spec.ts b/packages/compiler-core/__tests__/parse.spec.ts
index 882133a5387..429a7968616 100644
--- a/packages/compiler-core/__tests__/parse.spec.ts
+++ b/packages/compiler-core/__tests__/parse.spec.ts
@@ -2070,6 +2070,16 @@ describe('compiler: parse', () => {
baseParse(``, { parseMode: 'sfc', onError() {} })
expect(() => baseParse(`{ foo }`)).not.toThrow()
})
+
+ test('correct loc when the closing > is foarmatted', () => {
+ const [span] = baseParse(` `).children
+
+ expect(span.loc.source).toBe(' ')
+ expect(span.loc.start.offset).toBe(0)
+ expect(span.loc.end.offset).toBe(27)
+ })
})
describe('decodeEntities option', () => {
diff --git a/packages/compiler-core/src/parser.ts b/packages/compiler-core/src/parser.ts
index 202fba81b18..da8861b9237 100644
--- a/packages/compiler-core/src/parser.ts
+++ b/packages/compiler-core/src/parser.ts
@@ -613,7 +613,7 @@ function onCloseTag(el: ElementNode, end: number, isImplied = false) {
// implied close, end should be backtracked to close
setLocEnd(el.loc, backTrack(end, CharCodes.Lt))
} else {
- setLocEnd(el.loc, end + 1)
+ setLocEnd(el.loc, lookAhead(end, CharCodes.Gt) + 1)
}
if (tokenizer.inSFCRoot) {
@@ -736,6 +736,12 @@ function onCloseTag(el: ElementNode, end: number, isImplied = false) {
}
}
+function lookAhead(index: number, c: number) {
+ let i = index
+ while (currentInput.charCodeAt(i) !== c && i < currentInput.length - 1) i++
+ return i
+}
+
function backTrack(index: number, c: number) {
let i = index
while (currentInput.charCodeAt(i) !== c && i >= 0) i--
From 7ae9dbf57dd0b5dedb560a318ba6c7340a42093d Mon Sep 17 00:00:00 2001
From: Evan You
Date: Mon, 15 Apr 2024 13:36:43 +0800
Subject: [PATCH 47/67] chore(deps): bump TS to 5.4
---
package.json | 4 +-
packages/compiler-core/src/codegen.ts | 47 ++++++++-
packages/compiler-core/src/index.ts | 8 +-
packages/compiler-sfc/src/parse.ts | 7 +-
packages/dts-built-test/package.json | 2 +-
packages/dts-built-test/tsconfig.json | 14 +++
packages/global.d.ts | 12 ---
packages/reactivity/src/reactive.ts | 4 +-
.../sfc-playground/src/vue-dev-proxy-prod.ts | 1 -
pnpm-lock.yaml | 97 ++++++++++---------
tsconfig.build.json | 3 +-
11 files changed, 127 insertions(+), 72 deletions(-)
create mode 100644 packages/dts-built-test/tsconfig.json
diff --git a/package.json b/package.json
index b0faeff0ab7..071c51311a3 100644
--- a/package.json
+++ b/package.json
@@ -20,7 +20,7 @@
"test-unit": "vitest -c vitest.unit.config.ts",
"test-e2e": "node scripts/build.js vue -f global -d && vitest -c vitest.e2e.config.ts",
"test-dts": "run-s build-dts test-dts-only",
- "test-dts-only": "tsc -p ./packages/dts-test/tsconfig.test.json",
+ "test-dts-only": "tsc -p packages/dts-built-test/tsconfig.json && tsc -p ./packages/dts-test/tsconfig.test.json",
"test-coverage": "vitest -c vitest.unit.config.ts --coverage",
"test-bench": "vitest bench",
"release": "node scripts/release.js",
@@ -111,7 +111,7 @@
"todomvc-app-css": "^2.4.3",
"tslib": "^2.6.2",
"tsx": "^4.7.2",
- "typescript": "^5.2.2",
+ "typescript": "~5.4.5",
"vite": "^5.2.7",
"vitest": "^1.4.0"
}
diff --git a/packages/compiler-core/src/codegen.ts b/packages/compiler-core/src/codegen.ts
index 4447e67aafa..987293d5124 100644
--- a/packages/compiler-core/src/codegen.ts
+++ b/packages/compiler-core/src/codegen.ts
@@ -28,7 +28,7 @@ import {
getVNodeHelper,
locStub,
} from './ast'
-import { type RawSourceMap, SourceMapGenerator } from 'source-map-js'
+import { SourceMapGenerator } from 'source-map-js'
import {
advancePositionWithMutation,
assert,
@@ -56,6 +56,45 @@ import {
} from './runtimeHelpers'
import type { ImportItem } from './transform'
+/**
+ * The `SourceMapGenerator` type from `source-map-js` is a bit incomplete as it
+ * misses `toJSON()`. We also need to add types for internal properties which we
+ * need to access for better performance.
+ *
+ * Since TS 5.3, dts generation starts to strangely include broken triple slash
+ * references for source-map-js, so we are inlining all source map related types
+ * here to to workaround that.
+ */
+export interface CodegenSourceMapGenerator {
+ setSourceContent(sourceFile: string, sourceContent: string): void
+ // SourceMapGenerator has this method but the types do not include it
+ toJSON(): RawSourceMap
+ _sources: Set
+ _names: Set
+ _mappings: {
+ add(mapping: MappingItem): void
+ }
+}
+
+export interface RawSourceMap {
+ file?: string
+ sourceRoot?: string
+ version: string
+ sources: string[]
+ names: string[]
+ sourcesContent?: string[]
+ mappings: string
+}
+
+interface MappingItem {
+ source: string
+ generatedLine: number
+ generatedColumn: number
+ originalLine: number
+ originalColumn: number
+ name: string | null
+}
+
const PURE_ANNOTATION = `/*#__PURE__*/`
const aliasHelper = (s: symbol) => `${helperNameMap[s]}: _${helperNameMap[s]}`
@@ -85,7 +124,7 @@ export interface CodegenContext
offset: number
indentLevel: number
pure: boolean
- map?: SourceMapGenerator
+ map?: CodegenSourceMapGenerator
helper(key: symbol): string
push(code: string, newlineIndex?: number, node?: CodegenNode): void
indent(): void
@@ -218,14 +257,14 @@ function createCodegenContext(
generatedLine: context.line,
generatedColumn: context.column - 1,
source: filename,
- // @ts-expect-error it is possible to be null
name,
})
}
if (!__BROWSER__ && sourceMap) {
// lazy require source-map implementation, only in non-browser builds
- context.map = new SourceMapGenerator()
+ context.map =
+ new SourceMapGenerator() as unknown as CodegenSourceMapGenerator
context.map.setSourceContent(filename, context.source)
context.map._sources.add(filename)
}
diff --git a/packages/compiler-core/src/index.ts b/packages/compiler-core/src/index.ts
index ef4e54cf2d7..47628b66979 100644
--- a/packages/compiler-core/src/index.ts
+++ b/packages/compiler-core/src/index.ts
@@ -21,7 +21,13 @@ export {
type StructuralDirectiveTransform,
type DirectiveTransform,
} from './transform'
-export { generate, type CodegenContext, type CodegenResult } from './codegen'
+export {
+ generate,
+ type CodegenContext,
+ type CodegenResult,
+ type CodegenSourceMapGenerator,
+ type RawSourceMap,
+} from './codegen'
export {
ErrorCodes,
errorMessages,
diff --git a/packages/compiler-sfc/src/parse.ts b/packages/compiler-sfc/src/parse.ts
index 00c97867cd0..f0ec926d1b9 100644
--- a/packages/compiler-sfc/src/parse.ts
+++ b/packages/compiler-sfc/src/parse.ts
@@ -1,15 +1,17 @@
import {
type BindingMetadata,
+ type CodegenSourceMapGenerator,
type CompilerError,
type ElementNode,
NodeTypes,
type ParserOptions,
+ type RawSourceMap,
type RootNode,
type SourceLocation,
createRoot,
} from '@vue/compiler-core'
import * as CompilerDOM from '@vue/compiler-dom'
-import { type RawSourceMap, SourceMapGenerator } from 'source-map-js'
+import { SourceMapGenerator } from 'source-map-js'
import type { TemplateCompiler } from './compileTemplate'
import { parseCssVars } from './style/cssVars'
import { createCache } from './cache'
@@ -375,7 +377,7 @@ function generateSourceMap(
const map = new SourceMapGenerator({
file: filename.replace(/\\/g, '/'),
sourceRoot: sourceRoot.replace(/\\/g, '/'),
- })
+ }) as unknown as CodegenSourceMapGenerator
map.setSourceContent(filename, source)
map._sources.add(filename)
generated.split(splitRE).forEach((line, index) => {
@@ -390,7 +392,6 @@ function generateSourceMap(
generatedLine,
generatedColumn: i,
source: filename,
- // @ts-expect-error
name: null,
})
}
diff --git a/packages/dts-built-test/package.json b/packages/dts-built-test/package.json
index dca0f80fae8..dd81cab68d6 100644
--- a/packages/dts-built-test/package.json
+++ b/packages/dts-built-test/package.json
@@ -2,7 +2,7 @@
"name": "@vue/dts-built-test",
"private": true,
"version": "0.0.0",
- "types": "dist/dts-built-test.d.ts",
+ "types": "dist/index.d.ts",
"dependencies": {
"@vue/shared": "workspace:*",
"@vue/reactivity": "workspace:*",
diff --git a/packages/dts-built-test/tsconfig.json b/packages/dts-built-test/tsconfig.json
new file mode 100644
index 00000000000..99d9024dcbe
--- /dev/null
+++ b/packages/dts-built-test/tsconfig.json
@@ -0,0 +1,14 @@
+{
+ "compilerOptions": {
+ "baseUrl": ".",
+ "outDir": "dist",
+ "jsx": "preserve",
+ "module": "esnext",
+ "strict": true,
+ "moduleResolution": "Bundler",
+ "lib": ["esnext", "dom"],
+ "declaration": true,
+ "emitDeclarationOnly": true
+ },
+ "include": ["./src"]
+}
diff --git a/packages/global.d.ts b/packages/global.d.ts
index 704f6d0220d..38320b81e04 100644
--- a/packages/global.d.ts
+++ b/packages/global.d.ts
@@ -45,18 +45,6 @@ declare module 'estree-walker' {
)
}
-declare module 'source-map-js' {
- export interface SourceMapGenerator {
- // SourceMapGenerator has this method but the types do not include it
- toJSON(): RawSourceMap
- _sources: Set
- _names: Set
- _mappings: {
- add(mapping: MappingItem): void
- }
- }
-}
-
declare interface String {
/**
* @deprecated Please use String.prototype.slice instead of String.prototype.substring in the repository.
diff --git a/packages/reactivity/src/reactive.ts b/packages/reactivity/src/reactive.ts
index 1e0f9365daa..7e80737fbcc 100644
--- a/packages/reactivity/src/reactive.ts
+++ b/packages/reactivity/src/reactive.ts
@@ -409,5 +409,5 @@ export const toReactive = (value: T): T =>
*
* @param value - The value for which a readonly proxy shall be created.
*/
-export const toReadonly = (value: T): T =>
- isObject(value) ? readonly(value) : value
+export const toReadonly = (value: T): DeepReadonly =>
+ isObject(value) ? readonly(value) : (value as DeepReadonly)
diff --git a/packages/sfc-playground/src/vue-dev-proxy-prod.ts b/packages/sfc-playground/src/vue-dev-proxy-prod.ts
index c20c51579a4..3b2faf19533 100644
--- a/packages/sfc-playground/src/vue-dev-proxy-prod.ts
+++ b/packages/sfc-playground/src/vue-dev-proxy-prod.ts
@@ -1,3 +1,2 @@
// serve vue to the iframe sandbox during dev.
-// @ts-expect-error
export * from 'vue/dist/vue.runtime.esm-browser.prod.js'
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 5dfee373f8f..3a5bf1f2b10 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -49,10 +49,10 @@ importers:
version: 7.5.8
'@typescript-eslint/eslint-plugin':
specifier: ^7.4.0
- version: 7.4.0(@typescript-eslint/parser@7.4.0)(eslint@8.57.0)(typescript@5.2.2)
+ version: 7.4.0(@typescript-eslint/parser@7.4.0)(eslint@8.57.0)(typescript@5.4.5)
'@typescript-eslint/parser':
specifier: ^7.4.0
- version: 7.4.0(eslint@8.57.0)(typescript@5.2.2)
+ version: 7.4.0(eslint@8.57.0)(typescript@5.4.5)
'@vitest/coverage-istanbul':
specifier: ^1.4.0
version: 1.4.0(vitest@1.4.0)
@@ -82,7 +82,7 @@ importers:
version: /eslint-plugin-i@2.29.1(@typescript-eslint/parser@7.4.0)(eslint@8.57.0)
eslint-plugin-jest:
specifier: ^27.9.0
- version: 27.9.0(@typescript-eslint/eslint-plugin@7.4.0)(eslint@8.57.0)(typescript@5.2.2)
+ version: 27.9.0(@typescript-eslint/eslint-plugin@7.4.0)(eslint@8.57.0)(typescript@5.4.5)
estree-walker:
specifier: ^2.0.2
version: 2.0.2
@@ -127,7 +127,7 @@ importers:
version: 3.0.2
puppeteer:
specifier: ~22.6.3
- version: 22.6.3(typescript@5.2.2)
+ version: 22.6.3(typescript@5.4.5)
rimraf:
specifier: ^5.0.5
version: 5.0.5
@@ -136,7 +136,7 @@ importers:
version: 4.13.2
rollup-plugin-dts:
specifier: ^6.1.0
- version: 6.1.0(rollup@4.13.2)(typescript@5.2.2)
+ version: 6.1.0(rollup@4.13.2)(typescript@5.4.5)
rollup-plugin-esbuild:
specifier: ^6.1.1
version: 6.1.1(esbuild@0.20.2)(rollup@4.13.2)
@@ -165,8 +165,8 @@ importers:
specifier: ^4.7.2
version: 4.7.2
typescript:
- specifier: ^5.2.2
- version: 5.2.2
+ specifier: ~5.4.5
+ version: 5.4.5
vite:
specifier: ^5.2.7
version: 5.2.7(@types/node@20.12.5)(terser@5.30.1)
@@ -1524,7 +1524,7 @@ packages:
dev: true
optional: true
- /@typescript-eslint/eslint-plugin@7.4.0(@typescript-eslint/parser@7.4.0)(eslint@8.57.0)(typescript@5.2.2):
+ /@typescript-eslint/eslint-plugin@7.4.0(@typescript-eslint/parser@7.4.0)(eslint@8.57.0)(typescript@5.4.5):
resolution: {integrity: sha512-yHMQ/oFaM7HZdVrVm/M2WHaNPgyuJH4WelkSVEWSSsir34kxW2kDJCxlXRhhGWEsMN0WAW/vLpKfKVcm8k+MPw==}
engines: {node: ^18.18.0 || >=20.0.0}
peerDependencies:
@@ -1536,10 +1536,10 @@ packages:
optional: true
dependencies:
'@eslint-community/regexpp': 4.9.1
- '@typescript-eslint/parser': 7.4.0(eslint@8.57.0)(typescript@5.2.2)
+ '@typescript-eslint/parser': 7.4.0(eslint@8.57.0)(typescript@5.4.5)
'@typescript-eslint/scope-manager': 7.4.0
- '@typescript-eslint/type-utils': 7.4.0(eslint@8.57.0)(typescript@5.2.2)
- '@typescript-eslint/utils': 7.4.0(eslint@8.57.0)(typescript@5.2.2)
+ '@typescript-eslint/type-utils': 7.4.0(eslint@8.57.0)(typescript@5.4.5)
+ '@typescript-eslint/utils': 7.4.0(eslint@8.57.0)(typescript@5.4.5)
'@typescript-eslint/visitor-keys': 7.4.0
debug: 4.3.4
eslint: 8.57.0
@@ -1547,13 +1547,13 @@ packages:
ignore: 5.2.4
natural-compare: 1.4.0
semver: 7.6.0
- ts-api-utils: 1.0.3(typescript@5.2.2)
- typescript: 5.2.2
+ ts-api-utils: 1.0.3(typescript@5.4.5)
+ typescript: 5.4.5
transitivePeerDependencies:
- supports-color
dev: true
- /@typescript-eslint/parser@7.4.0(eslint@8.57.0)(typescript@5.2.2):
+ /@typescript-eslint/parser@7.4.0(eslint@8.57.0)(typescript@5.4.5):
resolution: {integrity: sha512-ZvKHxHLusweEUVwrGRXXUVzFgnWhigo4JurEj0dGF1tbcGh6buL+ejDdjxOQxv6ytcY1uhun1p2sm8iWStlgLQ==}
engines: {node: ^18.18.0 || >=20.0.0}
peerDependencies:
@@ -1565,11 +1565,11 @@ packages:
dependencies:
'@typescript-eslint/scope-manager': 7.4.0
'@typescript-eslint/types': 7.4.0
- '@typescript-eslint/typescript-estree': 7.4.0(typescript@5.2.2)
+ '@typescript-eslint/typescript-estree': 7.4.0(typescript@5.4.5)
'@typescript-eslint/visitor-keys': 7.4.0
debug: 4.3.4
eslint: 8.57.0
- typescript: 5.2.2
+ typescript: 5.4.5
transitivePeerDependencies:
- supports-color
dev: true
@@ -1590,7 +1590,7 @@ packages:
'@typescript-eslint/visitor-keys': 7.4.0
dev: true
- /@typescript-eslint/type-utils@7.4.0(eslint@8.57.0)(typescript@5.2.2):
+ /@typescript-eslint/type-utils@7.4.0(eslint@8.57.0)(typescript@5.4.5):
resolution: {integrity: sha512-247ETeHgr9WTRMqHbbQdzwzhuyaJ8dPTuyuUEMANqzMRB1rj/9qFIuIXK7l0FX9i9FXbHeBQl/4uz6mYuCE7Aw==}
engines: {node: ^18.18.0 || >=20.0.0}
peerDependencies:
@@ -1600,12 +1600,12 @@ packages:
typescript:
optional: true
dependencies:
- '@typescript-eslint/typescript-estree': 7.4.0(typescript@5.2.2)
- '@typescript-eslint/utils': 7.4.0(eslint@8.57.0)(typescript@5.2.2)
+ '@typescript-eslint/typescript-estree': 7.4.0(typescript@5.4.5)
+ '@typescript-eslint/utils': 7.4.0(eslint@8.57.0)(typescript@5.4.5)
debug: 4.3.4
eslint: 8.57.0
- ts-api-utils: 1.0.3(typescript@5.2.2)
- typescript: 5.2.2
+ ts-api-utils: 1.0.3(typescript@5.4.5)
+ typescript: 5.4.5
transitivePeerDependencies:
- supports-color
dev: true
@@ -1620,7 +1620,7 @@ packages:
engines: {node: ^18.18.0 || >=20.0.0}
dev: true
- /@typescript-eslint/typescript-estree@5.62.0(typescript@5.2.2):
+ /@typescript-eslint/typescript-estree@5.62.0(typescript@5.4.5):
resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
@@ -1635,13 +1635,13 @@ packages:
globby: 11.1.0
is-glob: 4.0.3
semver: 7.6.0
- tsutils: 3.21.0(typescript@5.2.2)
- typescript: 5.2.2
+ tsutils: 3.21.0(typescript@5.4.5)
+ typescript: 5.4.5
transitivePeerDependencies:
- supports-color
dev: true
- /@typescript-eslint/typescript-estree@7.4.0(typescript@5.2.2):
+ /@typescript-eslint/typescript-estree@7.4.0(typescript@5.4.5):
resolution: {integrity: sha512-A99j5AYoME/UBQ1ucEbbMEmGkN7SE0BvZFreSnTd1luq7yulcHdyGamZKizU7canpGDWGJ+Q6ZA9SyQobipePg==}
engines: {node: ^18.18.0 || >=20.0.0}
peerDependencies:
@@ -1657,13 +1657,13 @@ packages:
is-glob: 4.0.3
minimatch: 9.0.3
semver: 7.6.0
- ts-api-utils: 1.0.3(typescript@5.2.2)
- typescript: 5.2.2
+ ts-api-utils: 1.0.3(typescript@5.4.5)
+ typescript: 5.4.5
transitivePeerDependencies:
- supports-color
dev: true
- /@typescript-eslint/utils@5.62.0(eslint@8.57.0)(typescript@5.2.2):
+ /@typescript-eslint/utils@5.62.0(eslint@8.57.0)(typescript@5.4.5):
resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
@@ -1674,7 +1674,7 @@ packages:
'@types/semver': 7.5.8
'@typescript-eslint/scope-manager': 5.62.0
'@typescript-eslint/types': 5.62.0
- '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.2.2)
+ '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.4.5)
eslint: 8.57.0
eslint-scope: 5.1.1
semver: 7.6.0
@@ -1683,7 +1683,7 @@ packages:
- typescript
dev: true
- /@typescript-eslint/utils@7.4.0(eslint@8.57.0)(typescript@5.2.2):
+ /@typescript-eslint/utils@7.4.0(eslint@8.57.0)(typescript@5.4.5):
resolution: {integrity: sha512-NQt9QLM4Tt8qrlBVY9lkMYzfYtNz8/6qwZg8pI3cMGlPnj6mOpRxxAm7BMJN9K0AiY+1BwJ5lVC650YJqYOuNg==}
engines: {node: ^18.18.0 || >=20.0.0}
peerDependencies:
@@ -1694,7 +1694,7 @@ packages:
'@types/semver': 7.5.8
'@typescript-eslint/scope-manager': 7.4.0
'@typescript-eslint/types': 7.4.0
- '@typescript-eslint/typescript-estree': 7.4.0(typescript@5.2.2)
+ '@typescript-eslint/typescript-estree': 7.4.0(typescript@5.4.5)
eslint: 8.57.0
semver: 7.6.0
transitivePeerDependencies:
@@ -2501,7 +2501,7 @@ packages:
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
dev: false
- /cosmiconfig@9.0.0(typescript@5.2.2):
+ /cosmiconfig@9.0.0(typescript@5.4.5):
resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==}
engines: {node: '>=14'}
peerDependencies:
@@ -2514,7 +2514,7 @@ packages:
import-fresh: 3.3.0
js-yaml: 4.1.0
parse-json: 5.2.0
- typescript: 5.2.2
+ typescript: 5.4.5
dev: true
/cross-spawn@7.0.3:
@@ -2866,7 +2866,7 @@ packages:
eslint-import-resolver-webpack:
optional: true
dependencies:
- '@typescript-eslint/parser': 7.4.0(eslint@8.57.0)(typescript@5.2.2)
+ '@typescript-eslint/parser': 7.4.0(eslint@8.57.0)(typescript@5.4.5)
debug: 3.2.7
eslint: 8.57.0
eslint-import-resolver-node: 0.3.9
@@ -2896,7 +2896,7 @@ packages:
- supports-color
dev: true
- /eslint-plugin-jest@27.9.0(@typescript-eslint/eslint-plugin@7.4.0)(eslint@8.57.0)(typescript@5.2.2):
+ /eslint-plugin-jest@27.9.0(@typescript-eslint/eslint-plugin@7.4.0)(eslint@8.57.0)(typescript@5.4.5):
resolution: {integrity: sha512-QIT7FH7fNmd9n4se7FFKHbsLKGQiw885Ds6Y/sxKgCZ6natwCsXdgPOADnYVxN2QrRweF0FZWbJ6S7Rsn7llug==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
peerDependencies:
@@ -2909,8 +2909,8 @@ packages:
jest:
optional: true
dependencies:
- '@typescript-eslint/eslint-plugin': 7.4.0(@typescript-eslint/parser@7.4.0)(eslint@8.57.0)(typescript@5.2.2)
- '@typescript-eslint/utils': 5.62.0(eslint@8.57.0)(typescript@5.2.2)
+ '@typescript-eslint/eslint-plugin': 7.4.0(@typescript-eslint/parser@7.4.0)(eslint@8.57.0)(typescript@5.4.5)
+ '@typescript-eslint/utils': 5.62.0(eslint@8.57.0)(typescript@5.4.5)
eslint: 8.57.0
transitivePeerDependencies:
- supports-color
@@ -4788,14 +4788,14 @@ packages:
- utf-8-validate
dev: true
- /puppeteer@22.6.3(typescript@5.2.2):
+ /puppeteer@22.6.3(typescript@5.4.5):
resolution: {integrity: sha512-KZOnthMbvr4+7cPKFeeOCJPe8DzOKGC0GbMXmZKOP/YusXQ6sqxA0vt6frstZq3rUJ277qXHlZNFf01VVwdHKw==}
engines: {node: '>=18'}
hasBin: true
requiresBuild: true
dependencies:
'@puppeteer/browsers': 2.2.1
- cosmiconfig: 9.0.0(typescript@5.2.2)
+ cosmiconfig: 9.0.0(typescript@5.4.5)
devtools-protocol: 0.0.1262051
puppeteer-core: 22.6.3
transitivePeerDependencies:
@@ -4967,7 +4967,7 @@ packages:
glob: 10.3.10
dev: true
- /rollup-plugin-dts@6.1.0(rollup@4.13.2)(typescript@5.2.2):
+ /rollup-plugin-dts@6.1.0(rollup@4.13.2)(typescript@5.4.5):
resolution: {integrity: sha512-ijSCPICkRMDKDLBK9torss07+8dl9UpY9z1N/zTeA1cIqdzMlpkV3MOOC7zukyvQfDyxa1s3Dl2+DeiP/G6DOw==}
engines: {node: '>=16'}
peerDependencies:
@@ -4976,7 +4976,7 @@ packages:
dependencies:
magic-string: 0.30.8
rollup: 4.13.2
- typescript: 5.2.2
+ typescript: 5.4.5
optionalDependencies:
'@babel/code-frame': 7.23.5
dev: true
@@ -5503,13 +5503,13 @@ packages:
punycode: 2.3.1
dev: true
- /ts-api-utils@1.0.3(typescript@5.2.2):
+ /ts-api-utils@1.0.3(typescript@5.4.5):
resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==}
engines: {node: '>=16.13.0'}
peerDependencies:
typescript: '>=4.2.0'
dependencies:
- typescript: 5.2.2
+ typescript: 5.4.5
dev: true
/tslib@1.14.1:
@@ -5520,14 +5520,14 @@ packages:
resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
dev: true
- /tsutils@3.21.0(typescript@5.2.2):
+ /tsutils@3.21.0(typescript@5.4.5):
resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
engines: {node: '>= 6'}
peerDependencies:
typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta'
dependencies:
tslib: 1.14.1
- typescript: 5.2.2
+ typescript: 5.4.5
dev: true
/tsx@4.7.2:
@@ -5577,6 +5577,13 @@ packages:
resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==}
engines: {node: '>=14.17'}
hasBin: true
+ dev: false
+
+ /typescript@5.4.5:
+ resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==}
+ engines: {node: '>=14.17'}
+ hasBin: true
+ dev: true
/ufo@1.3.1:
resolution: {integrity: sha512-uY/99gMLIOlJPwATcMVYfqDSxUR9//AUcgZMzwfSTJPDKzA1S8mX4VLqa+fiAtveraQUBCz4FFcwVZBGbwBXIw==}
diff --git a/tsconfig.build.json b/tsconfig.build.json
index 954103c0f2f..ea2aecc4500 100644
--- a/tsconfig.build.json
+++ b/tsconfig.build.json
@@ -10,6 +10,7 @@
"packages/runtime-test",
"packages/template-explorer",
"packages/sfc-playground",
- "packages/dts-test"
+ "packages/dts-test",
+ "packages/dts-built-test"
]
}
From 2ae908d00c7744e194dae5fd279b5db8603a988b Mon Sep 17 00:00:00 2001
From: Evan You
Date: Mon, 15 Apr 2024 15:52:48 +0800
Subject: [PATCH 48/67] chore(types): perform strict es2016 lib check when
building dts
---
package.json | 2 +-
packages/compiler-sfc/src/compileStyle.ts | 2 +-
packages/compiler-sfc/src/compileTemplate.ts | 7 ++-----
.../compiler-sfc/src/style/preprocessors.ts | 2 +-
packages/runtime-core/src/compat/global.ts | 5 ++---
packages/shared/src/general.ts | 3 +++
packages/shared/src/toDisplayString.ts | 4 +++-
tsconfig.build-browser.json | 20 +++++++++++++++++++
tsconfig.build-node.json | 15 ++++++++++++++
tsconfig.build.json | 16 ---------------
10 files changed, 48 insertions(+), 28 deletions(-)
create mode 100644 tsconfig.build-browser.json
create mode 100644 tsconfig.build-node.json
delete mode 100644 tsconfig.build.json
diff --git a/package.json b/package.json
index 071c51311a3..2c8ba0b817c 100644
--- a/package.json
+++ b/package.json
@@ -6,7 +6,7 @@
"scripts": {
"dev": "node scripts/dev.js",
"build": "node scripts/build.js",
- "build-dts": "tsc -p tsconfig.build.json && rollup -c rollup.dts.config.js",
+ "build-dts": "tsc -p tsconfig.build-browser.json && tsc -p tsconfig.build-node.json && rollup -c rollup.dts.config.js",
"clean": "rimraf packages/*/dist temp .eslintcache",
"size": "run-s \"size-*\" && tsx scripts/usage-size.ts",
"size-global": "node scripts/build.js vue runtime-dom -f global -p --size",
diff --git a/packages/compiler-sfc/src/compileStyle.ts b/packages/compiler-sfc/src/compileStyle.ts
index 4390014e89e..f27a6338e8e 100644
--- a/packages/compiler-sfc/src/compileStyle.ts
+++ b/packages/compiler-sfc/src/compileStyle.ts
@@ -13,7 +13,7 @@ import {
type StylePreprocessorResults,
processors,
} from './style/preprocessors'
-import type { RawSourceMap } from 'source-map-js'
+import type { RawSourceMap } from '@vue/compiler-core'
import { cssVarsPlugin } from './style/cssVars'
import postcssModules from 'postcss-modules'
diff --git a/packages/compiler-sfc/src/compileTemplate.ts b/packages/compiler-sfc/src/compileTemplate.ts
index 2d5ffdad7d8..5ba8a5e4812 100644
--- a/packages/compiler-sfc/src/compileTemplate.ts
+++ b/packages/compiler-sfc/src/compileTemplate.ts
@@ -6,14 +6,11 @@ import {
type NodeTransform,
NodeTypes,
type ParserOptions,
+ type RawSourceMap,
type RootNode,
createRoot,
} from '@vue/compiler-core'
-import {
- type RawSourceMap,
- SourceMapConsumer,
- SourceMapGenerator,
-} from 'source-map-js'
+import { SourceMapConsumer, SourceMapGenerator } from 'source-map-js'
import {
type AssetURLOptions,
type AssetURLTagConfig,
diff --git a/packages/compiler-sfc/src/style/preprocessors.ts b/packages/compiler-sfc/src/style/preprocessors.ts
index 7915d1d1406..6a974368ecc 100644
--- a/packages/compiler-sfc/src/style/preprocessors.ts
+++ b/packages/compiler-sfc/src/style/preprocessors.ts
@@ -1,5 +1,5 @@
import merge from 'merge-source-map'
-import type { RawSourceMap } from 'source-map-js'
+import type { RawSourceMap } from '@vue/compiler-core'
import type { SFCStyleCompileOptions } from '../compileStyle'
import { isFunction } from '@vue/shared'
diff --git a/packages/runtime-core/src/compat/global.ts b/packages/runtime-core/src/compat/global.ts
index 5bf234fcf45..1c633ed52a3 100644
--- a/packages/runtime-core/src/compat/global.ts
+++ b/packages/runtime-core/src/compat/global.ts
@@ -427,15 +427,14 @@ function applySingletonPrototype(app: App, Ctor: Function) {
app.config.globalProperties = Object.create(Ctor.prototype)
}
let hasPrototypeAugmentations = false
- const descriptors = Object.getOwnPropertyDescriptors(Ctor.prototype)
- for (const key in descriptors) {
+ for (const key of Object.getOwnPropertyNames(Ctor.prototype)) {
if (key !== 'constructor') {
hasPrototypeAugmentations = true
if (enabled) {
Object.defineProperty(
app.config.globalProperties,
key,
- descriptors[key],
+ Object.getOwnPropertyDescriptor(Ctor.prototype, key)!,
)
}
}
diff --git a/packages/shared/src/general.ts b/packages/shared/src/general.ts
index e04b961227a..47ab0229255 100644
--- a/packages/shared/src/general.ts
+++ b/packages/shared/src/general.ts
@@ -165,6 +165,9 @@ export const toNumber = (val: any): any => {
return isNaN(n) ? val : n
}
+// for typeof global checks without @types/node
+declare var global: {}
+
let _globalThis: any
export const getGlobalThis = (): any => {
return (
diff --git a/packages/shared/src/toDisplayString.ts b/packages/shared/src/toDisplayString.ts
index aff107cd97f..b63cb4112a5 100644
--- a/packages/shared/src/toDisplayString.ts
+++ b/packages/shared/src/toDisplayString.ts
@@ -54,4 +54,6 @@ const replacer = (_key: string, val: any): any => {
}
const stringifySymbol = (v: unknown, i: number | string = ''): any =>
- isSymbol(v) ? `Symbol(${v.description ?? i})` : v
+ // Symbol.description in es2019+ so we need to cast here to pass
+ // the lib: es2016 check
+ isSymbol(v) ? `Symbol(${(v as any).description ?? i})` : v
diff --git a/tsconfig.build-browser.json b/tsconfig.build-browser.json
new file mode 100644
index 00000000000..707c99e58a9
--- /dev/null
+++ b/tsconfig.build-browser.json
@@ -0,0 +1,20 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "types": [],
+ "declaration": true,
+ "emitDeclarationOnly": true,
+ "stripInternal": true
+ },
+ "include": [
+ "packages/global.d.ts",
+ "packages/vue/src",
+ "packages/vue-compat/src",
+ "packages/compiler-core/src",
+ "packages/compiler-dom/src",
+ "packages/runtime-core/src",
+ "packages/runtime-dom/src",
+ "packages/reactivity/src",
+ "packages/shared/src"
+ ]
+}
diff --git a/tsconfig.build-node.json b/tsconfig.build-node.json
new file mode 100644
index 00000000000..fac1412fadf
--- /dev/null
+++ b/tsconfig.build-node.json
@@ -0,0 +1,15 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "types": ["node"],
+ "declaration": true,
+ "emitDeclarationOnly": true,
+ "stripInternal": true
+ },
+ "include": [
+ "packages/global.d.ts",
+ "packages/compiler-sfc/src",
+ "packages/compiler-ssr/src",
+ "packages/server-renderer/src"
+ ]
+}
diff --git a/tsconfig.build.json b/tsconfig.build.json
deleted file mode 100644
index ea2aecc4500..00000000000
--- a/tsconfig.build.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "extends": "./tsconfig.json",
- "compilerOptions": {
- "declaration": true,
- "emitDeclarationOnly": true,
- "stripInternal": true
- },
- "exclude": [
- "packages/*/__tests__",
- "packages/runtime-test",
- "packages/template-explorer",
- "packages/sfc-playground",
- "packages/dts-test",
- "packages/dts-built-test"
- ]
-}
From b11dab99d1bd2e84d7059b29fb9a4982f8ff4d5f Mon Sep 17 00:00:00 2001
From: Evan You
Date: Mon, 15 Apr 2024 16:06:33 +0800
Subject: [PATCH 49/67] chore: more descriptive eslint error messages for
restricted syntax
---
.eslintrc.cjs | 24 +++++++++++++++++-------
rollup.config.js | 4 ++--
2 files changed, 19 insertions(+), 9 deletions(-)
diff --git a/.eslintrc.cjs b/.eslintrc.cjs
index 65653f40da2..0a44fb79aa9 100644
--- a/.eslintrc.cjs
+++ b/.eslintrc.cjs
@@ -26,13 +26,23 @@ module.exports = {
'no-restricted-syntax': [
'error',
banConstEnum,
- // since we target ES2015 for baseline support, we need to forbid object
- // rest spread usage in destructure as it compiles into a verbose helper.
- 'ObjectPattern > RestElement',
- // tsc compiles assignment spread into Object.assign() calls, but esbuild
- // still generates verbose helpers, so spread assignment is also prohiboted
- 'ObjectExpression > SpreadElement',
- 'AwaitExpression',
+ {
+ selector: 'ObjectPattern > RestElement',
+ message:
+ 'Our output target is ES2016, and object rest spread results in ' +
+ 'verbose helpers and should be avoided.',
+ },
+ {
+ selector: 'ObjectExpression > SpreadElement',
+ message:
+ 'esbuild transpiles object spread into very verbose inline helpers.\n' +
+ 'Please use the `extend` helper from @vue/shared instead.',
+ },
+ {
+ selector: 'AwaitExpression',
+ message:
+ 'Our output target is ES2016, so async/await syntax should be avoided.',
+ },
],
'sort-imports': ['error', { ignoreDeclarationSort: true }],
diff --git a/rollup.config.js b/rollup.config.js
index 6ab5ca4294a..e8d5984184d 100644
--- a/rollup.config.js
+++ b/rollup.config.js
@@ -331,7 +331,7 @@ function createConfig(format, output, plugins = []) {
tsconfig: path.resolve(__dirname, 'tsconfig.json'),
sourceMap: output.sourcemap,
minify: false,
- target: isServerRenderer || isCJSBuild ? 'es2019' : 'es2015',
+ target: isServerRenderer || isCJSBuild ? 'es2019' : 'es2016',
define: resolveDefine(),
}),
...resolveNodePlugins(),
@@ -367,7 +367,7 @@ function createMinifiedConfig(/** @type {PackageFormat} */ format) {
terser({
module: /^esm/.test(format),
compress: {
- ecma: 2015,
+ ecma: 2016,
pure_getters: true,
},
safari10: true,
From 6b4b8ec5b1b11d313b89c25152c9d4ac16fece20 Mon Sep 17 00:00:00 2001
From: Med Talhaouy <79597452+tal7aouy@users.noreply.github.com>
Date: Mon, 15 Apr 2024 08:21:23 +0000
Subject: [PATCH 50/67] chore: add download badge (#8550) [ci skip]
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index cbc05311ae7..afe5711e8bc 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# vuejs/core [](https://www.npmjs.com/package/vue) [](https://github.com/vuejs/core/actions/workflows/ci.yml)
+# vuejs/core [](https://www.npmjs.com/package/vue) [](https://github.com/vuejs/core/actions/workflows/ci.yml) [](https://www.npmjs.com/package/vue)
## Getting Started
From e5919d4658cfe0bb18c76611dd3c3432c57f94ab Mon Sep 17 00:00:00 2001
From: edison
Date: Mon, 15 Apr 2024 16:32:04 +0800
Subject: [PATCH 51/67] fix(compile-sfc): analyze v-bind shorthand usage in
template (#10518)
close #10515
---
.../__snapshots__/importUsageCheck.spec.ts.snap | 4 ++--
.../__tests__/compileScript/importUsageCheck.spec.ts | 5 +++--
packages/compiler-sfc/src/script/importUsageCheck.ts | 3 +++
3 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/packages/compiler-sfc/__tests__/compileScript/__snapshots__/importUsageCheck.spec.ts.snap b/packages/compiler-sfc/__tests__/compileScript/__snapshots__/importUsageCheck.spec.ts.snap
index 764d120a744..722e3340a74 100644
--- a/packages/compiler-sfc/__tests__/compileScript/__snapshots__/importUsageCheck.spec.ts.snap
+++ b/packages/compiler-sfc/__tests__/compileScript/__snapshots__/importUsageCheck.spec.ts.snap
@@ -66,14 +66,14 @@ return { get vMyDir() { return vMyDir } }
exports[`dynamic arguments 1`] = `
"import { defineComponent as _defineComponent } from 'vue'
-import { FooBar, foo, bar, unused, baz } from './x'
+import { FooBar, foo, bar, unused, baz, msg } from './x'
export default /*#__PURE__*/_defineComponent({
setup(__props, { expose: __expose }) {
__expose();
-return { get FooBar() { return FooBar }, get foo() { return foo }, get bar() { return bar }, get baz() { return baz } }
+return { get FooBar() { return FooBar }, get foo() { return foo }, get bar() { return bar }, get baz() { return baz }, get msg() { return msg } }
}
})"
diff --git a/packages/compiler-sfc/__tests__/compileScript/importUsageCheck.spec.ts b/packages/compiler-sfc/__tests__/compileScript/importUsageCheck.spec.ts
index d9fd1dfe529..b842f7a466d 100644
--- a/packages/compiler-sfc/__tests__/compileScript/importUsageCheck.spec.ts
+++ b/packages/compiler-sfc/__tests__/compileScript/importUsageCheck.spec.ts
@@ -45,7 +45,7 @@ test('directive', () => {
test('dynamic arguments', () => {
const { content } = compile(`
@@ -53,11 +53,12 @@ test('dynamic arguments', () => {
+
`)
expect(content).toMatch(
`return { get FooBar() { return FooBar }, get foo() { return foo }, ` +
- `get bar() { return bar }, get baz() { return baz } }`,
+ `get bar() { return bar }, get baz() { return baz }, get msg() { return msg } }`,
)
assertCode(content)
})
diff --git a/packages/compiler-sfc/src/script/importUsageCheck.ts b/packages/compiler-sfc/src/script/importUsageCheck.ts
index 211efc49089..6b9fbc634cc 100644
--- a/packages/compiler-sfc/src/script/importUsageCheck.ts
+++ b/packages/compiler-sfc/src/script/importUsageCheck.ts
@@ -60,6 +60,9 @@ function resolveTemplateUsedIdentifiers(sfc: SFCDescriptor): Set {
extractIdentifiers(ids, prop.forParseResult!.source)
} else if (prop.exp) {
extractIdentifiers(ids, prop.exp)
+ } else if (prop.name === 'bind' && !prop.exp) {
+ // v-bind shorthand name as identifier
+ ids.add((prop.arg as SimpleExpressionNode).content)
}
}
if (
From 969c5fb30f4c725757c7385abfc74772514eae4b Mon Sep 17 00:00:00 2001
From: Evan You
Date: Mon, 15 Apr 2024 17:18:39 +0800
Subject: [PATCH 52/67] fix(reactivity): fix hasOwnProperty key coercion edge
cases
---
.../reactivity/__tests__/reactive.spec.ts | 28 +++++++++++++++++++
packages/reactivity/src/baseHandlers.ts | 2 +-
2 files changed, 29 insertions(+), 1 deletion(-)
diff --git a/packages/reactivity/__tests__/reactive.spec.ts b/packages/reactivity/__tests__/reactive.spec.ts
index ab953ff891a..cdcd0325805 100644
--- a/packages/reactivity/__tests__/reactive.spec.ts
+++ b/packages/reactivity/__tests__/reactive.spec.ts
@@ -302,4 +302,32 @@ describe('reactivity/reactive', () => {
const observed = reactive(original)
expect(isReactive(observed)).toBe(false)
})
+
+ test('hasOwnProperty edge case: Symbol values', () => {
+ const key = Symbol()
+ const obj = reactive({ [key]: 1 }) as { [key]?: 1 }
+ let dummy
+ effect(() => {
+ dummy = obj.hasOwnProperty(key)
+ })
+ expect(dummy).toBe(true)
+
+ delete obj[key]
+ expect(dummy).toBe(false)
+ })
+
+ test('hasOwnProperty edge case: non-string values', () => {
+ const key = {}
+ const obj = reactive({ '[object Object]': 1 }) as { '[object Object]'?: 1 }
+ let dummy
+ effect(() => {
+ // @ts-expect-error
+ dummy = obj.hasOwnProperty(key)
+ })
+ expect(dummy).toBe(true)
+
+ // @ts-expect-error
+ delete obj[key]
+ expect(dummy).toBe(false)
+ })
})
diff --git a/packages/reactivity/src/baseHandlers.ts b/packages/reactivity/src/baseHandlers.ts
index 36707aa9138..943f329571c 100644
--- a/packages/reactivity/src/baseHandlers.ts
+++ b/packages/reactivity/src/baseHandlers.ts
@@ -82,7 +82,7 @@ function createArrayInstrumentations() {
function hasOwnProperty(this: object, key: unknown) {
// #10455 hasOwnProperty may be called with non-string values
- key = '' + key
+ if (!isSymbol(key)) key = String(key)
const obj = toRaw(this)
track(obj, TrackOpTypes.HAS, key)
return obj.hasOwnProperty(key as string)
From 04af9504a720c8e6de26c04b1282cf14fa1bcee3 Mon Sep 17 00:00:00 2001
From: Evan You
Date: Mon, 15 Apr 2024 17:36:05 +0800
Subject: [PATCH 53/67] fix(compiler-core): fix v-bind shorthand for component
:is
close #10469
close #10471
---
.../transforms/transformElement.spec.ts | 18 +++++++++++++++++
.../src/transforms/transformElement.ts | 20 ++++++++++++++-----
2 files changed, 33 insertions(+), 5 deletions(-)
diff --git a/packages/compiler-core/__tests__/transforms/transformElement.spec.ts b/packages/compiler-core/__tests__/transforms/transformElement.spec.ts
index 5d3f92ced18..c30840a21a6 100644
--- a/packages/compiler-core/__tests__/transforms/transformElement.spec.ts
+++ b/packages/compiler-core/__tests__/transforms/transformElement.spec.ts
@@ -1231,6 +1231,24 @@ describe('compiler: element transform', () => {
})
})
+ test('dynamic binding shorthand', () => {
+ const { node, root } = parseWithBind(` `)
+ expect(root.helpers).toContain(RESOLVE_DYNAMIC_COMPONENT)
+ expect(node).toMatchObject({
+ isBlock: true,
+ tag: {
+ callee: RESOLVE_DYNAMIC_COMPONENT,
+ arguments: [
+ {
+ type: NodeTypes.SIMPLE_EXPRESSION,
+ content: 'is',
+ isStatic: false,
+ },
+ ],
+ },
+ })
+ })
+
test('is casting', () => {
const { node, root } = parseWithBind(`
`)
expect(root.helpers).toContain(RESOLVE_COMPONENT)
diff --git a/packages/compiler-core/src/transforms/transformElement.ts b/packages/compiler-core/src/transforms/transformElement.ts
index c50f7f5e969..ca6e59df32b 100644
--- a/packages/compiler-core/src/transforms/transformElement.ts
+++ b/packages/compiler-core/src/transforms/transformElement.ts
@@ -64,6 +64,7 @@ import {
checkCompatEnabled,
isCompatEnabled,
} from '../compat/compatConfig'
+import { processExpression } from './transformExpression'
// some directive transforms (e.g. v-model) may return a symbol for runtime
// import, which should be used instead of a resolveDirective call.
@@ -253,7 +254,7 @@ export function resolveComponentType(
// 1. dynamic component
const isExplicitDynamic = isComponentTag(tag)
- const isProp = findProp(node, 'is')
+ const isProp = findProp(node, 'is', false, true /* allow empty */)
if (isProp) {
if (
isExplicitDynamic ||
@@ -263,10 +264,19 @@ export function resolveComponentType(
context,
))
) {
- const exp =
- isProp.type === NodeTypes.ATTRIBUTE
- ? isProp.value && createSimpleExpression(isProp.value.content, true)
- : isProp.exp
+ let exp: ExpressionNode | undefined
+ if (isProp.type === NodeTypes.ATTRIBUTE) {
+ exp = isProp.value && createSimpleExpression(isProp.value.content, true)
+ } else {
+ exp = isProp.exp
+ if (!exp) {
+ // #10469 handle :is shorthand
+ exp = createSimpleExpression(`is`, false, isProp.loc)
+ if (!__BROWSER__) {
+ exp = isProp.exp = processExpression(exp, context)
+ }
+ }
+ }
if (exp) {
return createCallExpression(context.helper(RESOLVE_DYNAMIC_COMPONENT), [
exp,
From d58d133b1cde5085cc5ab0012d544cafd62a6ee6 Mon Sep 17 00:00:00 2001
From: Evan You
Date: Mon, 15 Apr 2024 19:28:37 +0800
Subject: [PATCH 54/67] fix(compat): fix $options mutation + adjust private API
initialization
close #10626
close #10636
---
packages/runtime-core/src/compat/instance.ts | 114 +++++++++++-------
packages/runtime-core/src/component.ts | 7 ++
.../vue-compat/__tests__/instance.spec.ts | 41 +++++++
3 files changed, 119 insertions(+), 43 deletions(-)
diff --git a/packages/runtime-core/src/compat/instance.ts b/packages/runtime-core/src/compat/instance.ts
index 5beaf5f5ebb..d310de49ae6 100644
--- a/packages/runtime-core/src/compat/instance.ts
+++ b/packages/runtime-core/src/compat/instance.ts
@@ -15,6 +15,7 @@ import {
DeprecationTypes,
assertCompatEnabled,
isCompatEnabled,
+ warnDeprecation,
} from './compatConfig'
import { off, on, once } from './instanceEventEmitter'
import { getCompatListeners } from './instanceListeners'
@@ -121,50 +122,77 @@ export function installCompatInstanceProperties(map: PublicPropertiesMap) {
$children: getCompatChildren,
$listeners: getCompatListeners,
+
+ // inject additional properties into $options for compat
+ // e.g. vuex needs this.$options.parent
+ $options: i => {
+ if (!isCompatEnabled(DeprecationTypes.PRIVATE_APIS, i)) {
+ return resolveMergedOptions(i)
+ }
+ if (i.resolvedOptions) {
+ return i.resolvedOptions
+ }
+ const res = (i.resolvedOptions = extend({}, resolveMergedOptions(i)))
+ Object.defineProperties(res, {
+ parent: {
+ get() {
+ warnDeprecation(DeprecationTypes.PRIVATE_APIS, i, '$options.parent')
+ return i.proxy!.$parent
+ },
+ },
+ propsData: {
+ get() {
+ warnDeprecation(
+ DeprecationTypes.PRIVATE_APIS,
+ i,
+ '$options.propsData',
+ )
+ return i.vnode.props
+ },
+ },
+ })
+ return res
+ },
} as PublicPropertiesMap)
- /* istanbul ignore if */
- if (isCompatEnabled(DeprecationTypes.PRIVATE_APIS, null)) {
- extend(map, {
- // needed by many libs / render fns
- $vnode: i => i.vnode,
-
- // inject additional properties into $options for compat
- // e.g. vuex needs this.$options.parent
- $options: i => {
- const res = extend({}, resolveMergedOptions(i))
- res.parent = i.proxy!.$parent
- res.propsData = i.vnode.props
- return res
- },
-
- // some private properties that are likely accessed...
- _self: i => i.proxy,
- _uid: i => i.uid,
- _data: i => i.data,
- _isMounted: i => i.isMounted,
- _isDestroyed: i => i.isUnmounted,
-
- // v2 render helpers
- $createElement: () => compatH,
- _c: () => compatH,
- _o: () => legacyMarkOnce,
- _n: () => looseToNumber,
- _s: () => toDisplayString,
- _l: () => renderList,
- _t: i => legacyRenderSlot.bind(null, i),
- _q: () => looseEqual,
- _i: () => looseIndexOf,
- _m: i => legacyRenderStatic.bind(null, i),
- _f: () => resolveFilter,
- _k: i => legacyCheckKeyCodes.bind(null, i),
- _b: () => legacyBindObjectProps,
- _v: () => createTextVNode,
- _e: () => createCommentVNode,
- _u: () => legacyresolveScopedSlots,
- _g: () => legacyBindObjectListeners,
- _d: () => legacyBindDynamicKeys,
- _p: () => legacyPrependModifier,
- } as PublicPropertiesMap)
+ const privateAPIs = {
+ // needed by many libs / render fns
+ $vnode: i => i.vnode,
+
+ // some private properties that are likely accessed...
+ _self: i => i.proxy,
+ _uid: i => i.uid,
+ _data: i => i.data,
+ _isMounted: i => i.isMounted,
+ _isDestroyed: i => i.isUnmounted,
+
+ // v2 render helpers
+ $createElement: () => compatH,
+ _c: () => compatH,
+ _o: () => legacyMarkOnce,
+ _n: () => looseToNumber,
+ _s: () => toDisplayString,
+ _l: () => renderList,
+ _t: i => legacyRenderSlot.bind(null, i),
+ _q: () => looseEqual,
+ _i: () => looseIndexOf,
+ _m: i => legacyRenderStatic.bind(null, i),
+ _f: () => resolveFilter,
+ _k: i => legacyCheckKeyCodes.bind(null, i),
+ _b: () => legacyBindObjectProps,
+ _v: () => createTextVNode,
+ _e: () => createCommentVNode,
+ _u: () => legacyresolveScopedSlots,
+ _g: () => legacyBindObjectListeners,
+ _d: () => legacyBindDynamicKeys,
+ _p: () => legacyPrependModifier,
+ } as PublicPropertiesMap
+
+ for (const key in privateAPIs) {
+ map[key] = i => {
+ if (isCompatEnabled(DeprecationTypes.PRIVATE_APIS, i)) {
+ return privateAPIs[key](i)
+ }
+ }
}
}
diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts
index a551529e667..6f30053cfc2 100644
--- a/packages/runtime-core/src/component.ts
+++ b/packages/runtime-core/src/component.ts
@@ -45,6 +45,7 @@ import { type Directive, validateDirectiveName } from './directives'
import {
type ComponentOptions,
type ComputedOptions,
+ type MergedComponentOptions,
type MethodOptions,
applyOptions,
resolveMergedOptions,
@@ -524,6 +525,12 @@ export interface ComponentInternalInstance {
* @internal
*/
getCssVars?: () => Record
+
+ /**
+ * v2 compat only, for caching mutated $options
+ * @internal
+ */
+ resolvedOptions?: MergedComponentOptions
}
const emptyAppContext = createAppContext()
diff --git a/packages/vue-compat/__tests__/instance.spec.ts b/packages/vue-compat/__tests__/instance.spec.ts
index 63ce5581230..1feccabd8f8 100644
--- a/packages/vue-compat/__tests__/instance.spec.ts
+++ b/packages/vue-compat/__tests__/instance.spec.ts
@@ -14,6 +14,7 @@ beforeEach(() => {
Vue.configureCompat({
MODE: 2,
GLOBAL_MOUNT: 'suppress-warning',
+ PRIVATE_APIS: 'suppress-warning',
})
})
@@ -331,3 +332,43 @@ test('INSTANCE_ATTR_CLASS_STYLE', () => {
)('Anonymous'),
).toHaveBeenWarned()
})
+
+test('$options mutation', () => {
+ const Comp = {
+ props: ['id'],
+ template: '
',
+ data() {
+ return {
+ foo: '',
+ }
+ },
+ created(this: any) {
+ expect(this.$options.parent).toBeDefined()
+ expect(this.$options.test).toBeUndefined()
+ this.$options.test = this.id
+ expect(this.$options.test).toBe(this.id)
+ },
+ }
+
+ new Vue({
+ template: `
`,
+ components: { Comp },
+ }).$mount()
+})
+
+test('other private APIs', () => {
+ new Vue({
+ created() {
+ expect(this.$createElement).toBeTruthy()
+ },
+ })
+
+ new Vue({
+ compatConfig: {
+ PRIVATE_APIS: false,
+ },
+ created() {
+ expect(this.$createElement).toBeUndefined()
+ },
+ })
+})
From 54a6afa75a546078e901ce0882da53b97420fe94 Mon Sep 17 00:00:00 2001
From: Doctor Wu <44631608+Doctor-wu@users.noreply.github.com>
Date: Mon, 15 Apr 2024 19:36:13 +0800
Subject: [PATCH 55/67] fix(compiler-sfc): fix universal selector scope
(#10551)
close #10548
---
.../__tests__/compileStyle.spec.ts | 19 ++++++++++++++
.../compiler-sfc/src/style/pluginScoped.ts | 26 +++++++++++++++++++
2 files changed, 45 insertions(+)
diff --git a/packages/compiler-sfc/__tests__/compileStyle.spec.ts b/packages/compiler-sfc/__tests__/compileStyle.spec.ts
index 0da713a0504..71c0689a397 100644
--- a/packages/compiler-sfc/__tests__/compileStyle.spec.ts
+++ b/packages/compiler-sfc/__tests__/compileStyle.spec.ts
@@ -429,4 +429,23 @@ describe('SFC style preprocessors', () => {
expect(res.errors.length).toBe(0)
})
+
+ test('should mount scope on correct selector when have universal selector', () => {
+ expect(compileScoped(`* { color: red; }`)).toMatchInlineSnapshot(`
+ "[data-v-test] { color: red;
+ }"
+ `)
+ expect(compileScoped('* .foo { color: red; }')).toMatchInlineSnapshot(`
+ ".foo[data-v-test] { color: red;
+ }"
+ `)
+ expect(compileScoped(`*.foo { color: red; }`)).toMatchInlineSnapshot(`
+ ".foo[data-v-test] { color: red;
+ }"
+ `)
+ expect(compileScoped(`.foo * { color: red; }`)).toMatchInlineSnapshot(`
+ ".foo[data-v-test] * { color: red;
+ }"
+ `)
+ })
})
diff --git a/packages/compiler-sfc/src/style/pluginScoped.ts b/packages/compiler-sfc/src/style/pluginScoped.ts
index 0a46de7fcb4..3812e67092a 100644
--- a/packages/compiler-sfc/src/style/pluginScoped.ts
+++ b/packages/compiler-sfc/src/style/pluginScoped.ts
@@ -170,6 +170,32 @@ function rewriteSelector(
}
}
+ if (n.type === 'universal') {
+ const prev = selector.at(selector.index(n) - 1)
+ const next = selector.at(selector.index(n) + 1)
+ // * ... {}
+ if (!prev) {
+ // * .foo {} -> .foo[xxxxxxx] {}
+ if (next) {
+ if (next.type === 'combinator' && next.value === ' ') {
+ selector.removeChild(next)
+ }
+ selector.removeChild(n)
+ return
+ } else {
+ // * {} -> [xxxxxxx] {}
+ node = selectorParser.combinator({
+ value: '',
+ })
+ selector.insertBefore(n, node)
+ selector.removeChild(n)
+ return false
+ }
+ }
+ // .foo * -> .foo[xxxxxxx] *
+ if (node) return
+ }
+
if (
(n.type !== 'pseudo' && n.type !== 'combinator') ||
(n.type === 'pseudo' &&
From 67722ba23b7c36ab8f3fa2d2b4df08e4ddc322e1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=99=BD=E9=9B=BE=E4=B8=89=E8=AF=AD?=
<32354856+baiwusanyu-c@users.noreply.github.com>
Date: Mon, 15 Apr 2024 20:23:28 +0800
Subject: [PATCH 56/67] fix(runtime-dom): fix css v-bind for suspensed
components (#8523)
close #8520
---
.../__tests__/helpers/useCssVars.spec.ts | 57 +++++++++++++++++++
.../runtime-dom/src/helpers/useCssVars.ts | 3 +-
2 files changed, 58 insertions(+), 2 deletions(-)
diff --git a/packages/runtime-dom/__tests__/helpers/useCssVars.spec.ts b/packages/runtime-dom/__tests__/helpers/useCssVars.spec.ts
index e26b9dfb45e..9f860a5e3c3 100644
--- a/packages/runtime-dom/__tests__/helpers/useCssVars.spec.ts
+++ b/packages/runtime-dom/__tests__/helpers/useCssVars.spec.ts
@@ -118,6 +118,63 @@ describe('useCssVars', () => {
}
})
+ test('with v-if & async component & suspense', async () => {
+ const state = reactive({ color: 'red' })
+ const root = document.createElement('div')
+ const show = ref(false)
+ let resolveAsync: any
+ let asyncPromise: any
+
+ const AsyncComp = {
+ setup() {
+ useCssVars(() => state)
+ asyncPromise = new Promise(r => {
+ resolveAsync = () => {
+ r(() => h('p', 'default'))
+ }
+ })
+ return asyncPromise
+ },
+ }
+
+ const App = {
+ setup() {
+ return () =>
+ h(Suspense, null, {
+ default: h('div', {}, show.value ? h(AsyncComp) : h('p')),
+ })
+ },
+ }
+
+ render(h(App), root)
+ await nextTick()
+ // AsyncComp resolve
+ show.value = true
+ await nextTick()
+ resolveAsync()
+ await asyncPromise.then(() => {})
+ // Suspense effects flush
+ await nextTick()
+ // css vars use with default tree
+ for (const c of [].slice.call(root.children as any)) {
+ expect(
+ ((c as any).children[0] as HTMLElement).style.getPropertyValue(
+ `--color`,
+ ),
+ ).toBe(`red`)
+ }
+
+ state.color = 'green'
+ await nextTick()
+ for (const c of [].slice.call(root.children as any)) {
+ expect(
+ ((c as any).children[0] as HTMLElement).style.getPropertyValue(
+ `--color`,
+ ),
+ ).toBe('green')
+ }
+ })
+
test('with subTree changed', async () => {
const state = reactive({ color: 'red' })
const value = ref(true)
diff --git a/packages/runtime-dom/src/helpers/useCssVars.ts b/packages/runtime-dom/src/helpers/useCssVars.ts
index 1666e3cb3dc..286a4176076 100644
--- a/packages/runtime-dom/src/helpers/useCssVars.ts
+++ b/packages/runtime-dom/src/helpers/useCssVars.ts
@@ -42,9 +42,8 @@ export function useCssVars(getter: (ctx: any) => Record) {
updateTeleports(vars)
}
- watchPostEffect(setVars)
-
onMounted(() => {
+ watchPostEffect(setVars)
const ob = new MutationObserver(setVars)
ob.observe(instance.subTree.el!.parentNode, { childList: true })
onUnmounted(() => ob.disconnect())
From 0cef65cee411356e721bbc90d731fc52fc8fce94 Mon Sep 17 00:00:00 2001
From: yangxiuxiu <79584569+yangxiuxiu1115@users.noreply.github.com>
Date: Mon, 15 Apr 2024 21:18:59 +0800
Subject: [PATCH 57/67] fix(compiler-sfc): fix defineModel coercion for boolean
+ string union types (#9603)
close #9587
close #10676
---
.../__snapshots__/defineModel.spec.ts.snap | 20 +++++++++++++++++++
.../compileScript/defineModel.spec.ts | 20 +++++++++++++++++++
.../compiler-sfc/src/script/defineModel.ts | 18 ++++++++++-------
3 files changed, 51 insertions(+), 7 deletions(-)
diff --git a/packages/compiler-sfc/__tests__/compileScript/__snapshots__/defineModel.spec.ts.snap b/packages/compiler-sfc/__tests__/compileScript/__snapshots__/defineModel.spec.ts.snap
index b6a93541d36..6e9967fd011 100644
--- a/packages/compiler-sfc/__tests__/compileScript/__snapshots__/defineModel.spec.ts.snap
+++ b/packages/compiler-sfc/__tests__/compileScript/__snapshots__/defineModel.spec.ts.snap
@@ -103,6 +103,26 @@ return { modelValue }
})"
`;
+exports[`defineModel() > w/ Boolean And Function types, production mode 1`] = `
+"import { useModel as _useModel, defineComponent as _defineComponent } from 'vue'
+
+export default /*#__PURE__*/_defineComponent({
+ props: {
+ "modelValue": { type: [Boolean, String] },
+ "modelModifiers": {},
+ },
+ emits: ["update:modelValue"],
+ setup(__props, { expose: __expose }) {
+ __expose();
+
+ const modelValue = _useModel(__props, "modelValue")
+
+return { modelValue }
+}
+
+})"
+`;
+
exports[`defineModel() > w/ array props 1`] = `
"import { useModel as _useModel, mergeModels as _mergeModels } from 'vue'
diff --git a/packages/compiler-sfc/__tests__/compileScript/defineModel.spec.ts b/packages/compiler-sfc/__tests__/compileScript/defineModel.spec.ts
index 304258615a8..bd048a847e4 100644
--- a/packages/compiler-sfc/__tests__/compileScript/defineModel.spec.ts
+++ b/packages/compiler-sfc/__tests__/compileScript/defineModel.spec.ts
@@ -221,4 +221,24 @@ describe('defineModel()', () => {
assertCode(content)
expect(content).toMatch(`set: (v) => { return v + __props.x }`)
})
+
+ test('w/ Boolean And Function types, production mode', () => {
+ const { content, bindings } = compile(
+ `
+
+ `,
+ { isProd: true },
+ )
+ assertCode(content)
+ expect(content).toMatch('"modelValue": { type: [Boolean, String] }')
+ expect(content).toMatch('emits: ["update:modelValue"]')
+ expect(content).toMatch(
+ `const modelValue = _useModel(__props, "modelValue")`,
+ )
+ expect(bindings).toStrictEqual({
+ modelValue: BindingTypes.SETUP_REF,
+ })
+ })
})
diff --git a/packages/compiler-sfc/src/script/defineModel.ts b/packages/compiler-sfc/src/script/defineModel.ts
index 24fd0780eaa..e5e2ed0e53f 100644
--- a/packages/compiler-sfc/src/script/defineModel.ts
+++ b/packages/compiler-sfc/src/script/defineModel.ts
@@ -129,15 +129,19 @@ export function genModelProps(ctx: ScriptCompileContext) {
let runtimeTypes = type && inferRuntimeType(ctx, type)
if (runtimeTypes) {
+ const hasBoolean = runtimeTypes.includes('Boolean')
const hasUnknownType = runtimeTypes.includes(UNKNOWN_TYPE)
- runtimeTypes = runtimeTypes.filter(el => {
- if (el === UNKNOWN_TYPE) return false
- return isProd
- ? el === 'Boolean' || (el === 'Function' && options)
- : true
- })
- skipCheck = !isProd && hasUnknownType && runtimeTypes.length > 0
+ if (isProd || hasUnknownType) {
+ runtimeTypes = runtimeTypes.filter(
+ t =>
+ t === 'Boolean' ||
+ (hasBoolean && t === 'String') ||
+ (t === 'Function' && options),
+ )
+
+ skipCheck = !isProd && hasUnknownType && runtimeTypes.length > 0
+ }
}
let runtimeType =
From 2ec06fd6c8383e11cdf4efcab1707f973bd6a54c Mon Sep 17 00:00:00 2001
From: edison
Date: Mon, 15 Apr 2024 21:23:30 +0800
Subject: [PATCH 58/67] fix(hydration): properly handle optimized mode during
hydrate node (#10638)
close #10607
---
.../runtime-core/__tests__/hydration.spec.ts | 81 +++++++++++++++++++
packages/runtime-core/src/hydration.ts | 1 +
2 files changed, 82 insertions(+)
diff --git a/packages/runtime-core/__tests__/hydration.spec.ts b/packages/runtime-core/__tests__/hydration.spec.ts
index 6caa2442e18..e0277622c13 100644
--- a/packages/runtime-core/__tests__/hydration.spec.ts
+++ b/packages/runtime-core/__tests__/hydration.spec.ts
@@ -7,7 +7,10 @@ import {
Teleport,
Transition,
type VNode,
+ createBlock,
createCommentVNode,
+ createElementBlock,
+ createElementVNode,
createSSRApp,
createStaticVNode,
createTextVNode,
@@ -17,16 +20,19 @@ import {
h,
nextTick,
onMounted,
+ openBlock,
ref,
renderSlot,
useCssVars,
vModelCheckbox,
vShow,
+ withCtx,
withDirectives,
} from '@vue/runtime-dom'
import { type SSRContext, renderToString } from '@vue/server-renderer'
import { PatchFlags } from '@vue/shared'
import { vShowOriginalDisplay } from '../../runtime-dom/src/directives/vShow'
+import { expect } from 'vitest'
function mountWithHydration(html: string, render: () => any) {
const container = document.createElement('div')
@@ -1292,6 +1298,81 @@ describe('SSR hydration', () => {
`)
})
+ // #10607
+ test('update component stable slot (prod + optimized mode)', async () => {
+ __DEV__ = false
+ const container = document.createElement('div')
+ container.innerHTML = ` `
+ const Comp = {
+ render(this: any) {
+ return (
+ openBlock(),
+ createElementBlock('div', null, [renderSlot(this.$slots, 'default')])
+ )
+ },
+ }
+ const show = ref(false)
+ const clicked = ref(false)
+
+ const Wrapper = {
+ setup() {
+ const items = ref([])
+ onMounted(() => {
+ items.value = [1]
+ })
+ return () => {
+ return (
+ openBlock(),
+ createBlock(Comp, null, {
+ default: withCtx(() => [
+ createElementVNode('div', null, [
+ createElementVNode('div', null, [
+ clicked.value
+ ? (openBlock(),
+ createElementBlock('div', { key: 0 }, 'foo'))
+ : createCommentVNode('v-if', true),
+ ]),
+ ]),
+ createElementVNode(
+ 'div',
+ null,
+ items.value.length,
+ 1 /* TEXT */,
+ ),
+ ]),
+ _: 1 /* STABLE */,
+ })
+ )
+ }
+ },
+ }
+ createSSRApp({
+ components: { Wrapper },
+ data() {
+ return { show }
+ },
+ template: ` `,
+ }).mount(container)
+
+ await nextTick()
+ expect(container.innerHTML).toBe(
+ ``,
+ )
+
+ show.value = true
+ await nextTick()
+ expect(async () => {
+ clicked.value = true
+ await nextTick()
+ }).not.toThrow("Cannot read properties of null (reading 'insertBefore')")
+
+ await nextTick()
+ expect(container.innerHTML).toBe(
+ ``,
+ )
+ __DEV__ = true
+ })
+
describe('mismatch handling', () => {
test('text node', () => {
const { container } = mountWithHydration(`foo`, () => 'bar')
diff --git a/packages/runtime-core/src/hydration.ts b/packages/runtime-core/src/hydration.ts
index 8469577608e..a7832ac3d57 100644
--- a/packages/runtime-core/src/hydration.ts
+++ b/packages/runtime-core/src/hydration.ts
@@ -120,6 +120,7 @@ export function createHydrationFunctions(
slotScopeIds: string[] | null,
optimized = false,
): Node | null => {
+ optimized = optimized || !!vnode.dynamicChildren
const isFragmentStart = isComment(node) && node.data === '['
const onMismatch = () =>
handleMismatch(
From 5a9626708e970c6fc0b6f786e3c80c22273d126f Mon Sep 17 00:00:00 2001
From: Jonas
Date: Mon, 15 Apr 2024 15:26:19 +0200
Subject: [PATCH 59/67] fix(ssr): don't render v-if comments in TransitionGroup
(#6732)
close #6715
---
.../compiler-ssr/__tests__/ssrTransitionGroup.spec.ts | 2 --
packages/compiler-ssr/src/ssrCodegenTransform.ts | 8 +++++++-
.../src/transforms/ssrTransformTransitionGroup.ts | 9 ++++++++-
packages/compiler-ssr/src/transforms/ssrVIf.ts | 3 ++-
4 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/packages/compiler-ssr/__tests__/ssrTransitionGroup.spec.ts b/packages/compiler-ssr/__tests__/ssrTransitionGroup.spec.ts
index d2a576fd02a..905e6a4895d 100644
--- a/packages/compiler-ssr/__tests__/ssrTransitionGroup.spec.ts
+++ b/packages/compiler-ssr/__tests__/ssrTransitionGroup.spec.ts
@@ -82,8 +82,6 @@ describe('transition-group', () => {
})
if (_ctx.ok) {
_push(\`ok
\`)
- } else {
- _push(\`\`)
}
_push(\`\`)
}"
diff --git a/packages/compiler-ssr/src/ssrCodegenTransform.ts b/packages/compiler-ssr/src/ssrCodegenTransform.ts
index 1755be3a3b0..53a7a060510 100644
--- a/packages/compiler-ssr/src/ssrCodegenTransform.ts
+++ b/packages/compiler-ssr/src/ssrCodegenTransform.ts
@@ -141,6 +141,7 @@ export function processChildren(
context: SSRTransformContext,
asFragment = false,
disableNestedFragments = false,
+ disableCommentAsIfAlternate = false,
) {
if (asFragment) {
context.pushStringPart(``)
@@ -191,7 +192,12 @@ export function processChildren(
)
break
case NodeTypes.IF:
- ssrProcessIf(child, context, disableNestedFragments)
+ ssrProcessIf(
+ child,
+ context,
+ disableNestedFragments,
+ disableCommentAsIfAlternate,
+ )
break
case NodeTypes.FOR:
ssrProcessFor(child, context, disableNestedFragments)
diff --git a/packages/compiler-ssr/src/transforms/ssrTransformTransitionGroup.ts b/packages/compiler-ssr/src/transforms/ssrTransformTransitionGroup.ts
index 2d434010e2a..a2e284ae841 100644
--- a/packages/compiler-ssr/src/transforms/ssrTransformTransitionGroup.ts
+++ b/packages/compiler-ssr/src/transforms/ssrTransformTransitionGroup.ts
@@ -87,6 +87,13 @@ export function ssrProcessTransitionGroup(
* by disabling nested fragment wrappers from being generated.
*/
true,
+ /**
+ * TransitionGroup filters out comment children at runtime and thus
+ * doesn't expect comments to be present during hydration. We need to
+ * account for that by disabling the empty comment that is otherwise
+ * rendered for a falsy v-if that has no v-else specified. (#6715)
+ */
+ true,
)
context.pushStringPart(``)
context.pushStringPart(tag.exp!)
@@ -106,6 +113,6 @@ export function ssrProcessTransitionGroup(
}
} else {
// fragment
- processChildren(node, context, true, true)
+ processChildren(node, context, true, true, true)
}
}
diff --git a/packages/compiler-ssr/src/transforms/ssrVIf.ts b/packages/compiler-ssr/src/transforms/ssrVIf.ts
index 32a5a7c00f1..b30846c1eeb 100644
--- a/packages/compiler-ssr/src/transforms/ssrVIf.ts
+++ b/packages/compiler-ssr/src/transforms/ssrVIf.ts
@@ -26,6 +26,7 @@ export function ssrProcessIf(
node: IfNode,
context: SSRTransformContext,
disableNestedFragments = false,
+ disableCommentAsIfAlternate = false,
) {
const [rootBranch] = node.branches
const ifStatement = createIfStatement(
@@ -54,7 +55,7 @@ export function ssrProcessIf(
}
}
- if (!currentIf.alternate) {
+ if (!currentIf.alternate && !disableCommentAsIfAlternate) {
currentIf.alternate = createBlockStatement([
createCallExpression(`_push`, ['``']),
])
From 15ffe8f2c954359770c57e4d9e589b0b622e4a60 Mon Sep 17 00:00:00 2001
From: Wick
Date: Mon, 15 Apr 2024 22:02:57 +0800
Subject: [PATCH 60/67] fix(runtime-dom): force update v-model number with
leading 0 (#10506)
close #10503
close #10615
---
.../__tests__/directives/vModel.spec.ts | 37 +++++++++++++++++++
packages/runtime-dom/src/directives/vModel.ts | 5 ++-
2 files changed, 40 insertions(+), 2 deletions(-)
diff --git a/packages/runtime-dom/__tests__/directives/vModel.spec.ts b/packages/runtime-dom/__tests__/directives/vModel.spec.ts
index d6398f37321..66b57b68964 100644
--- a/packages/runtime-dom/__tests__/directives/vModel.spec.ts
+++ b/packages/runtime-dom/__tests__/directives/vModel.spec.ts
@@ -1269,4 +1269,41 @@ describe('vModel', () => {
expect(foo.selected).toEqual(true)
expect(bar.selected).toEqual(true)
})
+
+ // #10503
+ test('equal value with a leading 0 should trigger update.', async () => {
+ const setNum = function (this: any, value: any) {
+ this.num = value
+ }
+ const component = defineComponent({
+ data() {
+ return { num: 0 }
+ },
+ render() {
+ return [
+ withVModel(
+ h('input', {
+ id: 'input_num1',
+ type: 'number',
+ 'onUpdate:modelValue': setNum.bind(this),
+ }),
+ this.num,
+ ),
+ ]
+ },
+ })
+
+ render(h(component), root)
+ const data = root._vnode.component.data
+
+ const inputNum1 = root.querySelector('#input_num1')!
+ expect(inputNum1.value).toBe('0')
+
+ inputNum1.value = '01'
+ triggerEvent('input', inputNum1)
+ await nextTick()
+ expect(data.num).toBe(1)
+
+ expect(inputNum1.value).toBe('1')
+ })
})
diff --git a/packages/runtime-dom/src/directives/vModel.ts b/packages/runtime-dom/src/directives/vModel.ts
index e002e2e10da..b0ea41728bd 100644
--- a/packages/runtime-dom/src/directives/vModel.ts
+++ b/packages/runtime-dom/src/directives/vModel.ts
@@ -86,9 +86,10 @@ export const vModelText: ModelDirective<
el[assignKey] = getModelAssigner(vnode)
// avoid clearing unresolved text. #2302
if ((el as any).composing) return
-
const elValue =
- number || el.type === 'number' ? looseToNumber(el.value) : el.value
+ (number || el.type === 'number') && !/^0\d/.test(el.value)
+ ? looseToNumber(el.value)
+ : el.value
const newValue = value == null ? '' : value
if (elValue === newValue) {
From 7ccd453dd004076cad49ec9f56cd5fe97b7b6ed8 Mon Sep 17 00:00:00 2001
From: Adrien Foulon <6115458+Tofandel@users.noreply.github.com>
Date: Mon, 15 Apr 2024 16:28:34 +0200
Subject: [PATCH 61/67] fix(runtime-dom): sanitize wrongly passed string value
as event handler (#8953)
close #8818
---
.../runtime-dom/__tests__/patchEvents.spec.ts | 11 +++++++
packages/runtime-dom/src/modules/events.ts | 32 ++++++++++++++++---
2 files changed, 38 insertions(+), 5 deletions(-)
diff --git a/packages/runtime-dom/__tests__/patchEvents.spec.ts b/packages/runtime-dom/__tests__/patchEvents.spec.ts
index 1b08f85caa4..b7a5af0ed0e 100644
--- a/packages/runtime-dom/__tests__/patchEvents.spec.ts
+++ b/packages/runtime-dom/__tests__/patchEvents.spec.ts
@@ -192,4 +192,15 @@ describe(`runtime-dom: events patching`, () => {
testElement.dispatchEvent(new CustomEvent('foobar'))
expect(fn2).toHaveBeenCalledTimes(1)
})
+
+ it('handles an unknown type', () => {
+ const el = document.createElement('div')
+ patchProp(el, 'onClick', null, 'test')
+ el.dispatchEvent(new Event('click'))
+ expect(
+ '[Vue warn]: Wrong type passed to the event invoker, ' +
+ 'did you maybe forget @ or : in front of your prop?' +
+ '\nReceived onClick="test"',
+ ).toHaveBeenWarned()
+ })
})
diff --git a/packages/runtime-dom/src/modules/events.ts b/packages/runtime-dom/src/modules/events.ts
index 0335b6be0db..09e4a22a84c 100644
--- a/packages/runtime-dom/src/modules/events.ts
+++ b/packages/runtime-dom/src/modules/events.ts
@@ -1,8 +1,9 @@
-import { hyphenate, isArray } from '@vue/shared'
+import { NOOP, hyphenate, isArray, isFunction, isString } from '@vue/shared'
import {
type ComponentInternalInstance,
ErrorCodes,
callWithAsyncErrorHandling,
+ warn,
} from '@vue/runtime-core'
interface Invoker extends EventListener {
@@ -36,7 +37,7 @@ export function patchEvent(
el: Element & { [veiKey]?: Record },
rawName: string,
prevValue: EventValue | null,
- nextValue: EventValue | null,
+ nextValue: EventValue | unknown,
instance: ComponentInternalInstance | null = null,
) {
// vei = vue event invokers
@@ -44,12 +45,19 @@ export function patchEvent(
const existingInvoker = invokers[rawName]
if (nextValue && existingInvoker) {
// patch
- existingInvoker.value = nextValue
+ existingInvoker.value = __DEV__
+ ? sanitizeEventValue(nextValue, rawName)
+ : (nextValue as EventValue)
} else {
const [name, options] = parseName(rawName)
if (nextValue) {
// add
- const invoker = (invokers[rawName] = createInvoker(nextValue, instance))
+ const invoker = (invokers[rawName] = createInvoker(
+ __DEV__
+ ? sanitizeEventValue(nextValue, rawName)
+ : (nextValue as EventValue),
+ instance,
+ ))
addEventListener(el, name, invoker, options)
} else if (existingInvoker) {
// remove
@@ -116,6 +124,18 @@ function createInvoker(
return invoker
}
+function sanitizeEventValue(value: unknown, propName: string): EventValue {
+ if (isFunction(value) || isArray(value)) {
+ return value as EventValue
+ }
+ warn(
+ `Wrong type passed to the event invoker, did you maybe forget @ or : ` +
+ `in front of your prop?\nReceived ` +
+ `${propName}=${isString(value) ? JSON.stringify(value) : `[${typeof value}]`}`,
+ )
+ return NOOP
+}
+
function patchStopImmediatePropagation(
e: Event,
value: EventValue,
@@ -126,7 +146,9 @@ function patchStopImmediatePropagation(
originalStop.call(e)
;(e as any)._stopped = true
}
- return value.map(fn => (e: Event) => !(e as any)._stopped && fn && fn(e))
+ return (value as Function[]).map(
+ fn => (e: Event) => !(e as any)._stopped && fn && fn(e),
+ )
} else {
return value
}
From 53d15d3f76184eed67a18d35e43d9a2062f8e121 Mon Sep 17 00:00:00 2001
From: caomingrui <47497092+caomingrui@users.noreply.github.com>
Date: Mon, 15 Apr 2024 22:37:16 +0800
Subject: [PATCH 62/67] fix(runtime-core): handle invalid values in
callWithAsyncErrorHandling
---
packages/runtime-core/src/errorHandling.ts | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/packages/runtime-core/src/errorHandling.ts b/packages/runtime-core/src/errorHandling.ts
index dda6480385b..41c92cbd34a 100644
--- a/packages/runtime-core/src/errorHandling.ts
+++ b/packages/runtime-core/src/errorHandling.ts
@@ -2,7 +2,7 @@ import { pauseTracking, resetTracking } from '@vue/reactivity'
import type { VNode } from './vnode'
import type { ComponentInternalInstance } from './component'
import { popWarningContext, pushWarningContext, warn } from './warning'
-import { isFunction, isPromise } from '@vue/shared'
+import { isArray, isFunction, isPromise } from '@vue/shared'
import { LifecycleHooks } from './enums'
// contexts where user provided function may be executed, in addition to
@@ -79,7 +79,7 @@ export function callWithAsyncErrorHandling(
instance: ComponentInternalInstance | null,
type: ErrorTypes,
args?: unknown[],
-): any[] {
+): any {
if (isFunction(fn)) {
const res = callWithErrorHandling(fn, instance, type, args)
if (res && isPromise(res)) {
@@ -90,11 +90,17 @@ export function callWithAsyncErrorHandling(
return res
}
- const values = []
- for (let i = 0; i < fn.length; i++) {
- values.push(callWithAsyncErrorHandling(fn[i], instance, type, args))
+ if (isArray(fn)) {
+ const values = []
+ for (let i = 0; i < fn.length; i++) {
+ values.push(callWithAsyncErrorHandling(fn[i], instance, type, args))
+ }
+ return values
+ } else if (__DEV__) {
+ warn(
+ `Invalid value type passed to callWithAsyncErrorHandling(): ${typeof fn}`,
+ )
}
- return values
}
export function handleError(
From fc99e4d3f01b190ef9fd3c218a668ba9124a32bc Mon Sep 17 00:00:00 2001
From: edison
Date: Mon, 15 Apr 2024 22:40:38 +0800
Subject: [PATCH 63/67] fix(Transition): ensure the KeepAlive children unmount
w/ out-in mode (#10632)
close #10620
---
.../components/BaseTransition.spec.ts | 37 +++++++++++++++++++
.../runtime-core/src/components/KeepAlive.ts | 2 +-
2 files changed, 38 insertions(+), 1 deletion(-)
diff --git a/packages/runtime-core/__tests__/components/BaseTransition.spec.ts b/packages/runtime-core/__tests__/components/BaseTransition.spec.ts
index 7c389fe1ede..3184c9c9c6a 100644
--- a/packages/runtime-core/__tests__/components/BaseTransition.spec.ts
+++ b/packages/runtime-core/__tests__/components/BaseTransition.spec.ts
@@ -7,6 +7,7 @@ import {
h,
nextTick,
nodeOps,
+ onUnmounted,
ref,
render,
serialize,
@@ -768,6 +769,42 @@ describe('BaseTransition', () => {
test('w/ KeepAlive', async () => {
await runTestWithKeepAlive(testOutIn)
})
+
+ test('w/ KeepAlive + unmount innerChild', async () => {
+ const unmountSpy = vi.fn()
+ const includeRef = ref(['TrueBranch'])
+ const trueComp = {
+ name: 'TrueBranch',
+ setup() {
+ onUnmounted(unmountSpy)
+ const count = ref(0)
+ return () => h('div', count.value)
+ },
+ }
+
+ const toggle = ref(true)
+ const { props } = mockProps({ mode: 'out-in' }, true /*withKeepAlive*/)
+ const root = nodeOps.createElement('div')
+ const App = {
+ render() {
+ return h(BaseTransition, props, () => {
+ return h(
+ KeepAlive,
+ { include: includeRef.value },
+ toggle.value ? h(trueComp) : h('div'),
+ )
+ })
+ },
+ }
+ render(h(App), root)
+
+ // trigger toggle
+ toggle.value = false
+ includeRef.value = []
+
+ await nextTick()
+ expect(unmountSpy).toHaveBeenCalledTimes(1)
+ })
})
// #6835
diff --git a/packages/runtime-core/src/components/KeepAlive.ts b/packages/runtime-core/src/components/KeepAlive.ts
index db6088cf5c6..7697096bcd7 100644
--- a/packages/runtime-core/src/components/KeepAlive.ts
+++ b/packages/runtime-core/src/components/KeepAlive.ts
@@ -254,7 +254,7 @@ const KeepAliveImpl: ComponentOptions = {
pendingCacheKey = null
if (!slots.default) {
- return null
+ return (current = null)
}
const children = slots.default()
From 37ba93c213a81f99a68a99ef5d4065d61b150ba3 Mon Sep 17 00:00:00 2001
From: Thimo Sietsma
Date: Mon, 15 Apr 2024 16:50:34 +0200
Subject: [PATCH 64/67] fix(types): avoid merging object union types when using
withDefaults (#10596)
close #10594
---
packages/dts-test/setupHelpers.test-d.ts | 35 ++++++++++++++++++++
packages/runtime-core/src/apiSetupHelpers.ts | 5 ++-
2 files changed, 39 insertions(+), 1 deletion(-)
diff --git a/packages/dts-test/setupHelpers.test-d.ts b/packages/dts-test/setupHelpers.test-d.ts
index c749e80a5c7..883ebe6b254 100644
--- a/packages/dts-test/setupHelpers.test-d.ts
+++ b/packages/dts-test/setupHelpers.test-d.ts
@@ -102,6 +102,41 @@ describe('defineProps w/ union type declaration + withDefaults', () => {
)
})
+describe('defineProps w/ object union + withDefaults', () => {
+ const props = withDefaults(
+ defineProps<
+ {
+ foo: string
+ } & (
+ | {
+ type: 'hello'
+ bar: string
+ }
+ | {
+ type: 'world'
+ bar: number
+ }
+ )
+ >(),
+ {
+ foo: 'default value!',
+ },
+ )
+
+ expectType<
+ | {
+ readonly type: 'hello'
+ readonly bar: string
+ readonly foo: string
+ }
+ | {
+ readonly type: 'world'
+ readonly bar: number
+ readonly foo: string
+ }
+ >(props)
+})
+
describe('defineProps w/ generic type declaration + withDefaults', = T extends undefined ? never : T
+type MappedOmit = {
+ [P in keyof T as P extends K ? never : P]: T[P]
+}
type InferDefaults = {
[K in keyof T]?: InferDefault
@@ -299,7 +302,7 @@ type PropsWithDefaults<
T,
Defaults extends InferDefaults,
BKeys extends keyof T,
-> = Readonly> & {
+> = Readonly> & {
readonly [K in keyof Defaults]-?: K extends keyof T
? Defaults[K] extends undefined
? T[K]
From 9da34d7af81607fddd1f32f21b3b4002402ff1cc Mon Sep 17 00:00:00 2001
From: Wick
Date: Mon, 15 Apr 2024 22:55:37 +0800
Subject: [PATCH 65/67] fix(reactivity): computed should not be detected as
true by isProxy (#10401)
---
.../reactivity/__tests__/reactive.spec.ts | 31 ++++++++++++++++++-
packages/reactivity/src/reactive.ts | 4 +--
2 files changed, 32 insertions(+), 3 deletions(-)
diff --git a/packages/reactivity/__tests__/reactive.spec.ts b/packages/reactivity/__tests__/reactive.spec.ts
index cdcd0325805..bd4ec402bb2 100644
--- a/packages/reactivity/__tests__/reactive.spec.ts
+++ b/packages/reactivity/__tests__/reactive.spec.ts
@@ -1,5 +1,14 @@
import { isRef, ref } from '../src/ref'
-import { isReactive, markRaw, reactive, toRaw } from '../src/reactive'
+import {
+ isProxy,
+ isReactive,
+ markRaw,
+ reactive,
+ readonly,
+ shallowReactive,
+ shallowReadonly,
+ toRaw,
+} from '../src/reactive'
import { computed } from '../src/computed'
import { effect } from '../src/effect'
@@ -330,4 +339,24 @@ describe('reactivity/reactive', () => {
delete obj[key]
expect(dummy).toBe(false)
})
+
+ test('isProxy', () => {
+ const foo = {}
+ expect(isProxy(foo)).toBe(false)
+
+ const fooRe = reactive(foo)
+ expect(isProxy(fooRe)).toBe(true)
+
+ const fooSRe = shallowReactive(foo)
+ expect(isProxy(fooSRe)).toBe(true)
+
+ const barRl = readonly(foo)
+ expect(isProxy(barRl)).toBe(true)
+
+ const barSRl = shallowReadonly(foo)
+ expect(isProxy(barSRl)).toBe(true)
+
+ const c = computed(() => {})
+ expect(isProxy(c)).toBe(false)
+ })
})
diff --git a/packages/reactivity/src/reactive.ts b/packages/reactivity/src/reactive.ts
index 7e80737fbcc..f6fcbbdb98f 100644
--- a/packages/reactivity/src/reactive.ts
+++ b/packages/reactivity/src/reactive.ts
@@ -329,8 +329,8 @@ export function isShallow(value: unknown): boolean {
* @param value - The value to check.
* @see {@link https://vuejs.org/api/reactivity-utilities.html#isproxy}
*/
-export function isProxy(value: unknown): boolean {
- return isReactive(value) || isReadonly(value)
+export function isProxy(value: any): boolean {
+ return value ? !!value[ReactiveFlags.RAW] : false
}
/**
From f26d56601ca0d2726ad4350e1ddb7b95fbb1c31a Mon Sep 17 00:00:00 2001
From: Evan You
Date: Mon, 15 Apr 2024 23:39:59 +0800
Subject: [PATCH 66/67] chore: improve event value validation message
---
packages/runtime-dom/__tests__/patchEvents.spec.ts | 5 ++---
packages/runtime-dom/src/modules/events.ts | 7 +++----
2 files changed, 5 insertions(+), 7 deletions(-)
diff --git a/packages/runtime-dom/__tests__/patchEvents.spec.ts b/packages/runtime-dom/__tests__/patchEvents.spec.ts
index b7a5af0ed0e..f70bf327aff 100644
--- a/packages/runtime-dom/__tests__/patchEvents.spec.ts
+++ b/packages/runtime-dom/__tests__/patchEvents.spec.ts
@@ -198,9 +198,8 @@ describe(`runtime-dom: events patching`, () => {
patchProp(el, 'onClick', null, 'test')
el.dispatchEvent(new Event('click'))
expect(
- '[Vue warn]: Wrong type passed to the event invoker, ' +
- 'did you maybe forget @ or : in front of your prop?' +
- '\nReceived onClick="test"',
+ `Wrong type passed as event handler to onClick - did you forget @ or : ` +
+ `in front of your prop?\nExpected function or array of functions, received type string.`,
).toHaveBeenWarned()
})
})
diff --git a/packages/runtime-dom/src/modules/events.ts b/packages/runtime-dom/src/modules/events.ts
index 09e4a22a84c..fd049a88f0d 100644
--- a/packages/runtime-dom/src/modules/events.ts
+++ b/packages/runtime-dom/src/modules/events.ts
@@ -1,4 +1,4 @@
-import { NOOP, hyphenate, isArray, isFunction, isString } from '@vue/shared'
+import { NOOP, hyphenate, isArray, isFunction } from '@vue/shared'
import {
type ComponentInternalInstance,
ErrorCodes,
@@ -129,9 +129,8 @@ function sanitizeEventValue(value: unknown, propName: string): EventValue {
return value as EventValue
}
warn(
- `Wrong type passed to the event invoker, did you maybe forget @ or : ` +
- `in front of your prop?\nReceived ` +
- `${propName}=${isString(value) ? JSON.stringify(value) : `[${typeof value}]`}`,
+ `Wrong type passed as event handler to ${propName} - did you forget @ or : ` +
+ `in front of your prop?\nExpected function or array of functions, received type ${typeof value}.`,
)
return NOOP
}
From b4b856b3f0ebe937eacb6945d13b2561037057b5 Mon Sep 17 00:00:00 2001
From: Evan You
Date: Mon, 15 Apr 2024 23:59:36 +0800
Subject: [PATCH 67/67] release: v3.4.22
---
CHANGELOG.md | 41 +++++++++++++++++++++++++++
package.json | 2 +-
packages/compiler-core/package.json | 2 +-
packages/compiler-dom/package.json | 2 +-
packages/compiler-sfc/package.json | 2 +-
packages/compiler-ssr/package.json | 2 +-
packages/reactivity/package.json | 2 +-
packages/runtime-core/package.json | 2 +-
packages/runtime-dom/package.json | 2 +-
packages/server-renderer/package.json | 2 +-
packages/shared/package.json | 2 +-
packages/vue-compat/package.json | 2 +-
packages/vue/package.json | 2 +-
13 files changed, 53 insertions(+), 12 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 28447dfe309..a0d590a5b8b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,44 @@
+## [3.4.22](https://github.com/vuejs/core/compare/v3.4.21...v3.4.22) (2024-04-15)
+
+
+### Bug Fixes
+
+* **compat:** fix $options mutation + adjust private API initialization ([d58d133](https://github.com/vuejs/core/commit/d58d133b1cde5085cc5ab0012d544cafd62a6ee6)), closes [#10626](https://github.com/vuejs/core/issues/10626) [#10636](https://github.com/vuejs/core/issues/10636)
+* **compile-sfc:** analyze v-bind shorthand usage in template ([#10518](https://github.com/vuejs/core/issues/10518)) ([e5919d4](https://github.com/vuejs/core/commit/e5919d4658cfe0bb18c76611dd3c3432c57f94ab)), closes [#10515](https://github.com/vuejs/core/issues/10515)
+* **compiler-core:** fix loc.source for end tags with whitespace before > ([16174da](https://github.com/vuejs/core/commit/16174da21d6c8ac0aae027dd964fc35e221ded0a)), closes [#10694](https://github.com/vuejs/core/issues/10694) [#10695](https://github.com/vuejs/core/issues/10695)
+* **compiler-core:** fix v-bind shorthand for component :is ([04af950](https://github.com/vuejs/core/commit/04af9504a720c8e6de26c04b1282cf14fa1bcee3)), closes [#10469](https://github.com/vuejs/core/issues/10469) [#10471](https://github.com/vuejs/core/issues/10471)
+* **compiler-sfc:** :is() and :where() in compound selectors ([#10522](https://github.com/vuejs/core/issues/10522)) ([660cadc](https://github.com/vuejs/core/commit/660cadc7aadb909ef33a6055c4374902a82607a4)), closes [#10511](https://github.com/vuejs/core/issues/10511)
+* **compiler-sfc:** also search for `.tsx` when type import's extension is omitted ([#10637](https://github.com/vuejs/core/issues/10637)) ([34106bc](https://github.com/vuejs/core/commit/34106bc9c715247211273bb9c64712f04bd4879d)), closes [#10635](https://github.com/vuejs/core/issues/10635)
+* **compiler-sfc:** fix defineModel coercion for boolean + string union types ([#9603](https://github.com/vuejs/core/issues/9603)) ([0cef65c](https://github.com/vuejs/core/commit/0cef65cee411356e721bbc90d731fc52fc8fce94)), closes [#9587](https://github.com/vuejs/core/issues/9587) [#10676](https://github.com/vuejs/core/issues/10676)
+* **compiler-sfc:** fix universal selector scope ([#10551](https://github.com/vuejs/core/issues/10551)) ([54a6afa](https://github.com/vuejs/core/commit/54a6afa75a546078e901ce0882da53b97420fe94)), closes [#10548](https://github.com/vuejs/core/issues/10548)
+* **compiler-sfc:** use options module name if options provide runtimeModuleName options ([#10457](https://github.com/vuejs/core/issues/10457)) ([e76d743](https://github.com/vuejs/core/commit/e76d7430aa7470342f3fe263145a0fa92f5898ca)), closes [#10454](https://github.com/vuejs/core/issues/10454)
+* **custom-element:** avoid setting attr to null if it is removed ([#9012](https://github.com/vuejs/core/issues/9012)) ([b49306a](https://github.com/vuejs/core/commit/b49306adff4572d90a42ccd231387f16eb966bbe)), closes [#9006](https://github.com/vuejs/core/issues/9006) [#10324](https://github.com/vuejs/core/issues/10324)
+* **hydration:** properly handle optimized mode during hydrate node ([#10638](https://github.com/vuejs/core/issues/10638)) ([2ec06fd](https://github.com/vuejs/core/commit/2ec06fd6c8383e11cdf4efcab1707f973bd6a54c)), closes [#10607](https://github.com/vuejs/core/issues/10607)
+* **reactivity:** computed should not be detected as true by isProxy ([#10401](https://github.com/vuejs/core/issues/10401)) ([9da34d7](https://github.com/vuejs/core/commit/9da34d7af81607fddd1f32f21b3b4002402ff1cc))
+* **reactivity:** fix hasOwnProperty key coercion edge cases ([969c5fb](https://github.com/vuejs/core/commit/969c5fb30f4c725757c7385abfc74772514eae4b))
+* **reactivity:** fix tracking when hasOwnProperty is called with non-string value ([c3c5dc9](https://github.com/vuejs/core/commit/c3c5dc93fbccc196771458f0b43cd5b7ad1863f4)), closes [#10455](https://github.com/vuejs/core/issues/10455) [#10464](https://github.com/vuejs/core/issues/10464)
+* **runtime-core:** fix errorHandler causes an infinite loop during execution ([#9575](https://github.com/vuejs/core/issues/9575)) ([ab59bed](https://github.com/vuejs/core/commit/ab59bedae4e5e40b28804d88a51305b236d4a873))
+* **runtime-core:** handle invalid values in callWithAsyncErrorHandling ([53d15d3](https://github.com/vuejs/core/commit/53d15d3f76184eed67a18d35e43d9a2062f8e121))
+* **runtime-core:** show hydration mismatch details for non-rectified mismatches too when __PROD_HYDRATION_MISMATCH_DETAILS__ is set ([#10599](https://github.com/vuejs/core/issues/10599)) ([0dea7f9](https://github.com/vuejs/core/commit/0dea7f9a260d93eb6c39aabac8c94c2c9b2042dd))
+* **runtime-dom:** `v-model` string/number coercion for multiselect options ([#10576](https://github.com/vuejs/core/issues/10576)) ([db374e5](https://github.com/vuejs/core/commit/db374e54c9f5e07324728b85c74eca84e28dd352))
+* **runtime-dom:** fix css v-bind for suspensed components ([#8523](https://github.com/vuejs/core/issues/8523)) ([67722ba](https://github.com/vuejs/core/commit/67722ba23b7c36ab8f3fa2d2b4df08e4ddc322e1)), closes [#8520](https://github.com/vuejs/core/issues/8520)
+* **runtime-dom:** force update v-model number with leading 0 ([#10506](https://github.com/vuejs/core/issues/10506)) ([15ffe8f](https://github.com/vuejs/core/commit/15ffe8f2c954359770c57e4d9e589b0b622e4a60)), closes [#10503](https://github.com/vuejs/core/issues/10503) [#10615](https://github.com/vuejs/core/issues/10615)
+* **runtime-dom:** sanitize wrongly passed string value as event handler ([#8953](https://github.com/vuejs/core/issues/8953)) ([7ccd453](https://github.com/vuejs/core/commit/7ccd453dd004076cad49ec9f56cd5fe97b7b6ed8)), closes [#8818](https://github.com/vuejs/core/issues/8818)
+* **ssr:** don't render v-if comments in TransitionGroup ([#6732](https://github.com/vuejs/core/issues/6732)) ([5a96267](https://github.com/vuejs/core/commit/5a9626708e970c6fc0b6f786e3c80c22273d126f)), closes [#6715](https://github.com/vuejs/core/issues/6715)
+* **Transition:** ensure the KeepAlive children unmount w/ out-in mode ([#10632](https://github.com/vuejs/core/issues/10632)) ([fc99e4d](https://github.com/vuejs/core/commit/fc99e4d3f01b190ef9fd3c218a668ba9124a32bc)), closes [#10620](https://github.com/vuejs/core/issues/10620)
+* **TransitionGroup:** avoid set transition hooks for comment nodes and text nodes ([#9421](https://github.com/vuejs/core/issues/9421)) ([140a768](https://github.com/vuejs/core/commit/140a7681cc3bba22f55d97fd85a5eafe97a1230f)), closes [#4621](https://github.com/vuejs/core/issues/4621) [#4622](https://github.com/vuejs/core/issues/4622) [#5153](https://github.com/vuejs/core/issues/5153) [#5168](https://github.com/vuejs/core/issues/5168) [#7898](https://github.com/vuejs/core/issues/7898) [#9067](https://github.com/vuejs/core/issues/9067)
+* **types:** avoid merging object union types when using withDefaults ([#10596](https://github.com/vuejs/core/issues/10596)) ([37ba93c](https://github.com/vuejs/core/commit/37ba93c213a81f99a68a99ef5d4065d61b150ba3)), closes [#10594](https://github.com/vuejs/core/issues/10594)
+
+
+### Performance Improvements
+
+* add `__NO_SIDE_EFFECTS__` comments ([#9053](https://github.com/vuejs/core/issues/9053)) ([d46df6b](https://github.com/vuejs/core/commit/d46df6bdb14b0509eb2134b3f85297a306821c61))
+* optimize component props/slots internal object checks ([6af733d](https://github.com/vuejs/core/commit/6af733d68eb400a3d2c5ef5f465fff32b72a324e))
+* **ssr:** avoid calling markRaw on component instance proxy ([4bc9f39](https://github.com/vuejs/core/commit/4bc9f39f028af7313e5cf24c16915a1985d27bf8))
+* **ssr:** optimize setup context creation for ssr in v8 ([ca84316](https://github.com/vuejs/core/commit/ca84316bfb3410efe21333670a6ad5cd21857396))
+
+
+
## [3.4.21](https://github.com/vuejs/core/compare/v3.4.20...v3.4.21) (2024-02-28)
diff --git a/package.json b/package.json
index 2c8ba0b817c..acb12ffc926 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"private": true,
- "version": "3.4.21",
+ "version": "3.4.22",
"packageManager": "pnpm@8.15.6",
"type": "module",
"scripts": {
diff --git a/packages/compiler-core/package.json b/packages/compiler-core/package.json
index 6ffa0aa2197..19d0a416a98 100644
--- a/packages/compiler-core/package.json
+++ b/packages/compiler-core/package.json
@@ -1,6 +1,6 @@
{
"name": "@vue/compiler-core",
- "version": "3.4.21",
+ "version": "3.4.22",
"description": "@vue/compiler-core",
"main": "index.js",
"module": "dist/compiler-core.esm-bundler.js",
diff --git a/packages/compiler-dom/package.json b/packages/compiler-dom/package.json
index f6d90554deb..3826fb2c60c 100644
--- a/packages/compiler-dom/package.json
+++ b/packages/compiler-dom/package.json
@@ -1,6 +1,6 @@
{
"name": "@vue/compiler-dom",
- "version": "3.4.21",
+ "version": "3.4.22",
"description": "@vue/compiler-dom",
"main": "index.js",
"module": "dist/compiler-dom.esm-bundler.js",
diff --git a/packages/compiler-sfc/package.json b/packages/compiler-sfc/package.json
index d1c7b5419bb..9e732550000 100644
--- a/packages/compiler-sfc/package.json
+++ b/packages/compiler-sfc/package.json
@@ -1,6 +1,6 @@
{
"name": "@vue/compiler-sfc",
- "version": "3.4.21",
+ "version": "3.4.22",
"description": "@vue/compiler-sfc",
"main": "dist/compiler-sfc.cjs.js",
"module": "dist/compiler-sfc.esm-browser.js",
diff --git a/packages/compiler-ssr/package.json b/packages/compiler-ssr/package.json
index 700690be3e7..6e9648f5400 100644
--- a/packages/compiler-ssr/package.json
+++ b/packages/compiler-ssr/package.json
@@ -1,6 +1,6 @@
{
"name": "@vue/compiler-ssr",
- "version": "3.4.21",
+ "version": "3.4.22",
"description": "@vue/compiler-ssr",
"main": "dist/compiler-ssr.cjs.js",
"types": "dist/compiler-ssr.d.ts",
diff --git a/packages/reactivity/package.json b/packages/reactivity/package.json
index caccbc25ac3..414083ef6f1 100644
--- a/packages/reactivity/package.json
+++ b/packages/reactivity/package.json
@@ -1,6 +1,6 @@
{
"name": "@vue/reactivity",
- "version": "3.4.21",
+ "version": "3.4.22",
"description": "@vue/reactivity",
"main": "index.js",
"module": "dist/reactivity.esm-bundler.js",
diff --git a/packages/runtime-core/package.json b/packages/runtime-core/package.json
index 7171aa3d48e..8edddcc32c8 100644
--- a/packages/runtime-core/package.json
+++ b/packages/runtime-core/package.json
@@ -1,6 +1,6 @@
{
"name": "@vue/runtime-core",
- "version": "3.4.21",
+ "version": "3.4.22",
"description": "@vue/runtime-core",
"main": "index.js",
"module": "dist/runtime-core.esm-bundler.js",
diff --git a/packages/runtime-dom/package.json b/packages/runtime-dom/package.json
index 12ffce6d216..17712da8eed 100644
--- a/packages/runtime-dom/package.json
+++ b/packages/runtime-dom/package.json
@@ -1,6 +1,6 @@
{
"name": "@vue/runtime-dom",
- "version": "3.4.21",
+ "version": "3.4.22",
"description": "@vue/runtime-dom",
"main": "index.js",
"module": "dist/runtime-dom.esm-bundler.js",
diff --git a/packages/server-renderer/package.json b/packages/server-renderer/package.json
index 91015f51561..8cd53da98b5 100644
--- a/packages/server-renderer/package.json
+++ b/packages/server-renderer/package.json
@@ -1,6 +1,6 @@
{
"name": "@vue/server-renderer",
- "version": "3.4.21",
+ "version": "3.4.22",
"description": "@vue/server-renderer",
"main": "index.js",
"module": "dist/server-renderer.esm-bundler.js",
diff --git a/packages/shared/package.json b/packages/shared/package.json
index 2683c4ac810..a227ded9ecb 100644
--- a/packages/shared/package.json
+++ b/packages/shared/package.json
@@ -1,6 +1,6 @@
{
"name": "@vue/shared",
- "version": "3.4.21",
+ "version": "3.4.22",
"description": "internal utils shared across @vue packages",
"main": "index.js",
"module": "dist/shared.esm-bundler.js",
diff --git a/packages/vue-compat/package.json b/packages/vue-compat/package.json
index 7091e9a5761..4c5dd04e3cc 100644
--- a/packages/vue-compat/package.json
+++ b/packages/vue-compat/package.json
@@ -1,6 +1,6 @@
{
"name": "@vue/compat",
- "version": "3.4.21",
+ "version": "3.4.22",
"description": "Vue 3 compatibility build for Vue 2",
"main": "index.js",
"module": "dist/vue.runtime.esm-bundler.js",
diff --git a/packages/vue/package.json b/packages/vue/package.json
index 95a75640e94..1a297293d06 100644
--- a/packages/vue/package.json
+++ b/packages/vue/package.json
@@ -1,6 +1,6 @@
{
"name": "vue",
- "version": "3.4.21",
+ "version": "3.4.22",
"description": "The progressive JavaScript framework for building modern web UI.",
"main": "index.js",
"module": "dist/vue.runtime.esm-bundler.js",