Bladeren bron

fix(hmr): fix custom elements hmr edge cases

Evan You 4 jaren geleden
bovenliggende
commit
bff4ea74c5

+ 4 - 0
packages/runtime-core/src/component.ts

@@ -290,6 +290,10 @@ export interface ComponentInternalInstance {
    * is custom element?
    */
   isCE?: boolean
+  /**
+   * custom element specific HMR method
+   */
+  ceReload?: () => void
 
   // the rest are only for stateful components ---------------------------------
 

+ 6 - 3
packages/runtime-core/src/hmr.ts

@@ -7,7 +7,7 @@ import {
   ClassComponent,
   isClassComponent
 } from './component'
-import { queueJob, queuePostFlushCb } from './scheduler'
+import { nextTick, queueJob } from './scheduler'
 import { extend } from '@vue/shared'
 import { warn } from './warning'
 
@@ -124,7 +124,7 @@ function reload(id: string, newComp: ComponentOptions | ClassComponent) {
     // on patch.
     hmrDirtyComponents.add(component)
     // 3. Make sure to unmark the component after the reload.
-    queuePostFlushCb(() => {
+    nextTick(() => {
       hmrDirtyComponents.delete(component)
     })
   }
@@ -133,7 +133,10 @@ function reload(id: string, newComp: ComponentOptions | ClassComponent) {
     // invalidate options resolution cache
     instance.appContext.optionsCache.delete(instance.type as any)
 
-    if (instance.parent) {
+    if (instance.ceReload) {
+      // custom element
+      instance.ceReload()
+    } else if (instance.parent) {
       // 4. Force the parent instance to re-render. This will cause all updated
       // 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.

+ 16 - 9
packages/runtime-dom/src/apiCustomElement.ts

@@ -167,10 +167,9 @@ export class VueElement extends BaseClass {
    * @internal
    */
   _instance: ComponentInternalInstance | null = null
-  /**
-   * @internal
-   */
-  _connected = false
+
+  private _connected = false
+  private _styles?: HTMLStyleElement[]
 
   constructor(
     private _def: ComponentOptions & { styles?: string[] },
@@ -262,12 +261,16 @@ export class VueElement extends BaseClass {
         instance.isCE = true
         // HMR
         if (__DEV__) {
-          instance.appContext.reload = () => {
-            render(this._createVNode(), this.shadowRoot!)
-            this.shadowRoot!.querySelectorAll('style').forEach(s => {
-              this.shadowRoot!.removeChild(s)
-            })
+          instance.ceReload = () => {
+            this._instance = null
+            // reset styles
+            if (this._styles) {
+              this._styles.forEach(s => this.shadowRoot!.removeChild(s))
+              this._styles.length = 0
+            }
             this._applyStyles()
+            // reload
+            render(this._createVNode(), this.shadowRoot!)
           }
         }
 
@@ -302,6 +305,10 @@ export class VueElement extends BaseClass {
         const s = document.createElement('style')
         s.textContent = css
         this.shadowRoot!.appendChild(s)
+        // record for HMR
+        if (__DEV__) {
+          ;(this._styles || (this._styles = [])).push(s)
+        }
       })
     }
   }