Skip to content

Commit fe0c915

Browse files
committed
chore: Merge branch 'main' into minor
2 parents 1cc4870 + 7df0edd commit fe0c915

20 files changed

Lines changed: 1797 additions & 1115 deletions

File tree

changelogs/CHANGELOG-3.0.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@
132132
- **runtime-dom:** ensure readonly type prop on textarea is handled patched as attribute ([#2888](https://github.com/vuejs/core/issues/2888)) ([c5d147c](https://github.com/vuejs/core/commit/c5d147c57f75ca38cc334bb27b61a8bc153494bd)), closes [#2766](https://github.com/vuejs/core/issues/2766)
133133
- kebab-case events are attached correctly on web components, see [#2841](https://github.com/vuejs/core/issues/2841) ([#2847](https://github.com/vuejs/core/issues/2847)) ([b302cbb](https://github.com/vuejs/core/commit/b302cbbbd3fd512f2b8afbd9c873060a40bf8e62))
134134
- **types:** extract the correct props type for the DateConstructor ([#2676](https://github.com/vuejs/core/issues/2676)) ([48f0d29](https://github.com/vuejs/core/commit/48f0d2944f0f9d2f556e62782fc61985897b2ed4))
135-
- ensure all published packages contan a LICENCE file (close [#2650](https://github.com/vuejs/core/issues/2650)) ([#2857](https://github.com/vuejs/core/issues/2857)) ([6a48d23](https://github.com/vuejs/core/commit/6a48d23749e418b44ba17cd3e85f478484fd7ffe))
135+
- ensure all published packages contain a LICENCE file (close [#2650](https://github.com/vuejs/core/issues/2650)) ([#2857](https://github.com/vuejs/core/issues/2857)) ([6a48d23](https://github.com/vuejs/core/commit/6a48d23749e418b44ba17cd3e85f478484fd7ffe))
136136
- remove superfluous spaces when normalizing class ([#3083](https://github.com/vuejs/core/issues/3083)) ([4b55142](https://github.com/vuejs/core/commit/4b551420fc058c4683219db5d75893f9fc69aa04))
137137
- **runtime-dom:** enable set form attr to null on form-elements ([#2840](https://github.com/vuejs/core/issues/2840)) ([#2849](https://github.com/vuejs/core/issues/2849)) ([f262438](https://github.com/vuejs/core/commit/f2624380731cc32e71523e8c2c98037e98e09319))
138138
- **toRef:** ref created from union typed prop can't be used in watch ([#3048](https://github.com/vuejs/core/issues/3048)) ([4ca4666](https://github.com/vuejs/core/commit/4ca4666d58ee8025570dc14f1c163bdeac9c6012))

changelogs/CHANGELOG-3.1.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
- **compiler-sfc:** support method signature in defineProps ([afdd2f2](https://github.com/vuejs/core/commit/afdd2f28354ce8cea647279ed25d61e7b9946cf5)), closes [#2983](https://github.com/vuejs/core/issues/2983)
4646
- **compiler-sfc:** support TS runtime enum in `<script setup>` ([1ffd48a](https://github.com/vuejs/core/commit/1ffd48a2f5fd3eead3ea29dae668b7ed1c6f6130))
4747
- **runtime-core:** add missing serverPrefetch hook error string ([#4014](https://github.com/vuejs/core/issues/4014)) ([d069796](https://github.com/vuejs/core/commit/d069796b8f0cf8df9aa77d781c4b5429b9411204))
48-
- **runtime-core:** fix mouting of detached static vnode ([fded1e8](https://github.com/vuejs/core/commit/fded1e8dfa22ca7fecd300c4cbffd6a37b887be8)), closes [#4023](https://github.com/vuejs/core/issues/4023)
48+
- **runtime-core:** fix mounting of detached static vnode ([fded1e8](https://github.com/vuejs/core/commit/fded1e8dfa22ca7fecd300c4cbffd6a37b887be8)), closes [#4023](https://github.com/vuejs/core/issues/4023)
4949
- **runtime-dom:** fix static node content caching edge cases ([ba89ca9](https://github.com/vuejs/core/commit/ba89ca9ecafe86292e3adf751671ed5e9ca6e928)), closes [#4023](https://github.com/vuejs/core/issues/4023) [#4031](https://github.com/vuejs/core/issues/4031) [#4037](https://github.com/vuejs/core/issues/4037)
5050
- **sfc:** allow variables that start with \_ or $ in `<script setup>` ([0b8b576](https://github.com/vuejs/core/commit/0b8b5764287b4814a37034ad4bc6f2b8ac8f8700))
5151
- **ssr:** ensure behavior consistency between prod/dev when mounting SSR app to empty containers ([33708e8](https://github.com/vuejs/core/commit/33708e8bf44a037070af5c8eabdfe1ccad22bbc2)), closes [#4034](https://github.com/vuejs/core/issues/4034)

changelogs/CHANGELOG-3.5.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
1+
## [3.5.32](https://github.com/vuejs/core/compare/v3.5.31...v3.5.32) (2026-04-03)
2+
3+
4+
### Bug Fixes
5+
6+
* **runtime-core:** prevent currentInstance leak into sibling render during async setup re-entry ([#14668](https://github.com/vuejs/core/issues/14668)) ([f166353](https://github.com/vuejs/core/commit/f1663535a163057788d3285dec54a245c3efb3ad)), closes [#14667](https://github.com/vuejs/core/issues/14667)
7+
* **teleport:** handle updates before deferred mount ([#14642](https://github.com/vuejs/core/issues/14642)) ([32b44f1](https://github.com/vuejs/core/commit/32b44f19f67aa30899817a7e79a4510f3b52970a)), closes [#14640](https://github.com/vuejs/core/issues/14640)
8+
* **types:** allow customRef to have different getter/setter types ([#14639](https://github.com/vuejs/core/issues/14639)) ([e20ddb0](https://github.com/vuejs/core/commit/e20ddb00188e9935884930046fa572eab7c9dcba))
9+
* **types:** use private branding for shallowReactive ([#14641](https://github.com/vuejs/core/issues/14641)) ([302c47a](https://github.com/vuejs/core/commit/302c47a4994bc8b47b8a2af6693d8cb6bbd4b06b)), closes [#14638](https://github.com/vuejs/core/issues/14638) [#14493](https://github.com/vuejs/core/issues/14493)
10+
11+
12+
### Reverts
13+
14+
* Revert "fix(server-renderer): cleanup component effect scopes after SSR render" (#14674) ([219d83b](https://github.com/vuejs/core/commit/219d83bd305ce6fc052941acaaf02e7bc70616a4)), closes [#14674](https://github.com/vuejs/core/issues/14674) [#14669](https://github.com/vuejs/core/issues/14669)
15+
16+
17+
118
## [3.5.31](https://github.com/vuejs/core/compare/v3.5.30...v3.5.31) (2026-03-25)
219

320

package.json

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"private": true,
33
"version": "3.6.0-beta.9",
4-
"packageManager": "pnpm@10.28.2",
4+
"packageManager": "pnpm@10.33.0",
55
"type": "module",
66
"scripts": {
77
"dev": "node scripts/dev.js",
@@ -53,17 +53,18 @@
5353
"@babel/types": "catalog:",
5454
"@rolldown/plugin-node-polyfills": "^1.0.3",
5555
"@types/hash-sum": "^1.0.2",
56-
"@types/node": "^24.12.0",
56+
"@types/node": "^24.12.2",
5757
"@types/semver": "^7.7.1",
5858
"@types/serve-handler": "^6.1.4",
59-
"@vitest/coverage-v8": "^4.1.1",
60-
"@vitest/ui": "^4.1.1",
59+
"@vitest/coverage-v8": "^4.1.3",
60+
"@vitest/ui": "^4.1.3",
6161
"@vue/consolidate": "1.0.0",
62-
"conventional-changelog-cli": "^5.0.0",
62+
"conventional-changelog": "^7.2.0",
63+
"conventional-changelog-angular": "^8.3.1",
6364
"enquirer": "^2.4.1",
6465
"estree-walker": "catalog:",
6566
"fast-glob": "^3.3.2",
66-
"jsdom": "^29.0.1",
67+
"jsdom": "^29.0.2",
6768
"lodash": "^4.17.23",
6869
"magic-string": "^0.30.21",
6970
"markdown-table": "^3.0.4",
@@ -88,6 +89,6 @@
8889
"typescript": "~5.6.2",
8990
"vite": "catalog:",
9091
"vitest": "npm:@voidzero-dev/vite-plus-test@latest",
91-
"vite-plus": "^0.1.9"
92+
"vite-plus": "^0.1.16"
9293
}
9394
}

packages-private/benchmark/client/profiling.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
/* oxlint-disable no-console */
2-
/* oxlint-disable no-restricted-syntax */
32
/* oxlint-disable no-restricted-globals */
43
import { nextTick } from 'vue'
54

packages-private/dts-test/reactivity.test-d.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,3 +140,9 @@ describe('shallowReactive marker should not leak into value unions', () => {
140140
const value = {} as (typeof state)[keyof typeof state]
141141
expectType<string>(value.title)
142142
})
143+
144+
describe('shallowReactive type should accept plain object assignment', () => {
145+
const shallow = shallowReactive({ a: 1, b: 2 })
146+
let values: typeof shallow
147+
values = { a: 1, b: 2 }
148+
})

packages-private/dts-test/ref.test-d.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
type ToRefs,
99
type WritableComputedRef,
1010
computed,
11+
customRef,
1112
isRef,
1213
proxyRefs,
1314
reactive,
@@ -320,6 +321,12 @@ expectType<undefined>(p2.u)
320321
expectType<Ref<string>>(p2.obj.k)
321322
expectType<{ name: string } | null>(p2.union)
322323

324+
const r3 = shallowReactive({
325+
n: ref(1),
326+
})
327+
const p3 = proxyRefs(r3)
328+
expectType<Ref<number>>(p3.n)
329+
323330
// toRef and toRefs
324331
{
325332
const obj: {
@@ -436,6 +443,15 @@ describe('shallow reactive in reactive', () => {
436443
expectType<number>(foo.value.a.b.value)
437444
})
438445

446+
describe('shallow reactive collection in reactive', () => {
447+
const baz = reactive({
448+
foo: shallowReactive(new Map([['a', ref(42)]])),
449+
})
450+
451+
const foo = toRef(baz, 'foo')
452+
expectType<Ref<number> | undefined>(foo.value.get('a'))
453+
})
454+
439455
describe('shallow ref in reactive', () => {
440456
const x = reactive({
441457
foo: shallowRef({
@@ -548,3 +564,22 @@ expectType<TemplateRef>(tRef)
548564

549565
const tRef2 = useTemplateRef<HTMLElement>('bar')
550566
expectType<TemplateRef<HTMLElement>>(tRef2)
567+
568+
// #14637 customRef with different getter/setter types
569+
describe('customRef with different getter/setter types', () => {
570+
// customRef should support different getter/setter types like Ref<T, S>
571+
const cr = customRef<string, number>((track, trigger) => ({
572+
get: () => 'hello',
573+
set: (val: number) => {
574+
// setter accepts number, getter returns string
575+
trigger()
576+
},
577+
}))
578+
579+
// getter returns string
580+
expectType<string>(cr.value)
581+
// setter accepts number
582+
cr.value = 123
583+
// @ts-expect-error setter doesn't accept string
584+
cr.value = 'world'
585+
})

packages/compiler-sfc/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
"hash-sum": "^2.0.0",
6060
"lru-cache": "10.1.0",
6161
"merge-source-map": "^1.1.0",
62-
"minimatch": "~10.2.4",
62+
"minimatch": "~10.2.5",
6363
"postcss-modules": "^6.0.1",
6464
"postcss-selector-parser": "^7.1.1",
6565
"pug": "^3.0.4",

packages/reactivity/src/reactive.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,16 @@ export function reactive(target: object) {
104104
)
105105
}
106106

107-
export declare const ShallowReactiveMarker: unique symbol
107+
// Use a private class brand instead of a marker property so shallow-reactive
108+
// types remain distinguishable in `UnwrapRef` without leaking the brand into
109+
// `keyof`/indexed access types or requiring the property for plain assignment.
110+
declare class ShallowReactiveBrandClass {
111+
private __shallowReactiveBrand?: never
112+
}
113+
114+
export type ShallowReactiveBrand = ShallowReactiveBrandClass
108115

109-
export type ShallowReactive<T> = T & { [ShallowReactiveMarker]: never }
116+
export type ShallowReactive<T> = T & ShallowReactiveBrand
110117

111118
/**
112119
* Shallow version of {@link reactive}.

packages/reactivity/src/ref.ts

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { onTrack, triggerEventInfos } from './debug'
1313
import { getDepFromReactive } from './dep'
1414
import {
1515
type Builtin,
16-
type ShallowReactiveMarker,
16+
type ShallowReactiveBrand,
1717
type Target,
1818
isProxy,
1919
isReactive,
@@ -335,27 +335,27 @@ export function proxyRefs<T extends object>(
335335
: new Proxy(objectWithRefs, shallowUnwrapHandlers)
336336
}
337337

338-
export type CustomRefFactory<T> = (
338+
export type CustomRefFactory<T, S = T> = (
339339
track: () => void,
340340
trigger: () => void,
341341
) => {
342342
get: () => T
343-
set: (value: T) => void
343+
set: (value: S) => void
344344
}
345345

346-
class CustomRefImpl<T> implements ReactiveNode {
346+
class CustomRefImpl<T, S = T> implements ReactiveNode {
347347
subs: Link | undefined = undefined
348348
subsTail: Link | undefined = undefined
349349
flags: _ReactiveFlags = _ReactiveFlags.None
350350

351-
private readonly _get: ReturnType<CustomRefFactory<T>>['get']
352-
private readonly _set: ReturnType<CustomRefFactory<T>>['set']
351+
private readonly _get: ReturnType<CustomRefFactory<T, S>>['get']
352+
private readonly _set: ReturnType<CustomRefFactory<T, S>>['set']
353353

354354
public readonly [ReactiveFlags.IS_REF] = true
355355

356356
public _value: T = undefined!
357357

358-
constructor(factory: CustomRefFactory<T>) {
358+
constructor(factory: CustomRefFactory<T, S>) {
359359
const { get, set } = factory(
360360
() => trackRef(this),
361361
() => triggerRef(this as unknown as Ref),
@@ -368,11 +368,11 @@ class CustomRefImpl<T> implements ReactiveNode {
368368
return this
369369
}
370370

371-
get value() {
371+
get value(): T {
372372
return (this._value = this._get())
373373
}
374374

375-
set value(newVal) {
375+
set value(newVal: S) {
376376
this._set(newVal)
377377
}
378378
}
@@ -384,7 +384,9 @@ class CustomRefImpl<T> implements ReactiveNode {
384384
* @param factory - The function that receives the `track` and `trigger` callbacks.
385385
* @see {@link https://vuejs.org/api/reactivity-advanced.html#customref}
386386
*/
387-
export function customRef<T>(factory: CustomRefFactory<T>): Ref<T> {
387+
export function customRef<T, S = T>(
388+
factory: CustomRefFactory<T, S>,
389+
): Ref<T, S> {
388390
return new CustomRefImpl(factory) as any
389391
}
390392

@@ -592,9 +594,11 @@ function propertyToRef(
592594
*/
593595
export interface RefUnwrapBailTypes {}
594596

595-
export type ShallowUnwrapRef<T> = {
596-
[K in keyof T]: DistributeRef<T[K]>
597-
}
597+
export type ShallowUnwrapRef<T> = T extends ShallowReactiveBrand
598+
? T
599+
: {
600+
[K in keyof T]: DistributeRef<T[K]>
601+
}
598602

599603
type DistributeRef<T> = T extends Ref<infer V, unknown> ? V : T
600604

@@ -611,19 +615,20 @@ export type UnwrapRefSimple<T> = T extends
611615
| RefUnwrapBailTypes[keyof RefUnwrapBailTypes]
612616
| { [RawSymbol]?: true }
613617
? T
614-
: T extends Map<infer K, infer V>
615-
? Map<K, UnwrapRefSimple<V>> & UnwrapRef<Omit<T, keyof Map<any, any>>>
616-
: T extends WeakMap<infer K, infer V>
617-
? WeakMap<K, UnwrapRefSimple<V>> &
618-
UnwrapRef<Omit<T, keyof WeakMap<any, any>>>
619-
: T extends Set<infer V>
620-
? Set<UnwrapRefSimple<V>> & UnwrapRef<Omit<T, keyof Set<any>>>
621-
: T extends WeakSet<infer V>
622-
? WeakSet<UnwrapRefSimple<V>> & UnwrapRef<Omit<T, keyof WeakSet<any>>>
623-
: T extends ReadonlyArray<any>
624-
? { [K in keyof T]: UnwrapRefSimple<T[K]> }
625-
: T extends object & { [ShallowReactiveMarker]: never }
626-
? T
618+
: T extends ShallowReactiveBrand
619+
? T
620+
: T extends Map<infer K, infer V>
621+
? Map<K, UnwrapRefSimple<V>> & UnwrapRef<Omit<T, keyof Map<any, any>>>
622+
: T extends WeakMap<infer K, infer V>
623+
? WeakMap<K, UnwrapRefSimple<V>> &
624+
UnwrapRef<Omit<T, keyof WeakMap<any, any>>>
625+
: T extends Set<infer V>
626+
? Set<UnwrapRefSimple<V>> & UnwrapRef<Omit<T, keyof Set<any>>>
627+
: T extends WeakSet<infer V>
628+
? WeakSet<UnwrapRefSimple<V>> &
629+
UnwrapRef<Omit<T, keyof WeakSet<any>>>
630+
: T extends ReadonlyArray<any>
631+
? { [K in keyof T]: UnwrapRefSimple<T[K]> }
627632
: T extends object
628633
? {
629634
[P in keyof T]: P extends symbol ? T[P] : UnwrapRef<T[P]>

0 commit comments

Comments
 (0)