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)