From 72f97ba6da36ab3e68547d76bcbb0a5e947e624f Mon Sep 17 00:00:00 2001 From: arlo Date: Wed, 16 Sep 2026 23:08:37 +0800 Subject: [PATCH] feat(core): support devtools injection in builds --- docs/errors/DTK0035.md | 27 +++++++++++++++++++++ docs/errors/index.md | 1 + docs/guide/index.md | 15 ++++++++++++ packages/core/src/node/diagnostics.ts | 4 +++ packages/core/src/node/plugin-options.ts | 6 +++++ packages/core/src/node/plugins/index.ts | 2 +- packages/core/src/node/plugins/injection.ts | 15 +++++++++--- 7 files changed, 66 insertions(+), 4 deletions(-) create mode 100644 docs/errors/DTK0035.md diff --git a/docs/errors/DTK0035.md b/docs/errors/DTK0035.md new file mode 100644 index 000000000..c7b7a69ec --- /dev/null +++ b/docs/errors/DTK0035.md @@ -0,0 +1,27 @@ +--- +outline: deep +--- +# DTK0035: Build Injection Requires Assets + +## Message +> build.injection requires build.withApp: true. + +## Cause +`build.injection` is enabled, but `build.withApp` is disabled. + +## Example +```ts +export default defineConfig({ + devtools: { + build: { + injection: true, + }, + }, +}) +``` + +## Fix +Set `devtools.build.withApp: true`. + +## Source +- [`packages/core/src/node/plugins/injection.ts`](https://github.com/vitejs/devtools/blob/main/packages/core/src/node/plugins/injection.ts) — `configResolved()` validates asset generation. diff --git a/docs/errors/index.md b/docs/errors/index.md index d1d6a4fce..fb0409b9d 100644 --- a/docs/errors/index.md +++ b/docs/errors/index.md @@ -33,6 +33,7 @@ Emitted by `@vitejs/devtools` and `@vitejs/devtools-kit`. | [DTK0032](./DTK0032) | error | Dock Launch Error | | [DTK0033](./DTK0033) | warn | DevTools Mode Persist Failed | | [DTK0034](./DTK0034) | error | Duplicate DevTools Plugin | +| [DTK0035](./DTK0035) | error | Build Injection Requires Assets | | [DTK0050](./DTK0050) | error | Integration Install Failed | | [DTK0051](./DTK0051) | warn | Connection Meta Serve Failed | | [DTK0052](./DTK0052) | error | Launcher Process Exited Before Ready | diff --git a/docs/guide/index.md b/docs/guide/index.md index 14f5caa34..60d73b27d 100644 --- a/docs/guide/index.md +++ b/docs/guide/index.md @@ -143,6 +143,21 @@ export default defineConfig({ Open `/__devtools/` for the full-page UI, or load `/__devtools/embedded.js` to embed the dock in the built app. +To show the dock in the built app, enable `build.injection`: + +```ts +export default defineConfig({ + devtools: { + build: { + withApp: true, + injection: true, + }, + }, +}) +``` + +Injection defaults to `false` and requires `build.withApp: true`. Ensure the DevTools assets are served under Vite's `base` when deployed. + ## What's next - **Explore the built-in tools** — inspect Vite development with [Vite DevTools](/vite/) and production builds with [DevTools for Rolldown](/rolldown/). diff --git a/packages/core/src/node/diagnostics.ts b/packages/core/src/node/diagnostics.ts index ea0ba52f5..da5eee65d 100644 --- a/packages/core/src/node/diagnostics.ts +++ b/packages/core/src/node/diagnostics.ts @@ -4,6 +4,10 @@ export const diagnostics = /* #__PURE__ */ defineDiagnostics({ docsBase: 'https://devtools.vite.dev/errors', reporters: [createConsoleReporter()], codes: { + DTK0035: { + why: 'build.injection requires build.withApp: true.', + fix: 'Set devtools.build.withApp to true.', + }, DTK0008: { why: 'Client authentication is disabled. Any browser can connect to the devtools and access your server and filesystem.', }, diff --git a/packages/core/src/node/plugin-options.ts b/packages/core/src/node/plugin-options.ts index df0f7a069..5714b87aa 100644 --- a/packages/core/src/node/plugin-options.ts +++ b/packages/core/src/node/plugin-options.ts @@ -61,6 +61,12 @@ export interface DevToolsUserOptions { * @default false */ withApp?: boolean + /** + * Inject the dock into the built app. Requires `withApp: true`. + * Ensure the DevTools assets are served under Vite's `base` when deployed. + * @default false + */ + injection?: boolean /** Output directory relative to root. Defaults to Vite's `build.outDir`. */ outDir?: string } diff --git a/packages/core/src/node/plugins/index.ts b/packages/core/src/node/plugins/index.ts index b1b46f0c6..1de6472fe 100644 --- a/packages/core/src/node/plugins/index.ts +++ b/packages/core/src/node/plugins/index.ts @@ -60,7 +60,7 @@ export async function createDevToolsPlugins( const ui = { branding, embeddedVisibility, dockPreferences } const plugins = [ - DevToolsInjection(), + DevToolsInjection(build), DevToolsServer(ui, resolvedConfig, renderers), ] diff --git a/packages/core/src/node/plugins/injection.ts b/packages/core/src/node/plugins/injection.ts index 165d8885f..da135a597 100644 --- a/packages/core/src/node/plugins/injection.ts +++ b/packages/core/src/node/plugins/injection.ts @@ -1,5 +1,7 @@ import type { Plugin } from 'vite' +import type { DevToolsUserOptions } from '../plugin-options' import { DEVTOOLS_MOUNT_PATH } from '@vitejs/devtools-kit/constants' +import { diagnostics } from '../diagnostics' /** * Inject the `@devframes/hub-ui` embedded bootstrap into the host app's HTML. @@ -20,14 +22,21 @@ import { DEVTOOLS_MOUNT_PATH } from '@vitejs/devtools-kit/constants' * keeps `embedded.js` out of Vite's graph entirely, so the browser * fetches it straight from the hub with its real URL intact. */ -export function DevToolsInjection(): Plugin { - const src = `${DEVTOOLS_MOUNT_PATH}embedded.js` +export function DevToolsInjection(build?: DevToolsUserOptions['build']): Plugin { + let src = `${DEVTOOLS_MOUNT_PATH}embedded.js` return { name: 'vite:devtools:injection', enforce: 'post', apply(_config, env) { - return env.command === 'serve' && !env.isSsrBuild + return !env.isSsrBuild && (env.command === 'serve' || build?.injection === true) + }, + configResolved(config) { + if (config.command === 'build') { + if (!build?.withApp) + throw diagnostics.DTK0035({}) + src = `${config.base.replace(/\/+$/, '')}${DEVTOOLS_MOUNT_PATH}embedded.js` + } }, transformIndexHtml: { order: 'pre',