feat(kit): add updateTemplates utility (#8413)

This commit is contained in:
Daniel Roe 2022-10-24 09:53:02 +01:00 committed by GitHub
parent 708460ddc8
commit 5a88510cb7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 62 additions and 29 deletions

View File

@ -68,6 +68,7 @@ description: Nuxt Kit provides composable utilities to help interacting with Nux
[source code](https://github.com/nuxt/framework/blob/main/packages/kit/src/template.ts) [source code](https://github.com/nuxt/framework/blob/main/packages/kit/src/template.ts)
- `addTemplate(templateOptions)` - `addTemplate(templateOptions)`
- `updateTemplates({ filter?: ResolvedNuxtTemplate => boolean })`
### Nitro ### Nitro

View File

@ -71,3 +71,12 @@ export function normalizeTemplate (template: NuxtTemplate<any> | string): Resolv
return template as ResolvedNuxtTemplate<any> return template as ResolvedNuxtTemplate<any>
} }
/**
* Trigger rebuilding Nuxt templates
*
* You can pass a filter within the options to selectively regenerate a subset of templates.
*/
export function updateTemplates (options?: { filter?: (template: ResolvedNuxtTemplate<any>) => boolean }) {
return useNuxt().hooks.callHook('builder:generateApp', options)
}

View File

@ -1,6 +1,6 @@
import { statSync } from 'node:fs' import { statSync } from 'node:fs'
import { relative, resolve } from 'pathe' import { relative, resolve } from 'pathe'
import { defineNuxtModule, resolveAlias, addTemplate, addPluginTemplate } from '@nuxt/kit' import { defineNuxtModule, resolveAlias, addTemplate, addPluginTemplate, updateTemplates } from '@nuxt/kit'
import type { Component, ComponentsDir, ComponentsOptions } from '@nuxt/schema' import type { Component, ComponentsDir, ComponentsOptions } from '@nuxt/schema'
import { distDir } from '../dirs' import { distDir } from '../dirs'
import { componentsPluginTemplate, componentsTemplate, componentsTypeTemplate } from './templates' import { componentsPluginTemplate, componentsTemplate, componentsTypeTemplate } from './templates'
@ -122,12 +122,12 @@ export default defineNuxtModule<ComponentsOptions>({
nuxt.hook('vite:extendConfig', (config, { isClient }) => { nuxt.hook('vite:extendConfig', (config, { isClient }) => {
const mode = isClient ? 'client' : 'server' const mode = isClient ? 'client' : 'server'
;(config.resolve!.alias as any)['#components'] = resolve(nuxt.options.buildDir, `components.${mode}.mjs`) ; (config.resolve!.alias as any)['#components'] = resolve(nuxt.options.buildDir, `components.${mode}.mjs`)
}) })
nuxt.hook('webpack:config', (configs) => { nuxt.hook('webpack:config', (configs) => {
for (const config of configs) { for (const config of configs) {
const mode = config.name === 'server' ? 'server' : 'client' const mode = config.name === 'server' ? 'server' : 'client'
;(config.resolve!.alias as any)['#components'] = resolve(nuxt.options.buildDir, `components.${mode}.mjs`) ; (config.resolve!.alias as any)['#components'] = resolve(nuxt.options.buildDir, `components.${mode}.mjs`)
} }
}) })
@ -173,7 +173,14 @@ export default defineNuxtModule<ComponentsOptions>({
} }
const fPath = resolve(nuxt.options.srcDir, path) const fPath = resolve(nuxt.options.srcDir, path)
if (componentDirs.find(dir => fPath.startsWith(dir.path))) { if (componentDirs.find(dir => fPath.startsWith(dir.path))) {
await nuxt.callHook('builder:generateApp') await updateTemplates({
filter: template => [
'components.plugin.mjs',
'components.d.ts',
'components.server.mjs',
'components.client.mjs'
].includes(template.filename)
})
} }
}) })

View File

