feat(hmr): root instance reload
This commit is contained in:
		
							parent
							
								
									c3e1c812e3
								
							
						
					
					
						commit
						eda495efd8
					
				| @ -6,7 +6,7 @@ import { RootRenderFunction } from './renderer' | ||||
| import { InjectionKey } from './apiInject' | ||||
| import { isFunction, NO, isObject } from '@vue/shared' | ||||
| import { warn } from './warning' | ||||
| import { createVNode } from './vnode' | ||||
| import { createVNode, cloneVNode } from './vnode' | ||||
| 
 | ||||
| export interface App<HostElement = any> { | ||||
|   config: AppConfig | ||||
| @ -47,6 +47,7 @@ export interface AppContext { | ||||
|   components: Record<string, Component> | ||||
|   directives: Record<string, Directive> | ||||
|   provides: Record<string | symbol, any> | ||||
|   reload?: () => void // HMR only
 | ||||
| } | ||||
| 
 | ||||
| type PluginInstallFunction = (app: App) => any | ||||
| @ -175,6 +176,14 @@ export function createAppAPI<HostNode, HostElement>( | ||||
|           // store app context on the root VNode.
 | ||||
|           // this will be set on the root instance on initial mount.
 | ||||
|           vnode.appContext = context | ||||
| 
 | ||||
|           // HMR root reload
 | ||||
|           if (__BUNDLER__ && __DEV__) { | ||||
|             context.reload = () => { | ||||
|               render(cloneVNode(vnode), rootContainer) | ||||
|             } | ||||
|           } | ||||
| 
 | ||||
|           render(vnode, rootContainer) | ||||
|           isMounted = true | ||||
|           return vnode.component!.proxy | ||||
|  | ||||
| @ -60,7 +60,9 @@ function createRecord(id: string, comp: ComponentOptions): boolean { | ||||
| } | ||||
| 
 | ||||
| function rerender(id: string, newRender?: RenderFunction) { | ||||
|   map.get(id)!.instances.forEach(instance => { | ||||
|   // Array.from creates a snapshot which avoids the set being mutated during
 | ||||
|   // updates
 | ||||
|   Array.from(map.get(id)!.instances).forEach(instance => { | ||||
|     if (newRender) { | ||||
|       instance.render = newRender | ||||
|     } | ||||
| @ -85,13 +87,19 @@ function reload(id: string, newComp: ComponentOptions) { | ||||
|   // 2. Mark component dirty. This forces the renderer to replace the component
 | ||||
|   // on patch.
 | ||||
|   comp.__hmrUpdated = true | ||||
|   record.instances.forEach(instance => { | ||||
|   // Array.from creates a snapshot which avoids the set being mutated during
 | ||||
|   // updates
 | ||||
|   Array.from(record.instances).forEach(instance => { | ||||
|     if (instance.parent) { | ||||
|       // 3. 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.
 | ||||
|       queueJob(instance.parent.update) | ||||
|     } else if (instance.appContext.reload) { | ||||
|       // root instance mounted via createApp() has a reload method
 | ||||
|       instance.appContext.reload() | ||||
|     } else if (typeof window !== 'undefined') { | ||||
|       // root instance inside tree created via raw render(). Force reload.
 | ||||
|       window.location.reload() | ||||
|     } else { | ||||
|       console.warn( | ||||
|  | ||||
| @ -1727,12 +1727,12 @@ export function createRenderer< | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   const render: RootRenderFunction< | ||||
|     HostNode, | ||||
|     HostElement & { | ||||
|       _vnode: HostVNode | null | ||||
|     } | ||||
|   > = (vnode, container) => { | ||||
|   type HostRootElement = HostElement & { _vnode: HostVNode | null } | ||||
| 
 | ||||
|   const render: RootRenderFunction<HostNode, HostElement> = ( | ||||
|     vnode, | ||||
|     container: HostRootElement | ||||
|   ) => { | ||||
|     if (vnode == null) { | ||||
|       if (container._vnode) { | ||||
|         unmount(container._vnode, null, null, true) | ||||
|  | ||||
| @ -15,7 +15,7 @@ import { | ||||
| import { RawSlots } from './componentSlots' | ||||
| import { ShapeFlags } from './shapeFlags' | ||||
| import { isReactive, Ref } from '@vue/reactivity' | ||||
| import { AppContext } from './apiApp' | ||||
| import { AppContext } from './apiCreateApp' | ||||
| import { SuspenseBoundary } from './components/Suspense' | ||||
| import { DirectiveBinding } from './directives' | ||||
| import { SuspenseImpl } from './components/Suspense' | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user