编写 Nuxt 层

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

Nuxt 层是一个强大功能,您可以使用它在单体仓库(monorepo)中,或者从 git 仓库或 npm 包共享和复用部分 Nuxt 应用。层的结构几乎与标准的 Nuxt 应用完全相同,这使得编写和维护变得非常轻松。

阅读更多内容,请参见 文档 > 4 X > 入门指南 > 层

一个最简的 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: [
    // Local layer outside the project
    '../base',
    // NPM package
    '@my-themes/awesome',
    // Remote repository
    'github:my-themes/awesome#v1',
  ],
})

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

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

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

起步模板

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

终端
npm create nuxt -- --template layer nuxt-layer

请遵循 README 说明了解后续步骤。

发布层

你可以通过使用远程源或 npm 包来发布和共享层。

Git 仓库

你可以使用 git 仓库来共享你的 Nuxt 层。一些示例如下

nuxt.config.ts
export default defineNuxtConfig({
  extends: [
    // GitHub Remote Source
    'github:username/repoName',
    // GitHub Remote Source within /base directory
    'github:username/repoName/base',
    // GitHub Remote Source from dev branch
    'github:username/repoName#dev',
    // GitHub Remote Source from v1.0.0 tag
    'github:username/repoName#v1.0.0',
    // GitLab Remote Source example
    'gitlab:username/repoName',
    // Bitbucket Remote Source example
    'bitbucket:username/repoName',
  ],
})
我们建议将你的层的内容发布为 npm 包(公开或私有,例如通过 GitHub Packages),而不是依赖远程层。或者,你也可以直接将远程 git URL 作为依赖项添加
如果你想扩展一个私有远程源,你需要添加环境变量 GIGET_AUTH=<token> 来提供令牌。
如果你想扩展来自自建 GitHub 或 GitLab 实例的远程源,你需要通过环境变量 GIGET_GITHUB_URL=<url>GIGET_GITLAB_URL=<url> 提供其 URL,或者直接在你的 nuxt.config 中通过 auth 选项进行配置。
请记住,如果你将远程源作为层进行扩展,你将无法在 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 Module with scope
    '@scope/moduleName',
    // or just the module name
    '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 验证身份以便下载节点模块。

提示

命名层别名

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

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

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

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

相对路径与别名

当在层的组件和组合式函数中使用全局别名(如 ~/@/)进行导入时,请注意这些别名是相对于用户的项目路径进行解析的。作为一种变通方法,你可以使用相对路径来导入它们,或使用命名的层别名。

此外,当在层的 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'),
  ],
})

禁用层中的模块 v4.3

当扩展某个层时,你可能想要禁用它所包含的某些模块。你可以通过在你的 Nuxt 配置中将该模块的配置键设置为 false 来实现。

nuxt.config.ts
export default defineNuxtConfig({
  extends: ['./base-layer'],
  // Disable modules from the layer by setting their config key to false
  image: false, // Disables @nuxt/image
  pinia: false, // Disables @pinia/nuxt
})
配置键由各个模块定义。常见示例包括 @nuxt/image 对应的 image@pinia/nuxt 对应的 pinia,以及 @nuxt/content 对应的 content。请查阅模块的文档以获取其特定的配置键。

这在以下情况下非常有用:

  • 某个层包含了你在项目中不需要的模块
  • 你想使用与该层提供不同的实现
  • 你需要在特定环境中禁用分析或其他模块
你也可以使用此方法禁用你自己的项目中的模块 —— 不仅限于层中的模块。将模块的配置键设置为 false 将阻止其 setup 函数运行,同时仍会为该模块生成类型。

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
    }
  },
})

注意事项

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

深入了解

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

查看我们在 GitHub 上为层支持带来更多改进的持续开发进展。