Skip to content

Commit eda495e

Browse files
committedDec 22, 2019
feat(hmr): root instance reload
1 parent c3e1c81 commit eda495e

File tree

4 files changed

+27
-10
lines changed

4 files changed

+27
-10
lines changed
 

‎packages/runtime-core/src/apiCreateApp.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { RootRenderFunction } from './renderer'
66
import { InjectionKey } from './apiInject'
77
import { isFunction, NO, isObject } from '@vue/shared'
88
import { warn } from './warning'
9-
import { createVNode } from './vnode'
9+
import { createVNode, cloneVNode } from './vnode'
1010

1111
export interface App<HostElement = any> {
1212
config: AppConfig
@@ -47,6 +47,7 @@ export interface AppContext {
4747
components: Record<string, Component>
4848
directives: Record<string, Directive>
4949
provides: Record<string | symbol, any>
50+
reload?: () => void // HMR only
5051
}
5152

5253
type PluginInstallFunction = (app: App) => any
@@ -175,6 +176,14 @@ export function createAppAPI<HostNode, HostElement>(
175176
// store app context on the root VNode.
176177
// this will be set on the root instance on initial mount.
177178
vnode.appContext = context
179+
180+
// HMR root reload
181+
if (__BUNDLER__ && __DEV__) {
182+
context.reload = () => {
183+
render(cloneVNode(vnode), rootContainer)
184+
}
185+
}
186+
178187
render(vnode, rootContainer)
179188
isMounted = true
180189
return vnode.component!.proxy

‎packages/runtime-core/src/hmr.ts

+10-2
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,9 @@ function createRecord(id: string, comp: ComponentOptions): boolean {
6060
}
6161

6262
function rerender(id: string, newRender?: RenderFunction) {
63-
map.get(id)!.instances.forEach(instance => {
63+
// Array.from creates a snapshot which avoids the set being mutated during
64+
// updates
65+
Array.from(map.get(id)!.instances).forEach(instance => {
6466
if (newRender) {
6567
instance.render = newRender
6668
}
@@ -85,13 +87,19 @@ function reload(id: string, newComp: ComponentOptions) {
8587
// 2. Mark component dirty. This forces the renderer to replace the component
8688
// on patch.
8789
comp.__hmrUpdated = true
88-
record.instances.forEach(instance => {
90+
// Array.from creates a snapshot which avoids the set being mutated during
91+
// updates
92+
Array.from(record.instances).forEach(instance => {
8993
if (instance.parent) {
9094
// 3. Force the parent instance to re-render. This will cause all updated
9195
// components to be unmounted and re-mounted. Queue the update so that we
9296
// don't end up forcing the same parent to re-render multiple times.
9397
queueJob(instance.parent.update)
98+
} else if (instance.appContext.reload) {
99+
// root instance mounted via createApp() has a reload method
100+
instance.appContext.reload()
94101
} else if (typeof window !== 'undefined') {
102+
// root instance inside tree created via raw render(). Force reload.
95103
window.location.reload()
96104
} else {
97105
console.warn(

‎packages/runtime-core/src/renderer.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -1727,12 +1727,12 @@ export function createRenderer<
17271727
}
17281728
}
17291729

1730-
const render: RootRenderFunction<
1731-
HostNode,
1732-
HostElement & {
1733-
_vnode: HostVNode | null
1734-
}
1735-
> = (vnode, container) => {
1730+
type HostRootElement = HostElement & { _vnode: HostVNode | null }
1731+
1732+
const render: RootRenderFunction<HostNode, HostElement> = (
1733+
vnode,
1734+
container: HostRootElement
1735+
) => {
17361736
if (vnode == null) {
17371737
if (container._vnode) {
17381738
unmount(container._vnode, null, null, true)

‎packages/runtime-core/src/vnode.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {
1515
import { RawSlots } from './componentSlots'
1616
import { ShapeFlags } from './shapeFlags'
1717
import { isReactive, Ref } from '@vue/reactivity'
18-
import { AppContext } from './apiApp'
18+
import { AppContext } from './apiCreateApp'
1919
import { SuspenseBoundary } from './components/Suspense'
2020
import { DirectiveBinding } from './directives'
2121
import { SuspenseImpl } from './components/Suspense'

0 commit comments

Comments
 (0)
Please sign in to comment.