feat: Initial devtools support (#1125)
This commit is contained in:
@@ -13,6 +13,7 @@ import { isFunction, NO, isObject } from '@vue/shared'
|
||||
import { warn } from './warning'
|
||||
import { createVNode, cloneVNode, VNode } from './vnode'
|
||||
import { RootHydrateFunction } from './hydration'
|
||||
import { initApp, appUnmounted } from './devtools'
|
||||
import { version } from '.'
|
||||
|
||||
export interface App<HostElement = any> {
|
||||
@@ -31,7 +32,7 @@ export interface App<HostElement = any> {
|
||||
unmount(rootContainer: HostElement | string): void
|
||||
provide<T>(key: InjectionKey<T> | string, value: T): this
|
||||
|
||||
// internal. We need to expose these for the server-renderer
|
||||
// internal. We need to expose these for the server-renderer and devtools
|
||||
_component: Component
|
||||
_props: Data | null
|
||||
_container: HostElement | null
|
||||
@@ -73,6 +74,9 @@ export interface AppContext {
|
||||
directives: Record<string, Directive>
|
||||
provides: Record<string | symbol, any>
|
||||
reload?: () => void // HMR only
|
||||
|
||||
// internal for devtools
|
||||
__app?: App
|
||||
}
|
||||
|
||||
type PluginInstallFunction = (app: App, ...options: any[]) => any
|
||||
@@ -226,6 +230,9 @@ export function createAppAPI<HostElement>(
|
||||
}
|
||||
isMounted = true
|
||||
app._container = rootContainer
|
||||
|
||||
__DEV__ && initApp(app, version)
|
||||
|
||||
return vnode.component!.proxy
|
||||
} else if (__DEV__) {
|
||||
warn(
|
||||
@@ -240,6 +247,8 @@ export function createAppAPI<HostElement>(
|
||||
unmount() {
|
||||
if (isMounted) {
|
||||
render(null, app._container)
|
||||
|
||||
__DEV__ && appUnmounted(app)
|
||||
} else if (__DEV__) {
|
||||
warn(`Cannot unmount an app that is not mounted.`)
|
||||
}
|
||||
@@ -260,6 +269,8 @@ export function createAppAPI<HostElement>(
|
||||
}
|
||||
}
|
||||
|
||||
context.__app = app
|
||||
|
||||
return app
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ import {
|
||||
markAttrsAccessed
|
||||
} from './componentRenderUtils'
|
||||
import { startMeasure, endMeasure } from './profiling'
|
||||
import { componentAdded } from './devtools'
|
||||
|
||||
export type Data = { [key: string]: unknown }
|
||||
|
||||
@@ -408,6 +409,9 @@ export function createComponentInstance(
|
||||
}
|
||||
instance.root = parent ? parent.root : instance
|
||||
instance.emit = emit.bind(null, instance)
|
||||
|
||||
__DEV__ && componentAdded(instance)
|
||||
|
||||
return instance
|
||||
}
|
||||
|
||||
|
||||
78
packages/runtime-core/src/devtools.ts
Normal file
78
packages/runtime-core/src/devtools.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import { App } from './apiCreateApp'
|
||||
import { Fragment, Text, Comment, Static } from './vnode'
|
||||
import { ComponentInternalInstance } from './component'
|
||||
|
||||
export interface AppRecord {
|
||||
id: number
|
||||
app: App
|
||||
version: string
|
||||
types: { [key: string]: string | Symbol }
|
||||
}
|
||||
|
||||
enum DevtoolsHooks {
|
||||
APP_INIT = 'app:init',
|
||||
APP_UNMOUNT = 'app:unmount',
|
||||
COMPONENT_UPDATED = 'component:updated',
|
||||
COMPONENT_ADDED = 'component:added',
|
||||
COMPONENT_REMOVED = 'component:removed'
|
||||
}
|
||||
|
||||
export interface DevtoolsHook {
|
||||
emit: (event: string, ...payload: any[]) => void
|
||||
on: (event: string, handler: Function) => void
|
||||
once: (event: string, handler: Function) => void
|
||||
off: (event: string, handler: Function) => void
|
||||
appRecords: AppRecord[]
|
||||
}
|
||||
|
||||
export let devtools: DevtoolsHook
|
||||
|
||||
export function setDevtoolsHook(hook: DevtoolsHook) {
|
||||
devtools = hook
|
||||
}
|
||||
|
||||
export function initApp(app: App, version: string) {
|
||||
// TODO queue if devtools is undefined
|
||||
if (!devtools) return
|
||||
devtools.emit(DevtoolsHooks.APP_INIT, app, version, {
|
||||
Fragment: Fragment,
|
||||
Text: Text,
|
||||
Comment: Comment,
|
||||
Static: Static
|
||||
})
|
||||
}
|
||||
|
||||
export function appUnmounted(app: App) {
|
||||
if (!devtools) return
|
||||
devtools.emit(DevtoolsHooks.APP_UNMOUNT, app)
|
||||
}
|
||||
|
||||
export function componentAdded(component: ComponentInternalInstance) {
|
||||
if (!devtools || !component.appContext.__app) return
|
||||
devtools.emit(
|
||||
DevtoolsHooks.COMPONENT_ADDED,
|
||||
component.appContext.__app,
|
||||
component.uid,
|
||||
component.parent ? component.parent.uid : undefined
|
||||
)
|
||||
}
|
||||
|
||||
export function componentUpdated(component: ComponentInternalInstance) {
|
||||
if (!devtools || !component.appContext.__app) return
|
||||
devtools.emit(
|
||||
DevtoolsHooks.COMPONENT_UPDATED,
|
||||
component.appContext.__app,
|
||||
component.uid,
|
||||
component.parent ? component.parent.uid : undefined
|
||||
)
|
||||
}
|
||||
|
||||
export function componentRemoved(component: ComponentInternalInstance) {
|
||||
if (!devtools || !component.appContext.__app) return
|
||||
devtools.emit(
|
||||
DevtoolsHooks.COMPONENT_REMOVED,
|
||||
component.appContext.__app,
|
||||
component.uid,
|
||||
component.parent ? component.parent.uid : undefined
|
||||
)
|
||||
}
|
||||
@@ -93,7 +93,10 @@ export {
|
||||
getTransitionRawChildren
|
||||
} from './components/BaseTransition'
|
||||
|
||||
// Types -----------------------------------------------------------------------
|
||||
// For devtools
|
||||
export { devtools, setDevtoolsHook } from './devtools'
|
||||
|
||||
// Types -------------------------------------------------------------------------
|
||||
|
||||
import { VNode } from './vnode'
|
||||
import { ComponentInternalInstance } from './component'
|
||||
|
||||
@@ -65,6 +65,7 @@ import { createHydrationFunctions, RootHydrateFunction } from './hydration'
|
||||
import { invokeDirectiveHook } from './directives'
|
||||
import { startMeasure, endMeasure } from './profiling'
|
||||
import { ComponentPublicInstance } from './componentProxy'
|
||||
import { componentRemoved, componentUpdated } from './devtools'
|
||||
|
||||
export interface Renderer<HostElement = RendererElement> {
|
||||
render: RootRenderFunction<HostElement>
|
||||
@@ -1417,6 +1418,7 @@ function baseCreateRenderer(
|
||||
}
|
||||
if (__DEV__) {
|
||||
popWarningContext()
|
||||
componentUpdated(instance)
|
||||
}
|
||||
}
|
||||
}, __DEV__ ? createDevEffectOptions(instance) : prodEffectOptions)
|
||||
@@ -2068,6 +2070,8 @@ function baseCreateRenderer(
|
||||
parentSuspense.resolve()
|
||||
}
|
||||
}
|
||||
|
||||
__DEV__ && componentRemoved(instance)
|
||||
}
|
||||
|
||||
const unmountChildren: UnmountChildrenFn = (
|
||||
|
||||
Reference in New Issue
Block a user