撰写 Nuxt 层

Nuxt 提供了一个强大的系统,允许你扩展默认文件、配置等更多内容。

Nuxt 层(layers)是一个强大的特性,允许你在 monorepo 中或从 git 仓库或 npm 包中共享和重用部分 Nuxt 应用。层的结构与标准的 Nuxt 应用几乎相同,这使得它们易于编写和维护。

Read more in Docs > 4 X > Getting Started > Layers.

一个最小的 Nuxt 层目录应包含一个 nuxt.config.ts 文件,以表明它是一个层。

base/nuxt.config.ts
export default defineNuxtConfig({})

此外,层目录中的某些其他文件会被 Nuxt 自动扫描并用于扩展该层的项目。

基本示例

nuxt.config.ts
export default defineNuxtConfig({
  extends: [
    './base',
  ],
})

层优先级

当从多个层扩展时,理解覆盖顺序非常重要。当它们定义相同文件或组件时,优先级更高的层会覆盖优先级较低的层。

优先级从高到低依次为:

  1. 你的项目文件 - 始终拥有最高优先级
  2. 来自 ~~/layers 目录的自动扫描层 - 按字母顺序排列(Z 优先级高于 A)
  3. extends 配置中的层 - 越靠前的条目优先级越高

何时使用各自方式

  • extends - 用于外部依赖(npm 包、远程仓库)或项目目录外的层
  • ~~/layers 目录 - 用于作为项目一部分的本地层
如果你需要控制自动扫描层的顺序,可以给它们加数字前缀:~/layers/1.z-layer~/layers/2.a-layer。这样 2.a-layer 会优先于 1.z-layer

例子

nuxt.config.ts
export default defineNuxtConfig({
  extends: [
    // 项目外的本地层
    '../base',
    // NPM 包
    '@my-themes/awesome',
    // 远程仓库
    'github:my-themes/awesome#v1',
  ],
})

如果你还拥有 ~~/layers/custom,优先级顺序为:

  • 你的项目文件(最高)
  • ~~/layers/custom
  • ../base
  • @my-themes/awesome
  • github:my-themes/awesome#v1(最低)

这意味着你的项目文件会覆盖所有层,而 ~~/layers/custom 会覆盖任何 extends 中的内容。

启动模板

要开始,你可以使用 nuxt/starter/layer 模板 初始化一个层。这将创建一个基本结构供你构建。在终端中执行以下命令以开始:

Terminal
npm create nuxt -- --template layer nuxt-layer

按照 README 中的说明进行下一步操作。

发布层

你可以通过远程源或 npm 包发布并共享层。

Git 仓库

你可以使用 git 仓库来共享你的 Nuxt 层。示例:

nuxt.config.ts
export default defineNuxtConfig({
  extends: [
    // GitHub 远程源
    'github:username/repoName',
    // GitHub 远程源 /base 目录
    'github:username/repoName/base',
    // GitHub dev 分支
    'github:username/repoName#dev',
    // GitHub v1.0.0 标签
    'github:username/repoName#v1.0.0',
    // GitLab 远程源示例
    'gitlab:username/repoName',
    // Bitbucket 远程源示例
    'bitbucket:username/repoName',
  ],
})
如果你想扩展一个私有的远程源,需要添加环境变量 GIGET_AUTH=<token> 来提供令牌。
如果你想从自托管的 GitHub 或 GitLab 实例扩展远程源,需要通过环境变量 GIGET_GITHUB_URL=<url>GIGET_GITLAB_URL=<url> 提供其 URL — 或在你的 nuxt.config 中直接使用 the auth option 进行配置。
请注意,如果你将远程源作为层来扩展,则无法在 Nuxt 之外访问其依赖项。例如,如果远程层依赖于一个 eslint 插件,该插件将无法在你的 eslint 配置中使用。这是因为这些依赖项会位于一个特殊位置(node_modules/.c12/layer_name/node_modules/),你的包管理器无法访问该位置。
使用 git 远程源时,如果某个层具有 npm 依赖且你希望安装它们,可以在层选项中通过指定 install: true 来实现。
nuxt.config.ts
export default defineNuxtConfig({
  extends: [
    ['github:username/repoName', { install: true }],
  ],
})

