From 4c1eeb4eaf5afef4fb70e26daab55627fa8b6f20 Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Mon, 6 Jan 2025 14:54:50 +0000 Subject: [PATCH 1/6] feat(subcommand): add subcommand support --- pnpm-lock.yaml | 13 +++++++------ src/main.ts | 30 ++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ae23af782..0e56ffc1a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -843,9 +843,9 @@ packages: resolution: {integrity: sha512-n5kOHt8uUyUM9z4Wu/8tIZkBYh3KTCGvyruG6oD9bfeT4OaS21+X3M7XsTXFMe+eYBZA70IFFlWn1JJZIPsKeA==} engines: {node: ^14.18.0 || >=16.10.0} - '@nuxt/telemetry@2.6.2': - resolution: {integrity: sha512-UReyqp35ZFcsyMuP+DmDj/0W/odANCuObdqYyAIR+/Z/9yDHtBO6Cc/wWbjjhrt41yhhco7/+vILELPHWD+wxg==} - engines: {node: ^14.18.0 || >=16.10.0} + '@nuxt/telemetry@2.6.3': + resolution: {integrity: sha512-60KXgeONSu7iB5yDw0B77B8sHo82cs75uLaTB/+q/QtheLmdonE5o4LFdqrCegZjjtz9yeIzUi3ccjSYZrjRkA==} + engines: {node: '>=18.20.5'} hasBin: true '@nuxt/test-utils@3.15.1': @@ -3807,6 +3807,7 @@ packages: rollup-plugin-visualizer@5.13.1: resolution: {integrity: sha512-vMg8i6BprL8aFm9DKvL2c8AwS8324EgymYQo9o6E26wgVvwMhsJxS37aNL6ZsU7X9iAcMYwdME7gItLfG5fwJg==} engines: {node: '>=18'} + deprecated: Contains unintended breaking changes hasBin: true peerDependencies: rolldown: 1.x @@ -5420,7 +5421,7 @@ snapshots: pathe: 2.0.0 std-env: 3.8.0 - '@nuxt/telemetry@2.6.2(magicast@0.3.5)(rollup@4.30.0)': + '@nuxt/telemetry@2.6.3(magicast@0.3.5)(rollup@4.30.0)': dependencies: '@nuxt/kit': 3.15.1(magicast@0.3.5)(rollup@4.30.0) citty: 0.1.6 @@ -5433,7 +5434,7 @@ snapshots: ofetch: 1.4.1 package-manager-detector: 0.2.8 parse-git-config: 3.0.0 - pathe: 1.1.2 + pathe: 2.0.0 rc9: 2.1.2 std-env: 3.8.0 transitivePeerDependencies: @@ -8354,7 +8355,7 @@ snapshots: '@nuxt/devtools': 1.7.0(rollup@4.30.0)(vite@6.0.7(@types/node@22.10.5)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))(vue@3.5.13(typescript@5.7.2)) '@nuxt/kit': 3.15.1(magicast@0.3.5)(rollup@4.30.0) '@nuxt/schema': 3.15.1 - '@nuxt/telemetry': 2.6.2(magicast@0.3.5)(rollup@4.30.0) + '@nuxt/telemetry': 2.6.3(magicast@0.3.5)(rollup@4.30.0) '@nuxt/vite-builder': 3.15.1(@types/node@22.10.5)(eslint@9.17.0(jiti@2.4.2))(magicast@0.3.5)(optionator@0.9.4)(rollup@4.30.0)(terser@5.37.0)(typescript@5.7.2)(vue-tsc@2.2.0(typescript@5.7.2))(vue@3.5.13(typescript@5.7.2))(yaml@2.7.0) '@unhead/dom': 1.11.14 '@unhead/shared': 1.11.14 diff --git a/src/main.ts b/src/main.ts index 2919737c0..efde7fa42 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,7 +1,13 @@ +import { resolve } from 'node:path' +import process from 'node:process' + import { defineCommand } from 'citty' import { provider } from 'std-env' +import { x } from 'tinyexec' + import nuxiPkg from '../package.json' assert { type: 'json' } import { commands } from './commands' +import { cwdArgs } from './commands/_shared' import { setupGlobalConsole } from './utils/console' import { checkEngines } from './utils/engines' import { logger } from './utils/logger' @@ -12,6 +18,12 @@ export const main = defineCommand({ version: nuxiPkg.version, description: nuxiPkg.description, }, + args: { + ...cwdArgs, + command: { + type: 'positional', + }, + }, subCommands: commands, async setup(ctx) { const command = ctx.args._[0] @@ -30,5 +42,23 @@ export const main = defineCommand({ if (command === 'init') { await backgroundTasks } + + // allow running arbitrary commands if there's a locally registered binary with `nuxt-` prefix + if (ctx.args.command && !(ctx.args.command in commands)) { + const cwd = resolve(ctx.args.cwd) + try { + // `tinyexec` will resolve command from local binaries + await x(`nuxt-${ctx.args.command}`, ctx.rawArgs.slice(1), { + nodeOptions: { stdio: 'inherit', cwd }, + throwOnError: true, + }) + } + catch (err) { + if (err instanceof Error && 'code' in err && err.code === 'ENOENT') { + return + } + } + process.exit() + } }, }) From b869420a282cb027427f3bd4c5232c83b1f3cf86 Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Mon, 6 Jan 2025 15:07:05 +0000 Subject: [PATCH 2/6] fix: remove `build-module` command --- src/commands/build-module.ts | 63 ------------------------------------ src/commands/index.ts | 34 +++++++++---------- 2 files changed, 16 insertions(+), 81 deletions(-) delete mode 100644 src/commands/build-module.ts diff --git a/src/commands/build-module.ts b/src/commands/build-module.ts deleted file mode 100644 index 3a870d1d5..000000000 --- a/src/commands/build-module.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { defineCommand } from 'citty' -import { resolve } from 'pathe' -import { readPackageJSON } from 'pkg-types' -import { x } from 'tinyexec' - -import { logger } from '../utils/logger' -import { cwdArgs, legacyRootDirArgs, logLevelArgs } from './_shared' - -const MODULE_BUILDER_PKG = '@nuxt/module-builder' - -export default defineCommand({ - meta: { - name: 'build-module', - description: `Helper command for using ${MODULE_BUILDER_PKG}`, - }, - args: { - ...cwdArgs, - ...logLevelArgs, - ...legacyRootDirArgs, - stub: { - type: 'boolean', - description: 'Stub dist instead of actually building it for development', - }, - sourcemap: { - type: 'boolean', - description: 'Generate sourcemaps', - }, - prepare: { - type: 'boolean', - description: 'Prepare module for local development', - }, - }, - async run(ctx) { - // Find local installed version - const cwd = resolve(ctx.args.cwd || ctx.args.rootDir) - - const hasLocal = await readPackageJSON(MODULE_BUILDER_PKG, { url: cwd }).catch(() => false) - - const execArgs = Object.entries({ - '--stub': ctx.args.stub, - '--sourcemap': ctx.args.sourcemap, - '--prepare': ctx.args.prepare, - }) - .filter(([, value]) => value) - .map(([key]) => key) - - let cmd = 'nuxt-module-build' - if (!hasLocal) { - logger.warn( - `Cannot find locally installed version of \`${MODULE_BUILDER_PKG}\` (>=0.2.0). Falling back to \`npx ${MODULE_BUILDER_PKG}\``, - ) - cmd = 'npx' - execArgs.unshift(MODULE_BUILDER_PKG) - } - - await x(cmd, execArgs, { - nodeOptions: { - cwd, - stdio: 'inherit', - }, - }) - }, -}) diff --git a/src/commands/index.ts b/src/commands/index.ts index a3462443b..0eeb79d3c 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -3,22 +3,20 @@ import type { CommandDef } from 'citty' const _rDefault = (r: any) => (r.default || r) as Promise export const commands = { - 'add': () => import('./add').then(_rDefault), - 'analyze': () => import('./analyze').then(_rDefault), - 'build-module': () => import('./build-module').then(_rDefault), - 'build': () => import('./build').then(_rDefault), - 'cleanup': () => import('./cleanup').then(_rDefault), - '_dev': () => import('./dev-child').then(_rDefault), - 'dev': () => import('./dev').then(_rDefault), - 'devtools': () => import('./devtools').then(_rDefault), - 'generate': () => import('./generate').then(_rDefault), - 'info': () => import('./info').then(_rDefault), - 'init': () => import('./init').then(_rDefault), - 'module': () => import('./module').then(_rDefault), - 'prepare': () => import('./prepare').then(_rDefault), - 'preview': () => import('./preview').then(_rDefault), - 'start': () => import('./preview').then(_rDefault), - 'test': () => import('./test').then(_rDefault), - 'typecheck': () => import('./typecheck').then(_rDefault), - 'upgrade': () => import('./upgrade').then(_rDefault), + add: () => import('./add').then(_rDefault), + analyze: () => import('./analyze').then(_rDefault), + build: () => import('./build').then(_rDefault), + cleanup: () => import('./cleanup').then(_rDefault), + _dev: () => import('./dev-child').then(_rDefault), + dev: () => import('./dev').then(_rDefault), + generate: () => import('./generate').then(_rDefault), + info: () => import('./info').then(_rDefault), + init: () => import('./init').then(_rDefault), + module: () => import('./module').then(_rDefault), + prepare: () => import('./prepare').then(_rDefault), + preview: () => import('./preview').then(_rDefault), + start: () => import('./preview').then(_rDefault), + test: () => import('./test').then(_rDefault), + typecheck: () => import('./typecheck').then(_rDefault), + upgrade: () => import('./upgrade').then(_rDefault), } as const From 511237f83c84efc282f00fd3dd7ea69a98285675 Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Mon, 6 Jan 2025 15:36:20 +0000 Subject: [PATCH 3/6] fix: do not pass on parsed args --- src/main.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.ts b/src/main.ts index efde7fa42..cd731cec6 100644 --- a/src/main.ts +++ b/src/main.ts @@ -48,7 +48,7 @@ export const main = defineCommand({ const cwd = resolve(ctx.args.cwd) try { // `tinyexec` will resolve command from local binaries - await x(`nuxt-${ctx.args.command}`, ctx.rawArgs.slice(1), { + await x(`nuxt-${ctx.args.command}`, ctx.args._.slice(1), { nodeOptions: { stdio: 'inherit', cwd }, throwOnError: true, }) From b16386693dbcbb2ee795f003225d6c4b06e862ec Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Mon, 6 Jan 2025 15:59:10 +0000 Subject: [PATCH 4/6] fix: add back devtools command --- src/commands/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/commands/index.ts b/src/commands/index.ts index 0eeb79d3c..416196fe3 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -9,6 +9,7 @@ export const commands = { cleanup: () => import('./cleanup').then(_rDefault), _dev: () => import('./dev-child').then(_rDefault), dev: () => import('./dev').then(_rDefault), + devtools: () => import('./devtools').then(_rDefault), generate: () => import('./generate').then(_rDefault), info: () => import('./info').then(_rDefault), init: () => import('./init').then(_rDefault), From 16bd1baf9074f8f4bd475e9902727e3a4f929457 Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Mon, 6 Jan 2025 16:00:26 +0000 Subject: [PATCH 5/6] chore: revert lockfile change --- pnpm-lock.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 01d160a67..0d614579f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3807,7 +3807,6 @@ packages: rollup-plugin-visualizer@5.13.1: resolution: {integrity: sha512-vMg8i6BprL8aFm9DKvL2c8AwS8324EgymYQo9o6E26wgVvwMhsJxS37aNL6ZsU7X9iAcMYwdME7gItLfG5fwJg==} engines: {node: '>=18'} - deprecated: Contains unintended breaking changes hasBin: true peerDependencies: rolldown: 1.x From b28931cdc1e7ddb6eafad6c6e956edb9323d6c1a Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Mon, 6 Jan 2025 17:10:15 +0000 Subject: [PATCH 6/6] perf: lazily import `tinyexec` in main entry --- src/main.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.ts b/src/main.ts index cd731cec6..20b1c7eb6 100644 --- a/src/main.ts +++ b/src/main.ts @@ -3,7 +3,6 @@ import process from 'node:process' import { defineCommand } from 'citty' import { provider } from 'std-env' -import { x } from 'tinyexec' import nuxiPkg from '../package.json' assert { type: 'json' } import { commands } from './commands' @@ -47,6 +46,7 @@ export const main = defineCommand({ if (ctx.args.command && !(ctx.args.command in commands)) { const cwd = resolve(ctx.args.cwd) try { + const { x } = await import('tinyexec') // `tinyexec` will resolve command from local binaries await x(`nuxt-${ctx.args.command}`, ctx.args._.slice(1), { nodeOptions: { stdio: 'inherit', cwd },