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
6 changes: 3 additions & 3 deletions packages/nuxt-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,18 +62,15 @@
}
},
"dependencies": {
"@bomb.sh/tab": "^0.0.22",
"@clack/prompts": "^1.7.0",
"args-tokenizer": "^0.3.0",
"citty": "^0.2.2",
"clickable-path": "^0.0.1",
"confbox": "^0.2.4",
"consola": "^3.4.2",
"defu": "^6.1.7",
"exsolve": "^1.1.1",
"fuzzysort": "^4.0.1",
"get-port-please": "^3.2.0",
"nypm": "^0.6.9",
"obug": "^2.1.4",
"pathe": "^2.0.3",
"perfect-debounce": "^2.1.0",
Expand All @@ -88,16 +85,19 @@
"verkit": "^0.3.2"
},
"devDependencies": {
"@bomb.sh/tab": "^0.0.22",
"@nuxt/kit": "^4.5.2",
"@nuxt/schema": "^4.5.2",
"@nuxt/test-utils": "^4.1.0",
"@speed-highlight/core": "^2.0.0",
"@types/node": "^24.13.3",
"citty": "^0.2.2",
"giget": "^3.3.1",
"h3": "^1.15.11",
"jiti": "^2.7.0",
"nitro": "^3.0.1-alpha.2",
"nitropack": "^2.13.4",
"nypm": "^0.6.9",
"rolldown": "^1.2.4",
"rollup": "^4.62.4",
"tsdown": "^0.22.14",
Expand Down
26 changes: 22 additions & 4 deletions packages/nuxt-cli/src/commands/_shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,22 @@ export const cwdArgs = {
},
} as const satisfies Record<string, ArgDef>

/**
* The root command's `--cwd`, forwarded to every subcommand so it can be passed
* before the command name.
*
* No default, unlike {@link cwdArgs}: commands taking a ROOTDIR positional treat an
* explicit `--cwd` as an override of it, and cannot tell the two apart if it is
* always set.
*/
export const globalCwdArgs = {
cwd: {
...cwdArgs.cwd,
default: undefined as string | undefined,
inherit: true,
},
} as const satisfies Record<string, ArgDef>

