三咲智子 Kevin Deng 1 рік тому
батько
коміт
c7fd6ae2dc
43 змінених файлів з 700 додано та 526 видалено
  1. 49 0
      CHANGELOG.md
  2. 9 9
      package.json
  3. 18 0
      packages-private/dts-test/ref.test-d.ts
  4. 2 2
      packages-private/sfc-playground/src/download/template/package.json
  5. 1 1
      packages/compiler-core/package.json
  6. 1 1
      packages/compiler-dom/package.json
  7. 2 2
      packages/compiler-sfc/package.json
  8. 5 14
      packages/compiler-sfc/src/parse.ts
  9. 1 0
      packages/compiler-sfc/src/script/definePropsDestructure.ts
  10. 1 1
      packages/compiler-ssr/package.json
  11. 87 9
      packages/reactivity/__tests__/computed.spec.ts
  12. 11 0
      packages/reactivity/__tests__/reactive.spec.ts
  13. 68 0
      packages/reactivity/__tests__/watch.spec.ts
  14. 1 1
      packages/reactivity/package.json
  15. 6 2
      packages/reactivity/src/computed.ts
  16. 28 27
      packages/reactivity/src/dep.ts
  17. 36 16
      packages/reactivity/src/effect.ts
  18. 1 1
      packages/reactivity/src/reactive.ts
  19. 6 4
      packages/reactivity/src/ref.ts
  20. 27 1
      packages/runtime-core/__tests__/apiWatch.spec.ts
  21. 9 0
      packages/runtime-core/__tests__/rendererChildren.spec.ts
  22. 54 0
      packages/runtime-core/__tests__/scheduler.spec.ts
  23. 1 1
      packages/runtime-core/package.json
  24. 9 11
      packages/runtime-core/src/apiDefineComponent.ts
  25. 14 2
      packages/runtime-core/src/componentEmits.ts
  26. 2 1
      packages/runtime-core/src/helpers/useId.ts
  27. 2 2
      packages/runtime-core/src/hydration.ts
  28. 7 15
      packages/runtime-core/src/scheduler.ts
  29. 1 1
      packages/runtime-core/src/vnode.ts
  30. 15 0
      packages/runtime-dom/__tests__/customElement.spec.ts
  31. 1 1
      packages/runtime-dom/package.json
  32. 6 6
      packages/runtime-dom/src/directives/vModel.ts
  33. 8 10
      packages/runtime-dom/src/patchProp.ts
  34. 1 1
      packages/server-renderer/package.json
  35. 1 1
      packages/shared/package.json
  36. 9 0
      packages/shared/src/general.ts
  37. 6 0
      packages/shared/src/typeUtils.ts
  38. 1 1
      packages/vue-compat/package.json
  39. 8 2
      packages/vue-compat/src/index.ts
  40. 1 1
      packages/vue/package.json
  41. 5 18
      packages/vue/src/index.ts
  42. 170 355
      pnpm-lock.yaml
  43. 9 6
      scripts/release.js

+ 49 - 0
CHANGELOG.md

