Skip to content

Commit a55e4a5

Browse files
antfuclaude
andcommitted
merge: resolve conflicts with origin/main
Resolve conflicts in ViewBuiltinSettings.vue (keep decomposed sub-component approach) and .generated/css.ts (auto-merged). Incorporate HashBadge for action entries from main into SettingsDocks.vue. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2 parents 6f0cc0f + 22621ca commit a55e4a5

File tree

11 files changed

+192
-64
lines changed

11 files changed

+192
-64
lines changed

docs/guide/index.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,33 @@ pnpm dev
9898

9999
Then open your app in the browser and open the DevTools panel.
100100

101+
#### Building with the App
102+
103+
You can also generate a static DevTools build alongside your app's build output by enabling the `build.withApp` option:
104+
105+
```ts [vite.config.ts] twoslash
106+
import { DevTools } from '@vitejs/devtools'
107+
import { defineConfig } from 'vite'
108+
109+
export default defineConfig({
110+
plugins: [
111+
DevTools({
112+
build: {
113+
withApp: true, // generate DevTools output during `vite build`
114+
// outDir: 'custom-dir', // optional, defaults to Vite's build.outDir
115+
},
116+
}),
117+
],
118+
build: {
119+
rolldownOptions: {
120+
devtools: {},
121+
},
122+
}
123+
})
124+
```
125+
126+
When `build.withApp` is enabled, running `pnpm build` will automatically generate the static DevTools output into the build output directory. This captures real build data from the same build context, so DevTools can display accurate build analysis without a separate build step.
127+
101128
## What's Next?
102129

103130
Now that you have Vite DevTools set up, you can:

