Skip to content
This repository has been archived by the owner on Apr 6, 2023. It is now read-only.

Commit

Permalink
feat(kit): add updateTemplates utility (#8413)
Browse files Browse the repository at this point in the history
  • Loading branch information
danielroe committed Oct 24, 2022
1 parent 708460d commit 5a88510
Show file tree
Hide file tree
Showing 8 changed files with 66 additions and 33 deletions.
1 change: 1 addition & 0 deletions docs/content/3.api/4.advanced/2.kit.md
Expand Up @@ -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)

- `addTemplate(templateOptions)`
- `updateTemplates({ filter?: ResolvedNuxtTemplate => boolean })`

### Nitro

Expand Down
9 changes: 9 additions & 0 deletions packages/kit/src/template.ts
Expand Up @@ -71,3 +71,12 @@ export function normalizeTemplate (template: NuxtTemplate<any> | string): Resolv

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)
}
15 changes: 11 additions & 4 deletions packages/nuxt/src/components/module.ts
@@ -1,6 +1,6 @@
import { statSync } from 'node:fs'
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 { distDir } from '../dirs'
import { componentsPluginTemplate, componentsTemplate, componentsTypeTemplate } from './templates'
Expand Down Expand Up @@ -122,12 +122,12 @@ export default defineNuxtModule<ComponentsOptions>({

nuxt.hook('vite:extendConfig', (config, { isClient }) => {
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) => {
for (const config of configs) {
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`)
}
})

Expand Down Expand Up @@ -173,7 +173,14 @@ export default defineNuxtModule<ComponentsOptions>({
}
const fPath = resolve(nuxt.options.srcDir, 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)
})
}
})

Expand Down
44 changes: 23 additions & 21 deletions packages/nuxt/src/core/app.ts
@@ -1,7 +1,7 @@
import { promises as fsp } from 'node:fs'
import { dirname, resolve } from 'pathe'
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 * as defaultTemplates from './templates'
Expand All @@ -16,7 +16,7 @@ export function createApp (nuxt: Nuxt, options: Partial<NuxtApp> = {}): 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
await resolveApp(nuxt, app)

Expand All @@ -31,25 +31,27 @@ export async function generateApp (nuxt: Nuxt, app: NuxtApp) {

// Compile templates into vfs
const templateContext = { utils: templateUtils, nuxt, app }
await Promise.all(app.templates.map(async (template) => {
const contents = await compileTemplate(template, templateContext)

const fullPath = template.dst || resolve(nuxt.options.buildDir, template.filename!)
nuxt.vfs[fullPath] = contents

const aliasPath = '#build/' + template.filename!.replace(/\.\w+$/, '')
nuxt.vfs[aliasPath] = contents

// In case a non-normalized absolute path is called for on Windows
if (process.platform === 'win32') {
nuxt.vfs[fullPath.replace(/\//g, '\\')] = contents
}

if (template.write) {
await fsp.mkdir(dirname(fullPath), { recursive: true })
await fsp.writeFile(fullPath, contents, 'utf8')
}
}))
await Promise.all((app.templates as Array<ReturnType<typeof normalizeTemplate>>)
.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!)
nuxt.vfs[fullPath] = contents

const aliasPath = '#build/' + template.filename!.replace(/\.\w+$/, '')
nuxt.vfs[aliasPath] = contents

// In case a non-normalized absolute path is called for on Windows
if (process.platform === 'win32') {
nuxt.vfs[fullPath.replace(/\//g, '\\')] = contents
}

if (template.write) {
await fsp.mkdir(dirname(fullPath), { recursive: true })
await fsp.writeFile(fullPath, contents, 'utf8')
}
}))

await nuxt.callHook('app:templatesGenerated', app)
}
Expand Down
6 changes: 5 additions & 1 deletion packages/nuxt/src/core/builder.ts
Expand Up @@ -23,7 +23,11 @@ export async function build (nuxt: Nuxt) {
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)
Expand Down
12 changes: 9 additions & 3 deletions packages/nuxt/src/imports/module.ts
@@ -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 { createUnimport, Import, scanDirExports, toImports, Unimport } from 'unimport'
import { ImportsOptions, ImportPresetWithDeprecation } from '@nuxt/schema'
Expand Down Expand Up @@ -77,7 +77,6 @@ export default defineNuxtModule<Partial<ImportsOptions>>({
nuxt.options.alias['#imports'] = join(nuxt.options.buildDir, 'imports')

// Transpile and injection
// @ts-ignore temporary disabled due to #746
if (nuxt.options.dev && options.global) {
// Add all imports to globalThis in development mode
addPluginTemplate({
Expand Down Expand Up @@ -117,10 +116,17 @@ export default defineNuxtModule<Partial<ImportsOptions>>({
})

// Watch composables/ directory
const templates = [
'types/imports.d.ts',
'imports.d.ts',
'imports.mjs'
]
nuxt.hook('builder:watch', async (_, path) => {
const _resolved = resolve(nuxt.options.srcDir, path)
if (composablesDirs.find(dir => _resolved.startsWith(dir))) {
await nuxt.callHook('builder:generateApp')
await updateTemplates({
filter: template => templates.includes(template.filename)
})
}
})

Expand Down
4 changes: 2 additions & 2 deletions packages/nuxt/src/pages/module.ts
@@ -1,5 +1,5 @@
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 { genString, genImport, genObjectFromRawEntries } from 'knitwork'
import escapeRE from 'escape-string-regexp'
Expand Down Expand Up @@ -48,7 +48,7 @@ export default defineNuxtModule({

const pathPattern = new RegExp(`(^|\\/)(${dirs.map(escapeRE).join('|')})/`)
if (event !== 'change' && path.match(pathPattern)) {
await nuxt.callHook('builder:generateApp')
await updateTemplates()
}
})

Expand Down
8 changes: 6 additions & 2 deletions packages/schema/src/types/hooks.ts
Expand Up @@ -6,7 +6,7 @@ import type { InlineConfig as ViteInlineConfig, ViteDevServer } from 'vite'
import type { Manifest } from 'vue-bundle-renderer'
import type { EventHandler } from 'h3'
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 { NuxtConfig, NuxtOptions } from './config'
import type { Nitro, NitroConfig } from 'nitropack'
Expand Down Expand Up @@ -66,6 +66,10 @@ export interface ImportPresetWithDeprecation extends ImportPreset {
names?: string[]
}

export interface GenerateAppOptions {
filter?: (template: ResolvedNuxtTemplate<any>) => boolean
}

export interface NuxtHooks {
// Kit
'kit:compatibility': (compatibility: NuxtCompatibility, issues: NuxtCompatibilityIssues) => HookResult
Expand All @@ -74,7 +78,7 @@ export interface NuxtHooks {
'app:resolve': (app: NuxtApp) => HookResult
'app:templates': (app: NuxtApp) => HookResult
'app:templatesGenerated': (app: NuxtApp) => HookResult
'builder:generateApp': () => HookResult
'builder:generateApp': (options?: GenerateAppOptions) => HookResult
'pages:extend': (pages: NuxtPage[]) => HookResult
'build:manifest': (manifest: Manifest) => HookResult
'server:devHandler': (handler: EventHandler) => HookResult
Expand Down

0 comments on commit 5a88510

Please sign in to comment.