Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/devtools-kit/src/_types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export * from './client-api'
export * from './common'
export * from './custom-tabs'
export * from './integrations'
export * from './nitro'
export * from './options'
export * from './rpc'
export * from './server-ctx'
Expand Down
45 changes: 45 additions & 0 deletions packages/devtools-kit/src/_types/nitro.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Compatibility types for nitropack v2 and nitro v3
// Defines the subset of Nitro types used by devtools, compatible with both versions.

import type { Storage } from 'unstorage'

export interface StorageMounts {
[name: string]: {
driver: string
[option: string]: any
}
}

/**
* Merged Nitro instance type covering properties used by devtools.
* Works with both nitropack v2 (where `storage` exists) and nitro v3 (where it was removed).
*/
export interface NitroLike {
options: {
storage: StorageMounts
devStorage: StorageMounts
handlers: Array<{
route?: string
handler: string
method?: string
middleware?: boolean
}>
tasks: {
[name: string]: {
handler: string
description: string
}
}
scheduledTasks?: Record<string, string | string[]>
[key: string]: any
}
scannedHandlers: Array<{
route?: string
handler: string
method?: string
middleware?: boolean
}>
/** Present in nitropack v2, removed in nitro v3 */
storage?: Storage
[key: string]: any
}
4 changes: 2 additions & 2 deletions packages/devtools-kit/src/_types/rpc.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type { Nitro, StorageMounts } from 'nitropack'
import type { Component, NuxtApp, NuxtLayout, NuxtOptions, NuxtPage } from 'nuxt/schema'
import type { StorageValue } from 'unstorage'
import type { ResolvedConfig } from 'vite'
import type { AnalyzeBuildsInfo } from './analyze-build'
import type { ModuleCustomTab } from './custom-tabs'
import type { AssetEntry, AssetInfo, AutoImportsWithMetadata, ComponentRelationship, HookInfo, ImageMeta, NpmCommandOptions, NpmCommandType, PackageUpdateInfo, ScannedNitroTasks, ServerRouteInfo } from './integrations'
import type { NitroLike, StorageMounts } from './nitro'
import type { ModuleOptions, NuxtDevToolsOptions } from './options'
import type { InstallModuleReturn, ServerDebugContext } from './server-ctx'
import type { TerminalAction, TerminalInfo } from './terminals'
Expand Down Expand Up @@ -90,7 +90,7 @@ export interface ClientFunctions {

export interface NuxtServerData {
nuxt: NuxtOptions
nitro?: Nitro['options']
nitro?: NitroLike['options']
vite: {
server?: ResolvedConfig
client?: ResolvedConfig
Expand Down
1 change: 1 addition & 0 deletions packages/devtools/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@
"markdown-it": "catalog:frontend",
"markdown-it-link-attributes": "catalog:frontend",
"my-ua-parser": "catalog:frontend",
"nitro": "catalog:buildtools",
"nitropack": "catalog:buildtools",
"nuxt": "catalog:buildtools",
"ofetch": "catalog:frontend",
Expand Down
6 changes: 2 additions & 4 deletions packages/devtools/src/runtime/nitro/inline.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import type { NitroAppPlugin } from 'nitropack'

// @ts-expect-error injected
import { script } from '#nuxt-devtools-inline'

export default <NitroAppPlugin> function (nitro) {
nitro.hooks.hook('render:html', (htmlContext) => {
export default function (nitroApp: { hooks: { hook: (name: string, fn: (...args: any[]) => void) => void } }) {
nitroApp.hooks.hook('render:html', (htmlContext: { head: string[] }) => {
htmlContext.head.push(`<script>${script}</script>`)
})
}
5 changes: 2 additions & 3 deletions packages/devtools/src/server-rpc/server-data.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import type { Nitro } from 'nitropack'
import type { ResolvedConfig } from 'vite'
import type { NuxtDevtoolsServerContext, ServerFunctions } from '../types'
import type { NitroLike, NuxtDevtoolsServerContext, ServerFunctions } from '../types'
import { addVitePlugin } from '@nuxt/kit'

export function setupServerDataRPC({
nuxt,
ensureDevAuthToken,
}: NuxtDevtoolsServerContext) {
let nitro: Nitro | undefined
let nitro: NitroLike | undefined
let viteServer: ResolvedConfig | undefined
let viteClient: ResolvedConfig | undefined

Expand Down
32 changes: 12 additions & 20 deletions packages/devtools/src/server-rpc/server-routes.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import type { Nitro } from 'nitropack'
import type { NuxtDevtoolsServerContext, ServerFunctions, ServerRouteInfo } from '../types'
import type { NitroLike, NuxtDevtoolsServerContext, ServerFunctions, ServerRouteInfo } from '../types'
import { relative, resolve } from 'pathe'
import { debounce } from 'perfect-debounce'
import { watchStorageMount } from './storage-watch'

export function setupServerRoutesRPC({ nuxt, refresh }: NuxtDevtoolsServerContext) {
let nitro: Nitro
let unwatchStorage: (() => Promise<void> | void) | undefined
let nitro: NitroLike | undefined

let cache: ServerRouteInfo[] | null = null

Expand All @@ -14,26 +12,20 @@ export function setupServerRoutesRPC({ nuxt, refresh }: NuxtDevtoolsServerContex
refresh('getServerRoutes')
}, 500)

nuxt.hook('nitro:init', (_) => {
nuxt.hook('nitro:init', (_: NitroLike) => {
nitro = _
cache = null
refresh('getServerRoutes')
})

nuxt.hook('ready', async () => {
if (!nitro)
return

await unwatchStorage?.()
unwatchStorage = await watchStorageMount(nitro.storage, 'src', (_event, key) => {
if (key.startsWith('src:api:') || key.startsWith('src:routes:'))
refreshDebounced()
})
})

nuxt.hook('close', async () => {
await unwatchStorage?.()
unwatchStorage = undefined
// Watch for server route file changes
const serverDir = resolve(nuxt.options.srcDir, nuxt.options.serverDir)
nuxt.hook('builder:watch', (_event, path) => {
const absolutePath = resolve(nuxt.options.srcDir, path)
const rel = relative(serverDir, absolutePath)
if (!rel.startsWith('..') && (rel.startsWith('api/') || rel.startsWith('routes/'))) {
refreshDebounced()
}
})

function scan() {
Expand Down
32 changes: 12 additions & 20 deletions packages/devtools/src/server-rpc/server-tasks.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import type { Nitro } from 'nitropack'
import type { NuxtDevtoolsServerContext, ScannedNitroTasks, ServerFunctions } from '../types'
import type { NitroLike, NuxtDevtoolsServerContext, ScannedNitroTasks, ServerFunctions } from '../types'
import { relative, resolve } from 'pathe'
import { debounce } from 'perfect-debounce'
import { watchStorageMount } from './storage-watch'

export function setupServerTasksRPC({ nuxt, refresh }: NuxtDevtoolsServerContext) {
let nitro: Nitro
let unwatchStorage: (() => Promise<void> | void) | undefined
let nitro: NitroLike | undefined

let cache: ScannedNitroTasks | null = null

Expand All @@ -14,26 +12,20 @@ export function setupServerTasksRPC({ nuxt, refresh }: NuxtDevtoolsServerContext
refresh('getServerTasks')
}, 500)

nuxt.hook('nitro:init', (_) => {
nuxt.hook('nitro:init', (_: NitroLike) => {
nitro = _
cache = null
refresh('getServerTasks')
})

nuxt.hook('ready', async () => {
if (!nitro)
return

await unwatchStorage?.()
unwatchStorage = await watchStorageMount(nitro.storage, 'src', (_event, key) => {
if (key.startsWith('src:tasks:'))
refreshDebounced()
})
})

nuxt.hook('close', async () => {
await unwatchStorage?.()
unwatchStorage = undefined
// Watch for server task file changes
const serverDir = resolve(nuxt.options.srcDir, nuxt.options.serverDir)
nuxt.hook('builder:watch', (_event, path) => {
const absolutePath = resolve(nuxt.options.srcDir, path)
const rel = relative(serverDir, absolutePath)
if (rel.startsWith('tasks/')) {
refreshDebounced()
}
})

function scan() {
Expand Down
43 changes: 39 additions & 4 deletions packages/devtools/src/server-rpc/storage.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,48 @@
import type { StorageMounts } from 'nitropack'
import type { Storage, StorageValue } from 'unstorage'
import type { NuxtDevtoolsServerContext, ServerFunctions } from '../types'
import type { NitroLike, NuxtDevtoolsServerContext, ServerFunctions, StorageMounts } from '../types'
import { builtinDrivers, createStorage } from 'unstorage'
import { watchStorageMount } from './storage-watch'

const IGNORE_STORAGE_MOUNTS = ['root', 'build', 'src', 'cache']
function shouldIgnoreStorageKey(key: string) {
return IGNORE_STORAGE_MOUNTS.includes(key.split(':')[0]!)
}

/**
* Resolve the unstorage instance from the nitro instance
* - in nitropack v2, `nitro.storage` is available in build-time
* - in nitro v3, it is runtime only, so we must initialise it here
*/
async function resolveStorage(nitro: NitroLike): Promise<Storage> {
// nitropack v2
if (nitro.storage) {
return nitro.storage
}

// nitro v3
const storage = createStorage()
const mounts = {
...nitro.options.storage,
...nitro.options.devStorage,
}

for (const [mountName, opts] of Object.entries(mounts)) {
if (opts?.driver) {
try {
const driverPath = (builtinDrivers as Record<string, string>)[opts.driver] || opts.driver
const createDriver = await import(driverPath).then(r => r.default || r)
const { driver: _, ...driverOpts } = opts
storage.mount(mountName, createDriver(driverOpts))
}
catch (err) {
console.warn(`[nuxt-devtools] Failed to mount storage driver "${opts.driver}" for "${mountName}":`, err)
}
}
}

return storage
}

export function setupStorageRPC({
nuxt,
rpc,
Expand All @@ -18,8 +53,8 @@ export function setupStorageRPC({
let storage: Storage | undefined
let unwatchStorageMounts: Array<() => Promise<void> | void> = []

nuxt.hook('nitro:init', (nitro) => {
storage = nitro.storage
nuxt.hook('nitro:init', async (nitro: NitroLike) => {
storage = await resolveStorage(nitro)

// Taken from https://github.com/unjs/nitro/blob/d83f2b65165d7ba996e7ef129ea99ff5b551dccc/src/storage.ts#L7-L10
// Waiting for https://github.com/unjs/unstorage/issues/53
Expand Down
Loading