docs/kit/rpc.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ const plugin: Plugin = {
121121

122122
### Dump Feature for Build Mode
123123

124-
When using `vite devtools build` to create a static DevTools build, the server cannot execute functions at runtime. The **dump feature** solves this by pre-computing RPC results at build time.
124+
When creating a static DevTools build (via `vite devtools build` CLI or the [`build.withApp`](/guide/#building-with-the-app) plugin option), the server cannot execute functions at runtime. The **dump feature** solves this by pre-computing RPC results at build time.
125125

126126
#### How It Works
127127

packages/core/src/client/webcomponents/.generated/css.ts

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

packages/core/src/client/webcomponents/components/dock/DockEntries.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ function toggleDockEntry(dock: DevToolsDockEntry) {
4545
v-if="isDockVisible(dock)"
4646
:context="context"
4747
:dock
48+
:is-action="dock.type === 'action'"
4849
:is-selected="selected?.id === dock.id"
4950
:is-dimmed="selected ? (selected.id !== dock.id) : false"
5051
:is-vertical="isVertical"

packages/core/src/client/webcomponents/components/dock/DockEntry.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const props = withDefaults(
1111
defineProps<{
1212
context: DocksContext
1313
dock: DevToolsDockEntryBase
14+
isAction?: boolean
1415
isSelected?: boolean
1516
isDimmed?: boolean
1617
isVertical?: boolean
@@ -81,8 +82,9 @@ useEventListener('pointerdown', () => {
8182
isVertical ? 'rotate-270' : '',
8283
isDimmed ? 'op50 saturate-0' : '',
8384
isSelected ? 'scale-120 text-purple' : '',
85+
isAction ? 'bg-[#8881] hover:bg-[#8882] rounded-full' : 'rounded-xl',
8486
]"
85-
class="flex items-center justify-center p1.5 rounded-xl hover:bg-[#8881] hover:scale-110 transition-all duration-300 relative"
87+
class="flex items-center justify-center p1.5 hover:bg-[#8881] hover:scale-110 transition-all duration-300 relative"
8688
>
8789
<DockIcon :icon="dock.icon" :title="dock.title" class="w-5 h-5 select-none" />
8890
<div v-if="badge" class="absolute top-0.5 right-0 bg-gray-6 text-white text-0.6em px-1 rounded-full shadow">

packages/core/src/client/webcomponents/components/views-builtin/SettingsDocks.vue

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type { DevToolsDocksUserSettings } from '../../state/dock-settings'
55
import { computed } from 'vue'
66
import { docksGroupByCategories } from '../../state/dock-settings'
77
import { sharedStateToRef } from '../../state/docks'
8+
import HashBadge from '../display/HashBadge.vue'
89
import DockIcon from '../dock/DockIcon.vue'
910
1011
const props = defineProps<{
@@ -194,11 +195,18 @@ function resetCustomOrderForCategory(category: string) {
194195
:class="settings.docksHidden.includes(dock.id) ? 'saturate-0' : ''"
195196
/>
196197
<span
197-
class="flex-1 truncate"
198+
class="truncate"
198199
:class="settings.docksHidden.includes(dock.id) ? 'line-through op60' : ''"
199200
>
200201
{{ dock.title }}
201202
</span>
203+
<HashBadge
204+
v-if="dock.type === 'action'"
205+
label="Action"
206+
class="flex-none text-xs"
207+
/>
208+
209+
<div class="flex flex-auto" />
202210

203211
<!-- Order controls -->
204212
<div class="flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity">
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/* eslint-disable no-console */
2+
3+
import type { DevToolsNodeContext } from '@vitejs/devtools-kit'
4+
import { existsSync } from 'node:fs'
5+
import fs from 'node:fs/promises'
6+
import {
7+
DEVTOOLS_CONNECTION_META_FILENAME,
8+
DEVTOOLS_DIRNAME,
9+
DEVTOOLS_DOCK_IMPORTS_FILENAME,
10+
DEVTOOLS_MOUNT_PATH,
11+
DEVTOOLS_RPC_DUMP_DIRNAME,
12+
DEVTOOLS_RPC_DUMP_MANIFEST_FILENAME,
13+
} from '@vitejs/devtools-kit/constants'
14+
import c from 'ansis'
15+
import { dirname, join, relative, resolve } from 'pathe'
16+
import { dirClientStandalone } from '../dirs'
17+
import { MARK_NODE } from './constants'
18+
19+
export interface BuildStaticOptions {
20+
context: DevToolsNodeContext
21+
outDir: string
22+
}
23+
24+
export async function buildStaticDevTools(options: BuildStaticOptions): Promise<void> {
25+
const { context, outDir } = options
26+
27+
if (existsSync(outDir))
28+
await fs.rm(outDir, { recursive: true })
29+
30+
const devToolsRoot = join(outDir, DEVTOOLS_DIRNAME)
31+
await fs.mkdir(devToolsRoot, { recursive: true })
32+
await fs.cp(dirClientStandalone, devToolsRoot, { recursive: true })
33+
34+
for (const { baseUrl, distDir } of context.views.buildStaticDirs) {
35+
console.log(c.cyan`${MARK_NODE} Copying static files from ${distDir} to ${join(outDir, baseUrl)}`)
36+
await fs.mkdir(join(outDir, baseUrl), { recursive: true })
37+
await fs.cp(distDir, join(outDir, baseUrl), { recursive: true })
38+
}
39+
40+
const { renderDockImportsMap } = await import('./plugins/server')
41+
42+
await fs.mkdir(resolve(devToolsRoot, DEVTOOLS_RPC_DUMP_DIRNAME), { recursive: true })
43+
await fs.writeFile(resolve(devToolsRoot, DEVTOOLS_CONNECTION_META_FILENAME), JSON.stringify({ backend: 'static' }, null, 2), 'utf-8')
44+
await fs.writeFile(resolve(devToolsRoot, DEVTOOLS_DOCK_IMPORTS_FILENAME), renderDockImportsMap(context.docks.values()), 'utf-8')
45+
46+
console.log(c.cyan`${MARK_NODE} Writing RPC dump to ${resolve(devToolsRoot, DEVTOOLS_RPC_DUMP_MANIFEST_FILENAME)}`)
47+
const { collectStaticRpcDump } = await import('./static-dump')
48+
const dump = await collectStaticRpcDump(
49+
context.rpc.definitions.values(),
50+
context,
51+
)
52+
for (const [filepath, data] of Object.entries(dump.files)) {
53+
const fullpath = resolve(devToolsRoot, filepath)
54+
await fs.mkdir(dirname(fullpath), { recursive: true })
55+
await fs.writeFile(fullpath, JSON.stringify(data, null, 2), 'utf-8')
56+
}
57+
await fs.writeFile(resolve(devToolsRoot, DEVTOOLS_RPC_DUMP_MANIFEST_FILENAME), JSON.stringify(dump.manifest, null, 2), 'utf-8')
58+
await fs.writeFile(
59+
resolve(outDir, 'index.html'),
60+
[
61+
'<!doctype html>',
62+
'<html lang="en">',
63+
'<head>',
64+
' <meta charset="UTF-8">',
65+
' <meta name="viewport" content="width=device-width, initial-scale=1.0">',
66+
' <title>Vite DevTools</title>',
67+
` <meta http-equiv="refresh" content="0; url=${DEVTOOLS_MOUNT_PATH}">`,
68+
'</head>',
69+
'<body>',
70+
` <script>location.replace(${JSON.stringify(DEVTOOLS_MOUNT_PATH)})</script>`,
71+
'</body>',
72+
'</html>',
73+
].join('\n'),
74+
'utf-8',
75+
)
76+
77+
console.log(c.green`${MARK_NODE} Built DevTools to ${relative(context.cwd, outDir)}`)
78+
}

packages/core/src/node/cli-commands.ts

Lines changed: 6 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,10 @@
11
/* eslint-disable no-console */
22

3-
import { existsSync } from 'node:fs'
4-
import fs from 'node:fs/promises'
53
import {
6-
DEVTOOLS_CONNECTION_META_FILENAME,
7-
DEVTOOLS_DIRNAME,
8-
DEVTOOLS_DOCK_IMPORTS_FILENAME,
94
DEVTOOLS_MOUNT_PATH,
10-
DEVTOOLS_RPC_DUMP_DIRNAME,
11-
DEVTOOLS_RPC_DUMP_MANIFEST_FILENAME,
125
} from '@vitejs/devtools-kit/constants'
136
import c from 'ansis'
14-
import { dirname, join, relative, resolve } from 'pathe'
15-
import { dirClientStandalone } from '../dirs'
7+
import { resolve } from 'pathe'
168
import { MARK_NODE } from './constants'
179
import { normalizeHttpServerUrl } from './utils'
1810

@@ -93,57 +85,12 @@ export async function build(options: BuildOptions) {
9385

9486
const outDir = resolve(devtools.config.root, options.outDir)
9587

96-
if (existsSync(outDir))
97-
await fs.rm(outDir, { recursive: true })
98-
99-
const devToolsRoot = join(outDir, DEVTOOLS_DIRNAME)
100-
await fs.mkdir(devToolsRoot, { recursive: true })
101-
await fs.cp(dirClientStandalone, devToolsRoot, { recursive: true })
102-
103-
for (const { baseUrl, distDir } of devtools.context.views.buildStaticDirs) {
104-
console.log(c.cyan`${MARK_NODE} Copying static files from ${distDir} to ${join(outDir, baseUrl)}`)
105-
await fs.mkdir(join(outDir, baseUrl), { recursive: true })
106-
await fs.cp(distDir, join(outDir, baseUrl), { recursive: true })
107-
}
88+
const { buildStaticDevTools } = await import('./build-static')
89+
await buildStaticDevTools({
90+
context: devtools.context,
91+
outDir,
92+
})
10893

109-
const { renderDockImportsMap } = await import('./plugins/server')
110-
111-
await fs.mkdir(resolve(devToolsRoot, DEVTOOLS_RPC_DUMP_DIRNAME), { recursive: true })
112-
await fs.writeFile(resolve(devToolsRoot, DEVTOOLS_CONNECTION_META_FILENAME), JSON.stringify({ backend: 'static' }, null, 2), 'utf-8')
113-
await fs.writeFile(resolve(devToolsRoot, DEVTOOLS_DOCK_IMPORTS_FILENAME), renderDockImportsMap(devtools.context.docks.values()), 'utf-8')
114-
115-
console.log(c.cyan`${MARK_NODE} Writing RPC dump to ${resolve(devToolsRoot, DEVTOOLS_RPC_DUMP_MANIFEST_FILENAME)}`)
116-
const { collectStaticRpcDump } = await import('./static-dump')
117-
const dump = await collectStaticRpcDump(
118-
devtools.context.rpc.definitions.values(),
119-
devtools.context,
120-
)
121-
for (const [filepath, data] of Object.entries(dump.files)) {
122-
const fullpath = resolve(devToolsRoot, filepath)
123-
await fs.mkdir(dirname(fullpath), { recursive: true })
124-
await fs.writeFile(fullpath, JSON.stringify(data, null, 2), 'utf-8')
125-
}
126-
await fs.writeFile(resolve(devToolsRoot, DEVTOOLS_RPC_DUMP_MANIFEST_FILENAME), JSON.stringify(dump.manifest, null, 2), 'utf-8')
127-
await fs.writeFile(
128-
resolve(outDir, 'index.html'),
129-
[
130-
'<!doctype html>',
131-
'<html lang="en">',
132-
'<head>',
133-
' <meta charset="UTF-8">',
134-
' <meta name="viewport" content="width=device-width, initial-scale=1.0">',
135-
' <title>Vite DevTools</title>',
136-
` <meta http-equiv="refresh" content="0; url=${DEVTOOLS_MOUNT_PATH}">`,
137-
'</head>',
138-
'<body>',
139-
` <script>location.replace(${JSON.stringify(DEVTOOLS_MOUNT_PATH)})</script>`,
140-
'</body>',
141-
'</html>',
142-
].join('\n'),
143-
'utf-8',
144-
)
145-
146-
console.log(c.green`${MARK_NODE} Built to ${relative(devtools.config.root, outDir)}`)
14794
console.warn(c.yellow`${MARK_NODE} Static build is still experimental and not yet complete.`)
14895
console.warn(c.yellow`${MARK_NODE} Generated output may be missing features and can change without notice.`)
14996
}

packages/core/src/node/context.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ export async function createDevToolsContext(
6464
// json-render factory
6565
let jrCounter = 0
6666
context.createJsonRenderer = (initialSpec: JsonRenderSpec): JsonRenderer => {
67-
const stateKey = `__jr:${jrCounter++}`
67+
const stateKey = `devtoolskit:internal:json-render:${jrCounter++}`
6868
const statePromise = rpcHost.sharedState.get(stateKey as any, {
6969
initialValue: initialSpec as any,
7070
})
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/* eslint-disable no-console */
2+
3+
import type { DevToolsNodeContext } from '@vitejs/devtools-kit'
4+
import type { Plugin, ResolvedConfig } from 'vite'
5+
import c from 'ansis'
6+
import { resolve } from 'pathe'
7+
import { MARK_NODE } from '../constants'
8+
9+
export interface DevToolsBuildOptions {
10+
outDir?: string
11+
}
12+
13+
export function DevToolsBuild(options: DevToolsBuildOptions = {}): Plugin {
14+
let context: DevToolsNodeContext
15+
let resolvedConfig: ResolvedConfig
16+
17+
return {
18+
name: 'vite:devtools:build',
19+
apply: 'build',
20+
21+
configResolved(config) {
22+
resolvedConfig = config
23+
},
24+
25+
async buildStart() {
26+
const { createDevToolsContext } = await import('../context')
27+
context = await createDevToolsContext(resolvedConfig)
28+
},
29+
30+
async closeBundle() {
31+
console.log(c.cyan`${MARK_NODE} Building static Vite DevTools...`)
32+
33+
const outDir = options.outDir
34+
? resolve(resolvedConfig.root, options.outDir)
35+
: resolve(resolvedConfig.root, resolvedConfig.build.outDir)
36+
37+
const { buildStaticDevTools } = await import('../build-static')
38+
await buildStaticDevTools({ context, outDir })
39+
},
40+
}
41+
}

0 commit comments

Comments
 (0)