@ -1,7 +1,7 @@
import { promises as fsp } from 'node:fs' import { promises as fsp } from 'node:fs'
import { dirname, resolve } from 'pathe' import { dirname, resolve } from 'pathe'
import defu from 'defu' import defu from 'defu'
import type { Nuxt, NuxtApp, NuxtPlugin, NuxtTemplate } from '@nuxt/schema' import type { Nuxt, NuxtApp, NuxtPlugin, NuxtTemplate, ResolvedNuxtTemplate } from '@nuxt/schema'
import { findPath, resolveFiles, normalizePlugin, normalizeTemplate, compileTemplate, templateUtils, tryResolveModule, resolvePath, resolveAlias } from '@nuxt/kit' import { findPath, resolveFiles, normalizePlugin, normalizeTemplate, compileTemplate, templateUtils, tryResolveModule, resolvePath, resolveAlias } from '@nuxt/kit'
import * as defaultTemplates from './templates' import * as defaultTemplates from './templates'
@ -16,7 +16,7 @@ export function createApp (nuxt: Nuxt, options: Partial<NuxtApp> = {}): NuxtApp
} as unknown as NuxtApp) as NuxtApp } as unknown as NuxtApp) as NuxtApp
} }
export async function generateApp (nuxt: Nuxt, app: NuxtApp) { export async function generateApp (nuxt: Nuxt, app: NuxtApp, options: { filter?: (template: ResolvedNuxtTemplate<any>) => boolean } = {}) {
// Resolve app // Resolve app
await resolveApp(nuxt, app) await resolveApp(nuxt, app)
@ -31,25 +31,27 @@ export async function generateApp (nuxt: Nuxt, app: NuxtApp) {
// Compile templates into vfs // Compile templates into vfs
const templateContext = { utils: templateUtils, nuxt, app } const templateContext = { utils: templateUtils, nuxt, app }
await Promise.all(app.templates.map(async (template) => { await Promise.all((app.templates as Array<ReturnType<typeof normalizeTemplate>>)
const contents = await compileTemplate(template, templateContext) .filter(template => !options.filter || options.filter(template))
.map(async (template) => {
const contents = await compileTemplate(template, templateContext)
const fullPath = template.dst || resolve(nuxt.options.buildDir, template.filename!) const fullPath = template.dst || resolve(nuxt.options.buildDir, template.filename!)
nuxt.vfs[fullPath] = contents nuxt.vfs[fullPath] = contents
const aliasPath = '#build/' + template.filename!.replace(/\.\w+$/, '') const aliasPath = '#build/' + template.filename!.replace(/\.\w+$/, '')
nuxt.vfs[aliasPath] = contents nuxt.vfs[aliasPath] = contents
// In case a non-normalized absolute path is called for on Windows // In case a non-normalized absolute path is called for on Windows
if (process.platform === 'win32') { if (process.platform === 'win32') {
nuxt.vfs[fullPath.replace(/\//g, '\\')] = contents nuxt.vfs[fullPath.replace(/\//g, '\\')] = contents
} }
if (template.write) { if (template.write) {
await fsp.mkdir(dirname(fullPath), { recursive: true }) await fsp.mkdir(dirname(fullPath), { recursive: true })
await fsp.writeFile(fullPath, contents, 'utf8') await fsp.writeFile(fullPath, contents, 'utf8')
} }
})) }))
await nuxt.callHook('app:templatesGenerated', app) await nuxt.callHook('app:templatesGenerated', app)
} }

View File

@ -23,7 +23,11 @@ export async function build (nuxt: Nuxt) {
await generateApp() await generateApp()
} }
}) })
nuxt.hook('builder:generateApp', generateApp) nuxt.hook('builder:generateApp', (options) => {
// Bypass debounce if we are selectively invalidating templates
if (options) { return _generateApp(nuxt, app, options) }
return generateApp()
})
} }
await nuxt.callHook('build:before', { nuxt }, nuxt.options.build) await nuxt.callHook('build:before', { nuxt }, nuxt.options.build)

View File

