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: 6 additions & 0 deletions knip.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@
]
},
"playground": {
"entry": [
"test/**",
"pages/**",
"server/**",
"some-layer/**"
],
"ignoreDependencies": [
"@nuxt/test-utils",
"nuxt"
Expand Down
8 changes: 8 additions & 0 deletions packages/nuxi/src/commands/_shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ export const dotEnvArgs = {
},
} as const satisfies Record<string, ArgDef>

export const extendsArgs = {
extends: {
type: 'string',
description: 'Extend from a Nuxt layer',
valueHint: 'layer-name',
},
} as const satisfies Record<string, ArgDef>

export const legacyRootDirArgs = {
// cwd falls back to rootDir's default (indirect default)
cwd: {
Expand Down
4 changes: 3 additions & 1 deletion packages/nuxi/src/commands/analyze.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { overrideEnv } from '../utils/env'
import { clearDir } from '../utils/fs'
import { loadKit } from '../utils/kit'
import { logger } from '../utils/logger'
import { cwdArgs, dotEnvArgs, legacyRootDirArgs, logLevelArgs } from './_shared'
import { cwdArgs, dotEnvArgs, extendsArgs, legacyRootDirArgs, logLevelArgs } from './_shared'

export default defineCommand({
meta: {
Expand All @@ -25,6 +25,7 @@ export default defineCommand({
...logLevelArgs,
...legacyRootDirArgs,
...dotEnvArgs,
...extendsArgs,
name: {
type: 'string',
description: 'Name of the analysis',
Expand Down Expand Up @@ -56,6 +57,7 @@ export default defineCommand({
fileName: ctx.args.dotenv,
},
overrides: defu(ctx.data?.overrides, {
...(ctx.args.extends && { extends: ctx.args.extends }),
build: {
analyze: {
enabled: true,
Expand Down
4 changes: 3 additions & 1 deletion packages/nuxi/src/commands/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { overrideEnv } from '../utils/env'
import { clearBuildDir } from '../utils/fs'
import { loadKit } from '../utils/kit'
import { logger } from '../utils/logger'
import { cwdArgs, dotEnvArgs, envNameArgs, legacyRootDirArgs, logLevelArgs } from './_shared'
import { cwdArgs, dotEnvArgs, envNameArgs, extendsArgs, legacyRootDirArgs, logLevelArgs } from './_shared'

export default defineCommand({
meta: {
Expand All @@ -30,6 +30,7 @@ export default defineCommand({
},
...dotEnvArgs,
...envNameArgs,
...extendsArgs,
...legacyRootDirArgs,
},
async run(ctx) {
Expand All @@ -56,6 +57,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.data?.overrides,
},
})
Expand Down
6 changes: 4 additions & 2 deletions packages/nuxi/src/commands/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { showVersions } from '../utils/banner'
import { overrideEnv } from '../utils/env'
import { loadKit } from '../utils/kit'
import { logger } from '../utils/logger'
import { cwdArgs, dotEnvArgs, envNameArgs, legacyRootDirArgs, logLevelArgs } from './_shared'
import { cwdArgs, dotEnvArgs, envNameArgs, extendsArgs, legacyRootDirArgs, logLevelArgs } from './_shared'

const startTime: number | undefined = Date.now()
const forkSupported = !isTest && (!isBun || isBunForkSupported())
Expand All @@ -42,6 +42,7 @@ const command = defineCommand({
...dotEnvArgs,
...legacyRootDirArgs,
...envNameArgs,
...extendsArgs,
clear: {
type: 'boolean',
description: 'Clear console on restart',
Expand Down Expand Up @@ -101,6 +102,7 @@ const command = defineCommand({
overrides: {
dev: true,
logLevel: ctx.args.logLevel as 'silent' | 'info' | 'verbose',
...(ctx.args.extends && { extends: ctx.args.extends }),
...ctx.data?.overrides,
},
})
Expand Down Expand Up @@ -263,7 +265,7 @@ async function createDevProxy(cwd: string, nuxtOptions: NuxtOptions, listenOptio
}
}

async function startSubprocess(cwd: string, args: { logLevel: string, clear: boolean, dotenv: string, envName: string }, rawArgs: string[], listenOptions: Partial<ListenOptions>) {
async function startSubprocess(cwd: string, args: { logLevel: string, clear: boolean, dotenv: string, envName: string, extends?: string }, rawArgs: string[], listenOptions: Partial<ListenOptions>) {
let childProc: ChildProcess | undefined
let devProxy: DevProxy
let ready: Promise<void> | undefined
Expand Down
3 changes: 2 additions & 1 deletion packages/nuxi/src/commands/generate.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { defineCommand } from 'citty'

import { cwdArgs, dotEnvArgs, envNameArgs, legacyRootDirArgs, logLevelArgs } from './_shared'
import { cwdArgs, dotEnvArgs, envNameArgs, extendsArgs, legacyRootDirArgs, logLevelArgs } from './_shared'
import buildCommand from './build'

export default defineCommand({
Expand All @@ -17,6 +17,7 @@ export default defineCommand({
},
...dotEnvArgs,
...envNameArgs,
...extendsArgs,
...legacyRootDirArgs,
},
async run(ctx) {
Expand Down
4 changes: 3 additions & 1 deletion packages/nuxi/src/commands/prepare.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { relative, resolve } from 'pathe'
import { clearBuildDir } from '../utils/fs'
import { loadKit } from '../utils/kit'
import { logger } from '../utils/logger'
import { cwdArgs, dotEnvArgs, envNameArgs, legacyRootDirArgs, logLevelArgs } from './_shared'
import { cwdArgs, dotEnvArgs, envNameArgs, extendsArgs, legacyRootDirArgs, logLevelArgs } from './_shared'

export default defineCommand({
meta: {
Expand All @@ -18,6 +18,7 @@ export default defineCommand({
...cwdArgs,
...logLevelArgs,
...envNameArgs,
...extendsArgs,
...legacyRootDirArgs,
},
async run(ctx) {
Expand All @@ -36,6 +37,7 @@ export default defineCommand({
overrides: {
_prepare: true,
logLevel: ctx.args.logLevel as 'silent' | 'info' | 'verbose',
...(ctx.args.extends && { extends: ctx.args.extends }),
...ctx.data?.overrides,
},
})
Expand Down
4 changes: 3 additions & 1 deletion packages/nuxi/src/commands/preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { x } from 'tinyexec'

import { loadKit } from '../utils/kit'
import { logger } from '../utils/logger'
import { cwdArgs, dotEnvArgs, envNameArgs, legacyRootDirArgs, logLevelArgs } from './_shared'
import { cwdArgs, dotEnvArgs, envNameArgs, extendsArgs, legacyRootDirArgs, logLevelArgs } from './_shared'

const command = defineCommand({
meta: {
Expand All @@ -23,6 +23,7 @@ const command = defineCommand({
...cwdArgs,
...logLevelArgs,
...envNameArgs,
...extendsArgs,
...legacyRootDirArgs,
port: getListhenArgs().port,
...dotEnvArgs,
Expand All @@ -40,6 +41,7 @@ const command = defineCommand({
envName: ctx.args.envName, // c12 will fall back to NODE_ENV
ready: true,
overrides: {
...(ctx.args.extends && { extends: ctx.args.extends }),
modules: [
function (_, nuxt) {
nuxt.hook('nitro:init', (nitro) => {
Expand Down
8 changes: 5 additions & 3 deletions packages/nuxi/src/commands/typecheck.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { isBun } from 'std-env'
import { x } from 'tinyexec'

import { loadKit } from '../utils/kit'
import { cwdArgs, dotEnvArgs, legacyRootDirArgs, logLevelArgs } from './_shared'
import { cwdArgs, dotEnvArgs, extendsArgs, legacyRootDirArgs, logLevelArgs } from './_shared'

export default defineCommand({
meta: {
Expand All @@ -19,6 +19,7 @@ export default defineCommand({
...cwdArgs,
...logLevelArgs,
...dotEnvArgs,
...extendsArgs,
...legacyRootDirArgs,
},
async run(ctx) {
Expand All @@ -31,7 +32,7 @@ export default defineCommand({
// Prefer local install if possible
resolveModulePath('typescript', { try: true }),
resolveModulePath('vue-tsc/bin/vue-tsc.js', { try: true }),
writeTypes(cwd, ctx.args.dotenv, ctx.args.logLevel as 'silent' | 'info' | 'verbose'),
writeTypes(cwd, ctx.args.dotenv, ctx.args.logLevel as 'silent' | 'info' | 'verbose', ctx.args.extends),
])

const typeCheckArgs = supportsProjects ? ['-b', '--noEmit'] : ['--noEmit']
Expand Down Expand Up @@ -67,14 +68,15 @@ export default defineCommand({
},
})

async function writeTypes(cwd: string, dotenv?: string, logLevel?: 'silent' | 'info' | 'verbose') {
async function writeTypes(cwd: string, dotenv?: string, logLevel?: 'silent' | 'info' | 'verbose', extendsValue?: string) {
const { loadNuxt, buildNuxt, writeTypes } = await loadKit(cwd)
const nuxt = await loadNuxt({
cwd,
dotenv: { cwd, fileName: dotenv },
overrides: {
_prepare: true,
logLevel,
...(extendsValue && { extends: extendsValue }),
},
})

Expand Down
2 changes: 2 additions & 0 deletions packages/nuxi/src/dev/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export interface NuxtDevContext {
logLevel: string
dotenv: string
envName: string
extends?: string
}
proxy?: {
url?: string
Expand Down Expand Up @@ -232,6 +233,7 @@ export class NuxtDevServer extends EventEmitter<DevServerEventMap> {
defaults: defu(this.options.defaults, devServerDefaults),
overrides: {
logLevel: this.options.logLevel as 'silent' | 'info' | 'verbose',
...(this.options.devContext.args.extends && { extends: this.options.devContext.args.extends }),
...this.options.overrides,
vite: {
clearScreen: this.options.clear,
Expand Down
38 changes: 21 additions & 17 deletions packages/nuxt-cli/test/e2e/commands.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { fileURLToPath } from 'node:url'
import { getPort } from 'get-port-please'
import { isCI, isWindows } from 'std-env'
import { isWindows } from 'std-env'
import { x } from 'tinyexec'
import { describe, expect, it } from 'vitest'
import { fetchWithPolling } from '../utils'

const fixtureDir = fileURLToPath(new URL('../../../../playground', import.meta.url))
const nuxi = fileURLToPath(new URL('../../bin/nuxi.mjs', import.meta.url))
Expand Down Expand Up @@ -160,21 +161,24 @@ describe('commands', () => {
}
})

async function fetchWithPolling(url: string, options: RequestInit = {}, maxAttempts = 10, interval = 100): Promise<Response | null> {
let response: Response | null = null
let attempts = 0
while (attempts < maxAttempts) {
describe('extends support', () => {
it('works with dev server', { timeout: isWindows ? 200000 : 50000 }, async () => {
const controller = new AbortController()
const port = await getPort({ host: '127.0.0.1', port: 3003 })
const devProcess = x(nuxi, ['dev', `--host=127.0.0.1`, `--port=${port}`, '--extends=some-layer'], {
nodeOptions: { stdio: 'pipe', cwd: fixtureDir },
signal: controller.signal,
})

// Test that server responds
const response = await fetchWithPolling(`http://127.0.0.1:${port}/extended`, {}, 30, 300)
expect.soft(response?.status).toBe(200)
expect(await response?.text()).toContain('This is an extended page from a layer.')

controller.abort()
try {
response = await fetch(url, options)
if (response.ok) {
return response
}
await devProcess
}
catch {
// Ignore errors and retry
}
attempts++
await new Promise(resolve => setTimeout(resolve, isCI ? interval * 10 : interval))
}
return response
}
catch {}
})
})
20 changes: 20 additions & 0 deletions packages/nuxt-cli/test/utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { isCI } from 'std-env'

export async function fetchWithPolling(url: string, options: RequestInit = {}, maxAttempts = 10, interval = 100): Promise<Response | null> {
let response: Response | null = null
let attempts = 0
while (attempts < maxAttempts) {
try {
response = await fetch(url, options)
if (response.ok) {
return response
}
}
catch {
// Ignore errors and retry
}
attempts++
await new Promise(resolve => setTimeout(resolve, isCI ? interval * 10 : interval))
}
return response
}
1 change: 1 addition & 0 deletions playground/some-layer/nuxt.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default defineNuxtConfig({})
5 changes: 5 additions & 0 deletions playground/some-layer/pages/extended.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<template>
<div>
This is an extended page from a layer.
</div>
</template>
Loading