]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(hmr): reload async child wrapped in Suspense + KeepAlive (#11907)
authoredison <daiwei521@126.com>
Fri, 13 Sep 2024 12:19:47 +0000 (20:19 +0800)
committerGitHub <noreply@github.com>
Fri, 13 Sep 2024 12:19:47 +0000 (20:19 +0800)
close #11868

packages/runtime-core/__tests__/hmr.spec.ts
packages/runtime-core/src/hmr.ts
packages/runtime-core/src/renderer.ts

index ba9c7c0780b3f86811aeb3430e4a259fdf9ba2f1..3f157d009a93e247a18ff210c9ae585c8438e696 100644 (file)
@@ -851,4 +851,47 @@ describe('hot module replacement', () => {
 
     expect(serializeInner(root)).toBe(`<div>1</div><div>1</div>`)
   })
+
+  test('reload async child wrapped in Suspense + KeepAlive', async () => {
+    const id = 'async-child-reload'
+    const AsyncChild: ComponentOptions = {
+      __hmrId: id,
+      async setup() {
+        await nextTick()
+        return () => 'foo'
+      },
+    }
+    createRecord(id, AsyncChild)
+
+    const appId = 'test-app-id'
+    const App: ComponentOptions = {
+      __hmrId: appId,
+      components: { AsyncChild },
+      render: compileToFunction(`
+        <div>
+        <Suspense>
+          <KeepAlive>
+            <AsyncChild />
+          </KeepAlive>
+        </Suspense>
+      </div>
+      `),
+    }
+
+    const root = nodeOps.createElement('div')
+    render(h(App), root)
+    expect(serializeInner(root)).toBe('<div><!----></div>')
+    await timeout()
+    expect(serializeInner(root)).toBe('<div>foo</div>')
+
+    reload(id, {
+      __hmrId: id,
+      async setup() {
+        await nextTick()
+        return () => 'bar'
+      },
+    })
+    await timeout()
+    expect(serializeInner(root)).toBe('<div>bar</div>')
+  })
 })
index 0adf4fd43292a0cfdef448b57347623ced3e4add..7aedf52dd3ea562045200e411947c7ca937aa90f 100644 (file)
@@ -144,7 +144,9 @@ function reload(id: string, newComp: HMRComponent): void {
       // components to be unmounted and re-mounted. Queue the update so that we
       // don't end up forcing the same parent to re-render multiple times.
       queueJob(() => {
+        isHmrUpdating = true
         instance.parent!.update()
+        isHmrUpdating = false
         // #6930, #11248 avoid infinite recursion
         dirtyInstances.delete(instance)
       })
index 9b50dca23f9570117b1bb3c6c3488f9448ca548c..90cc22f547032c5a830be2fdda6bc1b96fceeeb3 100644 (file)
@@ -1211,6 +1211,9 @@ function baseCreateRenderer(
     // setup() is async. This component relies on async logic to be resolved
     // before proceeding
     if (__FEATURE_SUSPENSE__ && instance.asyncDep) {
+      // avoid hydration for hmr updating
+      if (__DEV__ && isHmrUpdating) initialVNode.el = null
+
       parentSuspense &&
         parentSuspense.registerDep(instance, setupRenderEffect, optimized)