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 { InjectionKey } from './apiInject' | ||||||
| import { isFunction, NO, isObject } from '@vue/shared' | import { isFunction, NO, isObject } from '@vue/shared' | ||||||
| import { warn } from './warning' | import { warn } from './warning' | ||||||
| import { createVNode } from './vnode' | import { createVNode, cloneVNode } from './vnode' | ||||||
| 
 | 
 | ||||||
| export interface App<HostElement = any> { | export interface App<HostElement = any> { | ||||||
|   config: AppConfig |   config: AppConfig | ||||||
| @ -47,6 +47,7 @@ export interface AppContext { | |||||||
|   components: Record<string, Component> |   components: Record<string, Component> | ||||||
|   directives: Record<string, Directive> |   directives: Record<string, Directive> | ||||||
|   provides: Record<string | symbol, any> |   provides: Record<string | symbol, any> | ||||||
|  |   reload?: () => void // HMR only
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type PluginInstallFunction = (app: App) => any | type PluginInstallFunction = (app: App) => any | ||||||
| @ -175,6 +176,14 @@ export function createAppAPI<HostNode, HostElement>( | |||||||
|           // store app context on the root VNode.
 |           // store app context on the root VNode.
 | ||||||
|           // this will be set on the root instance on initial mount.
 |           // this will be set on the root instance on initial mount.
 | ||||||
|           vnode.appContext = context |           vnode.appContext = context | ||||||
|  | 
 | ||||||
|  |           // HMR root reload
 | ||||||
|  |           if (__BUNDLER__ && __DEV__) { | ||||||
|  |             context.reload = () => { | ||||||
|  |               render(cloneVNode(vnode), rootContainer) | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  | 
 | ||||||
|           render(vnode, rootContainer) |           render(vnode, rootContainer) | ||||||
|           isMounted = true |           isMounted = true | ||||||
|           return vnode.component!.proxy |           return vnode.component!.proxy | ||||||
|  | |||||||
| @ -60,7 +60,9 @@ function createRecord(id: string, comp: ComponentOptions): boolean { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function rerender(id: string, newRender?: RenderFunction) { | 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) { |     if (newRender) { | ||||||
|       instance.render = 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
 |   // 2. Mark component dirty. This forces the renderer to replace the component
 | ||||||
|   // on patch.
 |   // on patch.
 | ||||||
|   comp.__hmrUpdated = true |   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) { |     if (instance.parent) { | ||||||
|       // 3. Force the parent instance to re-render. This will cause all updated
 |       // 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
 |       // 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.
 |       // don't end up forcing the same parent to re-render multiple times.
 | ||||||
|       queueJob(instance.parent.update) |       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') { |     } else if (typeof window !== 'undefined') { | ||||||
|  |       // root instance inside tree created via raw render(). Force reload.
 | ||||||
|       window.location.reload() |       window.location.reload() | ||||||
|     } else { |     } else { | ||||||
|       console.warn( |       console.warn( | ||||||
|  | |||||||
| @ -1727,12 +1727,12 @@ export function createRenderer< | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   const render: RootRenderFunction< |   type HostRootElement = HostElement & { _vnode: HostVNode | null } | ||||||
|     HostNode, | 
 | ||||||
|     HostElement & { |   const render: RootRenderFunction<HostNode, HostElement> = ( | ||||||
|       _vnode: HostVNode | null |     vnode, | ||||||
|     } |     container: HostRootElement | ||||||
|   > = (vnode, container) => { |   ) => { | ||||||
|     if (vnode == null) { |     if (vnode == null) { | ||||||
|       if (container._vnode) { |       if (container._vnode) { | ||||||
|         unmount(container._vnode, null, null, true) |         unmount(container._vnode, null, null, true) | ||||||
|  | |||||||
| @ -15,7 +15,7 @@ import { | |||||||
| import { RawSlots } from './componentSlots' | import { RawSlots } from './componentSlots' | ||||||
| import { ShapeFlags } from './shapeFlags' | import { ShapeFlags } from './shapeFlags' | ||||||
| import { isReactive, Ref } from '@vue/reactivity' | import { isReactive, Ref } from '@vue/reactivity' | ||||||
| import { AppContext } from './apiApp' | import { AppContext } from './apiCreateApp' | ||||||
| import { SuspenseBoundary } from './components/Suspense' | import { SuspenseBoundary } from './components/Suspense' | ||||||
| import { DirectiveBinding } from './directives' | import { DirectiveBinding } from './directives' | ||||||
| import { SuspenseImpl } from './components/Suspense' | import { SuspenseImpl } from './components/Suspense' | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user