Skip to content

Commit f0405f1

Browse files
committed
Merge tag 'v3.5.0-alpha.4'
2 parents 61ddfe9 + 4ffd9db commit f0405f1

File tree

20 files changed

+163
-42
lines changed

20 files changed

+163
-42
lines changed

CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
# [3.5.0-alpha.4](https://github.com/vuejs/core/compare/v3.4.34...v3.5.0-alpha.4) (2024-07-24)
2+
3+
4+
### Bug Fixes
5+
6+
* **suspense/hydration:** fix hydration timing of async component inside suspense ([1b8e197](https://github.com/vuejs/core/commit/1b8e197a5b65d67a9703b8511786fb81df9aa7cc)), closes [#6638](https://github.com/vuejs/core/issues/6638)
7+
* **useId:** properly mark async boundary for already resolved async component ([cd28172](https://github.com/vuejs/core/commit/cd281725781ada2ab279e919031ae307e146a9d9))
8+
9+
10+
11+
## [3.4.34](https://github.com/vuejs/core/compare/v3.4.33...v3.4.34) (2024-07-24)
12+
13+
* **defineModel:** correct update with multiple changes in same tick ([#11430](https://github.com/vuejs/core/issues/11430)) ([a18f1ec](https://github.com/vuejs/core/commit/a18f1ecf05842337f1eb39a6871adb8cb4024093)), closes [#11429](https://github.com/vuejs/core/issues/11429)
14+
15+
16+
117
# [3.5.0-alpha.3](https://github.com/vuejs/core/compare/v3.4.33...v3.5.0-alpha.3) (2024-07-19)
218

319

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"private": true,
3-
"version": "3.0.0-vapor",
3+
"version": "3.5.0-alpha.4",
44
"packageManager": "[email protected]",
55
"type": "module",
66
"scripts": {

packages/compiler-core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@vue/compiler-core",
3-
"version": "3.5.0-alpha.3",
3+
"version": "3.5.0-alpha.4",
44
"description": "@vue/compiler-core",
55
"main": "index.js",
66
"module": "dist/compiler-core.esm-bundler.js",

packages/compiler-dom/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@vue/compiler-dom",
3-
"version": "3.5.0-alpha.3",
3+
"version": "3.5.0-alpha.4",
44
"description": "@vue/compiler-dom",
55
"main": "index.js",
66
"module": "dist/compiler-dom.esm-bundler.js",

packages/compiler-sfc/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@vue/compiler-sfc",
3-
"version": "3.5.0-alpha.3",
3+
"version": "3.5.0-alpha.4",
44
"description": "@vue/compiler-sfc",
55
"main": "dist/compiler-sfc.cjs.js",
66
"module": "dist/compiler-sfc.esm-browser.js",

packages/compiler-ssr/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@vue/compiler-ssr",
3-
"version": "3.5.0-alpha.3",
3+
"version": "3.5.0-alpha.4",
44
"description": "@vue/compiler-ssr",
55
"main": "dist/compiler-ssr.cjs.js",
66
"types": "dist/compiler-ssr.d.ts",

packages/reactivity/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@vue/reactivity",
3-
"version": "3.5.0-alpha.3",
3+
"version": "3.5.0-alpha.4",
44
"description": "@vue/reactivity",
55
"main": "index.js",
66
"module": "dist/reactivity.esm-bundler.js",

packages/runtime-core/__tests__/helpers/useId.spec.ts

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@ import {
1212
} from 'vue'
1313
import { renderToString } from '@vue/server-renderer'
1414

15-
type TestCaseFactory = () => [App, Promise<any>[]]
15+
type FactoryRes = [App, Promise<any>[]]
16+
type TestCaseFactory = () => FactoryRes | Promise<FactoryRes>
1617

1718
async function runOnClient(factory: TestCaseFactory) {
18-
const [app, deps] = factory()
19+
const [app, deps] = await factory()
1920
const root = document.createElement('div')
2021
app.mount(root)
2122
await Promise.all(deps)
@@ -24,7 +25,7 @@ async function runOnClient(factory: TestCaseFactory) {
2425
}
2526

2627
async function runOnServer(factory: TestCaseFactory) {
27-
const [app, _] = factory()
28+
const [app, _] = await factory()
2829
return (await renderToString(app))
2930
.replace(/<!--[\[\]]-->/g, '') // remove fragment wrappers
3031
.trim()
@@ -95,8 +96,8 @@ describe('useId', () => {
9596
'v:0-0 v:0-1 ' + // inside first async subtree
9697
'v:1-0 v:1-1' // inside second async subtree
9798
// assert different async resolution order does not affect id stable-ness
98-
expect(await getOutput(() => factory(10, 20))).toBe(expected)
99-
expect(await getOutput(() => factory(20, 10))).toBe(expected)
99+
expect(await getOutput(() => factory(0, 16))).toBe(expected)
100+
expect(await getOutput(() => factory(16, 0))).toBe(expected)
100101
})
101102

102103
test('serverPrefetch', async () => {
@@ -140,8 +141,8 @@ describe('useId', () => {
140141
'v:0-0 v:0-1 ' + // inside first async subtree
141142
'v:1-0 v:1-1' // inside second async subtree
142143
// assert different async resolution order does not affect id stable-ness
143-
expect(await getOutput(() => factory(10, 20))).toBe(expected)
144-
expect(await getOutput(() => factory(20, 10))).toBe(expected)
144+
expect(await getOutput(() => factory(0, 16))).toBe(expected)
145+
expect(await getOutput(() => factory(16, 0))).toBe(expected)
145146
})
146147

147148
test('async setup()', async () => {
@@ -192,8 +193,8 @@ describe('useId', () => {
192193
'v:1-0 v:1-1' + // inside second async subtree
193194
'</div>'
194195
// assert different async resolution order does not affect id stable-ness
195-
expect(await getOutput(() => factory(10, 20))).toBe(expected)
196-
expect(await getOutput(() => factory(20, 10))).toBe(expected)
196+
expect(await getOutput(() => factory(0, 16))).toBe(expected)
197+
expect(await getOutput(() => factory(16, 0))).toBe(expected)
197198
})
198199

199200
test('deep nested', async () => {
@@ -239,4 +240,49 @@ describe('useId', () => {
239240
expect(await getOutput(() => factory())).toBe(expected)
240241
expect(await getOutput(() => factory())).toBe(expected)
241242
})
243+
244+
test('async component inside async setup, already resolved', async () => {
245+
const factory = async (
246+
delay1: number,
247+
delay2: number,
248+
): Promise<FactoryRes> => {
249+
const p1 = promiseWithDelay(null, delay1)
250+
const p2 = promiseWithDelay(BasicComponentWithUseId, delay2)
251+
const AsyncInner = defineAsyncComponent(() => p2)
252+
253+
const AsyncSetup = defineComponent({
254+
async setup() {
255+
await p1
256+
return {}
257+
},
258+
render() {
259+
return h(AsyncInner)
260+
},
261+
})
262+
263+
const app = createApp({
264+
setup() {
265+
const id1 = useId()
266+
const id2 = useId()
267+
return () =>
268+
h(Suspense, null, {
269+
default: h('div', [id1, ' ', id2, ' ', h(AsyncSetup)]),
270+
})
271+
},
272+
})
273+
274+
// the async component may have already been resolved
275+
await AsyncInner.__asyncLoader()
276+
return [app, [p1, p2]]
277+
}
278+
279+
const expected =
280+
'<div>' +
281+
'v:0 v:1 ' + // root
282+
'v:0-0-0 v:0-0-1' + // async component inside async setup
283+
'</div>'
284+
// assert different async resolution order does not affect id stable-ness
285+
expect(await getOutput(async () => factory(0, 16))).toBe(expected)
286+
expect(await getOutput(() => factory(16, 0))).toBe(expected)
287+
})
242288
})

packages/runtime-core/__tests__/helpers/useModel.spec.ts

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -614,32 +614,31 @@ describe('useModel', () => {
614614
})
615615

616616
test('set no change value', async () => {
617-
let changeChildMsg: (() => void) | null = null
617+
let changeChildMsg!: (val: string) => void
618618

619-
const compRender = vi.fn()
619+
const setValue = vi.fn()
620620
const Comp = defineComponent({
621621
props: ['msg'],
622622
emits: ['update:msg'],
623623
setup(props) {
624624
const childMsg = useModel(props, 'msg')
625-
changeChildMsg = () => {
626-
childMsg.value = childMsg.value
627-
}
625+
changeChildMsg = (val: string) => (childMsg.value = val)
628626
return () => {
629627
return childMsg.value
630628
}
631629
},
632630
})
633631

634-
const msg = ref('HI')
632+
const defaultVal = 'defaultVal'
633+
const msg = ref(defaultVal)
635634
const Parent = defineComponent({
636635
setup() {
637636
return () =>
638637
h(Comp, {
639638
msg: msg.value,
640639
'onUpdate:msg': val => {
641640
msg.value = val
642-
compRender()
641+
setValue()
643642
},
644643
})
645644
},
@@ -648,8 +647,14 @@ describe('useModel', () => {
648647
const root = nodeOps.createElement('div')
649648
render(h(Parent), root)
650649

651-
expect(compRender).toBeCalledTimes(0)
652-
changeChildMsg!()
653-
expect(compRender).toBeCalledTimes(0)
650+
expect(setValue).toBeCalledTimes(0)
651+
652+
changeChildMsg(defaultVal)
653+
expect(setValue).toBeCalledTimes(0)
654+
655+
changeChildMsg('changed')
656+
changeChildMsg(defaultVal)
657+
expect(setValue).toBeCalledTimes(2)
658+
expect(msg.value).toBe(defaultVal)
654659
})
655660
})

packages/runtime-core/__tests__/hydration.spec.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,54 @@ describe('SSR hydration', () => {
688688
expect(container.innerHTML).toBe(`<span>1</span>`)
689689
})
690690

691+
// #6638
692+
test('Suspense + async component', async () => {
693+
let isSuspenseResolved = false
694+
let isSuspenseResolvedInChild: any
695+
const AsyncChild = defineAsyncComponent(() =>
696+
Promise.resolve(
697+
defineComponent({
698+
setup() {
699+
isSuspenseResolvedInChild = isSuspenseResolved
700+
const count = ref(0)
701+
return () =>
702+
h(
703+
'span',
704+
{
705+
onClick: () => {
706+
count.value++
707+
},
708+
},
709+
count.value,
710+
)
711+
},
712+
}),
713+
),
714+
)
715+
const { vnode, container } = mountWithHydration('<span>0</span>', () =>
716+
h(
717+
Suspense,
718+
{
719+
onResolve() {
720+
isSuspenseResolved = true
721+
},
722+
},
723+
() => h(AsyncChild),
724+
),
725+
)
726+
expect(vnode.el).toBe(container.firstChild)
727+
// wait for hydration to finish
728+
await new Promise(r => setTimeout(r))
729+
730+
expect(isSuspenseResolvedInChild).toBe(false)
731+
expect(isSuspenseResolved).toBe(true)
732+
733+
// assert interaction
734+
triggerEvent('click', container.querySelector('span')!)
735+
await nextTick()
736+
expect(container.innerHTML).toBe(`<span>1</span>`)
737+
})
738+
691739
test('Suspense (full integration)', async () => {
692740
const mountedCalls: number[] = []
693741
const asyncDeps: Promise<any>[] = []

0 commit comments

Comments
 (0)