Skip to content

Commit

Permalink
Merge branch 'main' into feat/nextTick
Browse files Browse the repository at this point in the history
  • Loading branch information
edison1105 authored Sep 29, 2024
2 parents 6b11d44 + 29de6f8 commit 6eb3494
Show file tree
Hide file tree
Showing 35 changed files with 646 additions and 428 deletions.
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,29 @@
## [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)


Expand Down
14 changes: 7 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"private": true,
"version": "3.5.8",
"version": "3.5.10",
"packageManager": "pnpm@9.10.0",
"type": "module",
"scripts": {
Expand Down Expand Up @@ -61,12 +61,12 @@
"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/semver": "^7.5.8",
Expand All @@ -75,7 +75,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",
Expand All @@ -94,7 +94,7 @@
"pug": "^3.0.3",
"puppeteer": "~23.3.0",
"rimraf": "^6.0.1",
"rollup": "^4.21.3",
"rollup": "^4.22.4",
"rollup-plugin-dts": "^6.1.1",
"rollup-plugin-esbuild": "^6.1.1",
"rollup-plugin-polyfill-node": "^0.13.0",
Expand Down
18 changes: 18 additions & 0 deletions packages-private/dts-test/ref.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
}
2 changes: 1 addition & 1 deletion packages/compiler-core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@vue/compiler-core",
"version": "3.5.8",
"version": "3.5.10",
"description": "@vue/compiler-core",
"main": "index.js",
"module": "dist/compiler-core.esm-bundler.js",
Expand Down
2 changes: 1 addition & 1 deletion packages/compiler-dom/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@vue/compiler-dom",
"version": "3.5.8",
"version": "3.5.10",
"description": "@vue/compiler-dom",
"main": "index.js",
"module": "dist/compiler-dom.esm-bundler.js",
Expand Down
2 changes: 1 addition & 1 deletion packages/compiler-sfc/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@vue/compiler-sfc",
"version": "3.5.8",
"version": "3.5.10",
"description": "@vue/compiler-sfc",
"main": "dist/compiler-sfc.cjs.js",
"module": "dist/compiler-sfc.esm-browser.js",
Expand Down
19 changes: 5 additions & 14 deletions packages/compiler-sfc/src/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'

Expand Down Expand Up @@ -103,24 +104,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
Expand Down
1 change: 1 addition & 0 deletions packages/compiler-sfc/src/script/definePropsDestructure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
2 changes: 1 addition & 1 deletion packages/compiler-ssr/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@vue/compiler-ssr",
"version": "3.5.8",
"version": "3.5.10",
"description": "@vue/compiler-ssr",
"main": "dist/compiler-ssr.cjs.js",
"types": "dist/compiler-ssr.d.ts",
Expand Down
70 changes: 70 additions & 0 deletions packages/reactivity/__tests__/computed.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1023,6 +1023,7 @@ describe('reactivity/computed', () => {
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 })
Expand All @@ -1037,4 +1038,73 @@ describe('reactivity/computed', () => {
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 changes: 11 additions & 0 deletions packages/reactivity/__tests__/reactive.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down Expand Up @@ -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()
})
})
51 changes: 51 additions & 0 deletions packages/reactivity/__tests__/watch.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
WatchErrorCodes,
type WatchOptions,
type WatchScheduler,
computed,
onWatcherCleanup,
ref,
watch,
Expand Down Expand Up @@ -209,4 +210,54 @@ 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)
})
})
2 changes: 1 addition & 1 deletion packages/reactivity/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@vue/reactivity",
"version": "3.5.8",
"version": "3.5.10",
"description": "@vue/reactivity",
"main": "index.js",
"module": "dist/reactivity.esm-bundler.js",
Expand Down
6 changes: 5 additions & 1 deletion packages/reactivity/src/computed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading

0 comments on commit 6eb3494

Please sign in to comment.