feat(kit): addTypeTemplate helper with auto-registration (#21331)

This commit is contained in:
Hebilicious 2023-06-10 04:24:03 +07:00 committed by GitHub
parent 31a1b98f3f
commit ee6869b1ba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 88 additions and 15 deletions

View File

@ -443,22 +443,40 @@ export default defineNuxtModule({
:: ::
#### Augmenting Types #### Adding Templates/Virtual Files
If your module should augment types handled by Nuxt, you can use the `prepare:types` hook to perform this operation. If you need to add a virtual file that can be imported into the user's app, you can use the `addTemplate` utility.
```js ```ts
import { defineNuxtModule, addTemplate, createResolver } from '@nuxt/kit' import { defineNuxtModule, addTemplate } from '@nuxt/kit'
export default defineNuxtModule({ export default defineNuxtModule({
setup (options, nuxt) { setup (options, nuxt) {
const { resolve } = createResolver(import.meta.url) // The file is added to Nuxt's internal virtual file system and can be imported from '#build/my-module-feature.mjs'
// Generating types to be injected
addTemplate({ addTemplate({
filename: 'my-module.d.ts', filename: 'my-module-feature.mjs',
getContents: () => { getContents: () => 'export const myModuleFeature = () => "hello world !"'
return `// Generated by my-module })
}
})
```
#### Adding Type Declarations
You might also want to add a type declaration to the user's project (for example, to augment an Nuxt interface
or provide a global type of your own). For this, Nuxt provides the `addTypeTemplate` utility that both
writes a template to disk and adds a reference to it in the generated `nuxt.d.ts` file that.
If your module should augment types handled by Nuxt, you can use `addTypeTemplate` to perform this operation:
```js
import { defineNuxtModule, addTemplate, addTypeTemplate } from '@nuxt/kit'
export default defineNuxtModule({
setup (options, nuxt) {
addTypeTemplate({
filename: 'types/my-module.d.ts',
getContents: () => `// Generated by my-module
interface MyModuleNitroRules { interface MyModuleNitroRules {
myModule?: { foo: 'bar' } myModule?: { foo: 'bar' }
} }
@ -467,13 +485,29 @@ export default defineNuxtModule({
interface NitroRouteConfig extends MyModuleNitroRules {} interface NitroRouteConfig extends MyModuleNitroRules {}
} }
export {}` export {}`
},
}) })
}
})
```
// Injecting previously generated types If you need more granular control, you can use the `prepare:types` hook to register a callback that will inject your types.
nuxt.hooks.hook('prepare:types', ({ references }) => {
references.push({ path: resolve(nuxt.options.buildDir, 'my-module.d.ts') }) ```ts
}) const template = addTemplate({ /* template options */ })
nuxt.hook('prepare:types', ({ references }) => {
references.push({ path: template.dst })
})
```
##### Updating Templates
If you need to update your templates/virtual files, you can leverage the `updateTemplates` utility like this :
```ts
nuxt.hook('builder:watch', async (event, path) => {
if (path.includes('my-module-feature.config')) {
// This will reload the template that you registered
updateTemplates({ filter: t => t.filename === 'my-module-feature.mjs' })
} }
}) })
``` ```

View File

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

View File

@ -23,6 +23,27 @@ export function addTemplate (_template: NuxtTemplate<any> | string) {
return template return template
} }
/**
* Renders given types using lodash template during build into the project buildDir
* and register them as types.
*/
export function addTypeTemplate (_template: NuxtTemplate<any>) {
const nuxt = useNuxt()
const template = addTemplate(_template)
if (!template.filename.endsWith('.d.ts')) {
throw new Error(`Invalid type template. Filename must end with .d.ts : "${template.filename}"`)
}
// Add template to types reference
nuxt.hook('prepare:types', ({ references }) => {
references.push({ path: template.dst })
})
return template
}
/** /**
* Normalize a nuxt template object * Normalize a nuxt template object
*/ */

View File

@ -1,3 +1,5 @@
import { addTypeTemplate } from 'nuxt/kit'
export default defineNuxtConfig({ export default defineNuxtConfig({
experimental: { experimental: {
typedPages: true typedPages: true
@ -33,6 +35,12 @@ export default defineNuxtConfig({
} }
}, },
modules: [ modules: [
function () {
addTypeTemplate({
filename: 'test.d.ts',
getContents: () => 'declare type Fromage = "cheese"'
})
},
'./modules/test', './modules/test',
[ [
'~/modules/example', '~/modules/example',

View File

@ -401,3 +401,12 @@ describe('composables inference', () => {
expectTypeOf<typeof bob>().toEqualTypeOf<boolean | Promise<boolean>>() expectTypeOf<typeof bob>().toEqualTypeOf<boolean | Promise<boolean>>()
}) })
}) })
describe('kit utilities', () => {
it('addTypeTemplate', () => {
// @ts-expect-error Fromage is 'cheese'
const _fake: Fromage = 'babybel'
const _fromage: Fromage = 'cheese'
})
})