diff --git a/CHANGELOG.md b/CHANGELOG.md index 6acaa893f..28447dfe3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ +## [3.4.21](https://github.com/vuejs/core/compare/v3.4.20...v3.4.21) (2024-02-28) + + +### Bug Fixes + +* **runtime-dom:** avoid unset option's value ([#10416](https://github.com/vuejs/core/issues/10416)) ([b3f8b5a](https://github.com/vuejs/core/commit/b3f8b5a4e700d4c47a146b6040882287d180f6cb)), closes [#10412](https://github.com/vuejs/core/issues/10412) [#10396](https://github.com/vuejs/core/issues/10396) +* **suspense:** ensure nested suspense patching if in fallback state ([#10417](https://github.com/vuejs/core/issues/10417)) ([7c97778](https://github.com/vuejs/core/commit/7c97778aec1e3513035e5df265e1b8a7801f6106)), closes [#10415](https://github.com/vuejs/core/issues/10415) +* **warning:** stringify args in warn handler ([#10414](https://github.com/vuejs/core/issues/10414)) ([bc37258](https://github.com/vuejs/core/commit/bc37258caa2f6f67f4554ab8587aca3798d92124)), closes [#10409](https://github.com/vuejs/core/issues/10409) + + + ## [3.4.20](https://github.com/vuejs/core/compare/v3.4.19...v3.4.20) (2024-02-26) diff --git a/packages/compiler-core/package.json b/packages/compiler-core/package.json index 899e72b37..98bb107ec 100644 --- a/packages/compiler-core/package.json +++ b/packages/compiler-core/package.json @@ -1,6 +1,6 @@ { "name": "@vue/compiler-core", - "version": "3.4.20", + "version": "3.4.21", "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 1337dbc6c..a92d1315c 100644 --- a/packages/compiler-dom/package.json +++ b/packages/compiler-dom/package.json @@ -1,6 +1,6 @@ { "name": "@vue/compiler-dom", - "version": "3.4.20", + "version": "3.4.21", "description": "@vue/compiler-dom", "main": "index.js", "module": "dist/compiler-dom.esm-bundler.js", 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 cfdbf5f45..764d120a7 100644 --- a/packages/compiler-sfc/__tests__/compileScript/__snapshots__/importUsageCheck.spec.ts.snap +++ b/packages/compiler-sfc/__tests__/compileScript/__snapshots__/importUsageCheck.spec.ts.snap @@ -79,21 +79,6 @@ return { get FooBar() { return FooBar }, get foo() { return foo }, get bar() { r })" `; -exports[`import namespace 1`] = ` -"import { defineComponent as _defineComponent } from 'vue' -import * as Foo from './foo' - -export default /*#__PURE__*/_defineComponent({ - setup(__props, { expose: __expose }) { - __expose(); - - -return { get Foo() { return Foo } } -} - -})" -`; - exports[`js template string interpolations 1`] = ` "import { defineComponent as _defineComponent } from 'vue' import { VAR, VAR2, VAR3 } from './x' diff --git a/packages/compiler-sfc/package.json b/packages/compiler-sfc/package.json index bf30add51..b624cdacc 100644 --- a/packages/compiler-sfc/package.json +++ b/packages/compiler-sfc/package.json @@ -1,6 +1,6 @@ { "name": "@vue/compiler-sfc", - "version": "3.4.20", + "version": "3.4.21", "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 59861946c..fede83c2c 100644 --- a/packages/compiler-ssr/package.json +++ b/packages/compiler-ssr/package.json @@ -1,6 +1,6 @@ { "name": "@vue/compiler-ssr", - "version": "3.4.20", + "version": "3.4.21", "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 5b404c0e8..60997b87b 100644 --- a/packages/reactivity/package.json +++ b/packages/reactivity/package.json @@ -1,6 +1,6 @@ { "name": "@vue/reactivity", - "version": "3.4.20", + "version": "3.4.21", "description": "@vue/reactivity", "main": "index.js", "module": "dist/reactivity.esm-bundler.js", diff --git a/packages/runtime-core/__tests__/components/Suspense.spec.ts b/packages/runtime-core/__tests__/components/Suspense.spec.ts index fd1913b2c..a448972e1 100644 --- a/packages/runtime-core/__tests__/components/Suspense.spec.ts +++ b/packages/runtime-core/__tests__/components/Suspense.spec.ts @@ -54,6 +54,18 @@ describe('Suspense', () => { } } + const RouterView = { + setup(_: any, { slots }: any) { + const route = inject('route') as any + const depth = inject('depth', 0) + provide('depth', depth + 1) + return () => { + const current = route.value[depth] + return slots.default({ Component: current })[0] + } + }, + } + test('fallback content', async () => { const Async = defineAsyncComponent({ render() { @@ -1041,18 +1053,6 @@ describe('Suspense', () => { // #10098 test('switching branches w/ nested suspense', async () => { - const RouterView = { - setup(_: any, { slots }: any) { - const route = inject('route') as any - const depth = inject('depth', 0) - provide('depth', depth + 1) - return () => { - const current = route.value[depth] - return slots.default({ Component: current })[0] - } - }, - } - const OuterB = defineAsyncComponent({ setup: () => { return () => @@ -1132,6 +1132,121 @@ describe('Suspense', () => { expect(serializeInner(root)).toBe(`
innerA
`) }) + // #10415 + test('nested suspense (w/ suspensible) switch several times before parent suspense resolve', async () => { + const OuterA = defineAsyncComponent({ + setup: () => { + return () => + h(RouterView, null, { + default: ({ Component }: any) => [ + h(Suspense, null, { + default: () => h(Component), + }), + ], + }) + }, + }) + + const InnerA = defineAsyncComponent({ + setup: () => { + return () => h('div', 'innerA') + }, + }) + + const route = shallowRef([OuterA, InnerA]) + const InnerB = defineAsyncComponent( + { + setup: () => { + return () => h('div', 'innerB') + }, + }, + 5, + ) + + const InnerB1 = defineAsyncComponent( + { + setup: () => { + return () => h('div', 'innerB1') + }, + }, + 5, + ) + + const InnerB2 = defineAsyncComponent( + { + setup: () => { + return () => h('div', 'innerB2') + }, + }, + 5, + ) + + const OuterB = defineAsyncComponent( + { + setup() { + nextTick(async () => { + await new Promise(resolve => setTimeout(resolve, 1)) + route.value = [OuterB, InnerB1] + }) + + nextTick(async () => { + await new Promise(resolve => setTimeout(resolve, 1)) + route.value = [OuterB, InnerB2] + }) + + return () => + h(RouterView, null, { + default: ({ Component }: any) => [ + h( + Suspense, + { suspensible: true }, + { + default: () => h(Component), + }, + ), + ], + }) + }, + }, + 5, + ) + + const Comp = { + setup() { + provide('route', route) + return () => + h(RouterView, null, { + default: ({ Component }: any) => [ + h(Suspense, null, { + default: () => h(Component), + }), + ], + }) + }, + } + + const root = nodeOps.createElement('div') + render(h(Comp), root) + await Promise.all(deps) + await nextTick() + expect(serializeInner(root)).toBe(``) + + await Promise.all(deps) + await nextTick() + expect(serializeInner(root)).toBe(`
innerA
`) + + deps.length = 0 + + route.value = [OuterB, InnerB] + await nextTick() + + await Promise.all(deps) + await Promise.all(deps) + await Promise.all(deps) + await nextTick() + expect(serializeInner(root)).toBe(`
innerB2
`) + }) + test('branch switch to 3rd branch before resolve', async () => { const calls: string[] = [] diff --git a/packages/runtime-core/package.json b/packages/runtime-core/package.json index 611f9cef0..d38b8fa21 100644 --- a/packages/runtime-core/package.json +++ b/packages/runtime-core/package.json @@ -1,6 +1,6 @@ { "name": "@vue/runtime-core", - "version": "3.4.20", + "version": "3.4.21", "description": "@vue/runtime-core", "main": "index.js", "module": "dist/runtime-core.esm-bundler.js", diff --git a/packages/runtime-core/src/components/Suspense.ts b/packages/runtime-core/src/components/Suspense.ts index 65b05c3dd..9461d7fec 100644 --- a/packages/runtime-core/src/components/Suspense.ts +++ b/packages/runtime-core/src/components/Suspense.ts @@ -99,7 +99,11 @@ export const SuspenseImpl = { // 2. mounting along with the pendingBranch of parentSuspense // it is necessary to skip the current patch to avoid multiple mounts // of inner components. - if (parentSuspense && parentSuspense.deps > 0) { + if ( + parentSuspense && + parentSuspense.deps > 0 && + !n1.suspense!.isInFallback + ) { n2.suspense = n1.suspense! n2.suspense.vnode = n2 n2.el = n1.el diff --git a/packages/runtime-core/src/warning.ts b/packages/runtime-core/src/warning.ts index 14f1b020a..eea810f57 100644 --- a/packages/runtime-core/src/warning.ts +++ b/packages/runtime-core/src/warning.ts @@ -44,7 +44,7 @@ export function warn(msg: string, ...args: any[]) { instance, ErrorCodes.APP_WARN_HANDLER, [ - msg + args.join(''), + msg + args.map(a => a.toString?.() ?? JSON.stringify(a)).join(''), instance && instance.proxy, trace .map( diff --git a/packages/runtime-dom/__tests__/patchProps.spec.ts b/packages/runtime-dom/__tests__/patchProps.spec.ts index 7c356f1a6..61dd98513 100644 --- a/packages/runtime-dom/__tests__/patchProps.spec.ts +++ b/packages/runtime-dom/__tests__/patchProps.spec.ts @@ -291,6 +291,18 @@ describe('runtime-dom: props patching', () => { expect(el.value).toBe('baz') }) + test('init empty value for option', () => { + const root = document.createElement('div') + render( + h('select', { value: 'foo' }, [h('option', { value: '' }, 'foo')]), + root, + ) + const select = root.children[0] as HTMLSelectElement + const option = select.children[0] as HTMLOptionElement + expect(select.value).toBe('') + expect(option.value).toBe('') + }) + // #8780 test('embedded tag with width and height', () => { // Width and height of some embedded element such as img、video、source、canvas diff --git a/packages/runtime-dom/package.json b/packages/runtime-dom/package.json index bd645877f..591cae2be 100644 --- a/packages/runtime-dom/package.json +++ b/packages/runtime-dom/package.json @@ -1,6 +1,6 @@ { "name": "@vue/runtime-dom", - "version": "3.4.20", + "version": "3.4.21", "description": "@vue/runtime-dom", "main": "index.js", "module": "dist/runtime-dom.esm-bundler.js", diff --git a/packages/runtime-dom/src/modules/props.ts b/packages/runtime-dom/src/modules/props.ts index e9b3bca35..c4bb4987b 100644 --- a/packages/runtime-dom/src/modules/props.ts +++ b/packages/runtime-dom/src/modules/props.ts @@ -34,20 +34,20 @@ export function patchDOMProp( // custom elements may use _value internally !tag.includes('-') ) { - // store value as _value as well since - // non-string values will be stringified. - el._value = value // #4956: