diff --git a/README.md b/README.md index b55f7670a5..18d7e262d2 100644 --- a/README.md +++ b/README.md @@ -24,15 +24,15 @@ Unleash Nuxt Developer Experience.

> [!NOTE] -> You are current at the `main` branch for v4 development. The latest stable branch is [`v3`](https://github.com/nuxt/devtools/tree/v3). +> You are at the `main` branch for v4. The v3 branch is [`v3`](https://github.com/nuxt/devtools/tree/v3).
## Installation -> Nuxt DevTools v2 requires **Nuxt v3.15.0 or higher**. +> Nuxt DevTools v4 requires **Nuxt v4.5.0 or higher** (Vite 8). It is built on [Vite DevTools](https://github.com/vitejs/devtools) and shows up as the `Nuxt` group inside the Vite DevTools panel. -Nuxt DevTools is **enabled by default** in Nuxt v3.8.0. You can press Shift + Alt / ⇧ Shift + ⌥ Option + D in your app to open it up. +Nuxt DevTools is **enabled by default**. You can press Shift + Alt / ⇧ Shift + ⌥ Option + D in your app to open it up. If you want to explicitly enable or disable Nuxt DevTools, you can update your `nuxt.config` with: @@ -44,52 +44,9 @@ export default defineNuxtConfig({ }) ``` -### Opting in to v4.0 +### Nuxt 4 -Nuxt DevTools v4.0 is currently in alpha. Since Nuxt ships with a built-in version of DevTools, you can opt-in to v4.0 by using package manager resolutions to override the bundled version: - -
-npm - -```json -{ - "overrides": { - "@nuxt/devtools": "npm:@nuxt/devtools-nightly@latest" - } -} -``` - -
- -
-yarn - -```json -{ - "resolutions": { - "@nuxt/devtools": "npm:@nuxt/devtools-nightly@latest" - } -} -``` - -
- -
-pnpm - -```json -{ - "pnpm": { - "overrides": { - "@nuxt/devtools": "npm:@nuxt/devtools-nightly@latest" - } - } -} -``` - -
- -Remove lockfile (`package-lock.json`, `yarn.lock`, or `pnpm-lock.yaml`) and reinstall dependencies. +Nuxt 5 ships with Nuxt DevTools v4. Nuxt 4.5+ still bundles v3; override `@nuxt/devtools` to `^4.0.0` with your package manager (`overrides` for npm and pnpm, `resolutions` for yarn), remove your lockfile and reinstall. See the [upgrade guide](https://devtools.nuxt.com/guide/upgrading-to-v4) for details and for what changed. ### Nightly Release Channel diff --git a/docs/content/1.guide/0.getting-started.md b/docs/content/1.guide/0.getting-started.md index 55e9cad740..86ecf3d3ef 100644 --- a/docs/content/1.guide/0.getting-started.md +++ b/docs/content/1.guide/0.getting-started.md @@ -15,47 +15,11 @@ export default defineNuxtConfig({ ### Open the DevTools Panel -Restart your Nuxt server and open your app in browser. Click the Nuxt icon on the bottom (or press :kbd{value="Shift"} + :kbd{value="Alt"} / :kbd{value="⇧ Shift"} + :kbd{value="⌥ Option"} + :kbd{value="D"}) to toggle the DevTools. +Restart your Nuxt server and open your app in browser. Click the Vite DevTools trigger at the bottom of the page (or press :kbd{value="Shift"} + :kbd{value="Alt"} / :kbd{value="⇧ Shift"} + :kbd{value="⌥ Option"} + :kbd{value="D"}) to toggle the DevTools. The first time, Vite DevTools asks you to authorize the browser with the code printed in your terminal. -### Opting in to v4.0 +### Nuxt 4 -Nuxt DevTools v4.0 is currently in alpha and requires Vite 8 — it integrates -with [Vite DevTools](https://github.com/vitejs/devtools), whose Code Server -dock only peers with Vite 8. Since Nuxt ships with a built-in version of -DevTools, you can opt-in to v4.0 by using package manager resolutions to -override the bundled version: - -::code-group - -```json [npm] -{ - "overrides": { - "@nuxt/devtools": "npm:@nuxt/devtools-nightly@latest" - } -} -``` - -```json [yarn] -{ - "resolutions": { - "@nuxt/devtools": "npm:@nuxt/devtools-nightly@latest" - } -} -``` - -```json [pnpm] -{ - "pnpm": { - "overrides": { - "@nuxt/devtools": "npm:@nuxt/devtools-nightly@latest" - } - } -} -``` - -:: - -Remove lockfile (`package-lock.json`, `yarn.lock`, or `pnpm-lock.yaml`) and reinstall dependencies. +Nuxt 5 ships with Nuxt DevTools v4. Nuxt 4.5+ still bundles v3; override it to `^4.0.0` with your package manager as described in [Upgrading to v4](/guide/upgrading-to-v4#nuxt-45). Nuxt 4.0–4.4 ship Vite 7 and cannot run v4. ### Nightly Release Channel diff --git a/docs/content/1.guide/1.features.md b/docs/content/1.guide/1.features.md index dbf475409b..1f8512440b 100644 --- a/docs/content/1.guide/1.features.md +++ b/docs/content/1.guide/1.features.md @@ -168,19 +168,3 @@ Inspect expose the [`vite-plugin-inspect`](https://github.com/antfu/vite-plugin- ## Settings Settings tab allows you to configure the DevTools to your needs. you can hide tabs, change tabs order, scale, theme and more... - -## Nuxt Icon - -Nuxt Icon is the first item on sidebar, located at the top left corner of the DevTools. It gives you a quick access to some useful features such as `Toggle Theme`, `Settings`, `Split Screen`, `Popup`, `Refresh Data`, `Refresh Page`. you can simply click on it and see the them yourself. - -### Command Palette - -Command Palette is a quick way to access some useful features of the DevTools such as easy navigation, run commands and Nuxt Documentations. You can open it with `Ctrl+K` or `Cmd+K` shortcut. - -### Split Screen - -Split Screen is a useful feature to use multiple tabs at the same time. You can open it from `Command Palette` or by clicking the `Nuxt Icon` in the top left corner of the DevTools and activate it from there. - -### Popup - -Popup is very useful for those who has a second screen, you can open it by clicking the `Nuxt Icon` in the top left corner of the DevTools and activate it from there. diff --git a/docs/content/1.guide/3.upgrading-to-v4.md b/docs/content/1.guide/3.upgrading-to-v4.md new file mode 100644 index 0000000000..10f6ec6005 --- /dev/null +++ b/docs/content/1.guide/3.upgrading-to-v4.md @@ -0,0 +1,140 @@ +--- +title: Upgrading to v4 +description: 'What changes for your app when you move from Nuxt DevTools v3 to v4.' +--- + +Nuxt DevTools v4 is built on [Vite DevTools](https://github.com/vitejs/devtools). Instead of shipping its own floating panel, it registers a `Nuxt` group inside the Vite DevTools panel, next to Vue DevTools, Vite Inspect, Terminals, Messages and the other tools your Vite plugins provide. Everything you know from the Nuxt side (Pages, Components, Imports, Modules, Server Routes, Timeline, …) lives in that group. + +This page is for app developers. If you maintain a Nuxt module that integrates with DevTools, read the [module migration guide](/module/migration-v4) as well. + +## Requirements + +- **Vite 8.1.5 or later.** Vite DevTools only works with Vite 8. +- That means **Nuxt 4.5 or later**, or **Nuxt 5**. Nuxt 4.0–4.4 ship Vite 7 and cannot run DevTools v4. + +If you are on an older Nuxt 4, upgrade Nuxt first. Overriding `vite` on Nuxt 4.4 to Vite 8 is not supported. + +## Installing + +### Nuxt 5 + +Nuxt 5 ships with DevTools v4. There is nothing to install: + +```ts [nuxt.config.ts] +export default defineNuxtConfig({ + devtools: { enabled: true }, +}) +``` + +### Nuxt 4.5+ + +Nuxt 4 still bundles DevTools v3. Override the bundled version with your package manager, then reinstall: + +::code-group + +```json [npm] +{ + "overrides": { + "@nuxt/devtools": "^4.0.0" + } +} +``` + +```json [yarn] +{ + "resolutions": { + "@nuxt/devtools": "^4.0.0" + } +} +``` + +```json [pnpm] +{ + "pnpm": { + "overrides": { + "@nuxt/devtools": "^4.0.0" + } + } +} +``` + +:: + +Remove your lockfile (`package-lock.json`, `yarn.lock`, or `pnpm-lock.yaml`) and run the install again so the override takes effect. + +## Opening DevTools + +The floating Nuxt button at the bottom of the page is gone; the Vite DevTools trigger takes its place. The keyboard shortcut is unchanged: :kbd{value="Shift"} + :kbd{value="Alt"} / :kbd{value="⇧ Shift"} + :kbd{value="⌥ Option"} + :kbd{value="D"} toggles the Nuxt entry. + +Vite DevTools can run shell commands and read files on your machine, so it asks you to **authorize the browser once per project**. On first open you will see an _Unauthorized_ badge; enter the 6-digit code printed in your terminal (or click the link printed next to it). In sandboxed environments such as StackBlitz and CodeSandbox the prompt is skipped automatically. To skip it elsewhere, set `devtools.disableAuthorization: true` in `nuxt.config.ts` — only do this on a machine you trust. + +To turn Vite DevTools off entirely (Nuxt DevTools included), disable it in your Vite config on Vite 8.3+: + +```ts [nuxt.config.ts] +export default defineNuxtConfig({ + vite: { + devtools: false, + }, +}) +``` + +## What moved + +| v3 | v4 | +| ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------- | +| Floating Nuxt panel | `Nuxt` group in the Vite DevTools panel | +| Nuxt Options Viewer | **Data Inspector** → `Nuxt Application` source, with a live [jora](https://discoveryjs.github.io/jora/) query workbench | +| Terminals tab | Vite DevTools **Terminals** dock (shared with every tool) | +| Built-in VS Code integration (`devtools.vscode`) | **Code Server** dock (`devtools.codeServer`), see below | +| Vue DevTools tab | Vue DevTools dock, next to the `Nuxt` group (`vite-plugin-vue-devtools` v9) | +| Popup (Picture-in-Picture) and Split Screen | Removed; Vite DevTools owns the panel layout | +| `nuxi devtools enable/disable` | Removed; set `devtools.enabled` in `nuxt.config.ts` | + +Module tabs contributed by Nuxt modules you install (for example `@nuxt/fonts`, `@nuxt/scripts`, `nuxt-og-image`) keep working. They appear in the `Nuxt` group under the _Modules_ category. + +## Configuration changes + +### `vscode` is replaced by `codeServer` {#code-server} + +The VS Code integration is now the Code Server plugin. It supports a locally installed Coder [`code-server`](https://coder.com/docs/code-server/install), detected when DevTools starts and launched on demand. + +```diff [nuxt.config.ts] +export default defineNuxtConfig({ + devtools: { +- vscode: { enabled: true }, ++ codeServer: { enabled: true }, + }, +}) +``` + +The old `vscode` value is ignored and a `NDT_DEP_0008` warning is printed. The following v3 modes no longer exist: + +- Microsoft `code serve-web` and `code-server serve-local` +- VS Code tunnels +- reusing an already running server, or starting one on boot +- the `vscode-server-controller` extension + +The generic _open in editor_ action (from component and file links) is unaffected. `codeServer` accepts `enabled`, `bin`, `cwd`, `serverPort`, `host`, `args`, `env`, `cookieSuffix` and `startTimeout`. + +### Removed options + +- `viteDevTools` — Vite DevTools is always on; use `vite.devtools: false` to turn it off. +- `ui.showPanel` and `ui.minimizePanelInactive` — the floating panel no longer exists. +- `devtoolsGlobal` — DevTools cannot be installed globally any more. +- `experimental.timeline` — still honored, but use `timeline.enabled` instead. + +### New options + +- `vueDevTools` (default `true`) — set to `false` to skip the Vue DevTools dock. +- `dataInspector` (default `true`) — set to `false` to skip the Data Inspector source. +- `disableAuthorization` (default: on in sandboxes) — skips the authorization prompt described above. + +## Deprecation warnings in your terminal + +Lines such as `[NDT_DEP_0003] extendServerRpc is deprecated` come from a Nuxt module you installed, not from your app. The module keeps working; the warning tells its author which v4 API to move to. Each code links to the relevant section of the [module migration guide](/module/migration-v4), which is the right place to point the maintainer to. + +## Troubleshooting + +- **The dev server crashes at startup mentioning `@vitejs/devtools-rolldown`.** You are on Vite 7 (Nuxt ≤ 4.4). Upgrade to Nuxt 4.5 or later. +- **Opening `/__nuxt_devtools__/client/` directly shows empty data.** The client needs the connection the Vite DevTools panel gives it; open DevTools from the app page instead. +- **The authorization code does not appear.** It is printed by the dev server process; look in the terminal running `nuxt dev`, not in the browser console. diff --git a/docs/content/2.module/0.guide.md b/docs/content/2.module/0.guide.md index 54961c1c78..e038e13ab5 100644 --- a/docs/content/2.module/0.guide.md +++ b/docs/content/2.module/0.guide.md @@ -5,6 +5,8 @@ description: 'Add your own modules integration to the Nuxt DevTools.' Nuxt DevTools is designed to be extensible. You can add your own modules integration to the DevTools. +Nuxt DevTools v4 is built on [Vite DevTools](https://github.com/vitejs/devtools): your module registers **dock entries** (tabs), **RPC functions** and **terminals** on the same hosts every other Vite tool uses, from one hook, [`onDevtoolsReady()`](/module/utils-kit#ondevtoolsready). If your module still uses the v3 API (`addCustomTab`, `extendServerRpc`, …), see the [migration guide](/module/migration-v4). + ## Starter Template If you want to try integrating with Nuxt DevTools, you can run @@ -13,181 +15,136 @@ If you want to try integrating with Nuxt DevTools, you can run npx nuxi init my-module -t module-devtools ``` -to create a new module starter with Nuxt DevTools integration pre-configured (contributing a fully custom view as a tab). +to create a new module starter with Nuxt DevTools integration pre-configured (contributing a fully custom view as a tab). The [`module-starter` playground](https://github.com/nuxt/devtools/tree/main/playgrounds/module-starter) in the DevTools repo is the same setup on the v4 API. ## Contributing to View -Currently the only way to contribute to Nuxt DevTools View is via iframe. You need to serve your module's view yourself and then register it to the DevTools. - -You can use the utility kit provided by Nuxt DevTools to register your custom tab: +Currently the only way to contribute to Nuxt DevTools View is via iframe. You need to serve your module's view yourself and then register it as a dock entry in the `Nuxt` group: ```ts -import { addCustomTab } from '@nuxt/devtools-kit' - -addCustomTab({ - // unique identifier - name: 'my-module', - // title to display in the tab - title: 'My Module', - // any icon from Iconify, or a URL to an image - icon: 'carbon:apps', - // iframe view - view: { - type: 'iframe', - src: '/url-to-your-module-view', - }, -}) -``` - -Or if you prefer to use Nuxt hooks: +import { NUXT_DEVTOOLS_GROUP_ID, onDevtoolsReady } from '@nuxt/devtools-kit' -```ts -nuxt.hook('devtools:customTabs', (tabs) => { - tabs.push({ +onDevtoolsReady((ctx) => { + ctx.docks.register({ // unique identifier - name: 'my-module', - // title to display in the tab + id: 'my-module', + // title to display in the dock title: 'My Module', // any icon from Iconify, or a URL to an image icon: 'carbon:apps', // iframe view - view: { - type: 'iframe', - src: '/url-to-your-module-view', - }, + type: 'iframe', + url: '/url-to-your-module-view', + // show it inside the `Nuxt` group, next to the built-in tabs + groupId: NUXT_DEVTOOLS_GROUP_ID, }) }) ``` -### Iframe Permissions +Set `category` (`app`, `analyze`, `server`, `modules`, `documentation`, `advanced`) to choose the section of the `Nuxt` group the entry appears in, or omit `groupId` to register a top-level dock next to Vue DevTools and Vite Inspect. -By default, iframes have `clipboard-write` and `clipboard-read` permissions enabled. You can add additional permissions using the `permissions` option: +`register()` returns a handle to patch the entry later, for example to show a badge: ```ts -const view: ModuleIframeView = { - type: 'iframe', - src: '/url-to-your-module-view', - // Additional permissions to allow in the iframe - permissions: ['camera', 'microphone', 'geolocation'], -} +const entry = ctx.docks.register({ id: 'my-module', /* ... */ }) +entry.update({ badge: '3' }) ``` -These permissions will be merged with the default ones and set on the iframe's `allow` attribute. - Learn more about [DevTools Utility Kit](/module/utils-kit). ## Lazy Service Launching -If the view you are contributing is heavy to load, you can have the tab first and let user launch it when they need it. +If the view you are contributing is heavy to load, register a `launcher` entry first and swap it for the iframe once the user starts it. Re-registering the same `id` with `true` as the second argument replaces the entry: ```ts -let isReady = false -const promise: Promise | null = null +let promise: Promise | undefined -async function launchService() { - // ...launch your service - isReady = true -} - -nuxt.hook('devtools:customTabs', (tabs) => { - tabs.push({ - name: 'my-module', +onDevtoolsReady((ctx) => { + ctx.docks.register({ + id: 'my-module', title: 'My Module', - view: isReady - ? { + icon: 'carbon:apps', + type: 'launcher', + groupId: NUXT_DEVTOOLS_GROUP_ID, + launcher: { + title: 'Start My Module', + description: 'Starts the inspector server on demand.', + async onLaunch() { + promise ||= launchService() + await promise + ctx.docks.register({ + id: 'my-module', + title: 'My Module', + icon: 'carbon:apps', type: 'iframe', - src: '/url-to-your-module-view', - } - : { - type: 'launch', - description: 'Launch My Module', - actions: [{ - label: 'Start', - async handle() { - if (!promise) - promise = launchService() - await promise - }, - }] - }, + url: '/url-to-your-module-view', + groupId: NUXT_DEVTOOLS_GROUP_ID, + }, true) + }, + }, }) }) ``` -It will first display a launch page with a button to start the service. When user click the button, the `handle()` will be called, and the view will be updated to iframe. - -When you need to refresh the custom tabs, you can call `nuxt.callHook('devtools:customTabs:refresh')` and the hooks on `devtools:customTabs` will be revaluated again. - -## API for Custom View - -Please refer to [Iframe Client](/module/utils-kit#nuxtdevtools-kitiframe-client). +It will first display a launch page with a button to start the service. When the user clicks the button, `onLaunch()` is called, and the entry becomes the iframe. ## Custom RPC Functions -Nuxt DevTools uses Remote Procedure Call (RPC) to communicate between the server and client. For modules you can also leverage that to communicate your server code. - -To do that, we recommend to define your types in a shared TypeScript file first: - -```ts -// rpc-types.ts - -export interface ServerFunctions { - getMyModuleOptions: () => MyModuleOptions -} - -export interface ClientFunctions { - showNotification: (message: string) => void -} -``` +Nuxt DevTools uses Remote Procedure Call (RPC) to communicate between the server and client. For modules you can also leverage that to communicate with your server code. -And then in your module code: +Scope the RPC host to your module so every function and event name is prefixed with your namespace (`my-module:` below) without repeating it: ```ts -import type { ClientFunctions, ServerFunctions } from './rpc-types' -import { extendServerRpc, onDevToolsInitialized } from '@nuxt/devtools-kit' +import { onDevtoolsReady } from '@nuxt/devtools-kit' import { defineNuxtModule } from '@nuxt/kit' -const RPC_NAMESPACE = 'my-module-rpc' - export default defineNuxtModule({ setup(options, nuxt) { - // wait for DevTools to be initialized - onDevToolsInitialized(async () => { - const rpc = extendServerRpc(RPC_NAMESPACE, { - // register server RPC functions - getMyModuleOptions() { + onDevtoolsReady((ctx) => { + const { rpc } = ctx.scope('my-module') + + // register server RPC functions + rpc.register({ + name: 'get-options', + type: 'query', + handler() { return options }, }) // call client RPC functions - // since it might have multiple clients connected, we use `broadcast` to call all of them - await rpc.broadcast.showNotification('Hello from My Module!') + // since there might be multiple clients connected, `broadcast` calls all of them + rpc.broadcast({ method: 'show-notification', args: ['Hello from My Module!'], event: true }) }) - } + }, }) ``` -And on the embedded iframe client side, you can do: +`type` is `'query'` for reads, `'action'` for mutations, `'event'` for fire-and-forget and `'static'` for values that never change. -```ts -import type { ClientFunctions, ServerFunctions } from './rpc-types' -import { onDevtoolsClientConnected } from '@nuxt/devtools-kit/iframe-client' +And on the embedded iframe client side, connect to Vite DevTools and use the same scope: -const RPC_NAMESPACE = 'my-module-rpc' +```ts +import { getDevToolsRpcClient } from '@vitejs/devtools-kit/client' -onDevtoolsClientConnected(async (client) => { - const rpc = client.devtools.extendClientRpc(RPC_NAMESPACE, { - showNotification(message) { - console.log(message) - }, - }) +const kit = await getDevToolsRpcClient() +const { rpc } = kit.scope('my-module') - // call server RPC functions - const options = await rpc.getMyModuleOptions() +// register client RPC functions +rpc.register({ + name: 'show-notification', + type: 'event', + handler(message: string) { + console.log(message) + }, }) + +// call server RPC functions +const options = await rpc.call('get-options') ``` +See the [iframe client](/module/utils-kit#nuxtdevtools-kitiframe-client) section for how to reach the user's app from your iframe. + ## Trying Local Changes You can clone Nuxt DevTools repo and try your changes locally. @@ -198,7 +155,7 @@ Please refer to [Trying Local Changes](/development/contributing#trying-local-ch Here are a few examples of how to integrate Nuxt DevTools in modules: -- [Built-in VS Code integration with lazy initialize](https://github.com/nuxt/devtools/blob/a8d372bd10d34d8c2fba2613558df2b9b99d6ff9/packages/devtools/src/integrations/vscode.ts#L140-L172) +- [Nuxt DevTools `module-starter` playground](https://github.com/nuxt/devtools/tree/main/playgrounds/module-starter) - [VueUse adds a docs tab](https://github.com/vueuse/vueuse/blob/ce28cef154489c73abe308104bef8568594a9bcd/packages/nuxt/index.ts#L89-L99) - [UnoCSS Inspector](https://github.com/unocss/unocss/blob/25021a751494e99e85cfd82cca3855cdf78f6a12/packages/nuxt/src/index.ts#L81-L94) - [Nuxt Test Utils](https://github.com/nuxt/test-utils/blob/fd024f45f752c2faa4c9e0cc1fc1f8b3eae59553/src/module.ts#L150-L192) diff --git a/docs/content/2.module/1.utils-kit.md b/docs/content/2.module/1.utils-kit.md index c86326fe6a..b2eb3fedb7 100644 --- a/docs/content/2.module/1.utils-kit.md +++ b/docs/content/2.module/1.utils-kit.md @@ -44,7 +44,7 @@ onDevtoolsReady((ctx) => { ::warning **Deprecated.** `addCustomTab()` is soft-deprecated (`NDT_DEP_0005`) in favour of registering a dock entry on the Vite DevTools docks host -(`nuxt.devtools.docks.register(...)`). It still works as a shim. Note the docks +(`onDevtoolsReady((ctx) => ctx.docks.register(...))`). It still works as a shim. Note the docks host does not yet cover `vnode` views or tab categories. See the [migration guide](/module/migration-v4#ndt_dep_0005). :: @@ -89,7 +89,7 @@ const view: ModuleIframeView = { ::warning **Deprecated.** `refreshCustomTabs()` is soft-deprecated (`NDT_DEP_0006`). Update dock entries directly via the handle returned by -`nuxt.devtools.docks.register(...)`. It still works as a shim. See the +`ctx.docks.register(...)`. It still works as a shim. See the [migration guide](/module/migration-v4#ndt_dep_0006). :: @@ -174,20 +174,19 @@ const rpc = extendServerRpc('my-module', { ``` The forward path registers functions on the Vite DevTools RPC host from the -[`onDevtoolsReady()`](#ondevtoolsready) hook: +[`onDevtoolsReady()`](#ondevtoolsready) hook, scoped to your module's namespace: ```ts import { onDevtoolsReady } from '@nuxt/devtools-kit' -import { defineRpcFunction } from '@vitejs/devtools-kit' export default defineNuxtModule({ setup(_options, nuxt) { onDevtoolsReady((ctx) => { - ctx.rpc.register(defineRpcFunction({ - name: 'my-module:my-method', + ctx.scope('my-module').rpc.register({ + name: 'my-method', // registered as `my-module:my-method` type: 'query', - setup: () => ({ handler: async () => 'hello' }), - })) + handler: async () => 'hello', + }) }) }, }) @@ -203,8 +202,7 @@ the Vite DevTools kit has connected and receives the connected available — no connect-safe buffering needed. Do all your DevTools integration here: ```ts -import { onDevtoolsReady } from '@nuxt/devtools-kit' -import { defineRpcFunction } from '@vitejs/devtools-kit' +import { NUXT_DEVTOOLS_GROUP_ID, onDevtoolsReady } from '@nuxt/devtools-kit' export default defineNuxtModule({ setup(_options, nuxt) { @@ -213,17 +211,19 @@ export default defineNuxtModule({ ctx.docks.register({ id: 'my-module', title: 'My Module', + icon: 'carbon:apps', type: 'iframe', url: '/__my-module__/', + groupId: NUXT_DEVTOOLS_GROUP_ID, }) - ctx.rpc.register(defineRpcFunction({ - name: 'my-module:my-method', + ctx.scope('my-module').rpc.register({ + name: 'my-method', // registered as `my-module:my-method` type: 'query', - setup: () => ({ handler: async () => 'hello' }), - })) + handler: async () => 'hello', + }) - ctx.messages.info('My module is ready') + ctx.messages.add({ message: 'My module is ready', level: 'info' }) }) }, }) @@ -246,6 +246,7 @@ which exposes the full devframe-native surface: - `ctx.commands` — command-palette entries - `ctx.diagnostics` — structured, coded diagnostics (powered by [nostics](https://github.com/vercel-labs/nostics)) - `ctx.rpc` — the devframe RPC host (`register`/`invokeLocal`/`broadcast`/`sharedState`/`streaming`/…) +- `ctx.scope(namespace)` — the same RPC host with every name prefixed by `namespace:` If you need the raw context outside the hook, `nuxt.devtools.devtoolsKit` is available as an escape hatch (it is `undefined` until the kit connects). @@ -289,7 +290,24 @@ injected client as `client.devtools.notify(...)`. To provide complex interactions for your module integrations, we recommend to host your own view and display it in devtools via iframe. -To get the infomation from the devtools and the client app, you can do this in your client app: +::warning +The helpers below depend on the `__NUXT_DEVTOOLS__` object that the Nuxt client injects into **legacy** custom tabs (`addCustomTab()`). A dock entry registered with `ctx.docks.register()` is rendered by Vite DevTools itself and does not receive it. In a native dock, connect to Vite DevTools directly and read the host client from the parent window: + +```ts +import type { NuxtDevtoolsHostClient } from '@nuxt/devtools-kit/types' +import { getDevToolsRpcClient } from '@vitejs/devtools-kit/client' + +const kit = await getDevToolsRpcClient() +const { rpc } = kit.scope('my-module') + +// the user's app is the parent window of every dock iframe (same origin only) +const host = (window.parent as Window & { __NUXT_DEVTOOLS_HOST__?: NuxtDevtoolsHostClient }).__NUXT_DEVTOOLS_HOST__ +``` + +See [Custom RPC Functions](/module/guide#custom-rpc-functions) for the full flow. +:: + +To get the information from the devtools and the client app in a legacy custom tab, you can do this in your client app: ```ts import { useDevtoolsClient } from '@nuxt/devtools-kit/iframe-client' diff --git a/docs/content/2.module/3.migration-v4.md b/docs/content/2.module/3.migration-v4.md index d3ac6938b5..d42177a39e 100644 --- a/docs/content/2.module/3.migration-v4.md +++ b/docs/content/2.module/3.migration-v4.md @@ -1,344 +1,309 @@ --- title: Migration to v4 -description: 'Breaking changes and migration guide for Nuxt DevTools v4.' +description: 'Move your module integration from the Nuxt DevTools v3 API to the Vite DevTools based v4 API.' --- -## `vscode` option removed {#ndt_dep_0008} +Nuxt DevTools v4 is a [Vite DevTools](https://github.com/vitejs/devtools) integration. The Nuxt-specific hooks and helpers of v3 (`addCustomTab`, `extendServerRpc`, `startSubprocess`, `devtools:customTabs`, …) are replaced by one entry point, [`onDevtoolsReady()`](/module/utils-kit#ondevtoolsready), which hands you the Vite DevTools node context. From there you register **docks** (tabs), **RPC functions**, **terminals** and **messages** on the same hosts every other Vite tool uses. -The bespoke `devtools.vscode` integration has been replaced by the Code Server -Devframe plugin. Supplying `vscode` emits `NDT_DEP_0008`; the complete value is -ignored and is not translated, because partially mapping the old modes would -silently change their behavior. +If you only use Nuxt DevTools in your app, read [Upgrading to v4](/guide/upgrading-to-v4) instead. -```diff -export default defineNuxtConfig({ - devtools: { -- vscode: { enabled: true }, -+ codeServer: { enabled: true }, - }, -}) -``` +## Should I migrate now? -The replacement supports only a locally installed Coder -[`code-server`](https://coder.com/docs/code-server/install), detected at setup -and started on demand. These legacy capabilities were removed: +Yes. DevTools v4 runs on Nuxt 4.5+ and Nuxt 5, so the new API covers every Nuxt version that can run v4. -- Microsoft `code serve-web` and Microsoft `code-server serve-local`; -- VS Code tunnels; -- reusing an existing server; -- starting the server on boot; -- installing the `vscode-server-controller` extension; -- opening a specific file through that controller extension. +The v3 API keeps working on v4 through compatibility shims, each of which prints a coded `NDT_DEP_xxxx` warning in the user's terminal with a link to the matching section below. Those shims stay for the whole v4 cycle and are removed in v5. -The generic open-in-editor feature remains available. For the new integration, -configure only `enabled`, `bin`, `cwd`, `serverPort`, `host`, `args`, `env`, -`cookieSuffix`, or `startTimeout` under `devtools.codeServer`. +A migrated module requires DevTools v4. On a project still running DevTools v3 (Nuxt 4 without the [override](/guide/upgrading-to-v4#nuxt-45)), the `devtools:ready` hook never fires and your integration simply does not register; nothing breaks. -## `startSubprocess()` API Changes +## At a glance -The subprocess system has been migrated from `execa` to `tinyexec`. +| v3 | v4 | Warning | +| -------------------------------------------- | ----------------------------------------------------------- | ------------------------------- | +| `addCustomTab()` / `devtools:customTabs` | `ctx.docks.register({ type: 'iframe', … })` | [`NDT_DEP_0005`](#ndt_dep_0005) | +| `refreshCustomTabs()` | `ctx.docks.register(entry, true)` or the `update()` handle | [`NDT_DEP_0006`](#ndt_dep_0006) | +| `view: { type: 'launch' }` | `ctx.docks.register({ type: 'launcher', … })` | [`NDT_DEP_0005`](#ndt_dep_0005) | +| `extendServerRpc()` | `ctx.scope('my-module').rpc.register()` | [`NDT_DEP_0003`](#ndt_dep_0003) | +| `nuxt.devtools.rpc.broadcast` / `.functions` | `ctx.scope('my-module').rpc.broadcast()` | [`NDT_DEP_0007`](#ndt_dep_0007) | +| `startSubprocess()` / `devtools:terminal:*` | `ctx.terminals.startChildProcess()` | [`NDT_DEP_0004`](#ndt_dep_0004) | +| `startSubprocess().getProcess()` | `.getResult()` | [`NDT_DEP_0001`](#ndt_dep_0001) | +| `getServerData` RPC | Data Inspector `Nuxt Application` source | [`NDT_DEP_0009`](#ndt_dep_0009) | +| `client.devtools.extendClientRpc()` (iframe) | `kit.scope('my-module').rpc.register()` | console warning | +| `useDevtoolsClient()` (iframe) | `getDevToolsRpcClient()` from `@vitejs/devtools-kit/client` | — | +| `devtools.vscode` option | `devtools.codeServer` | [`NDT_DEP_0008`](#ndt_dep_0008) | -### `SubprocessOptions` no longer extends `ExecaOptions` +The rest of this page walks through a migration in the order you will hit it. The repo's [`module-starter` playground](https://github.com/nuxt/devtools/tree/main/playgrounds/module-starter) is the finished result. -Previously, `SubprocessOptions` extended `ExecaOptions` from `execa`, allowing you to pass any execa option directly. It now has its own interface: +## Step 1: dependencies -```ts -interface SubprocessOptions { - command: string - args?: string[] - cwd?: string - env?: Record - nodeOptions?: SpawnOptions // from 'node:child_process' +```diff [package.json] +{ + "dependencies": { +- "@nuxt/devtools-kit": "^3.0.0" ++ "@nuxt/devtools-kit": "^4.0.0", ++ "@vitejs/devtools-kit": "^0.7.6" + } } ``` -Common fields like `cwd` and `env` are still available as top-level options. Other execa-specific options should be migrated to `nodeOptions` (Node.js `SpawnOptions`): +`@vitejs/devtools-kit` provides the browser-side RPC client for your iframe and the types for the node context. Keep `@nuxt/devtools` as a dev dependency for your playground. -```diff -startSubprocess({ - command: 'my-command', - args: ['--flag'], - cwd: '/some/path', -- stdio: 'pipe', -+ nodeOptions: { -+ stdio: 'pipe', -+ }, -}) -``` - -### `startSubprocess()` is deprecated {#ndt_dep_0004} +## Step 2: register your tab as a dock entry {#ndt_dep_0005} -`startSubprocess()` is soft-deprecated in favour of the Vite DevTools terminals -host, used from the [`onDevtoolsReady`](/module/utils-kit#ondevtoolsready) hook. -It still works as a shim, but emits the `NDT_DEP_0004` deprecation diagnostic. +`addCustomTab()` and the `devtools:customTabs` hook are deprecated (`NDT_DEP_0005`). Register a dock entry from `onDevtoolsReady()` and put it in the `Nuxt` group so it shows up next to the built-in tabs: ```diff -- import { startSubprocess } from '@nuxt/devtools-kit' -+ import { onDevtoolsReady } from '@nuxt/devtools-kit' +- import { addCustomTab } from '@nuxt/devtools-kit' ++ import { NUXT_DEVTOOLS_GROUP_ID, onDevtoolsReady } from '@nuxt/devtools-kit' -- const subprocess = startSubprocess( -- { command: 'vite', args: ['build', '--watch'] }, -- { id: 'my-module:build', name: 'Build', icon: 'ph:terminal-duotone' }, -- ) -+ onDevtoolsReady(async (ctx) => { -+ const session = await ctx.terminals.startChildProcess( -+ { command: 'vite', args: ['build', '--watch'], cwd: process.cwd() }, -+ { id: 'my-module:build', title: 'Build', icon: 'ph:terminal-duotone' }, -+ ) +- addCustomTab({ +- name: 'my-module', +- title: 'My Module', +- icon: 'carbon:apps', +- view: { type: 'iframe', src: '/__my-module' }, +- }) ++ onDevtoolsReady((ctx) => { ++ ctx.docks.register({ ++ id: 'my-module', ++ title: 'My Module', ++ icon: 'carbon:apps', ++ type: 'iframe', ++ url: '/__my-module', ++ groupId: NUXT_DEVTOOLS_GROUP_ID, ++ }) + }) ``` -The terminals host session exposes `terminate()`, `restart()`, -`getChildProcess()`, and `getResult()` — a `tinyexec`-style awaitable handle that -resolves to `{ stdout, stderr, exitCode }` — so the `startSubprocess().getResult()` -ergonomics carry over: - -```ts -onDevtoolsReady(async (ctx) => { - const session = await ctx.terminals.startChildProcess( - { command: 'npm', args: ['install'] }, - { id: 'my-module:install', title: 'Install' }, - ) - const { exitCode, stderr } = await session.getResult() - if (exitCode !== 0) - console.error(stderr) -}) -``` - -### Direct `devtools:terminal:*` hooks are legacy (output-only bridge) - -Calling the `devtools:terminal:register` / `:write` / `:exit` / `:remove` hooks -directly (including via `startSubprocess()`, which emits them internally) is -legacy. Nuxt DevTools no longer ships its own xterm terminal UI; instead these -hooks are **bridged onto the built-in Vite DevTools Terminals dock**. - -The bridge is **output + final status only**: - -- terminal output (`:write`) and the final `stopped`/`error` status (`:exit`) - appear live in the Terminals dock; -- the legacy `restartable` / `terminatable` flags and the - `onActionRestart` / `onActionTerminate` callbacks are **ignored** — Devframe - cannot attach action controls to an externally registered session, so no - restart/terminate button is shown for a bridged terminal; -- re-registering the same id (`clear()` / `restart()`) is surfaced as a new - session; the previous run's output is not reset in place. - -Programmatic control (`terminate()` / `restart()` on a `startSubprocess()` -handle) keeps working because that helper owns its process. Only the old Nuxt UI -controls are gone. - -This compatibility bridge, the `devtools:terminal:*` hooks, and the deprecated -`TerminalState` action fields are scheduled for **removal in v5**. Spawn -terminals through `ctx.terminals.startChildProcess()` / `startPtySession()` from -`onDevtoolsReady` instead — those are owned by Devframe and keep full controls. - -### `getProcess()` is deprecated {#ndt_dep_0001} +Field mapping: `name` → `id`, `view.src` → `url`, `view.type` → `type`. Icons are Iconify names or image URLs, as before. + +- **Categories.** Set `category` on the entry (`app`, `analyze`, `server`, `modules`, `documentation`, `advanced`) to pick its section inside the `Nuxt` group. Legacy custom tabs are listed under `modules`; set `category: 'modules'` to sit beside them. +- **Lazy launch.** Replace `view: { type: 'launch' }` with a native `launcher` entry, then re-register the same `id` as an `iframe` once the service is up (the second argument forces the replacement): + + ```ts + onDevtoolsReady((ctx) => { + ctx.docks.register({ + id: 'my-module', + title: 'My Module', + icon: 'carbon:apps', + type: 'launcher', + groupId: NUXT_DEVTOOLS_GROUP_ID, + launcher: { + title: 'Start My Module', + description: 'Starts the inspector server on demand.', + async onLaunch() { + await startInspector() + ctx.docks.register({ + id: 'my-module', + title: 'My Module', + icon: 'carbon:apps', + type: 'iframe', + url: '/__my-module', + groupId: NUXT_DEVTOOLS_GROUP_ID, + }, true) + }, + }, + }) + }) + ``` -The return value of `startSubprocess()` now also provides `getResult()`; use it instead of the deprecated `getProcess()` method. +- **Leaving the group.** Omit `groupId` to register a top-level dock next to Vue DevTools and Vite Inspect instead of inside `Nuxt`. +- **`vnode` views** have no native equivalent: a dock renders in its own iframe, so it cannot receive a Vue vnode from the Nuxt client. Move the UI into an iframe page, or keep `addCustomTab()` for that tab until you do. -- `getProcess()` still works but emits the `NDT_DEP_0001` deprecation diagnostic and returns `ChildProcess | undefined` (was `ExecaChildProcess`) -- `getResult()` returns a tinyexec `Result` object with `.kill()`, `.process`, `.pipe()`, and more +### `refreshCustomTabs()` {#ndt_dep_0006} -```diff -const subprocess = startSubprocess(/* ... */) +Deprecated (`NDT_DEP_0006`). There is no tab list to re-collect; change the entry itself. `register()` returns a handle for patching the fields of an entry, and `register(entry, true)` replaces it wholesale (for example to change its `type`, as in the launcher example above): -- const proc = subprocess.getProcess() -- proc.stdout.on('data', handler) -+ const result = subprocess.getResult() -+ result.process?.stdout?.on('data', handler) +```ts +onDevtoolsReady((ctx) => { + const entry = ctx.docks.register({ id: 'my-module', /* … */ }) + entry.update({ badge: '3' }) +}) ``` -## `extendServerRpc()` is deprecated {#ndt_dep_0003} +## Step 3: server RPC {#ndt_dep_0003} -`extendServerRpc()` is soft-deprecated in favour of the Vite DevTools RPC -registration, done from the [`onDevtoolsReady`](/module/utils-kit#ondevtoolsready) -hook. It still works as a shim, but emits the `NDT_DEP_0003` deprecation -diagnostic. +`extendServerRpc()` is deprecated (`NDT_DEP_0003`). Register functions on the Vite DevTools RPC host. Use `ctx.scope()` so every name is prefixed with your namespace without you repeating it: ```diff -- import { extendServerRpc } from '@nuxt/devtools-kit' +- import { extendServerRpc, onDevToolsInitialized } from '@nuxt/devtools-kit' + import { onDevtoolsReady } from '@nuxt/devtools-kit' -+ import { defineRpcFunction } from '@vitejs/devtools-kit' -- const rpc = extendServerRpc('my-module', { -- async getData() { -- return 'hello' -- }, +- onDevToolsInitialized(() => { +- const rpc = extendServerRpc('my-module', { +- toUpperCase(t: string) { +- rpc.broadcast.greeting('world') +- return t.toUpperCase() +- }, +- }) - }) + onDevtoolsReady((ctx) => { -+ ctx.rpc.register(defineRpcFunction({ -+ name: 'my-module:get-data', ++ const { rpc } = ctx.scope('my-module') ++ ++ rpc.register({ ++ name: 'to-upper-case', // registered as `my-module:to-upper-case` + type: 'query', -+ setup: () => ({ handler: async () => 'hello' }), -+ })) ++ handler(t: string) { ++ rpc.broadcast({ method: 'greeting', args: ['world'], event: true }) ++ return t.toUpperCase() ++ }, ++ }) + }) ``` -To broadcast to clients from the same context, use `ctx.rpc.broadcast({ method, args, event })`. +`type` is `'query'` for reads, `'action'` for mutations, `'event'` for fire-and-forget and `'static'` for values that never change. Pass `args` / `returns` [Standard Schema](https://standardschema.dev/) validators to type and validate a function at the boundary. -## `nuxt.devtools.rpc` direct access is deprecated {#ndt_dep_0007} +### `nuxt.devtools.rpc` direct access {#ndt_dep_0007} -Directly accessing `nuxt.devtools.rpc.broadcast` or `nuxt.devtools.rpc.functions` -is deprecated (`NDT_DEP_0007`). They still work as a shim, but you should use the -connected `ctx.rpc` (the devframe `RpcFunctionsHost`) from the -[`onDevtoolsReady`](/module/utils-kit#ondevtoolsready) hook instead: +Reading `nuxt.devtools.rpc.broadcast` or writing to `nuxt.devtools.rpc.functions` is deprecated (`NDT_DEP_0007`). Both map onto the scoped RPC host above: ```diff - nuxt.devtools.rpc.broadcast.myEvent.asEvent(payload) + onDevtoolsReady((ctx) => { -+ ctx.rpc.broadcast({ method: 'myEvent', args: [payload], event: true }) ++ ctx.scope('my-module').rpc.broadcast({ method: 'my-event', args: [payload], event: true }) + }) - nuxt.devtools.rpc.functions.myFn = handler + onDevtoolsReady((ctx) => { -+ ctx.rpc.register({ name: 'myFn', handler }) ++ ctx.scope('my-module').rpc.register({ name: 'my-fn', handler }) + }) ``` -## `addCustomTab()` is deprecated {#ndt_dep_0005} +## Step 4: the iframe client -`addCustomTab()` is soft-deprecated in favour of registering a dock entry on the -Vite DevTools docks host, from the -[`onDevtoolsReady`](/module/utils-kit#ondevtoolsready) hook. It still works as a -shim, but emits the `NDT_DEP_0005` deprecation diagnostic. +A native dock is rendered by Vite DevTools, not by the Nuxt client, so the `__NUXT_DEVTOOLS__` object that `useDevtoolsClient()` and `onDevtoolsClientConnected()` rely on is **not injected** into it. Connect to Vite DevTools directly instead: ```diff -- import { addCustomTab } from '@nuxt/devtools-kit' -+ import { onDevtoolsReady } from '@nuxt/devtools-kit' - -- addCustomTab({ -- name: 'my-module', -- title: 'My Module', -- icon: 'carbon:apps', -- view: { type: 'iframe', src: '/url-to-your-module-view' }, +- import { onDevtoolsClientConnected } from '@nuxt/devtools-kit/iframe-client' ++ import { getDevToolsRpcClient } from '@vitejs/devtools-kit/client' + +- onDevtoolsClientConnected(async (client) => { +- const rpc = client.devtools.extendClientRpc('my-module', { +- greeting(t: string) { +- console.log(`Hello ${t}`) +- }, +- }) +- const result = await rpc.toUpperCase('hello') - }) -+ onDevtoolsReady((ctx) => { -+ ctx.docks.register({ -+ id: 'my-module', -+ title: 'My Module', -+ icon: 'carbon:apps', -+ type: 'iframe', -+ url: '/url-to-your-module-view', -+ }) ++ const kit = await getDevToolsRpcClient() ++ const { rpc } = kit.scope('my-module') ++ ++ rpc.register({ ++ name: 'greeting', // receives the `my-module:greeting` broadcast ++ type: 'event', ++ handler(t: string) { ++ console.log(`Hello ${t}`) ++ }, + }) ++ const result = await rpc.call('to-upper-case', 'hello') ``` -::warning -The docks host does not yet cover the Nuxt-specific custom-tab features such as -`vnode` views or tab categories. If you rely on those, keep using -`addCustomTab()` for now. -:: - -## `refreshCustomTabs()` is deprecated {#ndt_dep_0006} - -`refreshCustomTabs()` is soft-deprecated (`NDT_DEP_0006`). With the docks host you -no longer re-run a hook to refresh — update the dock entry directly via the -handle returned by `register()` inside the -[`onDevtoolsReady`](/module/utils-kit#ondevtoolsready) hook: +The user's app is the parent window of every dock iframe, so the host client that v3 exposed as `client.host` is still reachable on it from a same-origin iframe: ```ts -onDevtoolsReady((ctx) => { - const entry = ctx.docks.register({ id: 'my-module', /* ... */ }) - entry.update({ title: 'My Module (updated)' }) -}) -``` +import type { NuxtDevtoolsHostClient } from '@nuxt/devtools-kit/types' -## `getServerData()` RPC is deprecated {#ndt_dep_0009} - -The read-only **Nuxt Options Viewer** page has been replaced by the [Data Inspector](/guide/features#data-inspector) panel in the `Nuxt` group, backed by the `@devframes/plugin-data-inspector` `Nuxt Application` source. Its live jora workbench supersedes the pre-serialized snapshot the old page rendered. +const host = (window.parent as Window & { __NUXT_DEVTOOLS_HOST__?: NuxtDevtoolsHostClient }).__NUXT_DEVTOOLS_HOST__ +host?.nuxt.vueApp.version +host?.devtools.close() +``` -The `getServerData` server RPC that fed the old page is deprecated (`NDT_DEP_0009`). It still works as a compatibility shim — returning the legacy `NuxtServerData` shape (`{ nuxt, nitro, vite: { server, client } }`) with the Vite configs normalized for transport — but emits the diagnostic on first use and will be removed in a future major. Query the Data Inspector's `Nuxt Application` source instead of calling the RPC. +`host` is `undefined` when your page is opened outside DevTools or served from another origin. -To expose your own inspectable data, install [`@devframes/plugin-data-inspector`](https://npmx.dev/package/@devframes/plugin-data-inspector) and register a source through its native `registerDataSource` API; there is no Nuxt-specific wrapper. +`client.devtools.extendClientRpc()` is deprecated and logs a console warning; `useDevtoolsClient()` still works for tabs that are still registered through `addCustomTab()`. -## Global Install Support Removed +## Step 5: terminals {#ndt_dep_0004} -Nuxt DevTools no longer supports being installed globally. +`startSubprocess()` is deprecated (`NDT_DEP_0004`). Spawn processes through the Vite DevTools terminals host; they show up in the shared **Terminals** dock with restart and terminate controls: -- The `devtoolsGlobal` Nuxt config option (with `projects` whitelist) is no longer supported -- The `-g` flag is no longer used when installing/uninstalling `@nuxt/devtools` via the DevTools UI -- The `isGlobalInstall` property has been removed from `NuxtDevtoolsInfo` +```diff +- import { startSubprocess } from '@nuxt/devtools-kit' ++ import { onDevtoolsReady } from '@nuxt/devtools-kit' -## `@nuxt/devtools-wizard` Package and `nuxi devtools` Removed +- const subprocess = startSubprocess( +- { command: 'vite', args: ['build', '--watch'] }, +- { id: 'my-module:build', name: 'Build', icon: 'ph:terminal-duotone' }, +- ) ++ onDevtoolsReady(async (ctx) => { ++ const session = await ctx.terminals.startChildProcess( ++ { command: 'vite', args: ['build', '--watch'], cwd: process.cwd() }, ++ { id: 'my-module:build', title: 'Build', icon: 'ph:terminal-duotone' }, ++ ) ++ }) +``` -The `@nuxt/devtools-wizard` package, its CLI, and the `nuxi devtools enable/disable` subcommand have been removed. DevTools is shipped with Nuxt — to enable or disable it, update your `nuxt.config.ts` directly: +The session exposes `terminate()`, `restart()`, `getChildProcess()` and `getResult()`, an awaitable `{ stdout, stderr, exitCode }`: ```ts -export default defineNuxtConfig({ - devtools: { enabled: true }, // or false -}) +const { exitCode, stderr } = await session.getResult() +if (exitCode !== 0) + console.error(stderr) ``` -## `runWizard` RPC Removed +`ctx.terminals.startPtySession()` gives you an interactive PTY, and `ctx.terminals.register({ id, title, status, stream })` surfaces output from a process you keep owning yourself. -The `runWizard` server RPC function has been removed from `ServerFunctions`. The `enablePages` action is now available as a direct RPC function: +### Legacy `devtools:terminal:*` hooks -```diff -- await rpc.runWizard(token, 'enablePages') -+ await rpc.enablePages(token) -``` +Calling `devtools:terminal:register` / `:write` / `:exit` / `:remove` directly (which is what `startSubprocess()` does internally) is bridged onto the Terminals dock **for output and final status only**: -The `WizardFunctions`, `WizardActions`, and `GetWizardArgs` types have been removed from `@nuxt/devtools-kit`. +- `restartable` / `terminatable` and `onActionRestart` / `onActionTerminate` are ignored: no buttons are shown for a bridged session; +- re-registering an id (`clear()` / `restart()`) shows up as a new session rather than resetting the old one in place; +- `terminate()` / `restart()` on a `startSubprocess()` handle still work, because that helper owns its process. -## Vite DevTools Integration is Now Always Enabled +### `SubprocessOptions` no longer extends execa -The `viteDevTools` module option has been removed. Nuxt DevTools now always integrates with [Vite DevTools](https://github.com/vitejs/devtools) as a dock entry, nested under a `Nuxt` framework group. The built-in floating panel has been removed — DevTools is accessed through the Vite DevTools panel instead. +`startSubprocess()` moved from `execa` to `tinyexec`. `command`, `args`, `cwd` and `env` are unchanged; every other execa option goes under `nodeOptions` (Node's `SpawnOptions`): -On Vite 8.3+, Vite itself registers the Vite DevTools integration from its top-level [`devtools` option](https://vite.dev/config/shared-options#devtools) ([vitejs/vite#23333](https://github.com/vitejs/vite/pull/23333)), which Nuxt DevTools configures for you. That keeps the toggle in your hands — you can turn Vite DevTools off from your Vite config: - -```ts -export default defineNuxtConfig({ - vite: { - devtools: false, - }, +```diff +startSubprocess({ + command: 'my-command', + cwd: '/some/path', +- stdio: 'pipe', ++ nodeOptions: { stdio: 'pipe' }, }) ``` -On older Vite versions, Nuxt DevTools falls back to registering the Vite DevTools plugin itself. +### `getProcess()` {#ndt_dep_0001} -`@nuxt/devtools` now requires Vite 8 (`peerDependencies.vite` narrowed from -`>=6.0` to `^8.0.14`), matching the Vite DevTools plugins it depends on. Join -the `Nuxt` group from your own module by pointing a dock entry's `groupId` at -`'nuxt'`: +Deprecated (`NDT_DEP_0001`); it returns a plain `ChildProcess | undefined` now. `getResult()` returns the tinyexec result with `.process`, `.kill()` and `.pipe()`: -```ts -import { onDevtoolsReady } from '@nuxt/devtools-kit' +```diff +- const proc = subprocess.getProcess() +- proc.stdout.on('data', handler) ++ const result = subprocess.getResult() ++ result.process?.stdout?.on('data', handler) +``` + +## Step 6: notifications + +`ctx.messages` is the Vite DevTools messages host. `ctx.messages.add({ message, level, notify })` adds an entry to the **Messages** dock; `notify: true` also shows it as a toast: +```ts onDevtoolsReady((ctx) => { - ctx.docks.register({ - id: 'my-module', - type: 'iframe', - title: 'My Module', - icon: 'i-ph-puzzle-piece', - url: '/my-module/', - groupId: 'nuxt', - }) + ctx.messages.add({ message: 'My module is ready', level: 'info', notify: true }) }) ``` -```diff -export default defineNuxtConfig({ - devtools: { - enabled: true, -- viteDevTools: true, - }, -}) -``` +The `devtools:notify` Nuxt hook forwards to the same host and is not deprecated. + +## Other changes + +### `getServerData` RPC {#ndt_dep_0009} -### `client.devtools` Methods Now Control Vite DevTools +The read-only Nuxt Options Viewer is replaced by the [Data Inspector](/guide/features#data-inspector), whose `Nuxt Application` source exposes the same data through a live jora workbench. The `getServerData` RPC that fed the old page still answers with the legacy `{ nuxt, nitro, vite: { server, client } }` shape but prints `NDT_DEP_0009` on first use. -The `client.devtools.open()`, `client.devtools.close()`, and `client.devtools.toggle()` methods still work but now control the Vite DevTools panel: +To expose your own data, install [`@devframes/plugin-data-inspector`](https://npmx.dev/package/@devframes/plugin-data-inspector) and register a source with its `registerDataSource` API. -- `open()` opens the Vite DevTools panel and switches to the Nuxt DevTools dock entry -- `close()` closes the Vite DevTools panel -- `toggle()` toggles the Nuxt DevTools dock entry in the Vite DevTools panel +### `vscode` option {#ndt_dep_0008} -The `Shift+Alt+D` keyboard shortcut now toggles the Nuxt DevTools entry in the Vite DevTools panel. +The built-in VS Code integration is replaced by the Code Server plugin (`devtools.codeServer`). Supplying `devtools.vscode` prints `NDT_DEP_0008` and the value is ignored. See [Upgrading to v4](/guide/upgrading-to-v4#code-server) for the user-facing details. -### `client.devtools.popup` Removed +### Removed APIs -The Picture-in-Picture popup feature (`client.devtools.popup`) has been removed. This was an experimental feature that required Chrome 111+. +- `@nuxt/devtools-wizard`, `nuxi devtools enable/disable` and the `runWizard` RPC. The one action that remains, `enablePages`, is a direct RPC function with no arguments: `rpc.enablePages()`. The `WizardFunctions`, `WizardActions` and `GetWizardArgs` types are gone. +- `client.devtools.popup` (Picture-in-Picture) and the `showPanel` / `minimizePanelInactive` UI settings; Vite DevTools owns the panel. +- Global installs: `devtoolsGlobal`, the `-g` install flag and `NuxtDevtoolsInfo.isGlobalInstall`. +- The `viteDevTools` module option; Vite DevTools is always on. On Vite 8.3+ Nuxt DevTools configures Vite's top-level `devtools` option, so `vite: { devtools: false }` turns it off. +- `client.devtools.open()` / `close()` / `toggle()` still exist and now drive the Vite DevTools panel. -### `showPanel` and `minimizePanelInactive` Settings Removed +### Peer dependencies -The `showPanel` and `minimizePanelInactive` UI settings have been removed from `NuxtDevToolsOptions` as the built-in floating panel no longer exists. +`@nuxt/devtools` requires Vite `^8.1.5` (was `>=6.0`) and `@nuxt/kit` 4 or 5. Nitro v2 (`nitropack`, Nuxt 4) and Nitro v3 (`nitro`, Nuxt 5) are both optional peers; the one your user's Nuxt installs is the one that gets used. diff --git a/docs/content/3.development/0.contributing.md b/docs/content/3.development/0.contributing.md index feec2f41ed..2f48b031db 100644 --- a/docs/content/3.development/0.contributing.md +++ b/docs/content/3.development/0.contributing.md @@ -17,7 +17,7 @@ pnpm run build ``` ::callout -Nuxt DevTools uses pnpm v8. If you are working on multiple projects with different versions of pnpm, it's recommended to enable [Corepack](https://github.com/nodejs/corepack) by running `corepack enable`. +Nuxt DevTools uses pnpm v12. If you are working on multiple projects with different versions of pnpm, it's recommended to enable [Corepack](https://github.com/nodejs/corepack) by running `corepack enable`. :: ## Packages diff --git a/plans/008-fix-migration-docs.md b/plans/008-fix-migration-docs.md deleted file mode 100644 index df2f7feb4f..0000000000 --- a/plans/008-fix-migration-docs.md +++ /dev/null @@ -1,124 +0,0 @@ -# Plan 008: Fix the v4 migration guide's `enablePages` example - -> **Executor instructions**: Follow this plan step by step. Confirm each -> verification before moving on. If a STOP condition occurs, stop and report. -> When done, update the status row for this plan in `plans/README.md` — unless a -> reviewer dispatched you and told you they maintain the index. -> -> **Drift check (run first)**: `git diff --stat c75c3b9..HEAD -- docs/content/2.module/3.migration-v4.md packages/devtools/src/server-rpc/general.ts` -> If either changed since this plan was written, re-read them and reconcile the -> excerpts below; on a mismatch, STOP. - -## Status - -- **Priority**: P2 -- **Effort**: S -- **Risk**: LOW -- **Depends on**: none -- **Category**: docs -- **Planned at**: commit `c75c3b9`, 2026-07-14 - -## Why this matters - -The v4 migration guide tells module authors to replace `rpc.runWizard(token, 'enablePages')` -with `rpc.enablePages(token)` — but the current `enablePages` RPC takes **no -arguments** (auth tokens were removed from builtin RPC functions in v4). A module -author copying the documented replacement calls a signature that no longer accepts -`token`. A wrong doc example is worse than a missing one because it looks -authoritative. - -## Current state - -- `docs/content/2.module/3.migration-v4.md:72-81`, verbatim: - ```md - ## `runWizard` RPC Removed - - The `runWizard` server RPC function has been removed from `ServerFunctions`. The `enablePages` action is now available as a direct RPC function: - - ```diff - - await rpc.runWizard(token, 'enablePages') - + await rpc.enablePages(token) - ``` - - The `WizardFunctions`, `WizardActions`, and `GetWizardArgs` types have been removed from `@nuxt/devtools-kit`. - ``` -- The actual RPC signature, verbatim: - ```ts - // packages/devtools/src/server-rpc/general.ts:234 - async enablePages() { - ``` - It takes no parameters. - -## Commands you will need - -| Purpose | Command | Expected on success | -|---------|---------------|---------------------| -| Lint | `pnpm lint` | exit 0 | - -(No install/build/tests needed — Markdown-only change.) - -## Scope - -**In scope**: -- `docs/content/2.module/3.migration-v4.md` (fix the one diff example; optionally add a note) - -**Out of scope** (do NOT touch): -- Any source file (the RPC is already correct — the doc is wrong). -- Other docs pages (the stale contributing-guide pnpm version is a separate fix). -- The surrounding sections of the migration guide beyond the `runWizard` block. - -## Git workflow - -- Branch: `docs/008-migration-enablepages` off the base branch. -- Conventional Commits. Suggested: `docs: fix enablePages migration example (no token arg)`. -- Do NOT push or open a PR unless instructed. - -## Steps - -### Step 1: Correct the diff example - -In `docs/content/2.module/3.migration-v4.md`, change the added line so it matches -the real no-argument signature: - -```diff -- await rpc.runWizard(token, 'enablePages') -+ await rpc.enablePages() -``` - -Optionally (recommended) add one sentence after the code block noting that builtin -RPC functions in v4 no longer take a leading auth token argument — this is the one -place a reader would expect that context. Keep it to a sentence; do not restructure -the page. - -**Verify**: `grep -n "rpc.enablePages(token)" docs/content/2.module/3.migration-v4.md` → no matches; `grep -n "rpc.enablePages()" docs/content/2.module/3.migration-v4.md` → 1 match. - -### Step 2: Lint - -**Verify**: `pnpm lint` → exit 0 (`pnpm lint --fix` if the Markdown formatter flags it). - -## Test plan - -- No code tests. Verification is the two greps in Step 1 plus clean lint. - -## Done criteria - -- [ ] `grep -rn "rpc.enablePages(token)" docs/` returns no matches. -- [ ] The migration guide shows `+ await rpc.enablePages()`. -- [ ] `pnpm lint` exits 0. -- [ ] Only the migration-guide file is modified (`git status`). -- [ ] `plans/README.md` status row for 008 updated. - -## STOP conditions - -Stop and report if: - -- The `enablePages` RPC signature is no longer `enablePages()` (i.e. it takes args - again) — the doc fix would then be wrong. -- The migration guide's `runWizard` section doesn't match the "Current state" - excerpt (drift). - -## Maintenance notes - -- If the deprecated auth exports are later removed (see plan 009 / audit Direction - D2), add a short "builtin RPC functions no longer take an auth token" section here - so the token removal is documented in one canonical place. diff --git a/plans/README.md b/plans/README.md index e63067444f..abe86ac068 100644 --- a/plans/README.md +++ b/plans/README.md @@ -17,7 +17,7 @@ when done. | 005 | Harden assets RPC (path containment + collision-filename bug) | P1 | S–M | 001 | TODO | | 006 | Enforce storage denylist on item access (not just listing) | P1 | S | 001 | TODO | | 007 | Fix fn-metric metadata + server-data `environments` bug | P2 | S | 001 | TODO | -| 008 | Fix v4 migration guide `enablePages` example | P2 | S | — | TODO | +| 008 | Fix v4 migration guide `enablePages` example | P2 | S | — | DONE | | 009 | Remove dead auth-migration code | P2 | S | 001 | TODO | Status values: TODO | IN PROGRESS | DONE | BLOCKED (one-line reason) | REJECTED (one-line rationale) diff --git a/playgrounds/module-starter/client/components/ModuleAuthorNote.vue b/playgrounds/module-starter/client/components/ModuleAuthorNote.vue index 0b6416e612..5c7c08786e 100644 --- a/playgrounds/module-starter/client/components/ModuleAuthorNote.vue +++ b/playgrounds/module-starter/client/components/ModuleAuthorNote.vue @@ -1,7 +1,3 @@ - -