declare var __DEV__: boolean
declare var __TEST__: boolean
declare var __BROWSER__: boolean
+declare var __BUNDLER__: boolean
declare var __RUNTIME_COMPILE__: boolean
declare var __COMMIT__: string
declare var __VERSION__: string
directives?: Record<string, Directive>
inheritAttrs?: boolean
+ // SFC & dev only
+ __scopeId?: string
+ __hmrId?: string
+
// type-only differentiator to separate OptionWithoutProps from a constructor
// type returned by createComponent() or FunctionalComponent
call?: never
props?: ComponentPropsOptions<P>
inheritAttrs?: boolean
displayName?: string
+ __hmrId?: string
}
export type Component = ComponentOptions | FunctionalComponent
--- /dev/null
+import {
+ ComponentInternalInstance,
+ ComponentOptions,
+ RenderFunction
+} from './component'
+
+// Expose the HMR runtime on the global object
+// This makes it entirely tree-shakable without polluting the exports and makes
+// it easier to be used in toolings like vue-loader
+// Note: for a component to be eligible for HMR it also needs the __hmrId option
+// to be set so that its instances can be registered / removed.
+if (__BUNDLER__ && __DEV__) {
+ const globalObject: any =
+ typeof global !== 'undefined'
+ ? global
+ : typeof self !== 'undefined'
+ ? self
+ : typeof window !== 'undefined'
+ ? window
+ : {}
+
+ globalObject.__VUE_HMR_RUNTIME__ = {
+ isRecorded: tryWrap(isRecorded),
+ createRecord: tryWrap(createRecord),
+ rerender: tryWrap(rerender),
+ reload: tryWrap(reload)
+ }
+}
+
+interface HMRRecord {
+ comp: ComponentOptions
+ instances: Set<ComponentInternalInstance>
+}
+
+const map: Map<string, HMRRecord> = new Map()
+
+export function registerHMR(instance: ComponentInternalInstance) {
+ map.get(instance.type.__hmrId!)!.instances.add(instance)
+}
+
+export function unregisterHMR(instance: ComponentInternalInstance) {
+ map.get(instance.type.__hmrId!)!.instances.delete(instance)
+}
+
+function isRecorded(id: string): boolean {
+ return map.has(id)
+}
+
+function createRecord(id: string, comp: ComponentOptions) {
+ if (map.has(id)) {
+ return
+ }
+ map.set(id, {
+ comp,
+ instances: new Set()
+ })
+}
+
+function rerender(id: string, newRender: RenderFunction) {
+ map.get(id)!.instances.forEach(instance => {
+ instance.render = newRender
+ instance.renderCache = []
+ instance.update()
+ // TODO force scoped slots passed to children to have DYNAMIC_SLOTS flag
+ })
+}
+
+function reload(id: string, newComp: ComponentOptions) {
+ // TODO
+ console.log('reload', id)
+}
+
+function tryWrap(fn: (id: string, arg: any) => void): Function {
+ return (id: string, arg: any) => {
+ try {
+ fn(id, arg)
+ } catch (e) {
+ console.error(e)
+ console.warn(
+ `Something went wrong during Vue component hot-reload. ` +
+ `Full reload required.`
+ )
+ }
+ }
+}
TransitionHooks
} from './components/BaseTransition'
-// Internal, for compiler generated code
+// Internal API ----------------------------------------------------------------
+
+// For compiler generated code
// should sync with '@vue/compiler-core/src/runtimeConstants.ts'
export { withDirectives } from './directives'
export {
export const capitalize = _capitalize as (s: string) => string
export const camelize = _camelize as (s: string) => string
-// Internal, for integration with runtime compiler
+// For integration with runtime compiler
export { registerRuntimeCompiler } from './component'
// Types -----------------------------------------------------------------------
} from './components/Suspense'
import { ErrorCodes, callWithErrorHandling } from './errorHandling'
import { KeepAliveSink, isKeepAlive } from './components/KeepAlive'
+import { registerHMR, unregisterHMR } from './hmr'
export interface RendererOptions<HostNode = any, HostElement = any> {
patchProp(
parentComponent
))
+ // HMR
+ if (__BUNDLER__ && __DEV__ && instance.type.__hmrId != null) {
+ registerHMR(instance)
+ }
+
if (__DEV__) {
pushWarningContext(initialVNode)
}
parentSuspense: HostSuspenseBoundary | null,
doRemove?: boolean
) {
+ // HMR
+ if (__BUNDLER__ && __DEV__ && instance.type.__hmrId != null) {
+ unregisterHMR(instance)
+ }
+
const { bum, effects, update, subTree, um, da, isDeactivated } = instance
// beforeUnmount hook
if (bum !== null) {
__TEST__: isBundlerESMBuild ? `(process.env.NODE_ENV === 'test')` : false,
// If the build is expected to run directly in the browser (global / esm builds)
__BROWSER__: isBrowserBuild,
+ // is targeting bundlers?
+ __BUNDLER__: isBundlerESMBuild,
// support compile in browser?
__RUNTIME_COMPILE__: isRuntimeCompileBuild,
// support options?