From 57a29744509f11ffd2ceef32521024c5f3a5ea7f Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Mon, 26 Jul 2021 15:46:19 +0100 Subject: [PATCH] feat(cli): add `prepare` command to stub module types (#370) Co-authored-by: Pooya Parsa --- packages/cli/src/commands/index.ts | 1 + packages/cli/src/commands/prepare.ts | 57 ++++++++++++++++++++++++++++ packages/cli/src/utils/cjs.ts | 42 +++++++++++++------- packages/cli/src/utils/fs.ts | 11 ++++++ packages/cli/src/utils/log.ts | 9 +++-- packages/kit/src/types/hooks.ts | 3 ++ playground/nuxt.d.ts | 7 ++++ 7 files changed, 113 insertions(+), 17 deletions(-) create mode 100644 packages/cli/src/commands/prepare.ts create mode 100644 packages/cli/src/utils/fs.ts create mode 100644 playground/nuxt.d.ts diff --git a/packages/cli/src/commands/index.ts b/packages/cli/src/commands/index.ts index 27fcef31d7..8f28d14e2e 100644 --- a/packages/cli/src/commands/index.ts +++ b/packages/cli/src/commands/index.ts @@ -3,6 +3,7 @@ import type { Argv } from 'mri' export const commands = { dev: () => import('./dev'), build: () => import('./build'), + prepare: () => import('./prepare'), usage: () => import('./usage') } diff --git a/packages/cli/src/commands/prepare.ts b/packages/cli/src/commands/prepare.ts new file mode 100644 index 0000000000..def691ed27 --- /dev/null +++ b/packages/cli/src/commands/prepare.ts @@ -0,0 +1,57 @@ +import { promises as fsp } from 'fs' +import { relative, resolve } from 'upath' +import { cyan } from 'colorette' + +import { requireModule, getModulePaths, getNearestPackage } from '../utils/cjs' +import { exists } from '../utils/fs' +import { success } from '../utils/log' +import { defineNuxtCommand } from './index' + +export default defineNuxtCommand({ + meta: { + name: 'prepare', + usage: 'nu prepare', + description: 'Prepare nuxt for development/build' + }, + async invoke (args) { + process.env.NODE_ENV = process.env.NODE_ENV || 'production' + const rootDir = resolve(args._[0] || '.') + + const { loadNuxt } = requireModule('@nuxt/kit', rootDir) as typeof import('@nuxt/kit') + const nuxt = await loadNuxt({ rootDir }) + + const adHocModules = nuxt.options._majorVersion === 3 + ? ['@nuxt/kit', '@nuxt/app', '@nuxt/nitro'] + : ['@nuxt/kit'] + + const types = [ + ...adHocModules, + // Modules + ...nuxt.options.buildModules, + ...nuxt.options.modules, + ...nuxt.options._modules + ].filter(f => typeof f === 'string') + + const modulePaths = getModulePaths(nuxt.options.modulesDir) + const _references = await Promise.all(types.map(async (id) => { + const pkg = getNearestPackage(id, modulePaths) + return pkg ? `/// ` : await exists(id) && `/// ` + })).then(arr => arr.filter(Boolean)) + + const references = Array.from(new Set(_references)) as string[] + await nuxt.callHook('prepare:types', { references }) + + const declarationPath = resolve(`${rootDir}/nuxt.d.ts`) + + const declaration = [ + '// Declarations auto generated by `nuxt prepare`. Please do not manually modify this file.', + '', + ...references, + '' + ].join('\n') + + await fsp.writeFile(declarationPath, declaration) + + success('Generated', cyan(relative(process.cwd(), declarationPath))) + } +}) diff --git a/packages/cli/src/utils/cjs.ts b/packages/cli/src/utils/cjs.ts index 3936bdb8d0..08ac1af4d9 100644 --- a/packages/cli/src/utils/cjs.ts +++ b/packages/cli/src/utils/cjs.ts @@ -1,18 +1,34 @@ -import { normalize } from 'upath' +import { normalize, dirname } from 'upath' -export function resolveModule (id: string, paths?: string) { - return normalize(require.resolve(id, { - paths: [].concat( - // @ts-ignore - global.__NUXT_PREPATHS__, - paths, - process.cwd(), - // @ts-ignore - global.__NUXT_PATHS__ - ).filter(Boolean) - })) +export function getModulePaths (paths?: string | string[]): string[] { + return [].concat( + // @ts-ignore + global.__NUXT_PREPATHS__, + ...(Array.isArray(paths) ? paths : [paths]), + process.cwd(), + // @ts-ignore + global.__NUXT_PATHS__ + ).filter(Boolean) } -export function requireModule (id: string, paths?: string) { +export function resolveModule (id: string, paths?: string | string[]) { + return normalize(require.resolve(id, { paths: getModulePaths(paths) })) +} + +export function tryResolveModule (id: string, paths?: string | string[]) { + try { + return resolveModule(id, paths) + } catch { return null } +} + +export function requireModule (id: string, paths?: string | string[]) { return require(resolveModule(id, paths)) } + +export function getNearestPackage (id: string, paths?: string | string[]) { + while (dirname(id) !== id) { + try { return requireModule(id + '/package.json', paths) } catch { } + id = dirname(id) + } + return null +} diff --git a/packages/cli/src/utils/fs.ts b/packages/cli/src/utils/fs.ts new file mode 100644 index 0000000000..e646b35211 --- /dev/null +++ b/packages/cli/src/utils/fs.ts @@ -0,0 +1,11 @@ +import { promises as fsp } from 'fs' + +// Check if a file exists +export async function exists (path: string) { + try { + await fsp.access(path) + return true + } catch { + return false + } +} diff --git a/packages/cli/src/utils/log.ts b/packages/cli/src/utils/log.ts index ab3c895b07..92001b96af 100644 --- a/packages/cli/src/utils/log.ts +++ b/packages/cli/src/utils/log.ts @@ -1,5 +1,6 @@ -import { red, yellow, cyan } from 'colorette' +import { green, red, yellow, cyan } from 'colorette' -export const error = (...args) => console.error(red('[error]'), ...args) -export const warn = (...args) => console.warn(yellow('[warn]'), ...args) -export const info = (...args) => console.info(cyan('[info]'), ...args) +export const error = (...args: any[]) => console.error(red('[error]'), ...args) +export const warn = (...args: any[]) => console.warn(yellow('[warn]'), ...args) +export const info = (...args: any[]) => console.info(cyan('[info]'), ...args) +export const success = (...args: any[]) => console.log(green('[success]'), ...args) diff --git a/packages/kit/src/types/hooks.ts b/packages/kit/src/types/hooks.ts index 42bb644075..fbabf01c25 100644 --- a/packages/kit/src/types/hooks.ts +++ b/packages/kit/src/types/hooks.ts @@ -66,6 +66,9 @@ export interface NuxtHooks { 'config': (options: NuxtConfig) => HookResult 'run:before': (options: { argv: string[], cmd: { name: string, usage: string, description: string, options: Record }, rootDir: string }) => HookResult + // nuxt-cli + 'prepare:types': (options: { references: string[] }) => HookResult + // @nuxt/core 'ready': (nuxt: Nuxt) => HookResult 'close': (nuxt: Nuxt) => HookResult diff --git a/playground/nuxt.d.ts b/playground/nuxt.d.ts new file mode 100644 index 0000000000..b1cb579f47 --- /dev/null +++ b/playground/nuxt.d.ts @@ -0,0 +1,7 @@ +// Declarations auto generated by `nuxt prepare`. Please do not manually modify this file. + +/// +/// +/// +/// +///