遵循最佳实践

使用这些指导原则构建高性能且易维护的 Nuxt 模块。

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

处理异步初始化

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

但是,请谨慎处理异步行为,因为 Nuxt 会等待你的模块完成初始化后,才会进入下一个模块并启动开发服务器、构建流程等。更倾向于将耗时逻辑延迟到 Nuxt 钩子中执行。

如果你的模块初始化耗时超过 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 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({ /* ... */ })
  },
})

此模式避免了每次构建都执行不必要的工作,提升开发者体验。详情见 生命周期钩子文档

友好支持 TypeScript

Nuxt 原生支持 TypeScript,提供最佳开发体验。

暴露类型声明并使用 TypeScript 开发模块,即使用户不直接使用 TypeScript,也能从中获益。

使用 ESM 语法

Nuxt 依赖于原生 ESM。更多信息请参阅 原生 ES 模块

为你的模块编写文档

建议在 README 文件中说明模块的使用:

  • 为什么使用此模块?
  • 如何使用此模块?
  • 这个模块的功能是什么?

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

提供示例演示

用你的模块在 StackBlitz 上制作一个最简示例,并附加到模块的 README 中,是个好习惯。

这不仅为潜在用户提供了快速简单的体验方式,也方便他们发问题时附带最小复现示例。

保持版本无关性

Nuxt、Nuxt Kit 及其它新工具均考虑了向前和向后兼容性。

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

遵守起步约定

模块起步模板自带一套默认工具和配置(如 ESLint 配置)。如果你计划开源你的模块,遵循这些默认设置可以确保你模块的代码风格与其他社区模块 保持一致,也更方便他人贡献代码。