Browse Source

Merge remote-tracking branch 'upstream/main'

三咲智子 Kevin Deng 2 years ago
parent
commit
5a0365d944

+ 11 - 0
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)
 
 

+ 1 - 1
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",

+ 1 - 1
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",

+ 0 - 15
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'

+ 1 - 1
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",

+ 1 - 1
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",

+ 1 - 1
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",

+ 127 - 12
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(`<div>innerA</div>`)
   })
 
+  // #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(`<div>innerA</div>`)
+
+    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(`<div>innerB2</div>`)
+  })
+
   test('branch switch to 3rd branch before resolve', async () => {
     const calls: string[] = []
 

+ 1 - 1
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",

+ 5 - 1
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

+ 1 - 1
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(

+ 12 - 0
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

+ 1 - 1
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",

+ 4 - 4
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: <option> value will fallback to its text content so we need to
     // compare against its attribute value instead.
     const oldValue =
       tag === 'OPTION' ? el.getAttribute('value') || '' : el.value
     const newValue = value == null ? '' : value
-    if (oldValue !== newValue) {
+    if (oldValue !== newValue || !('_value' in el)) {
       el.value = newValue
     }
     if (value == null) {
       el.removeAttribute(key)
     }
+    // store value as _value as well since
+    // non-string values will be stringified.
+    el._value = value
     return
   }
 

+ 1 - 1
packages/server-renderer/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vue/server-renderer",
-  "version": "3.4.20",
+  "version": "3.4.21",
   "description": "@vue/server-renderer",
   "main": "index.js",
   "module": "dist/server-renderer.esm-bundler.js",

+ 1 - 1
packages/shared/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vue/shared",
-  "version": "3.4.20",
+  "version": "3.4.21",
   "description": "internal utils shared across @vue packages",
   "main": "index.js",
   "module": "dist/shared.esm-bundler.js",

+ 1 - 1
packages/vue-compat/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vue/compat",
-  "version": "3.4.20",
+  "version": "3.4.21",
   "description": "Vue 3 compatibility build for Vue 2",
   "main": "index.js",
   "module": "dist/vue.runtime.esm-bundler.js",

+ 1 - 1
packages/vue/package.json

@@ -1,6 +1,6 @@
 {
   "name": "vue",
-  "version": "3.4.20",
+  "version": "3.4.21",
   "description": "The progressive JavaScript framework for building modern web UI.",
   "main": "index.js",
   "module": "dist/vue.runtime.esm-bundler.js",