Skip to content
Merged
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
2 changes: 1 addition & 1 deletion packages/nuxt-cli/src/commands/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ export default defineCommand({
const serverBuild = resolveServerBuild(kit, nuxt)
const target = serverBuild.target
if (target) {
logger.info(`${serverBuild.label} ${serverBuild.targetLabel}: ${styleText('cyan', target)}`)
logger.info(`Deploy target: ${styleText('cyan', target)}`)
}

const outputDir = serverBuild.dir
Expand Down
6 changes: 5 additions & 1 deletion packages/nuxt-cli/src/commands/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ const command = defineCommand({
throw error
})

const { listener, close, reload, onRestart, onReady, onLoading, onEachReady, onLog, onRequests, onSpans, onRoutes, onBuilding, onReport, onReportClear, onFileChange } = started
const { listener, close, reload, onRestart, onReady, onLoading, onEachReady, onLog, onRequests, onSpans, onRoutes, onStack, onBuilding, onReport, onReportClear, onFileChange } = started

/** Feed the dev UI from the server running in this process. */
function attachDevUI(devUI: DevUIController): DevUIController {
Expand All @@ -273,6 +273,7 @@ const command = defineCommand({
onReport(report => devUI.pushReport(report))
onReportClear(id => devUI.clearReport(id))
onRoutes(payload => devUI.setRoutes(payload))
onStack(payload => devUI.setStack(payload))
return devUI
}

Expand Down Expand Up @@ -387,6 +388,9 @@ const command = defineCommand({
else if (message.type === 'nuxt:internal:dev:routes') {
devUI.setRoutes(message.payload)
}
else if (message.type === 'nuxt:internal:dev:stack') {
devUI.setStack(message.payload)
}
else if (message.type === 'nuxt:internal:dev:building') {
devUI.setStatus(message.building ? 'building' : 'ready')
}
Expand Down
41 changes: 38 additions & 3 deletions packages/nuxt-cli/src/commands/info.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { NuxtModule } from '@nuxt/schema'
import type { Nuxt, NuxtConfig, NuxtModule } from '@nuxt/schema'
import type { PackageJson } from 'pkg-types'

import os from 'node:os'
Expand All @@ -23,10 +23,17 @@ import { readDependencyPackageJson } from '../utils/package-json'
import { detectPackageManager, getPackageManagerVersion } from '../utils/package-managers'
import { resolveRootDir } from '../utils/paths'
import { tryResolveNuxt } from '../utils/resolve-nuxt'
import { getServerBuilderName } from '../utils/server-build'
import { rootDirArgs } from './_shared'

const LEADING_SLASH_RE = /^\//

/** Server builders other than Nitro released with Nuxt, by each `server.builder` value naming them. */
const NUXT_SERVER_BUILDERS: Record<string, string> = {
'vite': 'vite',
'@nuxt/vite-server': 'vite',
}

/** JSON key for each display label, so `--json` output stays stable if a label is reworded. */
const JSON_KEYS: Record<string, string> = {
'Operating system': 'operatingSystem',
Expand All @@ -37,7 +44,7 @@ const JSON_KEYS: Record<string, string> = {
'nuxt/cli version': 'cliVersion',
'Package manager': 'packageManager',
'Nuxt version': 'nuxtVersion',
'Nitro version': 'nitroVersion',
'Server builder': 'serverBuilder',
'Builder': 'builder',
'Config': 'config',
'Modules': 'modules',
Expand Down Expand Up @@ -94,6 +101,11 @@ export default defineCommand({
const configKeys = Object.keys(nuxtConfig).sort()
const moduleNames = modules.filter(module => module !== null)
const builder = nuxtConfig.builder || 'vite'
// Read from the config, without loading Nuxt, the same way as for a loaded app.
const usesNitro = getServerBuilderName({ options: nuxtConfig } as unknown as Nuxt) === 'Nitro'
const serverBuilder = usesNitro
? nitroVersion ? `nitro@${nitroVersion}` : 'nitro'
: await describeServerBuilder(nuxtConfig, getDepVersion)
const osType = os.type()
const cpus = os.cpus()
const builderInfo = typeof builder === 'string' && ['vite', '@nuxt/vite-builder', 'webpack', '@nuxt/webpack-builder', 'rspack', '@nuxt/rspack-builder'].includes(builder)
Expand All @@ -113,7 +125,7 @@ export default defineCommand({
'nuxt/cli version': nuxiVersion,
'Package manager': packageManager,
'Nuxt version': nuxtVersion,
'Nitro version': nitroVersion,
'Server builder': serverBuilder,
'Builder': builderInfo.name === 'custom' ? 'custom' : `${builderInfo.name.toLowerCase()}@${builderInfo.version}`,
'Config': configKeys.map(key => `\`${key}\``).join(', '),
'Modules': moduleNames.map(name => `\`${name}\``).join(', '),
Expand All @@ -129,6 +141,7 @@ export default defineCommand({
const key = JSON_KEYS[label]!
return [key, lists[key] ?? (value?.replaceAll('`', '') || null)]
})),
nitroVersion: (usesNitro && nitroVersion) || null,
})
return
}
Expand Down Expand Up @@ -253,3 +266,25 @@ export function normalizeConfigModule(
}
return null
}

/**
* A server builder other than Nitro: its name when it is released with Nuxt,
* otherwise the package or path `server.builder` names (with the package's
* version), or `custom` for one defined inline.
*/
async function describeServerBuilder(
nuxtConfig: NuxtConfig,
getDepVersion: (name: string) => Promise<string | undefined>,
): Promise<string> {
const configured = (nuxtConfig as { server?: { builder?: unknown } }).server?.builder
if (typeof configured !== 'string') {
return 'custom'
}
const nuxtBuilder = NUXT_SERVER_BUILDERS[configured]
if (nuxtBuilder) {
return nuxtBuilder
}
const packageName = getPackageName(configured)
const version = packageName && await getDepVersion(packageName)
return version ? `${configured}@${version}` : configured
}
6 changes: 2 additions & 4 deletions packages/nuxt-cli/src/commands/preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ const command = defineCommand({
let declared: {
label: string
target: string | undefined
targetLabel: string
dir: string
previewCommand: string | undefined
staticDir: string | undefined
Expand Down Expand Up @@ -106,7 +105,6 @@ const command = defineCommand({
declared = {
label: build.label,
target: build.target,
targetLabel: build.targetLabel,
dir: build.dir,
previewCommand: build.previewCommand,
staticDir: build.previewStaticDir,
Expand Down Expand Up @@ -162,7 +160,7 @@ const command = defineCommand({
previewCommand = declared.previewCommand
outputPath = declared.dir
if (declared.target) {
target = [`${declared.label} ${declared.targetLabel}:`, declared.target]
target = ['Deploy target:', declared.target]
}
}
if (declared.staticDir) {
Expand All @@ -184,7 +182,7 @@ const command = defineCommand({
previewCommand = nitroJSON.commands?.preview
outputPath = dirname(nitroJSONPath)
if (nitroJSON.preset) {
target = ['Nitro preset:', nitroJSON.preset]
target = ['Deploy target:', nitroJSON.preset]
}
}
}
Expand Down
14 changes: 13 additions & 1 deletion packages/nuxt-cli/src/dev/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type { DevRestartReason } from './reason'
import type { DevReportSummary } from './error-channel'
import type { ServerLogEvent } from './log-channel'
import type { DevRequestSpan } from './span-channel'
import type { DevRequestEvent, DevRoutes, NuxtDevContext, NuxtDevIPCMessage, NuxtParentIPCMessage } from './utils'
import type { DevRequestEvent, DevRoutes, DevStack, NuxtDevContext, NuxtDevIPCMessage, NuxtParentIPCMessage } from './utils'

import process from 'node:process'

Expand Down Expand Up @@ -242,6 +242,8 @@ interface InitializeReturn {
onBuilding: (callback: (building: boolean) => void) => void
/** Called whenever the app's routes are (re)discovered. */
onRoutes: (callback: (routes: DevRoutes) => void) => void
/** Called with the builders the app uses, each time Nuxt loads. */
onStack: (callback: (stack: DevStack) => void) => void
/** Called the first time a watched file changes, before Nuxt reloads. */
onFileChange: (callback: () => void) => void
onRestart: (callback: (reason?: DevRestartReason) => void) => void
Expand Down Expand Up @@ -318,6 +320,7 @@ export async function initialize(devContext: NuxtDevContext, ctx: InitializeOpti
const requests = createFeed<DevRequestEvent[]>(PENDING_REQUEST_BATCHES)
const spans = createFeed<DevRequestSpan[]>(PENDING_REQUEST_BATCHES)
const routes = createFeed<DevRoutes>(1)
const stack = createFeed<DevStack>(1)
const building = createFeed<boolean>(0)
const reports = createFeed<DevReportSummary>(PENDING_REPORTS)
const reportsCleared = createFeed<string | undefined>(0)
Expand Down Expand Up @@ -388,6 +391,14 @@ export async function initialize(devContext: NuxtDevContext, ctx: InitializeOpti
building.emit(value)
})

devServer.on('stack', (payload) => {
if (ipc.enabled) {
ipc.send({ type: 'nuxt:internal:dev:stack', payload })
return
}
stack.emit(payload)
})

devServer.on('routes', (payload) => {
if (ipc.enabled) {
ipc.send({ type: 'nuxt:internal:dev:routes', payload })
Expand Down Expand Up @@ -549,6 +560,7 @@ export async function initialize(devContext: NuxtDevContext, ctx: InitializeOpti
onReport: reports.subscribe,
onReportClear: reportsCleared.subscribe,
onRoutes: routes.subscribe,
onStack: stack.subscribe,
onFileChange: (callback: () => void) => {
devServer.once('change', callback)
},
Expand Down
5 changes: 4 additions & 1 deletion packages/nuxt-cli/src/dev/tui/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { DevReportSummary } from '../error-channel'
import type { ServerLogEvent } from '../log-channel'
import type { ShortcutContext } from '../shortcuts'
import type { DevRequestSpan } from '../span-channel'
import type { DevRequestEvent, DevRoutes } from '../utils'
import type { DevRequestEvent, DevRoutes, DevStack } from '../utils'
import type { DevUIOptions } from './index'
import type { DevStatus } from './panel'
import type { DevUISession } from './session'
Expand Down Expand Up @@ -33,6 +33,8 @@ export interface DevUIController {
clearReport: (id?: string) => void
/** Replace the routes shown in the route view. */
setRoutes: (routes: DevRoutes) => void
/** Name the builders the loaded app uses, for the versions in the info view. */
setStack: (stack: DevStack) => void
/**
* Report the render the server is busy with, or that it is busy with none.
* `awaiting` says no page has been rendered yet, which is what makes it a
Expand All @@ -52,6 +54,7 @@ export const NOOP_CONTROLLER: DevUIController = {
pushReport: () => {},
clearReport: () => {},
setRoutes: () => {},
setStack: () => {},
setRendering: () => {},
}

Expand Down
24 changes: 21 additions & 3 deletions packages/nuxt-cli/src/dev/tui/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { NuxtOptions } from '@nuxt/schema'
import type { TerminalNotification } from '../../utils/terminal-host'
import type { ShortcutContext } from '../shortcuts'
import type { DevStack } from '../utils'
import type { DevUIController } from './controller'
import type { PanelStart } from './first-frame'
import type { InfoSection } from './info-overlay'
Expand Down Expand Up @@ -53,6 +55,12 @@ const NOTICE_MS = 4000

const LOADING_STATUSES = new Set<DevStatus>(['starting', 'building', 'restarting'])

/** Display names for the server builders released with Nuxt. */
const SERVER_BUILDER_NAMES: Record<string, string> = {
nitro: 'Nitro',
vite: 'Vite',
}

interface UIShortcut {
keys: string[]
/** Short label for the hint line. Omitted shortcuts live only in the help view. */
Expand Down Expand Up @@ -122,12 +130,13 @@ export function setupDevUI(context: ShortcutContext, options: DevUIOptions = {})
events,
})
let shortcuts: UIShortcut[] = []
let stack: DevStack | undefined
let qrCode: string | undefined
let armedOpen = false
let ready = false
const helpOverlay = new HelpOverlay(() => shortcuts.filter(shortcut => shortcut.isAvailable?.() !== false), write, release)
const infoOverlay = new InfoOverlay(
() => describeSession(context, cwd, requests, sessionStart, state.update, state.updateLink),
() => describeSession(context, cwd, requests, sessionStart, stack, state.update, state.updateLink),
write,
release,
() => qrCode,
Expand Down Expand Up @@ -647,6 +656,9 @@ export function setupDevUI(context: ShortcutContext, options: DevUIOptions = {})
update({ note: undefined })
},
setRoutes: payload => routeOverlay.setRoutes(payload),
setStack: (payload) => {
stack = payload
},
setRendering: (pending, awaiting) => {
update({
rendering: pending && { label: pending.label, startedAt: pending.startedAt },
Expand Down Expand Up @@ -716,11 +728,17 @@ function describeSession(
cwd: string,
requests: RequestLog,
sessionStart: number,
stack?: DevStack,
update?: string,
updateLink?: string,
): InfoSection[] {
const versions = resolveStackVersions(cwd)
// Until Nuxt has loaded, the installed packages are all there is to go on.
const versions = resolveStackVersions(cwd, { builder: stack?.builder as NuxtOptions['builder'] | undefined })
const { listener } = context
const server = stack?.server ?? 'nitro'
const serverName = SERVER_BUILDER_NAMES[server] ?? server
// The Vite server builder shares the app builder's version, listed below.
const serverVersion = server === 'nitro' ? versions.nitro : undefined

return [
{
Expand All @@ -729,7 +747,7 @@ function describeSession(
['Nuxt', update
? `${linkVersion(versions.nuxt)} ${paint('warning', updateLink ?? `\u2192 ${update} available`)}`
: linkVersion(versions.nuxt)],
['Nitro', versions.nitro],
['Server builder', serverVersion ? `${serverName} ${serverVersion}` : serverName],
[versions.builder.name, versions.builder.version],
[versions.builder.provider?.name ?? 'via', versions.builder.provider?.version],
['Vue', versions.vue ?? undefined],
Expand Down
27 changes: 26 additions & 1 deletion packages/nuxt-cli/src/dev/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import { loadKit } from '../utils/kit'
import { acquireLock, formatLockError, getTakeoverPid, updateLock } from '../utils/lockfile'
import { debug, logger, writeNotice } from '../utils/logger'
import { loadNuxtManifest, resolveNuxtManifest, writeNuxtManifest } from '../utils/nuxt'
import { resolveServerBuild } from '../utils/server-build'
import { getServerBuilderId, resolveServerBuild } from '../utils/server-build'
import { createConfigWatcher, FileChangeTracker, getLocalLayerDirs } from './config-watcher'
import { createCliReport, DEFAULT_ERROR_CHANNEL, ERROR_CHANNEL_ENV, handleErrorChannelRequest, isErrorChannelRequest, isLocalPeer, isThreadRunner, openErrorBridge, publishCliProgress, renderErrorPage, resolveChannelPath, summariseReport, useErrorChannel, withErrorChannel } from './error-channel'
import { sendErrorResponse } from './error-response'
Expand Down Expand Up @@ -68,6 +68,7 @@ export type NuxtDevIPCMessage
| { type: 'nuxt:internal:dev:requests', requests: DevRequestEvent[] }
| { type: 'nuxt:internal:dev:spans', spans: DevRequestSpan[] }
| { type: 'nuxt:internal:dev:routes', payload: DevRoutes }
| { type: 'nuxt:internal:dev:stack', payload: DevStack }
| { type: 'nuxt:internal:dev:building', building: boolean }
| { type: 'nuxt:internal:dev:rendering', pending?: PendingRender, awaiting?: boolean }
| { type: 'nuxt:internal:dev:report', report: DevReportSummary }
Expand Down Expand Up @@ -181,6 +182,14 @@ export interface DevRoutes {
errorComponent?: string
}

/** What the loaded app is built with, for the versions the dev UI lists. */
export interface DevStack {
/** The configured app builder, e.g. `vite` or `@nuxt/webpack-builder`. */
builder?: string
/** The server builder's short name, e.g. `nitro` or `vite`, when Nuxt has one. */
server?: string
}

/** A page or server route the app defines, as listed in the dev UI. */
export interface DevRoute {
kind: 'page' | 'server'
Expand Down Expand Up @@ -216,6 +225,7 @@ interface DevServerEventMap {
/** Time spent serving a request that the app did not publish itself. */
'span': [span: DevRequestSpan]
'routes': [payload: DevRoutes]
'stack': [payload: DevStack]
'building': [building: boolean]
/** A report the app forwarded, rendered for a terminal. */
'report': [report: DevReportSummary]
Expand Down Expand Up @@ -858,6 +868,7 @@ export class NuxtDevServer extends EventEmitter<DevServerEventMap> {
this.#currentNuxt = await kit.loadNuxt(loadOptions)

if (this.options.captureUIEvents) {
this.#emitStack(this.#currentNuxt)
this.#collectRoutes(this.#currentNuxt)
this.#watchServerBuilds(this.#currentNuxt)
}
Expand Down Expand Up @@ -885,6 +896,15 @@ export class NuxtDevServer extends EventEmitter<DevServerEventMap> {
})
}

/** Report which builders the app uses, for the versions the dev UI lists. */
#emitStack(nuxt: Nuxt): void {
const builder = nuxt.options.builder
this.emit('stack', {
builder: typeof builder === 'string' ? builder : undefined,
server: getServerBuilderId(nuxt),
})
}

/**
* Gather the app's routes.
*
Expand Down Expand Up @@ -1217,6 +1237,11 @@ export class NuxtDevServer extends EventEmitter<DevServerEventMap> {

await Promise.all([typesPromise, kit.buildNuxt(this.#currentNuxt)])

// A server builder defined inline describes itself only once it has built.
if (this.options.captureUIEvents) {
this.#emitStack(this.#currentNuxt)
}

if (!this.#currentNuxt.server) {
throw new ActionableError(noDevServerMessage(serverBuild.label, true))
}
Expand Down
Loading
Loading