import { ConcreteComponent , ComponentInternalInstance , ComponentOptions , InternalRenderFunction , ClassComponent , isClassComponent } from './component' ; import { queueJob , queuePostFlushCb } from './scheduler' ; import { extend } from '@vue/shared' ; import { warn } from './warning' ; export let isHmrUpdating = false ; export const hmrDirtyComponents = new Set < ConcreteComponent > ( ) ; export interface HMRRuntime { createRecord : typeof createRecord ; rerender : typeof rerender ; reload : typeof reload ; } if ( __DEV__ ) { const globalObject = typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : typeof window !== 'undefined' ? window : { } ; globalObject . __VUE_HMR_RUNTIME__ = { createRecord : tryWrap ( createRecord ) , rerender : tryWrap ( rerender ) , reload : tryWrap ( reload ) } as HMRRuntime ; } type HMRRecord = { component : ComponentOptions ; instances : Set < ComponentInternalInstance > ; } ; const map = new Map ( ) ; export function registerHMR ( instance ) { const id = instance . type . __hmrId ! ; let record = map . get ( id ) ; if ( ! record ) { createRecord ( id , instance . type as ComponentOptions ) ; record = map . get ( id ) ! ; } record . instances . add ( instance ) ; } export function unregisterHMR ( instance ) { map . get ( instance . type . __hmrId ! ) ! . instances . delete ( instance ) ; } function createRecord ( id , component ) { if ( ! component ) { warn ( `HMR API usage is out of date.\n` + `Please upgrade vue-loader/vite/rollup-plugin-vue or other relevant ` + `dependency that handles Vue SFC compilation.` ) ; component = { } ; } if ( map . has ( id ) ) { return false ; } map . set ( id , { component : isClassComponent ( component ) ? component . __vccOpts : component , instances : new Set ( ) } ) ; return true ; } function rerender ( id , newRender ? ) { const record = map . get ( id ) ; if ( ! record ) return ; if ( newRender ) record . component . render = newRender ; Array . from ( record . instances ) . forEach ( instance => { if ( newRender ) { instance . render = newRender as InternalRenderFunction ; } instance . renderCache = [ ] ; isHmrUpdating = true ; instance . update ( ) ; isHmrUpdating = false ; } ) ; } function reload ( id , newComp ) { const record = map . get ( id ) ; if ( ! record ) return ; const { component , instances } = record ; if ( ! hmrDirtyComponents . has ( component ) ) { newComp = isClassComponent ( newComp ) ? newComp . __vccOpts : newComp ; extend ( component , newComp ) ; for ( const key in component ) { if ( key !== '__file' && ! ( key in newComp ) ) { delete ( component as any ) [ key ] ; } } hmrDirtyComponents . add ( component ) ; queuePostFlushCb ( ( ) => { hmrDirtyComponents . delete ( component ) ; } ) ; } Array . from ( instances ) . forEach ( instance => { instance . appContext . optionsCache . delete ( instance . type as any ) ; if ( instance . ceReload ) { hmrDirtyComponents . add ( component ) ; instance . ceReload ( ( newComp as any ) . styles ) ; hmrDirtyComponents . delete ( component ) ; } else if ( instance . parent ) { queueJob ( instance . parent . update ) ; if ( ( instance . parent . type as ComponentOptions ) . __asyncLoader && instance . parent . ceReload ) { instance . parent . ceReload ( ( newComp as any ) . styles ) ; } } else if ( instance . appContext . reload ) { instance . appContext . reload ( ) ; } else if ( typeof window !== 'undefined' ) { window . location . reload ( ) ; } else { console . warn ( '[HMR] Root or manually mounted instance modified. Full reload required.' ) ; } } ) ; } function tryWrap ( fn ) { return ( id , arg ) => { try { return fn ( id , arg ) ; } catch ( e ) { console . error ( e ) ; console . warn ( `[HMR] Something went wrong during Vue component hot-reload. ` + `Full reload required.` ) ; } } ; }