diff --git a/CHANGELOG.md b/CHANGELOG.md index 28a30bfa8c4..9f345f8fe75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +## [3.5.3](https://github.com/vuejs/core/compare/v3.5.2...v3.5.3) (2024-09-06) + + +### Bug Fixes + +* **hydration:** check __asyncHydrate presence for vue3-lazy-hydration compat ([#11825](https://github.com/vuejs/core/issues/11825)) ([8e6c337](https://github.com/vuejs/core/commit/8e6c3378676be05cea7f53664442acdfb86784f9)), closes [#11793](https://github.com/vuejs/core/issues/11793) +* Revert "fix(reactivity): self-referencing computed should refresh" ([35c760f](https://github.com/vuejs/core/commit/35c760f82f749f7c6e3f9bfead8221ce498e892f)) +* **ssr:** respect app.config.warnHandler during ssr ([bf3d9a2](https://github.com/vuejs/core/commit/bf3d9a2af41659a743706306fc798b3d215df5af)), closes [#11830](https://github.com/vuejs/core/issues/11830) +* **Transition:** handle KeepAlive child unmount in Transition out-in mode ([#11833](https://github.com/vuejs/core/issues/11833)) ([6b7901d](https://github.com/vuejs/core/commit/6b7901d28ed3a6a9242c666cc1b8e3c0b0b0fe62)), closes [#11775](https://github.com/vuejs/core/issues/11775) +* **useId:** make generated IDs selector compatible ([babfb4c](https://github.com/vuejs/core/commit/babfb4cbcbf98601d76c1d7653eae8d250ce2710)), closes [#11828](https://github.com/vuejs/core/issues/11828) + + + ## [3.5.2](https://github.com/vuejs/core/compare/v3.5.1...v3.5.2) (2024-09-05) diff --git a/package.json b/package.json index 3090d82b669..062fbdb23b4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "private": true, - "version": "3.5.2", + "version": "3.5.3", "packageManager": "pnpm@9.9.0", "type": "module", "scripts": { diff --git a/packages/compiler-core/package.json b/packages/compiler-core/package.json index 6f1ba3f8986..da4e3388e02 100644 --- a/packages/compiler-core/package.json +++ b/packages/compiler-core/package.json @@ -1,6 +1,6 @@ { "name": "@vue/compiler-core", - "version": "3.5.2", + "version": "3.5.3", "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 66e8da0b97e..de4aa7ea86b 100644 --- a/packages/compiler-dom/package.json +++ b/packages/compiler-dom/package.json @@ -1,6 +1,6 @@ { "name": "@vue/compiler-dom", - "version": "3.5.2", + "version": "3.5.3", "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 fd417236743..6c831a57679 100644 --- a/packages/compiler-sfc/package.json +++ b/packages/compiler-sfc/package.json @@ -1,6 +1,6 @@ { "name": "@vue/compiler-sfc", - "version": "3.5.2", + "version": "3.5.3", "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 e40bb080534..98636adde6e 100644 --- a/packages/compiler-ssr/package.json +++ b/packages/compiler-ssr/package.json @@ -1,6 +1,6 @@ { "name": "@vue/compiler-ssr", - "version": "3.5.2", + "version": "3.5.3", "description": "@vue/compiler-ssr", "main": "dist/compiler-ssr.cjs.js", "types": "dist/compiler-ssr.d.ts", diff --git a/packages/reactivity/__tests__/computed.spec.ts b/packages/reactivity/__tests__/computed.spec.ts index e0b47cf56eb..31daef559a8 100644 --- a/packages/reactivity/__tests__/computed.spec.ts +++ b/packages/reactivity/__tests__/computed.spec.ts @@ -594,7 +594,7 @@ describe('reactivity/computed', () => { v.value += ' World' await nextTick() - expect(serializeInner(root)).toBe('Hello World World World World') + expect(serializeInner(root)).toBe('Hello World World World') // expect(COMPUTED_SIDE_EFFECT_WARN).toHaveBeenWarned() }) @@ -892,7 +892,7 @@ describe('reactivity/computed', () => { v.value += ' World' await nextTick() expect(serializeInner(root)).toBe( - 'Hello World World World World | Hello World World World World', + 'Hello World World World | Hello World World World', ) }) @@ -962,7 +962,6 @@ describe('reactivity/computed', () => { }) }) - // #11797 test('should prevent endless recursion in self-referencing computed getters', async () => { const Comp = defineComponent({ data() { @@ -999,7 +998,7 @@ describe('reactivity/computed', () => { }) const root = nodeOps.createElement('div') render(h(Comp), root) - expect(serializeInner(root)).toBe(`

Step 1

`) + expect(serializeInner(root)).toBe(`

`) triggerEvent(root.children[1] as TestElement, 'click') await nextTick() expect(serializeInner(root)).toBe(`

