From 8c09d05ad26d72a066fe15dc7cea9c25fa5a7474 Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Mon, 26 Jul 2021 15:04:35 +0100 Subject: [PATCH] refactor: improve cli and kit types (#369) [skip-release] Co-authored-by: Pooya Parsa --- packages/cli/src/commands/build.ts | 35 +++++----- packages/cli/src/commands/dev.ts | 106 +++++++++++++++-------------- packages/cli/src/commands/index.ts | 20 ++++++ packages/cli/src/commands/usage.ts | 24 ++++--- packages/cli/src/index.ts | 6 +- packages/cli/src/utils/cjs.ts | 4 +- packages/cli/src/utils/server.ts | 9 +-- 7 files changed, 117 insertions(+), 87 deletions(-) diff --git a/packages/cli/src/commands/build.ts b/packages/cli/src/commands/build.ts index 7ede5161b0..cdbca49427 100644 --- a/packages/cli/src/commands/build.ts +++ b/packages/cli/src/commands/build.ts @@ -1,25 +1,28 @@ - import { resolve } from 'upath' import { requireModule } from '../utils/cjs' import { error } from '../utils/log' -export async function invoke (args) { - process.env.NODE_ENV = process.env.NODE_ENV || 'production' - const rootDir = resolve(args._[0] || '.') +import { defineNuxtCommand } from './index' - const { loadNuxt, buildNuxt } = requireModule('@nuxt/kit', rootDir) +export default defineNuxtCommand({ + meta: { + name: 'build', + usage: 'nu build [rootDir]', + description: 'Build nuxt for production deployment' + }, + async invoke (args) { + process.env.NODE_ENV = process.env.NODE_ENV || 'production' + const rootDir = resolve(args._[0] || '.') - const nuxt = await loadNuxt({ rootDir }) + const { loadNuxt, buildNuxt } = requireModule('@nuxt/kit', rootDir) as typeof import('@nuxt/kit') - nuxt.hook('error', (err) => { - error('Nuxt Build Error:', err) - process.exit(1) - }) + const nuxt = await loadNuxt({ rootDir }) - await buildNuxt(nuxt) -} + nuxt.hook('error', (err) => { + error('Nuxt Build Error:', err) + process.exit(1) + }) -export const meta = { - usage: 'nu build [rootDir]', - description: 'Build nuxt for production deployment' -} + await buildNuxt(nuxt) + } +}) diff --git a/packages/cli/src/commands/dev.ts b/packages/cli/src/commands/dev.ts index dfcbbcb289..6f3e87c159 100644 --- a/packages/cli/src/commands/dev.ts +++ b/packages/cli/src/commands/dev.ts @@ -1,65 +1,69 @@ import { resolve } from 'upath' import chokidar from 'chokidar' import debounce from 'debounce-promise' +import type { Nuxt } from '@nuxt/kit' import { createServer, createLoadingHandler } from '../utils/server' import { showBanner } from '../utils/banner' import { requireModule } from '../utils/cjs' import { error } from '../utils/log' +import { defineNuxtCommand } from './index' -export async function invoke (args) { - process.env.NODE_ENV = process.env.NODE_ENV || 'development' - const server = createServer() - const listener = await server.listen({ - clipboard: args.clipboard, - open: args.open || args.o - }) +export default defineNuxtCommand({ + meta: { + name: 'dev', + usage: 'nu dev [rootDir] [--clipboard] [--open, -o]', + description: 'Run nuxt development server' + }, + async invoke (args) { + process.env.NODE_ENV = process.env.NODE_ENV || 'development' + const server = createServer() + const listener = await server.listen({ + clipboard: args.clipboard, + open: args.open || args.o + }) - const rootDir = resolve(args._[0] || '.') + const rootDir = resolve(args._[0] || '.') - const { loadNuxt, buildNuxt } = requireModule('@nuxt/kit', rootDir) + const { loadNuxt, buildNuxt } = requireModule('@nuxt/kit', rootDir) as typeof import('@nuxt/kit') - let currentNuxt - const load = async (isRestart) => { - try { - const message = `${isRestart ? 'Restarting' : 'Starting'} nuxt...` - server.setApp(createLoadingHandler(message)) - if (isRestart) { - console.log(message) + let currentNuxt: Nuxt + const load = async (isRestart: boolean) => { + try { + const message = `${isRestart ? 'Restarting' : 'Starting'} nuxt...` + server.setApp(createLoadingHandler(message)) + if (isRestart) { + console.log(message) + } + if (currentNuxt) { + await currentNuxt.close() + } + const newNuxt = await loadNuxt({ rootDir, dev: true, ready: false }) + currentNuxt = newNuxt + await currentNuxt.ready() + await buildNuxt(currentNuxt) + server.setApp(currentNuxt.server.app) + if (isRestart && args.clear !== false) { + showBanner() + listener.showURL() + } + } catch (err) { + error(`Cannot ${isRestart ? 'restart' : 'start'} nuxt: `, err) + server.setApp(createLoadingHandler( + 'Error while loading nuxt. Please check console and fix errors.' + )) } - if (currentNuxt) { - await currentNuxt.close() - } - const newNuxt = await loadNuxt({ rootDir, dev: true, ready: false }) - currentNuxt = newNuxt - await currentNuxt.ready() - await buildNuxt(currentNuxt) - server.setApp(currentNuxt.server.app) - if (isRestart && args.clear !== false) { - showBanner() - listener.showURL() - } - } catch (err) { - error(`Cannot ${isRestart ? 'restart' : 'start'} nuxt: `, err) - server.setApp(createLoadingHandler( - 'Error while loading nuxt. Please check console and fix errors.' - )) } + + // Watch for config changes + // TODO: Watcher service, modules, and requireTree + const dLoad = debounce(load, 250) + const watcher = chokidar.watch([rootDir], { ignoreInitial: true, depth: 1 }) + watcher.on('all', (_event, file) => { + if (file.includes('nuxt.config') || file.includes('modules')) { + dLoad(true) + } + }) + + await load(false) } - - // Watch for config changes - // TODO: Watcher service, modules, and requireTree - const dLoad = debounce(load, 250) - const watcher = chokidar.watch([rootDir], { ignoreInitial: true, depth: 1 }) - watcher.on('all', (_event, file) => { - if (file.includes('nuxt.config') || file.includes('modules')) { - dLoad(true) - } - }) - - await load(false) -} - -export const meta = { - usage: 'nu dev [rootDir] [--clipboard] [--open, -o]', - description: 'Run nuxt development server' -} +}) diff --git a/packages/cli/src/commands/index.ts b/packages/cli/src/commands/index.ts index 6583694c55..27fcef31d7 100644 --- a/packages/cli/src/commands/index.ts +++ b/packages/cli/src/commands/index.ts @@ -1,5 +1,25 @@ +import type { Argv } from 'mri' + export const commands = { dev: () => import('./dev'), build: () => import('./build'), usage: () => import('./usage') } + +export type Command = keyof typeof commands + +export interface NuxtCommandMeta { + name: string; + usage: string; + description: string; + [key: string]: any; +} + +export interface NuxtCommand { + invoke(args: Argv): Promise | void + meta: NuxtCommandMeta +} + +export function defineNuxtCommand (command: NuxtCommand): NuxtCommand { + return command +} diff --git a/packages/cli/src/commands/usage.ts b/packages/cli/src/commands/usage.ts index 0efcaa5940..ae406bdca1 100644 --- a/packages/cli/src/commands/usage.ts +++ b/packages/cli/src/commands/usage.ts @@ -1,15 +1,17 @@ import { cyan } from 'colorette' -import { commands } from './index' +import { commands, defineNuxtCommand } from './index' -export function invoke (_args) { - const sections: string[] = [] +export default defineNuxtCommand({ + meta: { + name: 'help', + usage: 'nu help', + description: 'Show help' + }, + invoke (_args) { + const sections: string[] = [] - sections.push(`Usage: ${cyan(`nu ${Object.keys(commands).join('|')} [args]`)}`) + sections.push(`Usage: ${cyan(`nu ${Object.keys(commands).join('|')} [args]`)}`) - console.log(sections.join('\n\n') + '\n') -} - -export const meta = { - usage: 'nu help', - description: 'Show help' -} + console.log(sections.join('\n\n') + '\n') + } +}) diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index 5dacedcd8a..fb6a4c0c05 100755 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -1,7 +1,7 @@ import 'v8-compile-cache' import mri from 'mri' import { red, cyan } from 'colorette' -import { commands } from './commands' +import { commands, Command, NuxtCommand } from './commands' import { showHelp } from './utils/help' import { showBanner } from './utils/banner' import { error } from './utils/log' @@ -29,7 +29,7 @@ async function _main () { } try { - const cmd = await commands[command]() + const cmd = await commands[command as Command]().then(c => c.default || c) as NuxtCommand if (args.h || args.help) { showHelp(cmd.meta) } else { @@ -40,7 +40,7 @@ async function _main () { } } -function onFatalError (err) { +function onFatalError (err: unknown) { error(err) process.exit(1) } diff --git a/packages/cli/src/utils/cjs.ts b/packages/cli/src/utils/cjs.ts index 04ddb35569..3936bdb8d0 100644 --- a/packages/cli/src/utils/cjs.ts +++ b/packages/cli/src/utils/cjs.ts @@ -1,6 +1,6 @@ import { normalize } from 'upath' -export function resolveModule (id, paths?) { +export function resolveModule (id: string, paths?: string) { return normalize(require.resolve(id, { paths: [].concat( // @ts-ignore @@ -13,6 +13,6 @@ export function resolveModule (id, paths?) { })) } -export function requireModule (id, paths?) { +export function requireModule (id: string, paths?: string) { return require(resolveModule(id, paths)) } diff --git a/packages/cli/src/utils/server.ts b/packages/cli/src/utils/server.ts index bed996b5da..046afe8f2d 100644 --- a/packages/cli/src/utils/server.ts +++ b/packages/cli/src/utils/server.ts @@ -1,10 +1,11 @@ import type { RequestListener } from 'http' +import type { ListenOptions } from 'listhen' import { loading } from '@nuxt/design' export function createServer () { const listener = createDynamicFunction(createLoadingHandler('Loading...')) - async function listen (opts) { + async function listen (opts: Partial) { const { listen } = await import('listhen') return listen(listener.call, opts) } @@ -23,10 +24,10 @@ export function createLoadingHandler (message: string): RequestListener { } } -function createDynamicFunction any>(initialValue: T) { - let fn: T = initialValue +function createDynamicFunction any> (initialValue: T) { + let fn = initialValue return { set: (newFn: T) => { fn = newFn }, - call: ((...args) => fn(...args)) as T + call: ((...args: Parameters) => fn(...args)) as T } }