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…
Reference in New Issue
Block a user