能力越大,责任越重。虽然模块功能强大,但在编写模块时需要牢记一些最佳实践,以保持应用的高性能和良好的开发者体验。
如我们所见,Nuxt 模块可以是异步的。例如,你可能希望开发一个需要调用某些 API 或异步函数的模块。
但是,请谨慎处理异步行为,因为 Nuxt 会等待你的模块完成初始化后,才会进入下一个模块并启动开发服务器、构建流程等。更倾向于将耗时逻辑延迟到 Nuxt 钩子中执行。
Nuxt 模块应该对任何暴露的配置、插件、API、组合函数、组件或服务器路由提供明确的前缀,以避免与其他模块、Nuxt 内部或者用户定义的代码冲突。
理想情况下,使用模块名称作为前缀。例如,如果你的模块叫 nuxt-foo:
| 类型 | ❌ 不建议 | ✅ 推荐 |
|---|---|---|
| 组件 | <Button>,<Modal> | <FooButton>,<FooModal> |
| 组合函数 | useData(),useModal() | useFooData(),useFooModal() |
| 服务器路由 | /api/track,/api/data | /api/_foo/track,/api/_foo/data |
这对服务器路由尤为重要,因为像 /api/auth、/api/login、/api/user 这样的常用路径很可能已被应用占用。
请使用基于模块名的唯一前缀:
/api/_foo/...(使用下划线前缀)/_foo/...(非 API 路由)当你的模块需要执行一次性的初始化任务(如生成配置文件、设置数据库、安装依赖)时,使用生命周期钩子,而不是在主 setup 函数中执行这些逻辑。
import { addServerHandler, defineNuxtModule } from 'nuxt/kit'
import semver from 'semver'
export default defineNuxtModule({
meta: {
name: 'my-database-module',
version: '1.0.0',
},
async onInstall (nuxt) {
// 一次性设置:创建数据库 schema,生成配置文件等
await generateDatabaseConfig(nuxt.options.rootDir)
},
async onUpgrade (nuxt, options, previousVersion) {
// 处理特定版本的迁移
if (semver.lt(previousVersion, '1.0.0')) {
await migrateLegacyData()
}
},
setup (options, nuxt) {
// 每次构建时执行的常规设置逻辑
addServerHandler({ /* ... */ })
},
})
此模式避免了每次构建都执行不必要的工作,提升开发者体验。详情见 生命周期钩子文档。
Nuxt 原生支持 TypeScript,提供最佳开发体验。
暴露类型声明并使用 TypeScript 开发模块,即使用户不直接使用 TypeScript,也能从中获益。
Nuxt 依赖于原生 ESM。更多信息请参阅 原生 ES 模块。
建议在 README 文件中说明模块的使用:
链接至集成网站和文档总是一个好主意。
用你的模块在 StackBlitz 上制作一个最简示例,并附加到模块的 README 中,是个好习惯。
这不仅为潜在用户提供了快速简单的体验方式,也方便他们发问题时附带最小复现示例。
Nuxt、Nuxt Kit 及其它新工具均考虑了向前和向后兼容性。
请使用 “X for Nuxt” 而非 “X for Nuxt 3” 来避免生态碎片化,并优先用 meta.compatibility 来设置 Nuxt 版本约束。
模块起步模板自带一套默认工具和配置(如 ESLint 配置)。如果你计划开源你的模块,遵循这些默认设置可以确保你模块的代码风格与其他社区模块 保持一致,也更方便他人贡献代码。