Skip to content

Commit 2476eaa

Browse files
authored
fix(devtools): fix prod devtools detection + handle late devtools hook injection (#4653)
1 parent 64aa8e2 commit 2476eaa

File tree

5 files changed

+39
-24
lines changed

5 files changed

+39
-24
lines changed

packages/runtime-core/__tests__/helpers/renderSlot.spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ describe('renderSlot', () => {
4747
return [createVNode('div', null, 'foo', PatchFlags.TEXT)]
4848
},
4949
// mock instance
50-
{ type: {} } as any
50+
{ type: {}, appContext: {} } as any
5151
) as Slot
5252

5353
// manual invocation should not track

packages/runtime-core/src/devtools.ts

+28-19
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ const enum DevtoolsHooks {
2121
}
2222

2323
interface DevtoolsHook {
24+
enabled?: boolean
2425
emit: (event: string, ...payload: any[]) => void
2526
on: (event: string, handler: Function) => void
2627
once: (event: string, handler: Function) => void
@@ -30,14 +31,33 @@ interface DevtoolsHook {
3031

3132
export let devtools: DevtoolsHook
3233

33-
export function setDevtoolsHook(hook: DevtoolsHook) {
34+
let buffer: { event: string; args: any[] }[] = []
35+
36+
function emit(event: string, ...args: any[]) {
37+
if (devtools) {
38+
devtools.emit(event, ...args)
39+
} else {
40+
buffer.push({ event, args })
41+
}
42+
}
43+
44+
export function setDevtoolsHook(hook: DevtoolsHook, target: any) {
3445
devtools = hook
46+
if (devtools) {
47+
devtools.enabled = true
48+
buffer.forEach(({ event, args }) => devtools.emit(event, ...args))
49+
buffer = []
50+
} else {
51+
const replay = (target.__VUE_DEVTOOLS_HOOK_REPLAY__ =
52+
target.__VUE_DEVTOOLS_HOOK_REPLAY__ || [])
53+
replay.push((newHook: DevtoolsHook) => {
54+
setDevtoolsHook(newHook, target)
55+
})
56+
}
3557
}
3658

3759
export function devtoolsInitApp(app: App, version: string) {
38-
// TODO queue if devtools is undefined
39-
if (!devtools) return
40-
devtools.emit(DevtoolsHooks.APP_INIT, app, version, {
60+
emit(DevtoolsHooks.APP_INIT, app, version, {
4161
Fragment,
4262
Text,
4363
Comment,
@@ -46,8 +66,7 @@ export function devtoolsInitApp(app: App, version: string) {
4666
}
4767

4868
export function devtoolsUnmountApp(app: App) {
49-
if (!devtools) return
50-
devtools.emit(DevtoolsHooks.APP_UNMOUNT, app)
69+
emit(DevtoolsHooks.APP_UNMOUNT, app)
5170
}
5271

5372
export const devtoolsComponentAdded = /*#__PURE__*/ createDevtoolsComponentHook(
@@ -62,8 +81,7 @@ export const devtoolsComponentRemoved =
6281

6382
function createDevtoolsComponentHook(hook: DevtoolsHooks) {
6483
return (component: ComponentInternalInstance) => {
65-
if (!devtools) return
66-
devtools.emit(
84+
emit(
6785
hook,
6886
component.appContext.app,
6987
component.uid,
@@ -83,15 +101,7 @@ export const devtoolsPerfEnd = /*#__PURE__*/ createDevtoolsPerformanceHook(
83101

84102
function createDevtoolsPerformanceHook(hook: DevtoolsHooks) {
85103
return (component: ComponentInternalInstance, type: string, time: number) => {
86-
if (!devtools) return
87-
devtools.emit(
88-
hook,
89-
component.appContext.app,
90-
component.uid,
91-
component,
92-
type,
93-
time
94-
)
104+
emit(hook, component.appContext.app, component.uid, component, type, time)
95105
}
96106
}
97107

@@ -100,8 +110,7 @@ export function devtoolsComponentEmit(
100110
event: string,
101111
params: any[]
102112
) {
103-
if (!devtools) return
104-
devtools.emit(
113+
emit(
105114
DevtoolsHooks.COMPONENT_EMIT,
106115
component.appContext.app,
107116
component,

packages/runtime-core/src/renderer.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -340,10 +340,10 @@ function baseCreateRenderer(
340340
initFeatureFlags()
341341
}
342342

343+
const target = getGlobalThis()
344+
target.__VUE__ = true
343345
if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
344-
const target = getGlobalThis()
345-
target.__VUE__ = true
346-
setDevtoolsHook(target.__VUE_DEVTOOLS_GLOBAL_HOOK__)
346+
setDevtoolsHook(target.__VUE_DEVTOOLS_GLOBAL_HOOK__, target)
347347
}
348348

349349
const {

packages/sfc-playground/src/main.ts

+5
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,9 @@ import { createApp } from 'vue'
22
import App from './App.vue'
33
import '@vue/repl/style.css'
44

5+
// @ts-expect-error Custom window property
6+
window.VUE_DEVTOOLS_CONFIG = {
7+
defaultSelectedAppId: 'id:repl'
8+
}
9+
510
createApp(App).mount('#app')

packages/sfc-playground/vite.config.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ const commit = execa.sync('git', ['rev-parse', 'HEAD']).stdout.slice(0, 7)
99
export default defineConfig({
1010
plugins: [vue(), copyVuePlugin()],
1111
define: {
12-
__COMMIT__: JSON.stringify(commit)
12+
__COMMIT__: JSON.stringify(commit),
13+
__VUE_PROD_DEVTOOLS__: JSON.stringify(true)
1314
},
1415
optimizeDeps: {
1516
exclude: ['@vue/repl']

0 commit comments

Comments
 (0)