Хуки и типы
Продвинутые приёмы: хуки, шаблоны и расширение типов.
Хуки жизненного цикла
Хуки позволяют вмешиваться почти во все этапы Nuxt. Модуль может подписаться через карту hooks или в setup.
import { addPlugin, createResolver, defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule({
// Подписка на хук `app:error` через карту `hooks`
hooks: {
'app:error': (err) => {
console.info(`Произошла ошибка: ${err}`)
},
},
setup (options, nuxt) {
// Программная подписка на хук `pages:extend`
nuxt.hook('pages:extend', (pages) => {
console.info(`Найдено страниц: ${pages.length}`)
})
},
})
Если модуль открывает вотчеры или долгоживущие ресурсы, закройте их на
close.import { defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule({
setup (options, nuxt) {
nuxt.hook('close', async (nuxt) => {
// Ваш код очистки здесь
})
},
})
Свои хуки
Модуль может объявлять и вызывать собственные хуки — удобно для расширяемости.
Если другие модули должны подписаться, вызывайте хук в modules:done: к этому моменту они уже успели зарегистрировать слушатели в setup.
// пример: my-module/module.ts
import { defineNuxtModule } from '@nuxt/kit'
export interface ModuleHooks {
'my-module:custom-hook': (payload: { foo: string }) => void
}
export default defineNuxtModule({
setup (options, nuxt) {
// Вызовите свой хук в `modules:done`
nuxt.hook('modules:done', async () => {
const payload = { foo: 'bar' }
await nuxt.callHook('my-module:custom-hook', payload)
})
},
})
Виртуальные файлы
Чтобы добавить виртуальный файл, импортируемый в приложении пользователя, используйте addTemplate.
import { addTemplate, defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule({
setup (options, nuxt) {
// Файл попадает во внутреннюю виртуальную ФС Nuxt; импорт из '#build/my-module-feature.mjs'
addTemplate({
filename: 'my-module-feature.mjs',
getContents: () => 'export const myModuleFeature = () => "привет, мир!"',
})
},
})
Для сервера — addServerTemplate.
import { addServerTemplate, defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule({
setup (options, nuxt) {
// Файл в виртуальной ФС Nitro; в серверном коде — импорт из 'my-server-module.mjs'
addServerTemplate({
filename: 'my-server-module.mjs',
getContents: () => 'export const myServerModule = () => "привет, мир!"',
})
},
})
Обновление шаблонов
При изменении конфигурации виртуальных файлов вызывайте updateTemplates:
nuxt.hook('builder:watch', (event, path) => {
if (path.includes('my-module-feature.config')) {
// Перезагрузит зарегистрированный шаблон
updateTemplates({ filter: t => t.filename === 'my-module-feature.mjs' })
}
})
Объявления типов
Чтобы добавить типы в проект пользователя (расширить интерфейсы Nuxt или объявить свои глобальные типы), используйте addTypeTemplate: шаблон попадает на диск и в ссылки генерируемого nuxt.d.ts.
Расширение типов Nitro:
import { addTemplate, addTypeTemplate, defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule({
setup (options, nuxt) {
addTypeTemplate({
filename: 'types/my-module.d.ts',
getContents: () => `// Сгенерировано модулем my-module
interface MyModuleNitroRules {
myModule?: { foo: 'bar' }
}
declare module 'nitropack/types' {
interface NitroRouteRules extends MyModuleNitroRules {}
interface NitroRouteConfig extends MyModuleNitroRules {}
}
export {}`,
})
},
})
Тоньше — хук prepare:types:
const template = addTemplate({ /* параметры шаблона */ })
nuxt.hook('prepare:types', ({ references }) => {
references.push({ path: template.dst })
})
Расширение tsconfig
Проще всего править опции Nuxt:
// расширить tsconfig.app.json
nuxt.options.typescript.tsConfig.include ??= []
nuxt.options.typescript.tsConfig.include.push(resolve('./augments.d.ts'))
// расширить tsconfig.shared.json
nuxt.options.typescript.sharedTsConfig.include ??= []
nuxt.options.typescript.sharedTsConfig.include.push(resolve('./augments.d.ts'))
// расширить tsconfig.node.json
nuxt.options.typescript.nodeTsConfig.include ??= []
nuxt.options.typescript.nodeTsConfig.include.push(resolve('./augments.d.ts'))
// расширить tsconfig.server.json
nuxt.options.nitro.typescript ??= {}
nuxt.options.nitro.typescript.tsConfig ??= {}
nuxt.options.nitro.typescript.tsConfig.include ??= []
nuxt.options.nitro.typescript.tsConfig.include.push(resolve('./augments.d.ts'))
Или хуки prepare:types и nitro:prepare:types:
nuxt.hook('prepare:types', ({ references, sharedReferences, nodeReferences }) => {
// контекст приложения
references.push({ path: resolve('./augments.d.ts') })
// общий контекст
sharedReferences.push({ path: resolve('./augments.d.ts') })
// контекст Node
nodeReferences.push({ path: resolve('./augments.d.ts') })
})
nuxt.hook('nitro:prepare:types', ({ references }) => {
// серверный контекст
references.push({ path: resolve('./augments.d.ts') })
})
exclude в tsconfig.json.Дополнение типов
Nuxt сам подхватывает каталоги модуля в нужных контекстах типов. Файлы объявлений кладите в каталог, соответствующий контексту, или расширьте tsconfig.
my-module/runtime/— контекст приложения (кромеruntime/server)my-module/runtime/server/— серверный контекстmy-module/— Node-контекст (кромеruntime/иruntime/server/)
-| my-module/ # контекст типов Node
---| runtime/ # контекст типов приложения
------| augments.app.d.ts
------| server/ # контекст типов сервера
---------| augments.server.d.ts
---| module.ts
---| augments.node.d.ts
Ограничения
Типы серверных маршрутов в контексте приложения
Серверные маршруты проверяются и по tsconfig.app.json, и по tsconfig.server.json, потому что Nuxt выводит типы ответов для $fetch и useFetch.
addServerTemplate и типы объявлены только в серверном tsconfig, при проверке в контексте приложения их не видно. Тогда типы нужно продублировать (или сделать видимыми) и в контексте приложения.