export const logLevelArgs = {
logLevel: {
type: 'string',
Expand All @@ -27,7 +43,8 @@ export const envNameArgs = {
export const dotEnvArgs = {
dotenv: {
type: 'string',
description: 'Path to `.env` file to load, relative to the root directory',
description: 'Path to `.env` file to load, relative to the root directory. Can be repeated, with later files taking precedence.',
multiple: true,
},
} as const satisfies Record<string, ArgDef>

Expand All @@ -37,6 +54,7 @@ export const extendsArgs = {
description: 'Extend from a Nuxt layer',
valueHint: 'layer-name',
alias: ['e'],
multiple: true,
},
} as const satisfies Record<string, ArgDef>

Expand All @@ -50,9 +68,9 @@ export const profileArgs = {
} as const satisfies Record<string, ArgDef>

/**
* `--cwd` is deliberately not declared here: it is an undocumented alias for ROOTDIR,
* normalised out of `rawArgs` by `normaliseCwdArg` and read back off `args.cwd`.
* No default, so `resolveRootDir` can tell an explicit ROOTDIR from an absent one.
* `--cwd` is deliberately not declared here: commands taking a ROOTDIR positional
* inherit it from the root command (see {@link globalCwdArgs}) rather than listing
* it twice in their own help.
*/
export const rootDirArgs = {
rootDir: {
Expand Down
5 changes: 3 additions & 2 deletions packages/nuxt-cli/src/commands/analyze.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { defu } from 'defu'
import { join, relative, resolve } from 'pathe'
import { serve } from 'srvx'

import { resolveDotenvFileNames } from '../utils/args'
import { overrideEnv } from '../utils/env'
import { ActionableError } from '../utils/errors'
import { clearDir } from '../utils/fs'
Expand Down Expand Up @@ -86,10 +87,10 @@ export default defineCommand({
ready: false,
dotenv: {
cwd,
fileName: ctx.args.dotenv,
fileName: resolveDotenvFileNames(ctx.args.dotenv),
},
overrides: defu(ctx.data?.overrides, {
...(ctx.args.extends && { extends: ctx.args.extends }),
...(ctx.args.extends.length > 0 && { extends: ctx.args.extends }),
build: {
analyze: {
enabled: true,
Expand Down
5 changes: 3 additions & 2 deletions packages/nuxt-cli/src/commands/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { intro, outro } from '@clack/prompts'
import { defineCommand } from 'citty'

import { relative } from 'pathe'
import { resolveDotenvFileNames } from '../utils/args'
import { showBanner } from '../utils/banner'

import { overrideEnv } from '../utils/env'
Expand Down Expand Up @@ -63,7 +64,7 @@ export default defineCommand({
ready: false,
dotenv: {
cwd,
fileName: ctx.args.dotenv,
fileName: resolveDotenvFileNames(ctx.args.dotenv),
},
envName: ctx.args.envName, // nuxt will fall back to NODE_ENV
overrides: {
Expand All @@ -73,7 +74,7 @@ export default defineCommand({
static: ctx.args.prerender,
preset: ctx.args.preset || process.env.NITRO_PRESET || process.env.SERVER_PRESET,
},
...(ctx.args.extends && { extends: ctx.args.extends }),
...(ctx.args.extends.length > 0 && { extends: ctx.args.extends }),
...ctx.data?.overrides,
...((perfValue || ctx.data?.overrides?.debug) && {
debug: {
Expand Down
32 changes: 2 additions & 30 deletions packages/nuxt-cli/src/commands/curl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export default defineCommand({
alias: 'H',
description: 'Request header in `Name: Value` form. Can be repeated.',
valueHint: 'header',
multiple: true,
},
data: {
type: 'string',
Expand Down Expand Up @@ -106,7 +107,7 @@ export default defineCommand({
const url = await resolveRequestUrl(input, cwd)

const headers = new Headers()
for (const header of collectRepeated(ctx.rawArgs, 'header', 'H')) {
for (const header of ctx.args.header) {
const separator = header.indexOf(':')
if (separator <= 0) {
logger.error(`Invalid header ${styleText('cyan', header)}. Expected ${styleText('cyan', 'Name: Value')}.`)
Expand Down Expand Up @@ -181,35 +182,6 @@ async function resolveRequestUrl(input: string, cwd: string): Promise<URL> {
return new URL(input.startsWith('/') ? input : `/${input}`, server.url)
}

/**
* citty keeps only the last value of a repeated string flag, so repeatable
* options are read back off the raw argv instead of `ctx.args`.
*/
function collectRepeated(rawArgs: string[], name: string, alias: string): string[] {
const values: string[] = []
const end = rawArgs.indexOf('--')
const argv = end === -1 ? rawArgs : rawArgs.slice(0, end)

for (let index = 0; index < argv.length; index++) {
const arg = argv[index]!
if (arg === `--${name}` || arg === `-${alias}`) {
const value = argv[++index]
if (value !== undefined) {
values.push(value)
}
continue
}
if (arg.startsWith(`--${name}=`)) {
values.push(arg.slice(name.length + 3))
}
else if (arg.startsWith(`-${alias}=`)) {
values.push(arg.slice(alias.length + 2))
}
}

return values
}

async function readRequestBody(data: string | undefined): Promise<string | undefined> {
if (data === undefined) {
return undefined
Expand Down
9 changes: 5 additions & 4 deletions packages/nuxt-cli/src/commands/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,16 +141,19 @@ const command = defineCommand({
},
'https.domains': {
type: 'string',
description: 'Comma-separated domains for a generated certificate',
description: 'Domain for a generated certificate. Can be repeated, or given as a comma-separated list.',
multiple: true,
},
...profileArgs,
'sslCert': {
type: 'string',
description: '(DEPRECATED) Use `--https.cert` instead.',
hidden: true,
},
'sslKey': {
type: 'string',
description: '(DEPRECATED) Use `--https.key` instead.',
hidden: true,
},
},
async run(ctx) {
Expand Down Expand Up @@ -441,9 +444,7 @@ export function resolveListenOverrides(args: ParsedArgs<ArgsT>): DevListenOverri
pfx: args['https.pfx'] || undefined,
passphrase: args['https.passphrase'] || undefined,
validityDays: parsePositiveInteger(args['https.validityDays']),
domains: args['https.domains']
? args['https.domains'].split(',').map(domain => domain.trim()).filter(Boolean)
: undefined,
domains: args['https.domains']?.flatMap(value => value.split(',')).map(domain => domain.trim()).filter(Boolean),
}

const host = (args.host as string | boolean | undefined)
Expand Down
3 changes: 2 additions & 1 deletion packages/nuxt-cli/src/commands/module/add.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export function defineAddCommand({ layers = false }: { layers?: boolean } = {})
moduleName: {
type: 'positional',
description: `Specify one or more modules${layers ? ' or layers' : ''} to install by name, separated by spaces`,
multiple: true,
},
skipInstall: {
type: 'boolean',
Expand All @@ -80,7 +81,7 @@ export function defineAddCommand({ layers = false }: { layers?: boolean } = {})
},
async setup(ctx) {
const cwd = resolve(ctx.args.cwd)
let modules = ctx.args._.map(e => e.trim()).filter(Boolean)
let modules = ctx.args.moduleName.map(e => e.trim()).filter(Boolean)
const projectPkg = await readPackageJSON(cwd).catch(() => ({} as PackageJson))

if (!await ensureNuxtDependency(cwd, projectPkg)) {
Expand Down
5 changes: 3 additions & 2 deletions packages/nuxt-cli/src/commands/prepare.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import process from 'node:process'
import { styleText } from 'node:util'
import { defineCommand } from 'citty'

import { resolveDotenvFileNames } from '../utils/args'
import { clearBuildDir } from '../utils/fs'
import { loadKit } from '../utils/kit'
import { readActiveLock } from '../utils/lockfile'
Expand Down Expand Up @@ -32,13 +33,13 @@ export default defineCommand({
cwd,
dotenv: {
cwd,
fileName: ctx.args.dotenv,
fileName: resolveDotenvFileNames(ctx.args.dotenv),
},
envName: ctx.args.envName, // nuxt will fall back to NODE_ENV
overrides: {
_prepare: true,
logLevel: ctx.args.logLevel as 'silent' | 'info' | 'verbose',
...(ctx.args.extends && { extends: ctx.args.extends }),
...(ctx.args.extends.length > 0 && { extends: ctx.args.extends }),
...ctx.data?.overrides,
},
})
Expand Down
27 changes: 13 additions & 14 deletions packages/nuxt-cli/src/commands/preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { defineCommand } from 'citty'
import { resolve } from 'pathe'
import { x } from 'tinyexec'

import { resolveDotenvFileNames } from '../utils/args'
import { loadKit } from '../utils/kit'
import { logger } from '../utils/logger'
import { withPrependedPath } from '../utils/path-env'
Expand Down Expand Up @@ -51,12 +52,12 @@ const command = defineCommand({
cwd,
dotenv: {
cwd,
fileName: ctx.args.dotenv,
fileName: resolveDotenvFileNames(ctx.args.dotenv),
},
envName: ctx.args.envName,
ready: true,
overrides: {
...(ctx.args.extends && { extends: ctx.args.extends }),
...(ctx.args.extends.length > 0 && { extends: ctx.args.extends }),
Comment thread
coderabbitai[bot] marked this conversation as resolved.
modules: [
function (_, nuxt) {
envLoaded = true
Expand Down Expand Up @@ -124,24 +125,22 @@ const command = defineCommand({
},
)

const envFileName = ctx.args.dotenv || '.env'
const envFileNames = resolveDotenvFileNames(ctx.args.dotenv) ?? ['.env']
const existing = envFileNames.filter(fileName => existsSync(resolve(cwd, fileName)))
const missing = envFileNames.filter(fileName => !existing.includes(fileName))

const envExists = existsSync(resolve(cwd, envFileName))

if (envExists) {
if (existing.length > 0) {
const list = existing.map(fileName => styleText('cyan', fileName)).join(', ')
if (envLoaded) {
logger.info(
`Loaded ${styleText('cyan', envFileName)}. This will not be loaded when running the server in production.`,
)
logger.info(`Loaded ${list}. This will not be loaded when running the server in production.`)
}
else {
logger.warn(
`Could not load Nuxt, so ${styleText('cyan', envFileName)} may not be fully applied to the preview server.`,
)
logger.warn(`Could not load Nuxt, so ${list} may not be fully applied to the preview server.`)
}
}
else if (ctx.args.dotenv) {
logger.error(`Cannot find ${styleText('cyan', envFileName)}.`)

if (ctx.args.dotenv.length > 0 && missing.length > 0) {
logger.error(`Cannot find ${missing.map(fileName => styleText('cyan', fileName)).join(', ')}.`)
}

const port = ctx.args.port
Expand Down
7 changes: 4 additions & 3 deletions packages/nuxt-cli/src/commands/typecheck.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { readPackageJSON, readTSConfig } from 'pkg-types'
import { hasTTY } from 'std-env'
import { x } from 'tinyexec'

import { resolveDotenvFileNames } from '../utils/args'
import { loadKit } from '../utils/kit'
import { logger } from '../utils/logger'
import { resolveRootDir, withNodePath } from '../utils/paths'
Expand Down Expand Up @@ -145,7 +146,7 @@ export default defineCommand({
readTSConfig(cwd).catch(() => ({} as TSConfig)),
writeTypes(cwd, ctx.args.dotenv, ctx.args.logLevel as 'silent' | 'info' | 'verbose', {
...ctx.data?.overrides,
...(ctx.args.extends && { extends: ctx.args.extends }),
...(ctx.args.extends.length > 0 && { extends: ctx.args.extends }),
}),
])

Expand Down Expand Up @@ -366,11 +367,11 @@ async function installMissingPackages(options: {
}
}

async function writeTypes(cwd: string, dotenv?: string, logLevel?: 'silent' | 'info' | 'verbose', overrides?: Record<string, any>) {
async function writeTypes(cwd: string, dotenv?: string[], logLevel?: 'silent' | 'info' | 'verbose', overrides?: Record<string, any>) {
const { loadNuxt, buildNuxt, writeTypes } = await loadKit(cwd)
const nuxt = await loadNuxt({
cwd,
dotenv: { cwd, fileName: dotenv },
dotenv: { cwd, fileName: resolveDotenvFileNames(dotenv) },
overrides: {
_prepare: true,
logLevel,
Expand Down
3 changes: 2 additions & 1 deletion packages/nuxt-cli/src/dev/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type { NuxtDevContext, NuxtDevIPCMessage, NuxtParentIPCMessage } from './

import process from 'node:process'
import defu from 'defu'
import { resolveDotenvFileNames } from '../utils/args'
import { overrideEnv } from '../utils/env.ts'
import { isRemotePeerError } from '../utils/errors'
import { debug } from '../utils/logger'
Expand Down Expand Up @@ -149,7 +150,7 @@ export async function initialize(devContext: NuxtDevContext, ctx: InitializeOpti
),
logLevel: devContext.args.logLevel as 'silent' | 'info' | 'verbose',
clear: devContext.args.clear,
dotenv: { cwd: devContext.cwd, fileName: devContext.args.dotenv },
dotenv: { cwd: devContext.cwd, fileName: resolveDotenvFileNames(devContext.args.dotenv) },
envName: devContext.args.envName,
showBanner: ctx.showBanner !== false && !ipc.enabled,
listenOverrides: ctx.listenOverrides,
Expand Down
4 changes: 2 additions & 2 deletions packages/nuxt-cli/src/dev/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ export interface NuxtDevContext {
args: {
clear?: boolean
logLevel?: string
dotenv?: string
dotenv?: string[]
envName?: string
extends?: string
extends?: string[]
profile?: string | boolean
}
}
Expand Down
Loading
Loading