@ -1,4 +1,4 @@
import { addVitePlugin, addWebpackPlugin, defineNuxtModule, addTemplate, resolveAlias, useNuxt, addPluginTemplate, logger } from '@nuxt/kit' import { addVitePlugin, addWebpackPlugin, defineNuxtModule, addTemplate, resolveAlias, useNuxt, addPluginTemplate, logger, updateTemplates } from '@nuxt/kit'
import { isAbsolute, join, relative, resolve, normalize } from 'pathe' import { isAbsolute, join, relative, resolve, normalize } from 'pathe'
import { createUnimport, Import, scanDirExports, toImports, Unimport } from 'unimport' import { createUnimport, Import, scanDirExports, toImports, Unimport } from 'unimport'
import { ImportsOptions, ImportPresetWithDeprecation } from '@nuxt/schema' import { ImportsOptions, ImportPresetWithDeprecation } from '@nuxt/schema'
@ -77,7 +77,6 @@ export default defineNuxtModule<Partial<ImportsOptions>>({
nuxt.options.alias['#imports'] = join(nuxt.options.buildDir, 'imports') nuxt.options.alias['#imports'] = join(nuxt.options.buildDir, 'imports')
// Transpile and injection // Transpile and injection
// @ts-ignore temporary disabled due to #746
if (nuxt.options.dev && options.global) { if (nuxt.options.dev && options.global) {
// Add all imports to globalThis in development mode // Add all imports to globalThis in development mode
addPluginTemplate({ addPluginTemplate({
@ -117,10 +116,17 @@ export default defineNuxtModule<Partial<ImportsOptions>>({
}) })
// Watch composables/ directory // Watch composables/ directory
const templates = [
'types/imports.d.ts',
'imports.d.ts',
'imports.mjs'
]
nuxt.hook('builder:watch', async (_, path) => { nuxt.hook('builder:watch', async (_, path) => {
const _resolved = resolve(nuxt.options.srcDir, path) const _resolved = resolve(nuxt.options.srcDir, path)
if (composablesDirs.find(dir => _resolved.startsWith(dir))) { if (composablesDirs.find(dir => _resolved.startsWith(dir))) {
await nuxt.callHook('builder:generateApp') await updateTemplates({
filter: template => templates.includes(template.filename)
})
} }
}) })

View File

@ -1,5 +1,5 @@
import { existsSync } from 'node:fs' import { existsSync } from 'node:fs'
import { defineNuxtModule, addTemplate, addPlugin, addVitePlugin, addWebpackPlugin, findPath, addComponent } from '@nuxt/kit' import { defineNuxtModule, addTemplate, addPlugin, addVitePlugin, addWebpackPlugin, findPath, addComponent, updateTemplates } from '@nuxt/kit'
import { relative, resolve } from 'pathe' import { relative, resolve } from 'pathe'
import { genString, genImport, genObjectFromRawEntries } from 'knitwork' import { genString, genImport, genObjectFromRawEntries } from 'knitwork'
import escapeRE from 'escape-string-regexp' import escapeRE from 'escape-string-regexp'
@ -48,7 +48,7 @@ export default defineNuxtModule({
const pathPattern = new RegExp(`(^|\\/)(${dirs.map(escapeRE).join('|')})/`) const pathPattern = new RegExp(`(^|\\/)(${dirs.map(escapeRE).join('|')})/`)
if (event !== 'change' && path.match(pathPattern)) { if (event !== 'change' && path.match(pathPattern)) {
await nuxt.callHook('builder:generateApp') await updateTemplates()
} }
}) })

View File

@ -6,7 +6,7 @@ import type { InlineConfig as ViteInlineConfig, ViteDevServer } from 'vite'
import type { Manifest } from 'vue-bundle-renderer' import type { Manifest } from 'vue-bundle-renderer'
import type { EventHandler } from 'h3' import type { EventHandler } from 'h3'
import type { ModuleContainer } from './module' import type { ModuleContainer } from './module'
import type { NuxtTemplate, Nuxt, NuxtApp } from './nuxt' import type { NuxtTemplate, Nuxt, NuxtApp, ResolvedNuxtTemplate } from './nuxt'
import type { Preset as ImportPreset, Import } from 'unimport' import type { Preset as ImportPreset, Import } from 'unimport'
import type { NuxtConfig, NuxtOptions } from './config' import type { NuxtConfig, NuxtOptions } from './config'
import type { Nitro, NitroConfig } from 'nitropack' import type { Nitro, NitroConfig } from 'nitropack'
@ -66,6 +66,10 @@ export interface ImportPresetWithDeprecation extends ImportPreset {
names?: string[] names?: string[]
} }
export interface GenerateAppOptions {
filter?: (template: ResolvedNuxtTemplate<any>) => boolean
}
export interface NuxtHooks { export interface NuxtHooks {
// Kit // Kit
'kit:compatibility': (compatibility: NuxtCompatibility, issues: NuxtCompatibilityIssues) => HookResult 'kit:compatibility': (compatibility: NuxtCompatibility, issues: NuxtCompatibilityIssues) => HookResult
@ -74,7 +78,7 @@ export interface NuxtHooks {
'app:resolve': (app: NuxtApp) => HookResult 'app:resolve': (app: NuxtApp) => HookResult
'app:templates': (app: NuxtApp) => HookResult 'app:templates': (app: NuxtApp) => HookResult
'app:templatesGenerated': (app: NuxtApp) => HookResult 'app:templatesGenerated': (app: NuxtApp) => HookResult
'builder:generateApp': () => HookResult 'builder:generateApp': (options?: GenerateAppOptions) => HookResult
'pages:extend': (pages: NuxtPage[]) => HookResult 'pages:extend': (pages: NuxtPage[]) => HookResult
'build:manifest': (manifest: Manifest) => HookResult 'build:manifest': (manifest: Manifest) => HookResult
'server:devHandler': (handler: EventHandler) => HookResult 'server:devHandler': (handler: EventHandler) => HookResult