Step 2

`) diff --git a/packages/reactivity/package.json b/packages/reactivity/package.json index 08d3443cefd..8e6f64b4379 100644 --- a/packages/reactivity/package.json +++ b/packages/reactivity/package.json @@ -1,6 +1,6 @@ { "name": "@vue/reactivity", - "version": "3.5.2", + "version": "3.5.3", "description": "@vue/reactivity", "main": "index.js", "module": "dist/reactivity.esm-bundler.js", diff --git a/packages/reactivity/src/computed.ts b/packages/reactivity/src/computed.ts index d2dd67bf97c..aa5d2079061 100644 --- a/packages/reactivity/src/computed.ts +++ b/packages/reactivity/src/computed.ts @@ -111,9 +111,9 @@ export class ComputedRefImpl implements Subscriber { * @internal */ notify(): void { - this.flags |= EffectFlags.DIRTY // avoid infinite self recursion if (activeSub !== this) { + this.flags |= EffectFlags.DIRTY this.dep.notify() } else if (__DEV__) { // TODO warn diff --git a/packages/reactivity/src/effect.ts b/packages/reactivity/src/effect.ts index 51df32e9969..88493e4e9a9 100644 --- a/packages/reactivity/src/effect.ts +++ b/packages/reactivity/src/effect.ts @@ -345,6 +345,9 @@ function isDirty(sub: Subscriber): boolean { * @internal */ export function refreshComputed(computed: ComputedRefImpl): false | undefined { + if (computed.flags & EffectFlags.RUNNING) { + return false + } if ( computed.flags & EffectFlags.TRACKING && !(computed.flags & EffectFlags.DIRTY) diff --git a/packages/runtime-core/__tests__/helpers/useId.spec.ts b/packages/runtime-core/__tests__/helpers/useId.spec.ts index 564755e2fd8..d71260cdaff 100644 --- a/packages/runtime-core/__tests__/helpers/useId.spec.ts +++ b/packages/runtime-core/__tests__/helpers/useId.spec.ts @@ -59,7 +59,7 @@ describe('useId', () => { const app = createApp(BasicComponentWithUseId) return [app, []] }), - ).toBe('v:0 v:1') + ).toBe('v-0 v-1') }) test('with config.idPrefix', async () => { @@ -69,7 +69,7 @@ describe('useId', () => { app.config.idPrefix = 'foo' return [app, []] }), - ).toBe('foo:0 foo:1') + ).toBe('foo-0 foo-1') }) test('async component', async () => { @@ -92,9 +92,9 @@ describe('useId', () => { } const expected = - 'v:0 v:1 ' + // root - 'v:0-0 v:0-1 ' + // inside first async subtree - 'v:1-0 v:1-1' // inside second async subtree + 'v-0 v-1 ' + // root + 'v-0-0 v-0-1 ' + // inside first async subtree + 'v-1-0 v-1-1' // inside second async subtree // assert different async resolution order does not affect id stable-ness expect(await getOutput(() => factory(0, 16))).toBe(expected) expect(await getOutput(() => factory(16, 0))).toBe(expected) @@ -137,9 +137,9 @@ describe('useId', () => { } const expected = - 'v:0 v:1 ' + // root - 'v:0-0 v:0-1 ' + // inside first async subtree - 'v:1-0 v:1-1' // inside second async subtree + 'v-0 v-1 ' + // root + 'v-0-0 v-0-1 ' + // inside first async subtree + 'v-1-0 v-1-1' // inside second async subtree // assert different async resolution order does not affect id stable-ness expect(await getOutput(() => factory(0, 16))).toBe(expected) expect(await getOutput(() => factory(16, 0))).toBe(expected) @@ -188,9 +188,9 @@ describe('useId', () => { const expected = '
' + - 'v:0 v:1 ' + // root - 'v:0-0 v:0-1 ' + // inside first async subtree - 'v:1-0 v:1-1' + // inside second async subtree + 'v-0 v-1 ' + // root + 'v-0-0 v-0-1 ' + // inside first async subtree + 'v-1-0 v-1-1' + // inside second async subtree '
' // assert different async resolution order does not affect id stable-ness expect(await getOutput(() => factory(0, 16))).toBe(expected) @@ -232,10 +232,10 @@ describe('useId', () => { } const expected = - 'v:0 ' + // One - 'v:0-0 ' + // Two - 'v:0-0-0 v:0-0-1 ' + // Three + Three nested in Two - 'v:0-1' // Three after Two + 'v-0 ' + // One + 'v-0-0 ' + // Two + 'v-0-0-0 v-0-0-1 ' + // Three + Three nested in Two + 'v-0-1' // Three after Two // assert different async resolution order does not affect id stable-ness expect(await getOutput(() => factory())).toBe(expected) expect(await getOutput(() => factory())).toBe(expected) @@ -278,8 +278,8 @@ describe('useId', () => { const expected = '
' + - 'v:0 v:1 ' + // root - 'v:0-0-0 v:0-0-1' + // async component inside async setup + 'v-0 v-1 ' + // root + 'v-0-0-0 v-0-0-1' + // async component inside async setup '
' // assert different async resolution order does not affect id stable-ness expect(await getOutput(async () => factory(0, 16))).toBe(expected) diff --git a/packages/runtime-core/package.json b/packages/runtime-core/package.json index 79f2104f255..fb247fa7c25 100644 --- a/packages/runtime-core/package.json +++ b/packages/runtime-core/package.json @@ -1,6 +1,6 @@ { "name": "@vue/runtime-core", - "version": "3.5.2", + "version": "3.5.3", "description": "@vue/runtime-core", "main": "index.js", "module": "dist/runtime-core.esm-bundler.js", diff --git a/packages/runtime-core/src/componentRenderUtils.ts b/packages/runtime-core/src/componentRenderUtils.ts index 9fe381ff645..a15d18d56bf 100644 --- a/packages/runtime-core/src/componentRenderUtils.ts +++ b/packages/runtime-core/src/componentRenderUtils.ts @@ -27,6 +27,7 @@ import { warnDeprecation, } from './compat/compatConfig' import { shallowReadonly } from '@vue/reactivity' +import { setTransitionHooks } from './components/BaseTransition' /** * dev only flag to track whether $attrs was used during render. @@ -60,7 +61,6 @@ export function renderComponentRoot( setupState, ctx, inheritAttrs, - isMounted, } = instance const prev = setCurrentRenderingInstance(instance) @@ -254,9 +254,7 @@ export function renderComponentRoot( `that cannot be animated.`, ) } - root.transition = isMounted - ? vnode.component!.subTree.transition! - : vnode.transition + setTransitionHooks(root, vnode.transition) } if (__DEV__ && setRoot) { diff --git a/packages/runtime-core/src/components/BaseTransition.ts b/packages/runtime-core/src/components/BaseTransition.ts index 568a6382bfe..6ce06d28239 100644 --- a/packages/runtime-core/src/components/BaseTransition.ts +++ b/packages/runtime-core/src/components/BaseTransition.ts @@ -516,6 +516,7 @@ function getInnerChild(vnode: VNode): VNode | undefined { export function setTransitionHooks(vnode: VNode, hooks: TransitionHooks): void { if (vnode.shapeFlag & ShapeFlags.COMPONENT && vnode.component) { + vnode.transition = hooks setTransitionHooks(vnode.component.subTree, hooks) } else if (__FEATURE_SUSPENSE__ && vnode.shapeFlag & ShapeFlags.SUSPENSE) { vnode.ssContent!.transition = hooks.clone(vnode.ssContent!) diff --git a/packages/runtime-core/src/helpers/useId.ts b/packages/runtime-core/src/helpers/useId.ts index f4a199e2c39..f7a2b5fc330 100644 --- a/packages/runtime-core/src/helpers/useId.ts +++ b/packages/runtime-core/src/helpers/useId.ts @@ -7,7 +7,7 @@ import { warn } from '../warning' export function useId(): string | undefined { const i = getCurrentInstance() if (i) { - return (i.appContext.config.idPrefix || 'v') + ':' + i.ids[0] + i.ids[1]++ + return (i.appContext.config.idPrefix || 'v') + '-' + i.ids[0] + i.ids[1]++ } else if (__DEV__) { warn( `useId() is called when there is no active component ` + diff --git a/packages/runtime-core/src/index.ts b/packages/runtime-core/src/index.ts index 7f716b5f4e8..3871167b3ee 100644 --- a/packages/runtime-core/src/index.ts +++ b/packages/runtime-core/src/index.ts @@ -400,6 +400,7 @@ import { renderComponentRoot } from './componentRenderUtils' import { setCurrentRenderingInstance } from './componentRenderContext' import { isVNode, normalizeVNode } from './vnode' import { ensureValidVNode } from './helpers/renderSlot' +import { popWarningContext, pushWarningContext } from './warning' const _ssrUtils: { createComponentInstance: typeof createComponentInstance @@ -410,6 +411,8 @@ const _ssrUtils: { normalizeVNode: typeof normalizeVNode getComponentPublicInstance: typeof getComponentPublicInstance ensureValidVNode: typeof ensureValidVNode + pushWarningContext: typeof pushWarningContext + popWarningContext: typeof popWarningContext } = { createComponentInstance, setupComponent, @@ -419,6 +422,8 @@ const _ssrUtils: { normalizeVNode, getComponentPublicInstance, ensureValidVNode, + pushWarningContext, + popWarningContext, } /** diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts index 11736e9dff2..9b50dca23f9 100644 --- a/packages/runtime-core/src/renderer.ts +++ b/packages/runtime-core/src/renderer.ts @@ -1330,7 +1330,10 @@ function baseCreateRenderer( } } - if (isAsyncWrapperVNode) { + if ( + isAsyncWrapperVNode && + (type as ComponentOptions).__asyncHydrate + ) { ;(type as ComponentOptions).__asyncHydrate!( el as Element, instance, diff --git a/packages/runtime-dom/package.json b/packages/runtime-dom/package.json index 6af3be93a10..42f5d6c6e2f 100644 --- a/packages/runtime-dom/package.json +++ b/packages/runtime-dom/package.json @@ -1,6 +1,6 @@ { "name": "@vue/runtime-dom", - "version": "3.5.2", + "version": "3.5.3", "description": "@vue/runtime-dom", "main": "index.js", "module": "dist/runtime-dom.esm-bundler.js", diff --git a/packages/server-renderer/__tests__/render.spec.ts b/packages/server-renderer/__tests__/render.spec.ts index 1b1d6256e8c..d0a5223b2ff 100644 --- a/packages/server-renderer/__tests__/render.spec.ts +++ b/packages/server-renderer/__tests__/render.spec.ts @@ -81,6 +81,18 @@ function testRender(type: string, render: typeof renderToString) { expect(html).toBe(`
foo
`) }) + test('warnings should be suppressed by app.config.warnHandler', async () => { + const app = createApp({ + render() { + return h('div', this.foo) + }, + }) + app.config.warnHandler = vi.fn() + await render(app) + expect('not defined on instance').not.toHaveBeenWarned() + expect(app.config.warnHandler).toHaveBeenCalledTimes(1) + }) + describe('components', () => { test('vnode components', async () => { expect( diff --git a/packages/server-renderer/package.json b/packages/server-renderer/package.json index 078493d7689..80639a81dea 100644 --- a/packages/server-renderer/package.json +++ b/packages/server-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@vue/server-renderer", - "version": "3.5.2", + "version": "3.5.3", "description": "@vue/server-renderer", "main": "index.js", "module": "dist/server-renderer.esm-bundler.js", diff --git a/packages/server-renderer/src/render.ts b/packages/server-renderer/src/render.ts index 97179526456..f04080b9c31 100644 --- a/packages/server-renderer/src/render.ts +++ b/packages/server-renderer/src/render.ts @@ -35,6 +35,8 @@ const { setupComponent, renderComponentRoot, normalizeVNode, + pushWarningContext, + popWarningContext, } = ssrUtils export type SSRBuffer = SSRBufferItem[] & { hasAsync?: boolean } @@ -91,8 +93,14 @@ export function renderComponentVNode( parentComponent: ComponentInternalInstance | null = null, slotScopeId?: string, ): SSRBuffer | Promise { - const instance = createComponentInstance(vnode, parentComponent, null) + const instance = (vnode.component = createComponentInstance( + vnode, + parentComponent, + null, + )) + if (__DEV__) pushWarningContext(vnode) const res = setupComponent(instance, true /* isSSR */) + if (__DEV__) popWarningContext() const hasAsyncSetup = isPromise(res) let prefetches = instance.sp /* LifecycleHooks.SERVER_PREFETCH */ if (hasAsyncSetup || prefetches) { @@ -118,6 +126,7 @@ function renderComponentSubTree( instance: ComponentInternalInstance, slotScopeId?: string, ): SSRBuffer | Promise { + if (__DEV__) pushWarningContext(instance.vnode) const comp = instance.type as Component const { getBuffer, push } = createBuffer() if (isFunction(comp)) { @@ -207,6 +216,7 @@ function renderComponentSubTree( push(``) } } + if (__DEV__) popWarningContext() return getBuffer() } diff --git a/packages/shared/package.json b/packages/shared/package.json index 3de674cb693..636b6767ec7 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -1,6 +1,6 @@ { "name": "@vue/shared", - "version": "3.5.2", + "version": "3.5.3", "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 1f0ebbf6c18..4a015d2f4da 100644 --- a/packages/vue-compat/package.json +++ b/packages/vue-compat/package.json @@ -1,6 +1,6 @@ { "name": "@vue/compat", - "version": "3.5.2", + "version": "3.5.3", "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 96541cacfac..23fbbfd71fc 100644 --- a/packages/vue/package.json +++ b/packages/vue/package.json @@ -1,6 +1,6 @@ { "name": "vue", - "version": "3.5.2", + "version": "3.5.3", "description": "The progressive JavaScript framework for building modern web UI.", "main": "index.js", "module": "dist/vue.runtime.esm-bundler.js",