diff --git a/packages/cli/src/commands/prepare.ts b/packages/cli/src/commands/prepare.ts index def691ed27..35bcdf10d7 100644 --- a/packages/cli/src/commands/prepare.ts +++ b/packages/cli/src/commands/prepare.ts @@ -1,9 +1,8 @@ import { promises as fsp } from 'fs' import { relative, resolve } from 'upath' import { cyan } from 'colorette' - +import type { TSReference } from '@nuxt/kit' import { requireModule, getModulePaths, getNearestPackage } from '../utils/cjs' -import { exists } from '../utils/fs' import { success } from '../utils/log' import { defineNuxtCommand } from './index' @@ -24,29 +23,31 @@ export default defineNuxtCommand({ ? ['@nuxt/kit', '@nuxt/app', '@nuxt/nitro'] : ['@nuxt/kit'] - const types = [ + const modulePaths = getModulePaths(nuxt.options.modulesDir) + + const references: TSReference[] = [ ...adHocModules, - // Modules ...nuxt.options.buildModules, ...nuxt.options.modules, ...nuxt.options._modules - ].filter(f => typeof f === 'string') + ] + .filter(f => typeof f === 'string') + .map(id => ({ types: getNearestPackage(id, modulePaths)?.name || id })) - 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 declarations: string[] = [] - const references = Array.from(new Set(_references)) as string[] - await nuxt.callHook('prepare:types', { references }) + await nuxt.callHook('builder:generateApp') + await nuxt.callHook('prepare:types', { references, declarations }) const declarationPath = resolve(`${rootDir}/nuxt.d.ts`) const declaration = [ - '// Declarations auto generated by `nuxt prepare`. Please do not manually modify this file.', + '// This file is auto generated by `nuxt prepare`', + '// Please do not manually modify this file.', '', - ...references, + ...references.map(ref => `/// `), + ...declarations, + 'export {}', '' ].join('\n') @@ -55,3 +56,11 @@ export default defineNuxtCommand({ success('Generated', cyan(relative(process.cwd(), declarationPath))) } }) + +function renderAttrs (obj) { + return Object.entries(obj).map(e => renderAttr(e[0], e[1])).join(' ') +} + +function renderAttr (key, value) { + return value ? `${key}="${value}"` : '' +} diff --git a/packages/kit/src/module/container.ts b/packages/kit/src/module/container.ts index ba2c029e82..eafd8c0546 100644 --- a/packages/kit/src/module/container.ts +++ b/packages/kit/src/module/container.ts @@ -31,7 +31,15 @@ export function createModuleContainer (nuxt: Nuxt) { * If a fileName is not provided or the template is string, target file name defaults to * [dirName].[fileName].[pathHash].[ext]. */ - addTemplate, + addTemplate (template: string | NuxtTemplate) { + if (typeof template === 'string') { + template = { src: template } + } + if (template.write === undefined) { + template.write = true + } + return addTemplate(template) + }, /** * Registers a plugin template and prepends it to the plugins[] array. diff --git a/packages/kit/src/types/hooks.ts b/packages/kit/src/types/hooks.ts index fbabf01c25..3f71cc918f 100644 --- a/packages/kit/src/types/hooks.ts +++ b/packages/kit/src/types/hooks.ts @@ -32,6 +32,9 @@ type RenderResult = { preloadFiles: PreloadFile[] } +// https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html +export type TSReference = { types: string } | { path: string } + export interface NuxtHooks { // Don't break usage of untyped hooks [key: string]: (...args: any[]) => HookResult @@ -67,7 +70,7 @@ export interface NuxtHooks { '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 + 'prepare:types': (options: { references: TSReference[], declarations: string[] }) => HookResult // @nuxt/core 'ready': (nuxt: Nuxt) => HookResult diff --git a/packages/kit/src/types/nuxt.ts b/packages/kit/src/types/nuxt.ts index 2f871cc324..68b803df23 100644 --- a/packages/kit/src/types/nuxt.ts +++ b/packages/kit/src/types/nuxt.ts @@ -38,6 +38,8 @@ export interface NuxtTemplate { src?: string /** Provided compile option intead of src */ getContents?: (data: Record) => string | Promise + /** Write to filesystem */ + write?: boolean } export interface NuxtPlugin { diff --git a/packages/nuxt3/src/app.ts b/packages/nuxt3/src/app.ts index 49109a49bb..4f192727b1 100644 --- a/packages/nuxt3/src/app.ts +++ b/packages/nuxt3/src/app.ts @@ -3,7 +3,7 @@ import globby from 'globby' import lodashTemplate from 'lodash/template' import defu from 'defu' import { tryResolvePath, resolveFiles, Nuxt, NuxtApp, NuxtTemplate, normalizePlugin, normalizeTemplate } from '@nuxt/kit' -import { readFile } from 'fs-extra' +import { readFile, writeFile } from 'fs-extra' import * as templateUtils from './template.utils' export function createApp (nuxt: Nuxt, options: Partial = {}): NuxtApp { @@ -50,6 +50,10 @@ export async function generateApp (nuxt: Nuxt, app: NuxtApp) { if (process.platform === 'win32') { nuxt.vfs[fullPath.replace(/\//g, '\\')] = contents } + + if (template.write) { + await writeFile(fullPath, contents, 'utf8') + } })) await nuxt.callHook('app:templatesGenerated', app)