跳到主要内容

遵循最佳实践

使用这些指南构建高性能且可维护的 Nuxt 模块。

能力越大,责任越大。虽然模块功能强大,但在编写模块时请牢记以下一些最佳实践,以保持应用的高性能和良好的开发者体验。

处理异步 setup

如我们所见,Nuxt 模块可以是异步的。例如,你可能想开发一个需要请求某个 API 或调用异步函数的模块。

然而,要小心异步行为,因为 Nuxt 会等待你的模块 setup 完成之后,才会进入下一个模块并启动开发服务器、构建过程等。建议将耗时的逻辑推迟到 Nuxt 钩子中执行。

如果你的模块 setup 花费超过 1 秒,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 { isLess } from 'verkit'

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 (isLess(previousVersion, '1.0.0')) {
      await migrateLegacyData()
    }
  },
  setup (options, nuxt) {
    // 每次构建都会运行的常规 setup 逻辑
    addServerHandler({ /* ... */ })
  },
})

这种模式避免了每次构建时执行不必要的工作,并提供更好的开发者体验。更多细节请参阅生命周期钩子文档

对 TypeScript 友好

Nuxt 为获得最佳开发者体验,提供了一流的 TypeScript 集成。

暴露类型、并使用 TypeScript 开发模块,即使在不直接使用 TypeScript 的情况下也能让用户受益。

使用 ESM 语法

Nuxt 依赖原生 ESM。请阅读原生 ES 模块 以了解更多信息。

为你的模块编写文档

考虑在 readme 文件中说明模块的使用方法:

  • 为什么要使用这个模块?
  • 如何使用这个模块?
  • 这个模块做了什么?

链接到集成网站和文档总是一个好主意。

提供 Demo

用你的模块和一个 StackBlitz 创建一个最小复现示例,并将其添加到你的模块 readme 中,是一个好习惯。

这不仅为你的模块的潜在用户提供了一种快速简便的方式来试用模块,也为他们在遇到问题时向你发送最小复现示例提供了简便途径。

保持版本无关

Nuxt、Nuxt Kit 以及其它新工具在设计时都考虑了向前与向后兼容。

请使用「X for Nuxt」而非「X for Nuxt 3」,以避免生态碎片化,并优先使用 meta.compatibility 来设置 Nuxt 版本约束。

遵循启动模板约定

模块启动模板自带一组默认的工具和配置(例如 ESLint 配置)。如果你打算开源你的模块,遵循这些默认项能确保你的模块与其它社区模块 共享一致的代码风格,让其他人更容易参与贡献。