编写 Nuxt Layers
Nuxt 提供了一个强大的系统,允许你扩展默认文件、配置等等。
Nuxt layers 是一个强大的特性,你可以用来在 monorepo 中、或从 git 仓库或 npm 包中,共享和复用部分 Nuxt 应用。layer 的结构与标准的 Nuxt 应用几乎完全相同,这使得它们易于编写和维护。
一个最小的 Nuxt layer 目录应该包含一个 nuxt.config.ts 文件,以表明它是一个 layer。
export default defineNuxtConfig({})
此外,layer 目录中的某些其它文件会被 Nuxt 自动扫描,并被扩展该 layer 的项目所使用。
app/components/*- 扩展默认组件app/composables/*- 扩展默认组合式函数app/layouts/*- 扩展默认布局app/middleware/*- 扩展默认中间件app/pages/*- 扩展默认页面app/plugins/*- 扩展默认插件app/utils/*- 扩展默认工具函数app/app.config.ts- 扩展默认 app configserver/*- 扩展默认服务端端点和中间件nuxt.config.ts- 扩展默认 nuxt config
基础示例
export default defineNuxtConfig({
extends: [
'./base',
],
})
Layer 优先级
当从多个 layer 扩展时,理解覆盖顺序很重要。当它们定义了相同的文件或组件时,优先级更高的 layer 会覆盖优先级更低的 layer。
优先级从高到低为:
- 你的项目文件 - 始终拥有最高的优先级
- 来自
~~/layers目录的自动扫描 layer - 按字母顺序排序(Z 的优先级高于 A) extends配置中的 layer - 第一个条目的优先级高于第二个
何时使用哪种
extends- 用于外部依赖(npm 包、远程仓库)或项目目录之外的 layer~~/layers目录 - 用于作为你项目一部分的本地 layer
~/layers/1.z-layer、~/layers/2.a-layer。这样 2.a-layer 的优先级会高于 1.z-layer。示例
export default defineNuxtConfig({
extends: [
// 项目外的本地 layer
'../base',
// NPM 包
'@my-themes/awesome',
// 远程仓库
'github:my-themes/awesome#v1',
],
})
如果你同时拥有 ~~/layers/custom,优先级顺序是:
- 你的项目文件(最高)
~~/layers/custom../base@my-themes/awesomegithub:my-themes/awesome#v1(最低)
这意味着你的项目文件会覆盖任何 layer,而 ~~/layers/custom 会覆盖 extends 中的任何内容。
启动模板
要开始,你可以使用 nuxt/starter/layer 模板 初始化一个 layer。这会创建一个你可以继续构建的基础结构。在终端中执行此命令来开始:
npm create nuxt -- --template layer nuxt-layer
按照 README 中的说明进行后续步骤。
发布 Layers
你可以通过远程源或 npm 包来发布和共享 layer。
Git 仓库
你可以使用 git 仓库来共享你的 Nuxt layer。一些例子:
export default defineNuxtConfig({
extends: [
// GitHub 远程源
'github:username/repoName',
// GitHub 位于 /base 目录下的远程源
'github:username/repoName/base',
// 使用 dev 分支的 GitHub 远程源
'github:username/repoName#dev',
// 使用 v1.0.0 tag 的 GitHub 远程源
'github:username/repoName#v1.0.0',
// GitLab 远程源示例
'gitlab:username/repoName',
// Bitbucket 远程源示例
'bitbucket:username/repoName',
],
})
GIGET_AUTH=<token> 来提供一个 token。GIGET_GITHUB_URL=<url> 或 GIGET_GITLAB_URL=<url> 环境变量提供它的 URL——或者直接在 nuxt.config 中用 auth 选项配置。node_modules/.c12/layer_name/node_modules/),你的包管理器无法访问。install: true 来实现。export default defineNuxtConfig({
extends: [
['github:username/repoName', { install: true }],
],
})
npm 包
你可以将 Nuxt layers 作为 npm 包发布,其中包含你想要扩展的文件和依赖。这允许你与他人共享你的配置、在多个项目中使用它,或者私有地使用它。
要从 npm 包扩展,你需要确保该模块已发布到 npm,并作为 devDependency 安装在用户的项目中。然后你就可以使用该模块名来扩展当前的 nuxt 配置:
export default defineNuxtConfig({
extends: [
// 带作用域的 Node 模块
'@scope/moduleName',
// 或者仅仅是模块名
'moduleName',
],
})
要将一个 layer 目录作为 npm 包发布,你需要确保 package.json 中填写了正确的属性。这能确保在发布包时包含相应的文件。
{
"name": "my-theme",
"version": "1.0.0",
"type": "module",
"main": "./nuxt.config.ts",
"dependencies": {},
"devDependencies": {
"nuxt": "^3.0.0"
}
}
确保 layer 中导入的任何依赖都被显式添加到 dependencies 中。nuxt 依赖,以及任何仅用于在发布前测试 layer 的依赖,应该保留在 devDependencies 字段中。
现在你可以继续将模块发布到 npm,无论是公开还是私有。
当将 layer 作为私有 npm 包发布时,你需要确保已登录,以向 npm 进行身份验证来下载该 node 模块。
提示
具名 Layer 别名
自动扫描的 layer(来自你的 ~~/layers 目录)会自动创建别名。例如,你可以通过 #layers/test 访问你的 ~~/layers/test layer。
如果你想为其它 layer 创建具名 layer 别名,你可以在该 layer 的配置中指定一个名称。
export default defineNuxtConfig({
$meta: {
name: 'example',
},
})
这会生成一个指向你 layer 的 #layers/example 别名。
相对路径与别名
在 layer 的组件和组合式函数中使用全局别名(如 ~/ 和 @/)导入时,请注意这些别名是相对于用户项目路径解析的。作为变通方案,你可以使用相对路径来导入它们,或者使用具名 layer 别名。
同样,在 layer 的 nuxt.config 文件中使用相对路径时(嵌套的 extends 除外),它们是相对于用户的项目解析的,而不是相对于 layer。作为变通方案,在 nuxt.config 中使用完整的解析路径:
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'),
],
})
从 Layers 中禁用模块 v4.3
当扩展一个 layer 时,你可能想禁用它包含的某些模块。你可以通过将模块的 config key 设为 false 来做到这一点,在你的 Nuxt 配置中。
export default defineNuxtConfig({
extends: ['./base-layer'],
// 通过将它们的 config key 设为 false 来禁用 layer 中的模块
image: false, // 禁用 @nuxt/image
pinia: false, // 禁用 @pinia/nuxt
})
@nuxt/image 的 image、@pinia/nuxt 的 pinia,以及 @nuxt/content 的 content。请查阅模块的文档了解它特定的 config key。这在以下情况很有用:
- 一个 layer 包含了你的项目中不需要的模块
- 你想使用与该 layer 提供的不同的实现
- 你需要在特定环境中禁用分析或其它模块
false 会阻止其 setup 函数运行,同时仍然为该模块生成类型。Nuxt 模块对多 Layer 的支持
你可以使用 Nuxt Kit 中的 getLayerDirectories 工具函数,为你的模块支持自定义的多 layer 处理。
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}`)
// ... 其它目录
}
},
})
注意:
- 数组中靠前的项优先级更高,会覆盖靠后的项
- 用户的项目是数组中的第一项
深入了解
配置加载和 extends 支持由 unjs/c12 处理,使用 unjs/defu 合并,远程 git 源由 unjs/giget 支持。查看文档和源代码以了解更多信息。
在 GitHub 上查看我们为 layer 支持带来更多改进的持续推进。