Skip to content

Commit

Permalink
feat: Initial devtools support (#1125)
Browse files Browse the repository at this point in the history
  • Loading branch information
Akryum authored Jul 16, 2020
1 parent 5ed73cd commit 568b6db
Show file tree
Hide file tree
Showing 15 changed files with 132 additions and 17 deletions.
2 changes: 1 addition & 1 deletion packages/compiler-sfc/src/compileTemplate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export interface SFCTemplateCompileOptions {
*/
transformAssetUrls?: AssetURLOptions | AssetURLTagConfig | boolean
}

interface PreProcessor {
render(
source: string,
Expand Down
2 changes: 1 addition & 1 deletion packages/runtime-core/__tests__/componentProps.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ describe('component props', () => {
render(h(Comp, { 'foo-bar': 3, bar: 3, baz: 4, barBaz: 5 }), root)
expect(proxy.fooBar).toBe(3)
expect(proxy.barBaz).toBe(5)
expect(props).toEqual({ fooBar: 3,barBaz: 5 })
expect(props).toEqual({ fooBar: 3, barBaz: 5 })
expect(attrs).toEqual({ bar: 3, baz: 4 })

render(h(Comp, { qux: 5 }), root)
Expand Down
2 changes: 1 addition & 1 deletion packages/runtime-core/__tests__/helpers/renderSlot.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ describe('renderSlot', () => {
})

it('should warn render ssr slot', () => {
renderSlot({ default: (a, b, c) => [h('child')] }, 'default')
renderSlot({ default: (_a, _b, _c) => [h('child')] }, 'default')
expect('SSR-optimized slot function detected').toHaveBeenWarned()
})
})
13 changes: 12 additions & 1 deletion packages/runtime-core/src/apiCreateApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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(
Expand All @@ -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.`)
}
Expand All @@ -260,6 +269,8 @@ export function createAppAPI<HostElement>(
}
}

context.__app = app

return app
}
}
4 changes: 4 additions & 0 deletions packages/runtime-core/src/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import {
markAttrsAccessed
} from './componentRenderUtils'
import { startMeasure, endMeasure } from './profiling'
import { componentAdded } from './devtools'

export type Data = { [key: string]: unknown }

Expand Down Expand Up @@ -408,6 +409,9 @@ export function createComponentInstance(
}
instance.root = parent ? parent.root : instance
instance.emit = emit.bind(null, instance)

__DEV__ && componentAdded(instance)

return instance
}

Expand Down
78 changes: 78 additions & 0 deletions packages/runtime-core/src/devtools.ts
Original file line number Diff line number Diff line change
@@ -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
)
}
5 changes: 4 additions & 1 deletion packages/runtime-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
4 changes: 4 additions & 0 deletions packages/runtime-core/src/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -1417,6 +1418,7 @@ function baseCreateRenderer(
}
if (__DEV__) {
popWarningContext()
componentUpdated(instance)
}
}
}, __DEV__ ? createDevEffectOptions(instance) : prodEffectOptions)
Expand Down Expand Up @@ -2068,6 +2070,8 @@ function baseCreateRenderer(
parentSuspense.resolve()
}
}

__DEV__ && componentRemoved(instance)
}

const unmountChildren: UnmountChildrenFn = (
Expand Down
4 changes: 2 additions & 2 deletions packages/server-renderer/__tests__/renderToStream.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ describe('ssr: renderToStream', () => {
expect(
await renderToStream(
createApp(
defineComponent((props: {}) => {
defineComponent(() => {
const msg = ref('hello')
return () => h('div', msg.value)
})
Expand Down Expand Up @@ -266,7 +266,7 @@ describe('ssr: renderToStream', () => {
{ msg: 'hello' },
{
// optimized slot using string push
default: ({ msg }: any, push: any, p: any) => {
default: ({ msg }: any, push: any) => {
push(`<span>${msg}</span>`)
},
// important to avoid slots being normalized
Expand Down
16 changes: 16 additions & 0 deletions packages/vue/src/dev.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { version, setDevtoolsHook } from '@vue/runtime-dom'

export function initDev() {
const target: any = __BROWSER__ ? window : global

target.__VUE__ = version
setDevtoolsHook(target.__VUE_DEVTOOLS_GLOBAL_HOOK__)

if (__BROWSER__) {
// @ts-ignore `console.info` cannot be null error
console[console.info ? 'info' : 'log'](
`You are running a development build of Vue.\n` +
`Make sure to use the production build (*.prod.js) when deploying for production.`
)
}
}
7 changes: 0 additions & 7 deletions packages/vue/src/devCheck.ts

This file was deleted.

4 changes: 3 additions & 1 deletion packages/vue/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
// This entry is the "full-build" that includes both the runtime
// and the compiler, and supports on-the-fly compilation of the template option.
import './devCheck'
import { initDev } from './dev'
import { compile, CompilerOptions, CompilerError } from '@vue/compiler-dom'
import { registerRuntimeCompiler, RenderFunction, warn } from '@vue/runtime-dom'
import * as runtimeDom from '@vue/runtime-dom'
import { isString, NOOP, generateCodeFrame, extend } from '@vue/shared'

__DEV__ && initDev()

const compileCache: Record<string, RenderFunction> = Object.create(null)

function compileToFunction(
Expand Down
4 changes: 3 additions & 1 deletion packages/vue/src/runtime.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
// This entry exports the runtime only, and is built as
// `dist/vue.esm-bundler.js` which is used by default for bundlers.
import './devCheck'
import { initDev } from './dev'
import { warn } from '@vue/runtime-dom'

__DEV__ && initDev()

export * from '@vue/runtime-dom'

export const compile = () => {
Expand Down
2 changes: 1 addition & 1 deletion test-dts/defineComponent.test-d.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -622,7 +622,7 @@ describe('emits', () => {
defineComponent({
emits: {
click: (n: number) => typeof n === 'number',
input: (b: string) => null
input: (b: string) => b.length > 1
},
setup(props, { emit }) {
emit('click', 1)
Expand Down
2 changes: 2 additions & 0 deletions test-dts/ref.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,13 @@ function bailType(arg: HTMLElement | Ref<HTMLElement>) {
expectType<HTMLElement>(unref(arg))

// ref inner type should be unwrapped
// eslint-disable-next-line no-restricted-globals
const nestedRef = ref({ foo: ref(document.createElement('DIV')) })

expectType<Ref<{ foo: HTMLElement }>>(nestedRef)
expectType<{ foo: HTMLElement }>(nestedRef.value)
}
// eslint-disable-next-line no-restricted-globals
const el = document.createElement('DIV')
bailType(el)

Expand Down

0 comments on commit 568b6db

Please sign in to comment.