Skip to content

Commit

Permalink
feat(client): improve devtools and export constants (close #1625)
Browse files Browse the repository at this point in the history
  • Loading branch information
meteorlxy committed Feb 23, 2025
1 parent cd192c2 commit 4a105cb
Show file tree
Hide file tree
Showing 8 changed files with 109 additions and 40 deletions.
1 change: 1 addition & 0 deletions packages/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
},
"dependencies": {
"@vue/devtools-api": "^7.7.2",
"@vue/devtools-kit": "^7.7.2",
"@vuepress/shared": "workspace:*",
"vue": "^3.5.13",
"vue-router": "^4.5.0"
Expand Down
2 changes: 1 addition & 1 deletion packages/client/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export const createVueApp: CreateVueAppFunction = async () => {

// setup devtools in dev mode
if (__VUEPRESS_DEV__ || __VUE_PROD_DEVTOOLS__) {
const { setupDevtools } = await import('./setupDevtools.js')
const { setupDevtools } = await import('./devtools/setupDevtools.js')
setupDevtools(app, globalComputed)
}

Expand Down
50 changes: 50 additions & 0 deletions packages/client/src/devtools/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import type { InspectorNodeConfig } from './types.js'

export const PLUGIN_ID = 'org.vuejs.vuepress'
export const PLUGIN_LABEL = 'VuePress'

export const COMPONENT_STATE_TYPE = PLUGIN_LABEL

export const INSPECTOR_ID = PLUGIN_ID
export const INSPECTOR_LABEL = PLUGIN_LABEL

const INSPECTOR_NODE_INTERNAL = {
id: 'INTERNAL',
label: 'Internal',
keys: ['layouts', 'routes', 'redirects'],
} as const satisfies InspectorNodeConfig

const INSPECTOR_NODE_SITE = {
id: 'SITE',
label: 'Site',
keys: ['siteData', 'siteLocaleData'],
} as const satisfies InspectorNodeConfig

const INSPECTOR_NODE_ROUTE = {
id: 'ROUTE',
label: 'Route',
keys: ['routePath', 'routeLocale'],
} as const satisfies InspectorNodeConfig

const INSPECTOR_NODE_PAGE = {
id: 'PAGE',
label: 'Page',
keys: [
'pageData',
'pageFrontmatter',
'pageLang',
'pageHead',
'pageHeadTitle',
'pageLayout',
'pageComponent',
],
} as const satisfies InspectorNodeConfig

export const INSPECTOR_NODES = {
[INSPECTOR_NODE_INTERNAL.id]: INSPECTOR_NODE_INTERNAL,
[INSPECTOR_NODE_SITE.id]: INSPECTOR_NODE_SITE,
[INSPECTOR_NODE_ROUTE.id]: INSPECTOR_NODE_ROUTE,
[INSPECTOR_NODE_PAGE.id]: INSPECTOR_NODE_PAGE,
}

export const INSPECTOR_STATE_SECTION_NAME = 'State'
1 change: 1 addition & 0 deletions packages/client/src/devtools/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * as DEVTOOLS from './constants.js'
Original file line number Diff line number Diff line change
@@ -1,31 +1,25 @@
import { setupDevtoolsPlugin } from '@vue/devtools-api'
import type { App } from 'vue'
import { watch } from 'vue'
import type { ClientData } from './types/index.js'

const PLUGIN_ID = 'org.vuejs.vuepress'
const PLUGIN_LABEL = 'VuePress'
const PLUGIN_COMPONENT_STATE_TYPE = PLUGIN_LABEL

const INSPECTOR_ID = PLUGIN_ID
const INSPECTOR_LABEL = PLUGIN_LABEL
const INSPECTOR_CLIENT_DATA_ID = 'client-data'
const INSPECTOR_CLIENT_DATA_LABEL = 'Client Data'

type ClientDataKey = keyof ClientData
type ClientDataValue = ClientData[ClientDataKey]
import type { ClientData } from '../types/index.js'
import * as DEVTOOLS from './constants.js'
import type {
ClientDataKey,
ClientDataValue,
InspectorNodeConfig,
} from './types.js'

export const setupDevtools = (app: App, clientData: ClientData): void => {
setupDevtoolsPlugin(
{
// fix recursive reference
app: app as never,
id: PLUGIN_ID,
label: PLUGIN_LABEL,
id: DEVTOOLS.PLUGIN_ID,
label: DEVTOOLS.PLUGIN_LABEL,
packageName: '@vuepress/client',
homepage: 'https://vuepress.vuejs.org',
logo: 'https://vuepress.vuejs.org/images/hero.png',
componentStateTypes: [PLUGIN_COMPONENT_STATE_TYPE],
componentStateTypes: [DEVTOOLS.COMPONENT_STATE_TYPE],
},
(api) => {
const clientDataEntries = Object.entries(clientData) as [
Expand All @@ -39,7 +33,7 @@ export const setupDevtools = (app: App, clientData: ClientData): void => {
api.on.inspectComponent((payload) => {
payload.instanceData.state.push(
...clientDataEntries.map(([name, item]) => ({
type: PLUGIN_COMPONENT_STATE_TYPE,
type: DEVTOOLS.COMPONENT_STATE_TYPE,
editable: false,
key: name,
value: item.value,
Expand All @@ -49,38 +43,47 @@ export const setupDevtools = (app: App, clientData: ClientData): void => {

// setup custom inspector
api.addInspector({
id: INSPECTOR_ID,
label: INSPECTOR_LABEL,
id: DEVTOOLS.INSPECTOR_ID,
label: DEVTOOLS.INSPECTOR_LABEL,
icon: 'article',
})

api.on.getInspectorTree((payload) => {
if (payload.inspectorId !== INSPECTOR_ID) return
payload.rootNodes = [
{
id: INSPECTOR_CLIENT_DATA_ID,
label: INSPECTOR_CLIENT_DATA_LABEL,
children: clientDataKeys.map((name) => ({
id: name,
label: name,
if (payload.inspectorId !== DEVTOOLS.INSPECTOR_ID) return

payload.rootNodes = Object.values(DEVTOOLS.INSPECTOR_NODES).map(
(node) => ({
id: node.id,
label: node.label,
children: node.keys.map((key: ClientDataKey) => ({
id: key,
label: key,
})),
},
]
}),
)
})

api.on.getInspectorState((payload) => {
if (payload.inspectorId !== INSPECTOR_ID) return
if (payload.nodeId === INSPECTOR_CLIENT_DATA_ID) {
if (payload.inspectorId !== DEVTOOLS.INSPECTOR_ID) return

// root nodes state
const inspectorNode = DEVTOOLS.INSPECTOR_NODES[payload.nodeId] as
| InspectorNodeConfig
| undefined
if (inspectorNode) {
payload.state = {
[INSPECTOR_CLIENT_DATA_LABEL]: clientDataEntries.map(
([name, item]) => ({
key: name,
value: item.value,
}),
),
[inspectorNode.label]: inspectorNode.keys.map((key) => ({
key,
value: clientData[key].value,
})),
}
return
}

// root nodes children state
if (clientDataKeys.includes(payload.nodeId as ClientDataKey)) {
payload.state = {
[INSPECTOR_CLIENT_DATA_LABEL]: [
[DEVTOOLS.INSPECTOR_STATE_SECTION_NAME]: [
{
key: payload.nodeId,
value: clientData[payload.nodeId as ClientDataKey].value,
Expand All @@ -93,7 +96,7 @@ export const setupDevtools = (app: App, clientData: ClientData): void => {
// refresh the component state and inspector state
watch(clientDataValues, () => {
api.notifyComponentUpdate()
api.sendInspectorState(INSPECTOR_ID)
api.sendInspectorState(DEVTOOLS.INSPECTOR_ID)
})
},
)
Expand Down
10 changes: 10 additions & 0 deletions packages/client/src/devtools/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import type { CustomInspectorNode } from '@vue/devtools-kit'
import type { ClientData } from '../types/index.js'

export type ClientDataKey = keyof ClientData
export type ClientDataValue = ClientData[ClientDataKey]

export interface InspectorNodeConfig
extends Pick<CustomInspectorNode, 'id' | 'label'> {
keys: ClientDataKey[]
}
1 change: 1 addition & 0 deletions packages/client/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from './components/index.js'
export * from './composables/index.js'
export * from './devtools/index.js'
export * from './router/index.js'
export * from './resolvers.js'
export type * from './types/index.js'
Expand Down
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 4a105cb

Please # to comment.