npm 包

你可以将 Nuxt 层作为一个包含要扩展的文件和依赖项的 npm 包发布。这允许你共享配置,在多个项目中使用它,或私下使用它。

要从 npm 包扩展,需要确保该模块已发布到 npm 并作为 devDependency 安装在使用者的项目中。然后你可以使用模块名称来扩展当前的 nuxt 配置:

nuxt.config.ts
export default defineNuxtConfig({
  extends: [
    // 带作用域的 Node 模块
    '@scope/moduleName',
    // 或直接模块名
    'moduleName',
  ],
})

要将层目录发布为 npm 包,请确保 package.json 中的属性已正确填写。这将确保在发布包时包含所需的文件。

package.json
{
  "name": "my-theme",
  "version": "1.0.0",
  "type": "module",
  "main": "./nuxt.config.ts",
  "dependencies": {},
  "devDependencies": {
    "nuxt": "^3.0.0"
  }
}
确保层中导入的任何依赖都已显式添加dependencies 中。nuxt 依赖以及仅用于在发布前测试层的任何内容,应保留在 devDependencies 字段中。

现在你可以继续将模块发布到 npm,公开或私有均可。

将层作为私有 npm 包发布时,需要确保你已登录,以便进行 npm 认证来下载该 node 模块。

提示

命名层别名

自动扫描的层(来自你的 ~~/layers 目录)会自动创建别名。例如,你可以通过 #layers/test 访问 ~~/layers/test 层。

如果你想为其他层创建命名别名,可以在该层的配置中指定一个名称。

nuxt.config.ts
export default defineNuxtConfig({
  $meta: {
    name: 'example',
  },
})

这将生成一个指向你层的 #layers/example 别名。

相对路径与别名

在层的组件和 composables 中使用全局别名(例如 ~/@/)进行导入时,请注意这些别名是相对于使用者项目路径解析的。作为解决方法,你可以使用相对路径来导入它们,或使用命名层别名。

另外,在层的 nuxt.config 文件中使用相对路径时(嵌套 extends 除外),这些路径相对于使用者项目而不是层本身解析。作为解决方法,在 nuxt.config 中使用完整解析后的路径:

nuxt.config.ts
import { fileURLToPath } from 'node:url'
import { dirname, join } from 'node:path'

const currentDir = dirname(fileURLToPath(import.meta.url))

export default defineNuxtConfig({
  css: [
    join(currentDir, './app/assets/main.css'),
  ],
})

Nuxt 模块的多层支持

您可以使用 Nuxt Kit 中的 getLayerDirectories 工具来支持您的模块的自定义多层处理。

modules/my-module.ts
import { defineNuxtModule, getLayerDirectories } from 'nuxt/kit'

export default defineNuxtModule({
  setup (_options, nuxt) {
    const layerDirs = getLayerDirectories()

    for (const [index, layer] of layerDirs.entries()) {
      console.log(`Layer ${index}:`)
      console.log(`  Root: ${layer.root}`)
      console.log(`  App: ${layer.app}`)
      console.log(`  Server: ${layer.server}`)
      console.log(`  Pages: ${layer.appPages}`)
      // ... other directories
    }
  },
})

注意:

  • 数组中的前面项具有更高的优先级,并覆盖后面的项
  • 用户的项目是数组中的第一项

深入了解

配置加载和扩展支持由 unjs/c12 处理,使用 unjs/defu 合并,并通过 unjs/giget 支持远程 git 源。查看文档和源代码以了解更多信息。

查看我们在 GitHub 上持续进行的关于层支持改进的开发工作。