@@ -1,3 +1,52 @@
+## [3.5.11](https://github.com/vuejs/core/compare/v3.5.10...v3.5.11) (2024-10-03)
+
+
+### Bug Fixes
+
+* **compiler-sfc:** do not skip `TSSatisfiesExpression` when transforming props destructure ([#12062](https://github.com/vuejs/core/issues/12062)) ([2328b05](https://github.com/vuejs/core/commit/2328b051f4efa1f1394b7d4e73b7c3f76e430e7c)), closes [#12061](https://github.com/vuejs/core/issues/12061)
+* **reactivity:** prevent overwriting `next` property during batch processing ([#12075](https://github.com/vuejs/core/issues/12075)) ([d3f5e6e](https://github.com/vuejs/core/commit/d3f5e6e5319b4ffaa55ca9a2ea3d95d78e76fa58)), closes [#12072](https://github.com/vuejs/core/issues/12072)
+* **scheduler:** job ordering when the post queue is flushing ([#12090](https://github.com/vuejs/core/issues/12090)) ([577edca](https://github.com/vuejs/core/commit/577edca8e7795436efd710d1c289ea8ea2642b0e))
+* **types:** correctly infer `TypeProps` when it is `any` ([#12073](https://github.com/vuejs/core/issues/12073)) ([57315ab](https://github.com/vuejs/core/commit/57315ab9688c9741a271d1075bbd28cbe5f71e2f)), closes [#12058](https://github.com/vuejs/core/issues/12058)
+* **types:** should not intersect `PublicProps` with `Props` ([#12077](https://github.com/vuejs/core/issues/12077)) ([6f85894](https://github.com/vuejs/core/commit/6f8589437635706f825ccec51800effba1d2bf5f))
+* **types:** infer the first generic type of `Ref` correctly ([#12094](https://github.com/vuejs/core/issues/12094)) ([c97bb84](https://github.com/vuejs/core/commit/c97bb84d0b0a16b012f886b6498e924415ed63e5))
+
+
+
+## [3.5.10](https://github.com/vuejs/core/compare/v3.5.9...v3.5.10) (2024-09-27)
+
+
+### Bug Fixes
+
+* **custom-element:** properly set kebab-case props on Vue custom elements ([ea3efa0](https://github.com/vuejs/core/commit/ea3efa09e008918c1d9ba7226833a8b1a7a57244)), closes [#12030](https://github.com/vuejs/core/issues/12030) [#12032](https://github.com/vuejs/core/issues/12032)
+* **reactivity:** fix nested batch edge case ([93c95dd](https://github.com/vuejs/core/commit/93c95dd4cd416503f43a98a1455f62658d22b0b2))
+* **reactivity:** only clear notified flags for computed in first batch iteration ([aa9ef23](https://github.com/vuejs/core/commit/aa9ef2386a0cd39a174e5a887ec2b1a3525034fc)), closes [#12045](https://github.com/vuejs/core/issues/12045)
+* **types/ref:** handle nested refs in UnwrapRef ([#12049](https://github.com/vuejs/core/issues/12049)) ([e2c19c2](https://github.com/vuejs/core/commit/e2c19c20cfee9788519a80c0e53e216b78505994)), closes [#12044](https://github.com/vuejs/core/issues/12044)
+
+
+
+## [3.5.9](https://github.com/vuejs/core/compare/v3.5.8...v3.5.9) (2024-09-26)
+
+
+### Bug Fixes
+
+* **reactivity:** fix property dep removal regression ([6001e5c](https://github.com/vuejs/core/commit/6001e5c81a05c894586f9287fbd991677bdd0455)), closes [#12020](https://github.com/vuejs/core/issues/12020) [#12021](https://github.com/vuejs/core/issues/12021)
+* **reactivity:** fix recursive sync watcher on computed edge case ([10ff159](https://github.com/vuejs/core/commit/10ff15924053d9bd95ad706f78ce09e288213fcf)), closes [#12033](https://github.com/vuejs/core/issues/12033) [#12037](https://github.com/vuejs/core/issues/12037)
+* **runtime-core:** avoid rendering plain object as VNode ([#12038](https://github.com/vuejs/core/issues/12038)) ([cb34b28](https://github.com/vuejs/core/commit/cb34b28a4a9bf868be4785b001c526163eda342e)), closes [#12035](https://github.com/vuejs/core/issues/12035) [vitejs/vite-plugin-vue#353](https://github.com/vitejs/vite-plugin-vue/issues/353)
+* **runtime-core:** make useId() always return a string ([a177092](https://github.com/vuejs/core/commit/a177092754642af2f98c33a4feffe8f198c3c950))
+* **types:** correct type inference of union event names ([#12022](https://github.com/vuejs/core/issues/12022)) ([4da6881](https://github.com/vuejs/core/commit/4da688141d9e7c15b622c289deaa81b11845b2c7))
+* **vue:** properly cache runtime compilation ([#12019](https://github.com/vuejs/core/issues/12019)) ([fa0ba24](https://github.com/vuejs/core/commit/fa0ba24b3ace02d7ecab65e57c2bea89a2550dcb))
+
+
+
+## [3.5.8](https://github.com/vuejs/core/compare/v3.5.7...v3.5.8) (2024-09-22)
+
+
+### Bug Fixes
+
+* **reactivity:** do not remove dep from depsMap when cleaning up deps of computed ([#11995](https://github.com/vuejs/core/issues/11995)) ([0267a58](https://github.com/vuejs/core/commit/0267a588017eee4951ac2a877fe1ccae84cad905))
+
+
+
 ## [3.5.7](https://github.com/vuejs/core/compare/v3.5.6...v3.5.7) (2024-09-20)
 
 

+ 9 - 9
package.json

@@ -1,7 +1,7 @@
 {
   "private": true,
-  "version": "3.5.7",
-  "packageManager": "pnpm@9.10.0",
+  "version": "3.5.11",
+  "packageManager": "pnpm@9.12.0",
   "type": "module",
   "scripts": {
     "dev": "node scripts/dev.js vue vue-vapor",
@@ -61,14 +61,14 @@
   "devDependencies": {
     "@babel/parser": "catalog:",
     "@babel/types": "catalog:",
-    "@rollup/plugin-alias": "^5.1.0",
-    "@rollup/plugin-commonjs": "^26.0.1",
+    "@rollup/plugin-alias": "^5.1.1",
+    "@rollup/plugin-commonjs": "^26.0.3",
     "@rollup/plugin-json": "^6.1.0",
-    "@rollup/plugin-node-resolve": "^15.2.3",
+    "@rollup/plugin-node-resolve": "^15.3.0",
     "@rollup/plugin-replace": "5.0.4",
-    "@swc/core": "^1.7.26",
+    "@swc/core": "^1.7.28",
     "@types/hash-sum": "^1.0.2",
-    "@types/node": "^20.16.5",
+    "@types/node": "^20.16.10",
     "@types/semver": "^7.5.8",
     "@types/serve-handler": "^6.1.4",
     "@vitest/coverage-v8": "^2.1.1",
@@ -76,7 +76,7 @@
     "@vue/consolidate": "1.0.0",
     "conventional-changelog-cli": "^5.0.0",
     "enquirer": "^2.4.1",
-    "esbuild": "^0.23.1",
+    "esbuild": "^0.24.0",
     "esbuild-plugin-polyfill-node": "^0.3.0",
     "eslint": "^9.10.0",
     "eslint-plugin-import-x": "^4.2.1",
@@ -95,7 +95,7 @@
     "pug": "^3.0.3",
     "puppeteer": "~23.3.0",
     "rimraf": "^6.0.1",
-    "rollup": "^4.21.3",
+    "rollup": "^4.24.0",
     "rollup-plugin-dts": "^6.1.1",
     "rollup-plugin-esbuild": "^6.1.1",
     "rollup-plugin-polyfill-node": "^0.13.0",

+ 18 - 0
packages-private/dts-test/ref.test-d.ts

@@ -189,6 +189,24 @@ describe('allow getter and setter types to be unrelated', <T>() => {
   f.value = ref(1)
 })
 
+describe('correctly unwraps nested refs', () => {
+  const obj = {
+    n: 24,
+    ref: ref(24),
+    nestedRef: ref({ n: ref(0) }),
+  }
+
+  const a = ref(obj)
+  expectType<number>(a.value.n)
+  expectType<number>(a.value.ref)
+  expectType<number>(a.value.nestedRef.n)
+
+  const b = reactive({ a })
+  expectType<number>(b.a.n)
+  expectType<number>(b.a.ref)
+  expectType<number>(b.a.nestedRef.n)
+})
+
 // computed
 describe('allow computed getter and setter types to be unrelated', () => {
   const obj = ref({

+ 2 - 2
packages-private/sfc-playground/src/download/template/package.json

@@ -11,7 +11,7 @@
     "vue": "^3.4.0"
   },
   "devDependencies": {
-    "@vitejs/plugin-vue": "^5.1.3",
-    "vite": "^5.4.5"
+    "@vitejs/plugin-vue": "^5.1.4",
+    "vite": "^5.4.8"
   }
 }

+ 1 - 1
packages/compiler-core/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vue/compiler-core",
-  "version": "3.5.7",
+  "version": "3.5.11",
   "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.5.7",
+  "version": "3.5.11",
   "description": "@vue/compiler-dom",
   "main": "index.js",
   "module": "dist/compiler-dom.esm-bundler.js",

+ 2 - 2
packages/compiler-sfc/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vue/compiler-sfc",
-  "version": "3.5.7",
+  "version": "3.5.11",
   "description": "@vue/compiler-sfc",
   "main": "dist/compiler-sfc.cjs.js",
   "module": "dist/compiler-sfc.esm-browser.js",
@@ -63,6 +63,6 @@
     "postcss-modules": "^6.0.0",
     "postcss-selector-parser": "^6.1.2",
     "pug": "^3.0.3",
-    "sass": "^1.78.0"
+    "sass": "^1.79.4"
   }
 }

+ 5 - 14
packages/compiler-sfc/src/parse.ts

@@ -18,6 +18,7 @@ import { createCache } from './cache'
 import type { ImportBinding } from './compileScript'
 import { isImportUsed } from './script/importUsageCheck'
 import type { LRUCache } from 'lru-cache'
+import { genCacheKey } from '@vue/shared'
 
 export const DEFAULT_FILENAME = 'anonymous.vue'
 
@@ -105,24 +106,14 @@ export const parseCache:
   | Map<string, SFCParseResult>
   | LRUCache<string, SFCParseResult> = createCache<SFCParseResult>()
 
-function genCacheKey(source: string, options: SFCParseOptions): string {
-  return (
-    source +
-    JSON.stringify(
-      {
-        ...options,
-        compiler: { parse: options.compiler?.parse },
-      },
-      (_, val) => (typeof val === 'function' ? val.toString() : val),
-    )
-  )
-}
-
 export function parse(
   source: string,
   options: SFCParseOptions = {},
 ): SFCParseResult {
-  const sourceKey = genCacheKey(source, options)
+  const sourceKey = genCacheKey(source, {
+    ...options,
+    compiler: { parse: options.compiler?.parse },
+  })
   const cache = parseCache.get(sourceKey)
   if (cache) {
     return cache

+ 1 - 0
packages/compiler-sfc/src/script/definePropsDestructure.ts

@@ -242,6 +242,7 @@ export function transformDestructuredProps(
         parent.type.startsWith('TS') &&
         parent.type !== 'TSAsExpression' &&
         parent.type !== 'TSNonNullExpression' &&
+        parent.type !== 'TSSatisfiesExpression' &&
         parent.type !== 'TSTypeAssertion'
       ) {
         return this.skip()

+ 1 - 1
packages/compiler-ssr/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vue/compiler-ssr",
-  "version": "3.5.7",
+  "version": "3.5.11",
   "description": "@vue/compiler-ssr",
   "main": "dist/compiler-ssr.cjs.js",
   "types": "dist/compiler-ssr.d.ts",

+ 87 - 9
packages/reactivity/__tests__/computed.spec.ts

@@ -1013,20 +1013,98 @@ describe('reactivity/computed', () => {
   })
 
   test('computed should remain live after losing all subscribers', () => {
-    const toggle = ref(true)
-    const state = reactive({
-      a: 1,
-    })
+    const state = reactive({ a: 1 })
     const p = computed(() => state.a + 1)
-    const pp = computed(() => {
-      return toggle.value ? p.value : 111
-    })
-
-    const { effect: e } = effect(() => pp.value)
+    const { effect: e } = effect(() => p.value)
     e.stop()
 
     expect(p.value).toBe(2)
     state.a++
     expect(p.value).toBe(3)
   })
+
+  // #11995
+  test('computed dep cleanup should not cause property dep to be deleted', () => {
+    const toggle = ref(true)
+    const state = reactive({ a: 1 })
+    const p = computed(() => {
+      return toggle.value ? state.a : 111
+    })
+    const pp = computed(() => state.a)
+    effect(() => p.value)
+
+    expect(pp.value).toBe(1)
+    toggle.value = false
+    state.a++
+    expect(pp.value).toBe(2)
+  })
+
+  // #12020
+  test('computed value updates correctly after dep cleanup', () => {
+    const obj = reactive({ foo: 1, flag: 1 })
+    const c1 = computed(() => obj.foo)
+
+    let foo
+    effect(() => {
+      foo = obj.flag ? (obj.foo, c1.value) : 0
+    })
+    expect(foo).toBe(1)
+
+    obj.flag = 0
+    expect(foo).toBe(0)
+
+    obj.foo = 2
+    obj.flag = 1
+    expect(foo).toBe(2)
+  })
+
+  // #11928
+  test('should not lead to exponential perf cost with deeply chained computed', () => {
+    const start = {
+      prop1: shallowRef(1),
+      prop2: shallowRef(2),
+      prop3: shallowRef(3),
+      prop4: shallowRef(4),
+    }
+
+    let layer = start
+
+    const LAYERS = 1000
+
+    for (let i = LAYERS; i > 0; i--) {
+      const m = layer
+      const s = {
+        prop1: computed(() => m.prop2.value),
+        prop2: computed(() => m.prop1.value - m.prop3.value),
+        prop3: computed(() => m.prop2.value + m.prop4.value),
+        prop4: computed(() => m.prop3.value),
+      }
+      effect(() => s.prop1.value)
+      effect(() => s.prop2.value)
+      effect(() => s.prop3.value)
+      effect(() => s.prop4.value)
+
+      s.prop1.value
+      s.prop2.value
+      s.prop3.value
+      s.prop4.value
+
+      layer = s
+    }
+
+    const t = performance.now()
+    start.prop1.value = 4
+    start.prop2.value = 3
+    start.prop3.value = 2
+    start.prop4.value = 1
+    expect(performance.now() - t).toBeLessThan(process.env.CI ? 100 : 30)
+
+    const end = layer
+    expect([
+      end.prop1.value,
+      end.prop2.value,
+      end.prop3.value,
+      end.prop4.value,
+    ]).toMatchObject([-2, -4, 2, 3])
+  })
 })

+ 11 - 0
packages/reactivity/__tests__/reactive.spec.ts

@@ -13,6 +13,7 @@ import {
 } from '../src/reactive'
 import { computed } from '../src/computed'
 import { effect } from '../src/effect'
+import { targetMap } from '../src/dep'
 
 describe('reactivity/reactive', () => {
   test('Object', () => {
@@ -398,4 +399,14 @@ describe('reactivity/reactive', () => {
       a.value++
     }).not.toThrow()
   })
+
+  // #11979
+  test('should release property Dep instance if it no longer has subscribers', () => {
+    let obj = { x: 1 }
+    let a = reactive(obj)
+    const e = effect(() => a.x)
+    expect(targetMap.get(obj)?.get('x')).toBeTruthy()
+    e.effect.stop()
+    expect(targetMap.get(obj)?.get('x')).toBeFalsy()
+  })
 })

+ 68 - 0
packages/reactivity/__tests__/watch.spec.ts

@@ -4,6 +4,7 @@ import {
   WatchErrorCodes,
   type WatchOptions,
   type WatchScheduler,
+  computed,
   onWatcherCleanup,
   ref,
   watch,
@@ -209,4 +210,71 @@ describe('watch', () => {
     source.value++
     expect(dummy).toBe(1)
   })
+
+  // #12033
+  test('recursive sync watcher on computed', () => {
+    const r = ref(0)
+    const c = computed(() => r.value)
+
+    watch(c, v => {
+      if (v > 1) {
+        r.value--
+      }
+    })
+
+    expect(r.value).toBe(0)
+    expect(c.value).toBe(0)
+
+    r.value = 10
+    expect(r.value).toBe(1)
+    expect(c.value).toBe(1)
+  })
+
+  // edge case where a nested endBatch() causes an effect to be batched in a
+  // nested batch loop with its .next mutated, causing the outer loop to end
+  // early
+  test('nested batch edge case', () => {
+    // useClamp from VueUse
+    const clamp = (n: number, min: number, max: number) =>
+      Math.min(max, Math.max(min, n))
+    function useClamp(src: Ref<number>, min: number, max: number) {
+      return computed({
+        get() {
+          return (src.value = clamp(src.value, min, max))
+        },
+        set(val) {
+          src.value = clamp(val, min, max)
+        },
+      })
+    }
+
+    const src = ref(1)
+    const clamped = useClamp(src, 1, 5)
+    watch(src, val => (clamped.value = val))
+
+    const spy = vi.fn()
+    watch(clamped, spy)
+
+    src.value = 2
+    expect(spy).toHaveBeenCalledTimes(1)
+    src.value = 10
+    expect(spy).toHaveBeenCalledTimes(2)
+  })
+
+  test('should ensure correct execution order in batch processing', () => {
+    const dummy: number[] = []
+    const n1 = ref(0)
+    const n2 = ref(0)
+    const sum = computed(() => n1.value + n2.value)
+    watch(n1, () => {
+      dummy.push(1)
+      n2.value++
+    })
+    watch(sum, () => dummy.push(2))
+    watch(n1, () => dummy.push(3))
+
+    n1.value++
+
+    expect(dummy).toEqual([1, 2, 3])
+  })
 })

+ 1 - 1
packages/reactivity/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vue/reactivity",
-  "version": "3.5.7",
+  "version": "3.5.11",
   "description": "@vue/reactivity",
   "main": "index.js",
   "module": "dist/reactivity.esm-bundler.js",

+ 6 - 2
packages/reactivity/src/computed.ts

@@ -84,9 +84,13 @@ export class ComputedRefImpl<T = any> implements Subscriber {
    * @internal
    */
   isSSR: boolean
+  /**
+   * @internal
+   */
+  next?: Subscriber = undefined
+
   // for backwards compat
   effect: this = this
-
   // dev only
   onTrack?: (event: DebuggerEvent) => void
   // dev only
@@ -117,7 +121,7 @@ export class ComputedRefImpl<T = any> implements Subscriber {
       // avoid infinite self recursion
       activeSub !== this
     ) {
-      batch(this)
+      batch(this, true)
       return true
     } else if (__DEV__) {
       // TODO warn

+ 28 - 27
packages/reactivity/src/dep.ts

@@ -85,10 +85,14 @@ export class Dep {
   /**
    * For object property deps cleanup
    */
-  target?: unknown = undefined
   map?: KeyToDepMap = undefined
   key?: unknown = undefined
 
+  /**
+   * Subscriber counter
+   */
+  sc: number = 0
+
   constructor(public computed?: ComputedRefImpl | undefined) {
     if (__DEV__) {
       this.subsHead = undefined
@@ -113,9 +117,7 @@ export class Dep {
         activeSub.depsTail = link
       }
 
-      if (activeSub.flags & EffectFlags.TRACKING) {
-        addSub(link)
-      }
+      addSub(link)
     } else if (link.version === -1) {
       // reused from last run - already a sub, just sync version
       link.version = this.version
@@ -197,27 +199,30 @@ export class Dep {
 }
 
 function addSub(link: Link) {
-  const computed = link.dep.computed
-  // computed getting its first subscriber
-  // enable tracking + lazily subscribe to all its deps
-  if (computed && !link.dep.subs) {
-    computed.flags |= EffectFlags.TRACKING | EffectFlags.DIRTY
-    for (let l = computed.deps; l; l = l.nextDep) {
-      addSub(l)
+  link.dep.sc++
+  if (link.sub.flags & EffectFlags.TRACKING) {
+    const computed = link.dep.computed
+    // computed getting its first subscriber
+    // enable tracking + lazily subscribe to all its deps
+    if (computed && !link.dep.subs) {
+      computed.flags |= EffectFlags.TRACKING | EffectFlags.DIRTY
+      for (let l = computed.deps; l; l = l.nextDep) {
+        addSub(l)
+      }
     }
-  }
 
-  const currentTail = link.dep.subs
-  if (currentTail !== link) {
-    link.prevSub = currentTail
-    if (currentTail) currentTail.nextSub = link
-  }
+    const currentTail = link.dep.subs
+    if (currentTail !== link) {
+      link.prevSub = currentTail
+      if (currentTail) currentTail.nextSub = link
+    }
 
-  if (__DEV__ && link.dep.subsHead === undefined) {
-    link.dep.subsHead = link
-  }
+    if (__DEV__ && link.dep.subsHead === undefined) {
+      link.dep.subsHead = link
+    }
 
-  link.dep.subs = link
+    link.dep.subs = link
+  }
 }
 
 // The main WeakMap that stores {target -> key -> dep} connections.
@@ -257,7 +262,6 @@ export function track(target: object, type: TrackOpTypes, key: unknown): void {
     let dep = depsMap.get(key)
     if (!dep) {
       depsMap.set(key, (dep = new Dep()))
-      dep.target = target
       dep.map = depsMap
       dep.key = key
     }
@@ -378,13 +382,10 @@ export function trigger(
   endBatch()
 }
 
-/**
- * Test only
- */
 export function getDepFromReactive(
   object: any,
   key: string | number | symbol,
 ): Dep | undefined {
-  // eslint-disable-next-line
-  return targetMap.get(object)?.get(key)
+  const depMap = targetMap.get(object)
+  return depMap && depMap.get(key)
 }

+ 36 - 16
packages/reactivity/src/effect.ts

@@ -1,7 +1,7 @@
 import { extend, hasChanged } from '@vue/shared'
 import type { ComputedRefImpl } from './computed'
 import type { TrackOpTypes, TriggerOpTypes } from './constants'
-import { type Link, globalVersion, targetMap } from './dep'
+import { type Link, globalVersion } from './dep'
 import { activeEffectScope } from './effectScope'
 import { warn } from './warning'
 
@@ -234,9 +234,15 @@ export class ReactiveEffect<T = any>
 
 let batchDepth = 0
 let batchedSub: Subscriber | undefined
+let batchedComputed: Subscriber | undefined
 
-export function batch(sub: Subscriber): void {
+export function batch(sub: Subscriber, isComputed = false): void {
   sub.flags |= EffectFlags.NOTIFIED
+  if (isComputed) {
+    sub.next = batchedComputed
+    batchedComputed = sub
+    return
+  }
   sub.next = batchedSub
   batchedSub = sub
 }
@@ -257,6 +263,17 @@ export function endBatch(): void {
     return
   }
 
+  if (batchedComputed) {
+    let e: Subscriber | undefined = batchedComputed
+    batchedComputed = undefined
+    while (e) {
+      const next: Subscriber | undefined = e.next
+      e.next = undefined
+      e.flags &= ~EffectFlags.NOTIFIED
+      e = next
+    }
+  }
+
   let error: unknown
   while (batchedSub) {
     let e: Subscriber | undefined = batchedSub
@@ -399,7 +416,7 @@ export function refreshComputed(computed: ComputedRefImpl): undefined {
   }
 }
 
-function removeSub(link: Link, fromComputed = false) {
+function removeSub(link: Link, soft = false) {
   const { dep, prevSub, nextSub } = link
   if (prevSub) {
     prevSub.nextSub = nextSub
@@ -418,21 +435,24 @@ function removeSub(link: Link, fromComputed = false) {
     dep.subsHead = nextSub
   }
 
-  if (!dep.subs) {
-    // last subscriber removed
-    if (dep.computed) {
-      // if computed, unsubscribe it from all its deps so this computed and its
-      // value can be GCed
-      dep.computed.flags &= ~EffectFlags.TRACKING
-      for (let l = dep.computed.deps; l; l = l.nextDep) {
-        removeSub(l, true)
-      }
-    } else if (dep.map && !fromComputed) {
-      // property dep, remove it from the owner depsMap
-      dep.map.delete(dep.key)
-      if (!dep.map.size) targetMap.delete(dep.target!)
+  if (!dep.subs && dep.computed) {
+    // if computed, unsubscribe it from all its deps so this computed and its
+    // value can be GCed
+    dep.computed.flags &= ~EffectFlags.TRACKING
+    for (let l = dep.computed.deps; l; l = l.nextDep) {
+      // here we are only "soft" unsubscribing because the computed still keeps
+      // referencing the deps and the dep should not decrease its sub count
+      removeSub(l, true)
     }
   }
+
+  if (!soft && !--dep.sc && dep.map) {
+    // #11979
+    // property dep no longer has effect subscribers, delete it
+    // this mostly is for the case where an object is kept in memory but only a
+    // subset of its properties is tracked at one time
+    dep.map.delete(dep.key)
+  }
 }
 
 function removeDep(link: Link) {

+ 1 - 1
packages/reactivity/src/reactive.ts

@@ -167,7 +167,7 @@ export type DeepReadonly<T> = T extends Builtin
               ? WeakSet<DeepReadonly<U>>
               : T extends Promise<infer U>
                 ? Promise<DeepReadonly<U>>
-                : T extends Ref<infer U>
+                : T extends Ref<infer U, unknown>
                   ? Readonly<Ref<DeepReadonly<U>>>
                   : T extends {}
                     ? { readonly [K in keyof T]: DeepReadonly<T[K]> }

+ 6 - 4
packages/reactivity/src/ref.ts

@@ -62,7 +62,9 @@ export function ref(value?: unknown) {
 
 declare const ShallowRefMarker: unique symbol
 
-export type ShallowRef<T = any> = Ref<T> & { [ShallowRefMarker]?: true }
+export type ShallowRef<T = any, S = T> = Ref<T, S> & {
+  [ShallowRefMarker]?: true
+}
 
 /**
  * Shallow version of {@link ref()}.
@@ -487,12 +489,12 @@ export type ShallowUnwrapRef<T> = {
   [K in keyof T]: DistributeRef<T[K]>
 }
 
-type DistributeRef<T> = T extends Ref<infer V> ? V : T
+type DistributeRef<T> = T extends Ref<infer V, unknown> ? V : T
 
 export type UnwrapRef<T> =
-  T extends ShallowRef<infer V>
+  T extends ShallowRef<infer V, unknown>
     ? V
-    : T extends Ref<infer V>
+    : T extends Ref<infer V, unknown>
       ? UnwrapRefSimple<V>
       : UnwrapRefSimple<T>
 

+ 27 - 1
packages/runtime-core/__tests__/apiWatch.spec.ts

@@ -1930,7 +1930,7 @@ describe('api: watch', () => {
     warn.mockRestore()
   })
 
-  it('should be executed correctly', () => {
+  test('should be executed correctly', () => {
     const v = ref(1)
     let foo = ''
 
@@ -1957,4 +1957,30 @@ describe('api: watch', () => {
     v.value++
     expect(foo).toBe('12')
   })
+
+  // 12045
+  test('sync watcher should not break pre watchers', async () => {
+    const count1 = ref(0)
+    const count2 = ref(0)
+
+    watch(
+      count1,
+      () => {
+        count2.value++
+      },
+      { flush: 'sync' },
+    )
+
+    const spy1 = vi.fn()
+    watch([count1, count2], spy1)
+
+    const spy2 = vi.fn()
+    watch(count1, spy2)
+
+    count1.value++
+
+    await nextTick()
+    expect(spy1).toHaveBeenCalled()
+    expect(spy2).toHaveBeenCalled()
+  })
 })

+ 9 - 0
packages/runtime-core/__tests__/rendererChildren.spec.ts

@@ -65,6 +65,15 @@ test('array children -> text children', () => {
   expect(inner(root)).toBe('<div>hello</div>')
 })
 
+test('plain object child', () => {
+  const root = nodeOps.createElement('div')
+  const foo = { foo: '1' }
+  // @ts-expect-error
+  render(h('div', null, [foo]), root)
+  expect('Invalid VNode type').not.toHaveBeenWarned()
+  expect(inner(root)).toBe('<div>[object Object]</div>')
+})
+
 describe('renderer: keyed children', () => {
   let root: TestElement
   let elm: TestElement

+ 54 - 0
packages/runtime-core/__tests__/scheduler.spec.ts

@@ -441,6 +441,29 @@ describe('scheduler', () => {
       await nextTick()
       expect(calls).toEqual(['job1', 'job2', 'cb1', 'cb2'])
     })
+
+    test('jobs added during post flush are ordered correctly', async () => {
+      const calls: string[] = []
+
+      const job1: SchedulerJob = () => {
+        calls.push('job1')
+      }
+      job1.id = 1
+
+      const job2: SchedulerJob = () => {
+        calls.push('job2')
+      }
+      job2.id = 2
+
+      queuePostFlushCb(() => {
+        queueJob(job2)
+        queueJob(job1)
+      })
+
+      await nextTick()
+
+      expect(calls).toEqual(['job1', 'job2'])
+    })
   })
 
   test('sort job based on id', async () => {
@@ -758,6 +781,37 @@ describe('scheduler', () => {
     expect(spy).toHaveBeenCalledTimes(1)
   })
 
+  test('flushPreFlushCbs inside a post job', async () => {
+    const calls: string[] = []
+    const callsAfterFlush: string[] = []
+
+    const job1: SchedulerJob = () => {
+      calls.push('job1')
+    }
+    job1.id = 1
+    job1.flags! |= SchedulerJobFlags.PRE
+
+    const job2: SchedulerJob = () => {
+      calls.push('job2')
+    }
+    job2.id = 2
+    job2.flags! |= SchedulerJobFlags.PRE
+
+    queuePostFlushCb(() => {
+      queueJob(job2)
+      queueJob(job1)
+
+      // e.g. nested app.mount() call
+      flushPreFlushCbs()
+      callsAfterFlush.push(...calls)
+    })
+
+    await nextTick()
+
+    expect(callsAfterFlush).toEqual(['job1', 'job2'])
+    expect(calls).toEqual(['job1', 'job2'])
+  })
+
   it('nextTick should return promise', async () => {
     const fn = vi.fn(() => {
       return 1

+ 1 - 1
packages/runtime-core/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vue/runtime-core",
-  "version": "3.5.7",
+  "version": "3.5.11",
   "description": "@vue/runtime-core",
   "main": "index.js",
   "module": "dist/runtime-core.esm-bundler.js",

+ 9 - 11
packages/runtime-core/src/apiDefineComponent.ts

@@ -27,7 +27,7 @@ import type {
   EmitsToProps,
   TypeEmitsToOptions,
 } from './componentEmits'
-import { extend, isFunction } from '@vue/shared'
+import { type IsKeyValues, extend, isFunction } from '@vue/shared'
 import type { VNodeProps } from './vnode'
 import type {
   ComponentPublicInstanceConstructor,
@@ -79,7 +79,7 @@ export type DefineComponent<
     Mixin,
     Extends,
     E,
-    PP & Props,
+    PP,
     Defaults,
     MakeDefaultsOptional,
     {},
@@ -208,15 +208,13 @@ export function defineComponent<
   ResolvedEmits extends EmitsOptions = {} extends RuntimeEmitsOptions
     ? TypeEmitsToOptions<TypeEmits>
     : RuntimeEmitsOptions,
-  InferredProps = unknown extends TypeProps
-    ? keyof TypeProps extends never
-      ? string extends RuntimePropsKeys
-        ? ComponentObjectPropsOptions extends RuntimePropsOptions
-          ? {}
-          : ExtractPropTypes<RuntimePropsOptions>
-        : { [key in RuntimePropsKeys]?: any }
-      : TypeProps
-    : TypeProps,
+  InferredProps = IsKeyValues<TypeProps> extends true
+    ? TypeProps
+    : string extends RuntimePropsKeys
+      ? ComponentObjectPropsOptions extends RuntimePropsOptions
+        ? {}
+        : ExtractPropTypes<RuntimePropsOptions>
+      : { [key in RuntimePropsKeys]?: any },
   TypeRefs extends Record<string, unknown> = {},
   TypeEl extends Element = any,
 >(

+ 14 - 2
packages/runtime-core/src/componentEmits.ts

@@ -66,11 +66,23 @@ export type TypeEmitsToOptions<T extends ComponentTypeEmits> = {
   : {})
 
 type ParametersToFns<T extends any[]> = {
-  [K in T[0]]: K extends `${infer C}`
-    ? (...args: T extends [C, ...infer Args] ? Args : never) => any
+  [K in T[0]]: IsStringLiteral<K> extends true
+    ? (
+        ...args: T extends [e: infer E, ...args: infer P]
+          ? K extends E
+            ? P
+            : never
+          : never
+      ) => any
     : never
 }
 
+type IsStringLiteral<T> = T extends string
+  ? string extends T
+    ? false
+    : true
+  : false
+
 export type ShortEmitsToObject<E> =
   E extends Record<string, any[]>
     ? {

+ 2 - 1
packages/runtime-core/src/helpers/useId.ts

@@ -4,7 +4,7 @@ import {
 } from '../component'
 import { warn } from '../warning'
 
-export function useId(): string | undefined {
+export function useId(): string {
   const i = getCurrentInstance()
   if (i) {
     return (i.appContext.config.idPrefix || 'v') + '-' + i.ids[0] + i.ids[1]++
@@ -14,6 +14,7 @@ export function useId(): string | undefined {
         `instance to be associated with.`,
     )
   }
+  return ''
 }
 
 /**

+ 2 - 2
packages/runtime-core/src/hydration.ts

@@ -1,8 +1,8 @@
 import {
-  Comment,
   Fragment,
   Static,
   Text,
+  Comment as VComment,
   type VNode,
   type VNodeHook,
   createTextVNode,
@@ -195,7 +195,7 @@ export function createHydrationFunctions(
           nextNode = nextSibling(node)
         }
         break
-      case Comment:
+      case VComment:
         if (isTemplateNode(node)) {
           nextNode = nextSibling(node)
           // wrapped <transition appear>

+ 7 - 15
packages/runtime-core/src/scheduler.ts

@@ -40,11 +40,8 @@ export interface SchedulerJob extends Function {
 
 export type SchedulerJobs = SchedulerJob | SchedulerJob[]
 
-let isFlushing = false
-let isFlushPending = false
-
 const queue: SchedulerJob[] = []
-let flushIndex = 0
+let flushIndex = -1
 
 const pendingPostFlushCbs: SchedulerJob[] = []
 let activePostFlushCbs: SchedulerJob[] | null = null
@@ -74,7 +71,7 @@ export function nextTick<T = void, R = void>(
 // watcher should be inserted immediately before the update job. This allows
 // watchers to be skipped if the component is unmounted by the parent update.
 function findInsertionIndex(id: number) {
-  let start = isFlushing ? flushIndex + 1 : 0
+  let start = flushIndex + 1
   let end = queue.length
 
   while (start < end) {
@@ -115,8 +112,7 @@ export function queueJob(job: SchedulerJob): void {
 }
 
 function queueFlush() {
-  if (!isFlushing && !isFlushPending) {
-    isFlushPending = true
+  if (!currentFlushPromise) {
     currentFlushPromise = resolvedPromise.then(flushJobs)
   }
 }
@@ -141,8 +137,8 @@ export function queuePostFlushCb(cb: SchedulerJobs): void {
 export function flushPreFlushCbs(
   instance?: ComponentInternalInstance,
   seen?: CountMap,
-  // if currently flushing, skip the current job itself
-  i: number = isFlushing ? flushIndex + 1 : 0,
+  // skip the current job
+  i: number = flushIndex + 1,
 ): void {
   if (__DEV__) {
     seen = seen || new Map()
@@ -211,8 +207,6 @@ const getId = (job: SchedulerJob): number =>
   job.id == null ? (job.flags! & SchedulerJobFlags.PRE ? -1 : Infinity) : job.id
 
 function flushJobs(seen?: CountMap) {
-  isFlushPending = false
-  isFlushing = true
   if (__DEV__) {
     seen = seen || new Map()
   }
@@ -255,15 +249,13 @@ function flushJobs(seen?: CountMap) {
       }
     }
 
-    flushIndex = 0
+    flushIndex = -1
     queue.length = 0
 
     flushPostFlushCbs(seen)
 
-    isFlushing = false
     currentFlushPromise = null
-    // some postFlushCb queued jobs!
-    // keep flushing until it drains.
+    // If new jobs have been added to either queue, keep flushing
     if (queue.length || pendingPostFlushCbs.length) {
       flushJobs(seen)
     }

+ 1 - 1
packages/runtime-core/src/vnode.ts

@@ -793,7 +793,7 @@ export function normalizeVNode(child: VNodeChild): VNode {
       // #3666, avoid reference pollution when reusing vnode
       child.slice(),
     )
-  } else if (typeof child === 'object') {
+  } else if (isVNode(child)) {
     // already vnode, this should be the most common since compiled templates
     // always produce all-vnode children arrays
     return cloneIfMounted(child)

+ 15 - 0
packages/runtime-dom/__tests__/customElement.spec.ts

@@ -223,6 +223,21 @@ describe('defineCustomElement', () => {
       expect(e.getAttribute('baz-qux')).toBe('four')
     })
 
+    test('props via hyphen property', async () => {
+      const Comp = defineCustomElement({
+        props: {
+          fooBar: Boolean,
+        },
+        render() {
+          return 'Comp'
+        },
+      })
+      customElements.define('my-el-comp', Comp)
+      render(h('my-el-comp', { 'foo-bar': true }), container)
+      const el = container.children[0]
+      expect((el as any).outerHTML).toBe('<my-el-comp foo-bar=""></my-el-comp>')
+    })
+
     test('attribute -> prop type casting', async () => {
       const E = defineCustomElement({
         props: {

+ 1 - 1
packages/runtime-dom/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vue/runtime-dom",
-  "version": "3.5.7",
+  "version": "3.5.11",
   "description": "@vue/runtime-dom",
   "main": "index.js",
   "module": "dist/runtime-dom.esm-bundler.js",

+ 6 - 6
packages/runtime-dom/src/directives/vModel.ts

@@ -160,7 +160,7 @@ export const vModelCheckbox: ModelDirective<HTMLInputElement> = {
 
 function setChecked(
   el: HTMLInputElement,
-  { value, oldValue }: DirectiveBinding,
+  { value }: DirectiveBinding,
   vnode: VNode,
 ) {
   // store the v-model value on the element so it can be accessed by the
@@ -225,20 +225,20 @@ export const vModelSelect: ModelDirective<HTMLSelectElement, 'number'> = {
   },
   // set value in mounted & updated because <select> relies on its children
   // <option>s.
-  mounted(el, { value, modifiers: { number } }) {
-    setSelected(el, value, number)
+  mounted(el, { value }) {
+    setSelected(el, value)
   },
   beforeUpdate(el, _binding, vnode) {
     el[assignKey] = getModelAssigner(vnode)
   },
-  updated(el, { value, modifiers: { number } }) {
+  updated(el, { value }) {
     if (!el._assigning) {
-      setSelected(el, value, number)
+      setSelected(el, value)
     }
   },
 }
 
-function setSelected(el: HTMLSelectElement, value: any, number: boolean) {
+function setSelected(el: HTMLSelectElement, value: any) {
   const isMultiple = el.multiple
   const isArrayValue = isArray(value)
   if (isMultiple && !isArrayValue && !isSet(value)) {

+ 8 - 10
packages/runtime-dom/src/patchProp.ts

@@ -4,6 +4,7 @@ import { patchAttr } from './modules/attrs'
 import { patchDOMProp } from './modules/props'
 import { patchEvent } from './modules/events'
 import {
+  camelize,
   isFunction,
   isModelListener,
   isNativeOn,
@@ -50,6 +51,12 @@ export const patchProp: DOMRendererOptions['patchProp'] = (
     ) {
       patchAttr(el, key, nextValue, isSVG, parentComponent, key !== 'value')
     }
+  } else if (
+    // #11081 force set props for possible async custom element
+    (el as VueElement)._isVueCE &&
+    (/[A-Z]/.test(key) || !isString(nextValue))
+  ) {
+    patchDOMProp(el, camelize(key), nextValue, parentComponent)
   } else {
     // special case for <input v-model type="checkbox"> with
     // :true-value & :false-value
@@ -127,14 +134,5 @@ function shouldSetAsProp(
     return false
   }
 
-  if (key in el) {
-    return true
-  }
-
-  // #11081 force set props for possible async custom element
-  if ((el as VueElement)._isVueCE && (/[A-Z]/.test(key) || !isString(value))) {
-    return true
-  }
-
-  return false
+  return key in el
 }

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

@@ -1,6 +1,6 @@
 {
   "name": "@vue/server-renderer",
-  "version": "3.5.7",
+  "version": "3.5.11",
   "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.5.7",
+  "version": "3.5.11",
   "description": "internal utils shared across @vue packages",
   "main": "index.js",
   "module": "dist/shared.esm-bundler.js",

+ 9 - 0
packages/shared/src/general.ts

@@ -218,3 +218,12 @@ export function genPropsAccessExp(name: string): string {
     ? `__props.${name}`
     : `__props[${JSON.stringify(name)}]`
 }
+
+export function genCacheKey(source: string, options: any): string {
+  return (
+    source +
+    JSON.stringify(options, (_, val) =>
+      typeof val === 'function' ? val.toString() : val,
+    )
+  )
+}

+ 6 - 0
packages/shared/src/typeUtils.ts

@@ -13,6 +13,12 @@ export type LooseRequired<T> = { [P in keyof (T & Required<T>)]: T[P] }
 // https://stackoverflow.com/questions/49927523/disallow-call-with-any/49928360#49928360
 export type IfAny<T, Y, N> = 0 extends 1 & T ? Y : N
 
+export type IsKeyValues<T, K = string> = IfAny<
+  T,
+  false,
+  T extends object ? (keyof T extends K ? true : false) : false
+>
+
 /**
  * Utility for extracting the parameters from a function overload (for typed emits)
  * https://github.com/microsoft/TypeScript/issues/32164#issuecomment-1146737709

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

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

+ 8 - 2
packages/vue-compat/src/index.ts

@@ -12,7 +12,13 @@ import {
   registerRuntimeCompiler,
   warn,
 } from '@vue/runtime-dom'
-import { NOOP, extend, generateCodeFrame, isString } from '@vue/shared'
+import {
+  NOOP,
+  extend,
+  genCacheKey,
+  generateCodeFrame,
+  isString,
+} from '@vue/shared'
 import type { InternalRenderFunction } from 'packages/runtime-core/src/component'
 import * as runtimeDom from '@vue/runtime-dom'
 import {
@@ -35,7 +41,7 @@ function compileToFunction(
     }
   }
 
-  const key = template
+  const key = genCacheKey(template, options)
   const cached = compileCache[key]
   if (cached) {
     return cached

+ 1 - 1
packages/vue/package.json

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

+ 5 - 18
packages/vue/src/index.ts

@@ -13,9 +13,9 @@ import {
 } from '@vue/runtime-dom'
 import * as runtimeDom from '@vue/runtime-dom'
 import {
-  EMPTY_OBJ,
   NOOP,
   extend,
+  genCacheKey,
   generateCodeFrame,
   isString,
 } from '@vue/shared'
@@ -25,19 +25,7 @@ if (__DEV__) {
   initDev()
 }
 
-const compileCache = new WeakMap<
-  CompilerOptions,
-  Record<string, RenderFunction>
->()
-
-function getCache(options?: CompilerOptions) {
-  let c = compileCache.get(options ?? EMPTY_OBJ)
-  if (!c) {
-    c = Object.create(null) as Record<string, RenderFunction>
-    compileCache.set(options ?? EMPTY_OBJ, c)
-  }
-  return c
-}
+const compileCache: Record<string, RenderFunction> = Object.create(null)
 
 function compileToFunction(
   template: string | HTMLElement,
@@ -52,9 +40,8 @@ function compileToFunction(
     }
   }
 
-  const key = template
-  const cache = getCache(options)
-  const cached = cache[key]
+  const key = genCacheKey(template, options)
+  const cached = compileCache[key]
   if (cached) {
     return cached
   }
@@ -111,7 +98,7 @@ function compileToFunction(
   // mark the function as runtime compiled
   ;(render as InternalRenderFunction)._rc = true
 
-  return (cache[key] = render)
+  return (compileCache[key] = render)
 }
 
 registerRuntimeCompiler(compileToFunction)

Різницю між файлами не показано, бо вона завелика
+ 170 - 355
pnpm-lock.yaml


+ 9 - 6
scripts/release.js

@@ -306,12 +306,6 @@ async function main() {
   if (args.publish) {
     await buildPackages()
     await publishPackages(targetVersion)
-  } else {
-    console.log(
-      pico.yellow(
-        '\nPublish step skipped (will be done in GitHub actions on successful push)',
-      ),
-    )
   }
 
   // push to GitHub
@@ -322,6 +316,15 @@ async function main() {
     await runIfNotDry('git', ['push'])
   }
 
+  if (!args.publish) {
+    console.log(
+      pico.yellow(
+        '\nRelease will be done via GitHub Actions.\n' +
+          'Check status at https://github.com/vuejs/core/actions/workflows/release.yml',
+      ),
+    )
+  }
+
   if (isDryRun) {
     console.log(`\nDry run finished - run git diff to see package changes.`)
   }

Деякі файли не було показано, через те що забагато файлів було змінено