', () => {
}"
`)
})
+
+ test('inside transition-group', () => {
+ const { code } = compile(
+ ``,
+ )
+ expect(code).toMatch(ssrHelpers[SSR_RENDER_SLOT_INNER])
+ expect(code).toMatchInlineSnapshot(`
+ "const { ssrRenderSlotInner: _ssrRenderSlotInner, ssrRenderAttrs: _ssrRenderAttrs } = require("vue/server-renderer")
+
+ return function ssrRender(_ctx, _push, _parent, _attrs) {
+ _push(\`\`)
+ _ssrRenderSlotInner(_ctx.$slots, "default", {}, null, _push, _parent, null, true)
+ _push(\`
\`)
+ }"
+ `)
+ })
})
diff --git a/packages/compiler-ssr/package.json b/packages/compiler-ssr/package.json
index 211504c7a9b..7dd9f551f1f 100644
--- a/packages/compiler-ssr/package.json
+++ b/packages/compiler-ssr/package.json
@@ -1,6 +1,6 @@
{
"name": "@vue/compiler-ssr",
- "version": "3.4.1",
+ "version": "3.4.2",
"description": "@vue/compiler-ssr",
"main": "dist/compiler-ssr.cjs.js",
"types": "dist/compiler-ssr.d.ts",
diff --git a/packages/compiler-ssr/src/transforms/ssrTransformSlotOutlet.ts b/packages/compiler-ssr/src/transforms/ssrTransformSlotOutlet.ts
index b75b4d03366..ad08a23a445 100644
--- a/packages/compiler-ssr/src/transforms/ssrTransformSlotOutlet.ts
+++ b/packages/compiler-ssr/src/transforms/ssrTransformSlotOutlet.ts
@@ -4,6 +4,7 @@ import {
NodeTypes,
type SlotOutletNode,
TRANSITION,
+ TRANSITION_GROUP,
createCallExpression,
createFunctionExpression,
isSlotOutlet,
@@ -37,16 +38,19 @@ export const ssrTransformSlotOutlet: NodeTransform = (node, context) => {
let method = SSR_RENDER_SLOT
- // #3989
+ // #3989, #9933
// check if this is a single slot inside a transition wrapper - since
- // transition will unwrap the slot fragment into a single vnode at runtime,
+ // transition/transition-group will unwrap the slot fragment into vnode(s) at runtime,
// we need to avoid rendering the slot as a fragment.
const parent = context.parent
+ let componentType
if (
parent &&
parent.type === NodeTypes.ELEMENT &&
parent.tagType === ElementTypes.COMPONENT &&
- resolveComponentType(parent, context, true) === TRANSITION &&
+ ((componentType = resolveComponentType(parent, context, true)) ===
+ TRANSITION ||
+ componentType === TRANSITION_GROUP) &&
parent.children.filter(c => c.type === NodeTypes.ELEMENT).length === 1
) {
method = SSR_RENDER_SLOT_INNER
diff --git a/packages/reactivity/package.json b/packages/reactivity/package.json
index acc43e932d6..d903c9edf35 100644
--- a/packages/reactivity/package.json
+++ b/packages/reactivity/package.json
@@ -1,6 +1,6 @@
{
"name": "@vue/reactivity",
- "version": "3.4.1",
+ "version": "3.4.2",
"description": "@vue/reactivity",
"main": "index.js",
"module": "dist/reactivity.esm-bundler.js",
diff --git a/packages/runtime-core/__tests__/apiWatch.spec.ts b/packages/runtime-core/__tests__/apiWatch.spec.ts
index 3bc614ef9b7..b25635e664e 100644
--- a/packages/runtime-core/__tests__/apiWatch.spec.ts
+++ b/packages/runtime-core/__tests__/apiWatch.spec.ts
@@ -25,9 +25,11 @@ import {
type DebuggerEvent,
ITERATE_KEY,
type Ref,
+ type ShallowRef,
TrackOpTypes,
TriggerOpTypes,
effectScope,
+ shallowReactive,
shallowRef,
toRef,
triggerRef,
@@ -156,6 +158,59 @@ describe('api: watch', () => {
expect(dummy).toBe(1)
})
+ it('directly watching reactive object with explicit deep: false', async () => {
+ const src = reactive({
+ state: {
+ count: 0,
+ },
+ })
+ let dummy
+ watch(
+ src,
+ ({ state }) => {
+ dummy = state?.count
+ },
+ {
+ deep: false,
+ },
+ )
+
+ // nested should not trigger
+ src.state.count++
+ await nextTick()
+ expect(dummy).toBe(undefined)
+
+ // root level should trigger
+ src.state = { count: 1 }
+ await nextTick()
+ expect(dummy).toBe(1)
+ })
+
+ // #9916
+ it('directly watching shallow reactive array', async () => {
+ class foo {
+ prop1: ShallowRef = shallowRef('')
+ prop2: string = ''
+ }
+
+ const obj1 = new foo()
+ const obj2 = new foo()
+
+ const collection = shallowReactive([obj1, obj2])
+ const cb = vi.fn()
+ watch(collection, cb)
+
+ collection[0].prop1.value = 'foo'
+ await nextTick()
+ // should not trigger
+ expect(cb).toBeCalledTimes(0)
+
+ collection.push(new foo())
+ await nextTick()
+ // should trigger on array self mutation
+ expect(cb).toBeCalledTimes(1)
+ })
+
it('watching multiple sources', async () => {
const state = reactive({ count: 1 })
const count = ref(1)
diff --git a/packages/runtime-core/package.json b/packages/runtime-core/package.json
index 9e8b20e6246..a5d6bb12bfe 100644
--- a/packages/runtime-core/package.json
+++ b/packages/runtime-core/package.json
@@ -1,6 +1,6 @@
{
"name": "@vue/runtime-core",
- "version": "3.4.1",
+ "version": "3.4.2",
"description": "@vue/runtime-core",
"main": "index.js",
"module": "dist/runtime-core.esm-bundler.js",
diff --git a/packages/runtime-core/src/apiWatch.ts b/packages/runtime-core/src/apiWatch.ts
index a3cd3894f41..0c13e72988f 100644
--- a/packages/runtime-core/src/apiWatch.ts
+++ b/packages/runtime-core/src/apiWatch.ts
@@ -231,8 +231,11 @@ function doWatch(
getter = () => source.value
forceTrigger = isShallow(source)
} else if (isReactive(source)) {
- getter = () => source
- deep = true
+ getter =
+ isShallow(source) || deep === false
+ ? () => traverse(source, 1)
+ : () => traverse(source)
+ forceTrigger = true
} else if (isArray(source)) {
isMultiSource = true
forceTrigger = source.some(s => isReactive(s) || isShallow(s))
@@ -241,7 +244,7 @@ function doWatch(
if (isRef(s)) {
return s.value
} else if (isReactive(s)) {
- return traverse(s)
+ return traverse(s, isShallow(s) || deep === false ? 1 : undefined)
} else if (isFunction(s)) {
return callWithErrorHandling(s, instance, ErrorCodes.WATCH_GETTER)
} else {
@@ -460,28 +463,41 @@ export function createPathGetter(ctx: any, path: string) {
}
}
-export function traverse(value: unknown, seen?: Set) {
+export function traverse(
+ value: unknown,
+ depth?: number,
+ currentDepth = 0,
+ seen?: Set,
+) {
if (!isObject(value) || (value as any)[ReactiveFlags.SKIP]) {
return value
}
+
+ if (depth && depth > 0) {
+ if (currentDepth >= depth) {
+ return value
+ }
+ currentDepth++
+ }
+
seen = seen || new Set()
if (seen.has(value)) {
return value
}
seen.add(value)
if (isRef(value)) {
- traverse(value.value, seen)
+ traverse(value.value, depth, currentDepth, seen)
} else if (isArray(value)) {
for (let i = 0; i < value.length; i++) {
- traverse(value[i], seen)
+ traverse(value[i], depth, currentDepth, seen)
}
} else if (isSet(value) || isMap(value)) {
value.forEach((v: any) => {
- traverse(v, seen)
+ traverse(v, depth, currentDepth, seen)
})
} else if (isPlainObject(value)) {
for (const key in value) {
- traverse(value[key], seen)
+ traverse(value[key], depth, currentDepth, seen)
}
}
return value
diff --git a/packages/runtime-dom/package.json b/packages/runtime-dom/package.json
index acd4760e2c2..23c92b225c1 100644
--- a/packages/runtime-dom/package.json
+++ b/packages/runtime-dom/package.json
@@ -1,6 +1,6 @@
{
"name": "@vue/runtime-dom",
- "version": "3.4.1",
+ "version": "3.4.2",
"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 b41e757a27d..ee3cc84b936 100644
--- a/packages/server-renderer/package.json
+++ b/packages/server-renderer/package.json
@@ -1,6 +1,6 @@
{
"name": "@vue/server-renderer",
- "version": "3.4.1",
+ "version": "3.4.2",
"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 97fdfb01fc1..7ddc6d58f6d 100644
--- a/packages/shared/package.json
+++ b/packages/shared/package.json
@@ -1,6 +1,6 @@
{
"name": "@vue/shared",
- "version": "3.4.1",
+ "version": "3.4.2",
"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 0020a1c7fed..017879cc718 100644
--- a/packages/vue-compat/package.json
+++ b/packages/vue-compat/package.json
@@ -1,6 +1,6 @@
{
"name": "@vue/compat",
- "version": "3.4.1",
+ "version": "3.4.2",
"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 c0ec583c519..94b2f20c277 100644
--- a/packages/vue/package.json
+++ b/packages/vue/package.json
@@ -1,6 +1,6 @@
{
"name": "vue",
- "version": "3.4.1",
+ "version": "3.4.2",
"description": "The progressive JavaScript framework for building modern web UI.",
"main": "index.js",
"module": "dist/vue.runtime.esm-bundler.js",