diff --git a/docs/content/1.guide/1.features.md b/docs/content/1.guide/1.features.md index 1e52a1b65d..9008b95b95 100644 --- a/docs/content/1.guide/1.features.md +++ b/docs/content/1.guide/1.features.md @@ -161,6 +161,8 @@ Virtual Files tab shows the virtual files generated by Nuxt to support the conve Inspect expose the [`vite-plugin-inspect`](https://github.com/antfu/vite-plugin-inspect) integration, allowing you to inspect transformation steps of Vite. +`vite-plugin-inspect` is an optional peer dependency, so it is not installed by default. Until you add it to your project, DevTools shows an install launcher in the Inspect slot (the same experience as Vite Plus DevTools) — click it to install the plugin and restart the dev server to activate the view. + Nuxt DevTools Inspect tab ## Settings diff --git a/packages/devtools-kit/src/_types/options.ts b/packages/devtools-kit/src/_types/options.ts index f56884ff6b..30ef4440e3 100644 --- a/packages/devtools-kit/src/_types/options.ts +++ b/packages/devtools-kit/src/_types/options.ts @@ -43,7 +43,12 @@ export interface ModuleOptions { vueDevTools?: boolean /** - * Enable vite-plugin-inspect + * Enable the Vite Inspect integration. + * + * `vite-plugin-inspect` is an optional peer dependency. When it isn't + * installed, DevTools shows an install launcher in its place (like Vite Plus + * DevTools); once installed, the real Inspect view is mounted. Set this to + * `false` to disable the integration (and its launcher) entirely. * * @default true */ diff --git a/packages/devtools/package.json b/packages/devtools/package.json index 1a25391beb..c128132249 100644 --- a/packages/devtools/package.json +++ b/packages/devtools/package.json @@ -45,7 +45,8 @@ "peerDependencies": { "nitro": "^3.0.0-0", "nitropack": "^2.0.0", - "vite": "^8.1.5" + "vite": "^8.1.5", + "vite-plugin-inspect": "catalog:prod" }, "peerDependenciesMeta": { "nitro": { @@ -53,6 +54,9 @@ }, "nitropack": { "optional": true + }, + "vite-plugin-inspect": { + "optional": true } }, "dependencies": { @@ -85,7 +89,6 @@ "tinyglobby": "catalog:prod", "unstorage": "catalog:prod", "verkit": "catalog:prod", - "vite-plugin-inspect": "catalog:prod", "vite-plugin-vue-tracer": "catalog:prod", "ws": "catalog:prod" }, @@ -136,6 +139,7 @@ "vanilla-jsoneditor": "catalog:frontend", "vis-data": "catalog:frontend", "vis-network": "catalog:frontend", + "vite-plugin-inspect": "catalog:prod", "vue-tsc": "catalog:cli", "vue-virtual-scroller": "catalog:frontend" } diff --git a/packages/devtools/src/integrations/analyze-build.ts b/packages/devtools/src/integrations/analyze-build.ts index a0e4ae1841..1118eb122e 100644 --- a/packages/devtools/src/integrations/analyze-build.ts +++ b/packages/devtools/src/integrations/analyze-build.ts @@ -3,10 +3,12 @@ import type { AnalyzeBuildMeta, ModuleOptions } from '../types' import { addVitePlugin } from '@nuxt/kit' import { join } from 'pathe' import { getFolderSize } from '../utils/fs' -import { createVitePluginInspect } from './vite-inspect' +import { createVitePluginInspect, isVitePluginInspectAvailable } from './vite-inspect' export async function setup(nuxt: Nuxt, options: ModuleOptions) { - if (options.viteInspect !== false) { + // Only wire the Vite Inspect build report when the optional + // `vite-plugin-inspect` peer dependency is actually installed. + if (options.viteInspect !== false && isVitePluginInspectAvailable(nuxt.options.rootDir)) { addVitePlugin( await createVitePluginInspect({ build: true, diff --git a/packages/devtools/src/integrations/vite-inspect.ts b/packages/devtools/src/integrations/vite-inspect.ts index d82f509cb5..98ca9a32b7 100644 --- a/packages/devtools/src/integrations/vite-inspect.ts +++ b/packages/devtools/src/integrations/vite-inspect.ts @@ -3,16 +3,49 @@ import type { ViteInspectOptions } from 'vite-plugin-inspect' import type { NuxtDevtoolsServerContext, ServerFunctions } from '../types' import { onDevtoolsReady } from '@nuxt/devtools-kit' import { addVitePlugin, logger } from '@nuxt/kit' +import { createInstallLauncher } from '@vitejs/devtools-kit/node' +import { isPackageExists } from 'local-pkg' import { RPC_NAMESPACE } from '../rpc-namespace' const VERSION_QUERY_RE = /\?v=\w+$/ const VUE_EXT_RE = /\.vue($|\?v=)/ +// `vite-plugin-inspect` registers its own dock under this id/title/icon. The +// install launcher we mount when the package is absent reuses them so the rail +// slot stays stable before and after the user installs it. +const INSPECT_DOCK_ID = 'vite-plugin-inspect' +const INSPECT_DOCK_TITLE = 'Inspect' +const INSPECT_DOCK_ICON = 'ph:magnifying-glass-duotone' + +/** + * Whether the optional `vite-plugin-inspect` peer dependency is installed in + * the user's project. + */ +export function isVitePluginInspectAvailable(rootDir: string): boolean { + return isPackageExists('vite-plugin-inspect', { paths: [rootDir] }) +} + export async function createVitePluginInspect(options?: ViteInspectOptions): Promise { return await import('vite-plugin-inspect').then(r => r.default(options)) } export async function setup(ctx: NuxtDevtoolsServerContext) { + // `vite-plugin-inspect` is an optional peer dependency. When the user hasn't + // installed it, mount a discovery/install launcher in its dock slot (the same + // UX as Vite Plus DevTools' built-in integration launchers) instead of the + // real Inspect view. Clicking it installs the package as a tracked terminal + // session, then asks for a dev-server restart to activate the real plugin. + if (!isVitePluginInspectAvailable(ctx.nuxt.options.rootDir)) { + addVitePlugin(createInstallLauncher({ + id: INSPECT_DOCK_ID, + title: INSPECT_DOCK_TITLE, + icon: INSPECT_DOCK_ICON, + label: 'Vite Inspect', + install: ['vite-plugin-inspect'], + })) + return + } + const plugin = await createVitePluginInspect() addVitePlugin(plugin) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8e8dec8e49..696192979d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -594,9 +594,6 @@ importers: vite: specifier: ^8.1.5 version: 8.1.5(@types/node@26.1.1)(@vitejs/devtools@0.4.9)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0) - vite-plugin-inspect: - specifier: catalog:prod - version: 12.0.2(@nuxt/kit-nightly@5.0.0-29755283.b4586ef2(magic-string@1.1.0)(magicast@0.5.3)(oxc-parser@0.142.0)(rolldown@1.2.0)(unplugin@3.3.0(esbuild@0.28.1)(rolldown@1.2.0)(rollup@4.62.2)(vite@8.1.5)(webpack@5.108.4(cssnano@8.0.2(postcss@8.5.24))(csso@5.0.5)(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.24))))(cac@7.0.0)(srvx@0.11.22)(typescript@6.0.3)(vite@8.1.5) vite-plugin-vue-tracer: specifier: catalog:prod version: 1.4.0(vite@8.1.5)(vue@3.5.40(typescript@6.0.3)) @@ -739,6 +736,9 @@ importers: vis-network: specifier: catalog:frontend version: 10.1.0(@egjs/hammerjs@2.0.17)(component-emitter@2.0.0)(keycharm@0.4.0)(uuid@14.0.1)(vis-data@8.0.4(uuid@14.0.1)(vis-util@6.0.0(@egjs/hammerjs@2.0.17)(component-emitter@2.0.0)))(vis-util@6.0.0(@egjs/hammerjs@2.0.17)(component-emitter@2.0.0)) + vite-plugin-inspect: + specifier: catalog:prod + version: 12.0.2(@nuxt/kit-nightly@5.0.0-29755283.b4586ef2(magic-string@1.1.0)(magicast@0.5.3)(oxc-parser@0.142.0)(rolldown@1.2.0)(unplugin@3.3.0(esbuild@0.28.1)(rolldown@1.2.0)(rollup@4.62.2)(vite@8.1.5)(webpack@5.108.4(cssnano@8.0.2(postcss@8.5.24))(csso@5.0.5)(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.24))))(cac@7.0.0)(srvx@0.11.22)(typescript@6.0.3)(vite@8.1.5) vue-tsc: specifier: ^3.3.8 version: 3.3.8(typescript@6.0.3)