diff --git a/docs/content/1.guide/2.composables.md b/docs/content/1.guide/2.composables.md new file mode 100644 index 000000000..6ec950a75 --- /dev/null +++ b/docs/content/1.guide/2.composables.md @@ -0,0 +1,28 @@ +# Composables + +In case you might want to open or control the Nuxt DevTools in your application on development, a composable `useNuxtDevtools` is registered with auto-import. + +```vue + + + + + + Open DevTools + + +``` + +When you have auto-import disabled, you can also import it explicitly: + +```ts +import { useNuxtDevtools } from '#imports' +``` + +Checkout it's type definition for more available methods. diff --git a/packages/devtools/src/module-main.ts b/packages/devtools/src/module-main.ts index 6e961218e..51ef69a31 100644 --- a/packages/devtools/src/module-main.ts +++ b/packages/devtools/src/module-main.ts @@ -88,6 +88,13 @@ window.__NUXT_DEVTOOLS_TIME_METRIC__.appInit = Date.now() config.server.watch.ignored.push('**/.nuxt/analyze/**') }) + nuxt.hook('imports:extend', (imports) => { + imports.push({ + name: 'useNuxtDevTools', + from: join(runtimeDir, 'use-nuxt-devtools'), + }) + }) + // TODO: Use WS from nitro server when possible nuxt.hook('vite:serverCreated', (server: ViteDevServer) => { server.middlewares.use(ROUTE_ANALYZE, sirv(analyzeDir, { single: false, dev: true })) diff --git a/packages/devtools/src/runtime/plugins/view/client.ts b/packages/devtools/src/runtime/plugins/view/client.ts index 7cf26ccb7..30be677e0 100644 --- a/packages/devtools/src/runtime/plugins/view/client.ts +++ b/packages/devtools/src/runtime/plugins/view/client.ts @@ -102,6 +102,8 @@ export async function setupDevToolsClient({ }, }) + window.__NUXT_DEVTOOLS_HOST__ = client + let iframe: HTMLIFrameElement | undefined function syncClient() { diff --git a/packages/devtools/src/runtime/use-nuxt-devtools.ts b/packages/devtools/src/runtime/use-nuxt-devtools.ts new file mode 100644 index 000000000..585a44318 --- /dev/null +++ b/packages/devtools/src/runtime/use-nuxt-devtools.ts @@ -0,0 +1,34 @@ +import type { Ref } from 'vue' +import { shallowRef } from 'vue' +import type { NuxtDevtoolsHostClient } from '../types' + +/** + * Get Nuxt DevTools client for host app + * + * Returns undefined if not in development mode or the devtools is not enabled + */ +export function useNuxtDevTools(): Ref { + const r = shallowRef() + if (!process.dev) + return r + + if (process.server) + return r + + if (window.__NUXT_DEVTOOLS_HOST__) { + r.value = window.__NUXT_DEVTOOLS_HOST__ + } + else { + Object.defineProperty(window, '__NUXT_DEVTOOLS_HOST__', { + set(value) { + r.value = value + }, + get() { + return r.value + }, + enumerable: false, + configurable: true, + }) + } + return r +} diff --git a/packages/devtools/src/types/global.ts b/packages/devtools/src/types/global.ts index 8ab443763..09b663de3 100644 --- a/packages/devtools/src/types/global.ts +++ b/packages/devtools/src/types/global.ts @@ -1,5 +1,5 @@ import type { VueInspectorClient } from 'vite-plugin-vue-inspector' -import type { LoadingTimeMetric, NuxtDevtoolsIframeClient, NuxtDevtoolsGlobal as NuxtDevtoolsViewGlobal, PluginMetric, TimelineMetrics } from '.' +import type { LoadingTimeMetric, NuxtDevtoolsHostClient, NuxtDevtoolsIframeClient, NuxtDevtoolsGlobal as NuxtDevtoolsViewGlobal, PluginMetric, TimelineMetrics } from '.' declare global { interface Window { @@ -8,6 +8,11 @@ declare global { */ __NUXT_DEVTOOLS__?: NuxtDevtoolsIframeClient + /** + * Nuxt DevTools client for host app + */ + __NUXT_DEVTOOLS_HOST__?: NuxtDevtoolsHostClient + /** * Nuxt DevTools for receiving host client * diff --git a/playgrounds/tab-seo/components/GlobalNav.vue b/playgrounds/tab-seo/components/GlobalNav.vue index b1e1db302..8a8ab1def 100644 --- a/playgrounds/tab-seo/components/GlobalNav.vue +++ b/playgrounds/tab-seo/components/GlobalNav.vue @@ -1,6 +1,18 @@ + + Click to navigate and see the SEO tab + + + Open devtools + +