分层与主题

Layer 能把一组 Nuxt 配置、组件、composable、服务端路由和资源打包成一个可复用的单元 —— 本地目录、npm 包,或 Git 源都行。可以把它当作“可继承的功能”。

为什么用 Layer?

  • 跨项目复用配置预设(nuxt.configapp.config)。
  • app/components/ 搭建组件库。
  • app/composables/ / app/utils/ 发布工具函数。
  • 发布带默认值的 Nuxt 模块套装。
  • 在 monorepo 里按领域拆分(DDD),每层只管自己那片。
  • 做主题和脚手架模板。

Layer 的目录结构跟 Nuxt 应用本身一模一样,写 layer 就像写个小号 Nuxt 项目。

两种引入方式

自动注册 ~~/layers/*

从 Nuxt 3.12 起,~~/layers/ 下的任何目录都会被自动注册:

my-app/
├── layers/
│   ├── base/
│   └── admin/
├── app/
└── nuxt.config.ts

Nuxt 也会暴露别名,例如 #layers/admin,指向该 layer 的 srcDir

显式 extends

项目外、npm 包、Git 上的 layer 用 extends

export default defineNuxtConfig({
  extends: [
    '../base',                                // 相对路径
    '@my-themes/awesome',                     // npm 包
    'github:my-themes/awesome#v1',            // Git 分支/tag
    ['github:my-themes/private-awesome',
      { auth: process.env.GITHUB_TOKEN }],    // 私有仓库
  ],
})

远程 layer 由 unjs/giget 下载,配置合并由 unjs/c12 负责。

也可以改 layer 的别名:

export default defineNuxtConfig({
  extends: [
    ['github:my-themes/awesome',
      { meta: { name: 'my-awesome-theme' } }],
  ],
})

优先级与覆盖顺序

多个 layer 定义同一个文件时,Nuxt 按以下优先级合并(高 → 低):

  1. 你自己项目的文件
  2. 自动扫描的 ~~/layers/*(字母序,Z > A
  3. extends 中的条目(靠前 > 靠后)

用数字前缀控制顺序:

layers/
├── 1.base/          # layer 中优先级最低
├── 2.features/
└── 3.admin/         # layer 中优先级最高

项目自身的文件始终优先,除非显式不覆盖。

编写一个 Layer

一个 layer 就是迷你版 Nuxt 项目。比如一个 admin layer:

layers/admin/
├── app/
│   ├── components/AdminNav.vue
│   └── composables/useAdmin.ts
├── nuxt.config.ts
└── app.config.ts
// layers/admin/nuxt.config.ts
export default defineNuxtConfig({
  css: ['~/assets/admin.css'],
})

Layer 中声明的一切都会合入消费端:组件自动导入、app/pages/ 下的路由加入路由表、routeRules 一并合并。

发布 Layer

  1. package.json 暴露 nuxt.config.ts

    {
      "name": "@me/nuxt-awesome",
      "type": "module",
      "exports": {
        ".": {
          "import": "./nuxt.config.ts"
        }
      }
    }
    
  2. 用户安装后注册:

    export default defineNuxtConfig({
      extends: ['@me/nuxt-awesome'],
    })
    
  3. 记得把对外 API 写进文档:暴露的组件、composable、模块选项、需要的环境变量。

Layer、Module、Plugin 的差别

  • Layer:整块的应用切片(页面、组件、composable、配置、服务端路由)。适合复用面向用户的功能
  • Module:程序式扩展 Nuxt 构建(注入别名、追加模块、修改配置)。适合配置其他 layer 或集成外部库。
  • Plugin:运行时代码(客户端/服务端),启动时执行。适合在运行时提供服务。

一个大产品往往三者都有:Layer 提供业务 UI,Module 把它自动接上,Plugin 做运行时胶水。

值得抄作业的场景

  • 同一个 monorepo 里把「营销站 → 文档站 → 产品应用」拆成三个 layer。
  • 把登录(中间件、登录页、composable)打包成可复用 layer。
  • 跨项目共用设计系统,用 app.config 下发 token。
  • 面向公司定制的内部主题,所有 Nuxt 项目都来继承。

Layer 让 Nuxt 从“框架”进化成“你们团队的平台”。

分層與主題

Layer 能把一組 Nuxt 設定、元件、composable、伺服器路由與資源封裝為可重用單元 —— 本地目錄、npm 套件、Git 來源皆可。可將之視為「可繼承的功能」。

為甚麼用 Layer?

  • 跨專案重用設定預設(nuxt.configapp.config)。
  • app/components/ 打造元件庫。
  • app/composables/ / app/utils/ 發佈工具函式。
  • 發佈帶預設值的 Nuxt 模組套裝。
  • 於 monorepo 中按領域拆分(DDD),每層各司其職。
  • 製作主題與起始模板。

Layer 的目錄結構與 Nuxt 應用本身一致,撰寫 layer 就像寫一個小型 Nuxt 專案。

兩種引入方式

自動註冊 ~~/layers/*

自 Nuxt 3.12 起,~~/layers/ 下任何目錄皆會自動註冊:

my-app/
├── layers/
│   ├── base/
│   └── admin/
├── app/
└── nuxt.config.ts

Nuxt 亦會曝露別名,例如 #layers/admin,指向該 layer 的 srcDir

明確 extends

專案外、npm 套件、Git 上的 layer 以 extends 引入:

export default defineNuxtConfig({
  extends: [
    '../base',                                // 相對路徑
    '@my-themes/awesome',                     // npm 套件
    'github:my-themes/awesome#v1',            // Git 分支/tag
    ['github:my-themes/private-awesome',
      { auth: process.env.GITHUB_TOKEN }],    // 私有儲存庫
  ],
})

遠端 layer 由 unjs/giget 下載,設定合併由 unjs/c12 負責。

亦可更改 layer 的別名:

export default defineNuxtConfig({
  extends: [
    ['github:my-themes/awesome',
      { meta: { name: 'my-awesome-theme' } }],
  ],
})

優先級與覆寫順序

多個 layer 定義同一檔案時,Nuxt 依以下優先級合併(高 → 低):

  1. 專案自身檔案
  2. 自動掃描的 ~~/layers/*(字母序,Z > A
  3. extends 條目(越前面越優先)

以數字前綴控制順序:

layers/
├── 1.base/          # layer 中優先級最低
├── 2.features/
└── 3.admin/         # layer 中優先級最高

專案自身檔案永遠優先,除非明確放棄覆寫。

撰寫 Layer

一個 layer 即是迷你 Nuxt 專案。以下是 admin layer 範例:

layers/admin/
├── app/
│   ├── components/AdminNav.vue
│   └── composables/useAdmin.ts
├── nuxt.config.ts
└── app.config.ts
// layers/admin/nuxt.config.ts
export default defineNuxtConfig({
  css: ['~/assets/admin.css'],
})

Layer 所宣告者都會合入消費端:元件自動匯入、app/pages/ 內路由加入路由表、routeRules 亦一併合併。

發佈 Layer

  1. package.json 曝露 nuxt.config.ts

    {
      "name": "@me/nuxt-awesome",
      "type": "module",
      "exports": {
        ".": {
          "import": "./nuxt.config.ts"
        }
      }
    }
    
  2. 使用者安裝後註冊:

    export default defineNuxtConfig({
      extends: ['@me/nuxt-awesome'],
    })
    
  3. 將對外 API 記錄於文件:曝露的元件、composable、模組選項、所需環境變數。

Layer、Module、Plugin 的差異

  • Layer:整塊應用切片(頁面、元件、composable、設定、伺服器路由)。適合重用面向使用者的功能
  • Module:程式化擴充 Nuxt 建置(注入別名、追加模組、修改設定)。適合設定其他 layer 或整合外部函式庫。
  • Plugin:執行時程式碼(客戶端/伺服器端),啟動時執行。適合於執行時提供服務。

大型產品常三者並用:Layer 提供業務 UI、Module 將其自動接入、Plugin 擔任執行時黏著劑。

值得借鑑的場景

  • 同一 monorepo 內把「行銷站 → 文件站 → 產品應用」拆成三個 layer。
  • 將登入(中介層、登入頁、composable)封裝為可重用 layer。
  • 跨專案共用設計系統,以 app.config 下發 token。
  • 面向公司自訂的內部主題,所有 Nuxt 專案皆繼承之。

Layer 讓 Nuxt 從「框架」升級為「你們團隊的平台」。

Layers

Layers let you extract a set of Nuxt config, components, composables, server routes, and assets into a reusable bundle — local to a repo, published on npm, or pulled from Git. Think of them as "features you can extend from".

Why layers?

  • Share reusable config presets across projects (nuxt.config, app.config).
  • Build component libraries with app/components/.
  • Publish utilities and composables via app/composables/ / app/utils/.
  • Ship Nuxt module bundles that come with defaults.
  • Split a monorepo by domain (DDD) — each layer owns its slice.
  • Create themes and starter templates.

Layers use the same directory structure as a Nuxt app, so authoring them feels just like writing one.

Two ways to include a layer

Auto-registered ~~/layers/*

Since Nuxt 3.12, any folder under ~~/layers/ is picked up automatically:

my-app/
├── layers/
│   ├── base/
│   └── admin/
├── app/
└── nuxt.config.ts

Nuxt also exposes named aliases — e.g. #layers/admin — to import from the layer's srcDir.

Explicit extends

Use extends for layers outside the project, npm packages, or Git sources:

export default defineNuxtConfig({
  extends: [
    '../base',                                // relative path
    '@my-themes/awesome',                     // npm package
    'github:my-themes/awesome#v1',            // git branch / tag
    ['github:my-themes/private-awesome',
      { auth: process.env.GITHUB_TOKEN }],    // private repo
  ],
})

Remote layers are fetched via unjs/giget; config merging is handled by unjs/c12.

You can rename a layer's alias inline:

export default defineNuxtConfig({
  extends: [
    ['github:my-themes/awesome',
      { meta: { name: 'my-awesome-theme' } }],
  ],
})

Priority & override order

When multiple layers define the same file, Nuxt merges with this precedence (high → low):

  1. Your project files
  2. Auto-scanned ~~/layers/* (alphabetical; Z > A)
  3. extends entries (first > last)

Prefix folders with numbers to control the order:

layers/
├── 1.base/          # lowest priority among layers
├── 2.features/
└── 3.admin/         # highest priority among layers

Your project files always win unless you explicitly opt out.

Authoring a layer

A layer is just a mini Nuxt project. Here's a tiny admin layer:

layers/admin/
├── app/
│   ├── components/AdminNav.vue
│   └── composables/useAdmin.ts
├── nuxt.config.ts
└── app.config.ts
// layers/admin/nuxt.config.ts
export default defineNuxtConfig({
  css: ['~/assets/admin.css'],
})

Everything the layer declares is merged into the consuming app: components auto-import, routes under app/pages/ add to the route tree, and routeRules are combined.

Publishing a layer

  1. package.json should expose the layer's nuxt.config.ts:

    {
      "name": "@me/nuxt-awesome",
      "type": "module",
      "exports": {
        ".": {
          "import": "./nuxt.config.ts"
        }
      }
    }
    
  2. Users install and register:

    export default defineNuxtConfig({
      extends: ['@me/nuxt-awesome'],
    })
    
  3. Document the public API: exposed components, composables, module options, and any required env vars.

Layer vs module vs plugin

  • Layer — a whole chunk of app (pages, components, composables, config, server routes). Use when you want to share user-facing features.
  • Module — programmatic extension of Nuxt's build (inject aliases, add modules, patch config). Use when you want to configure other layers or integrate an external library.
  • Plugin — runtime code that runs on startup (client and/or server). Use for providing services at runtime.

A big product often uses all three: a layer for domain UI, a module to auto-wire it, plugins for runtime glue.

Use cases worth copying

  • Marketing site → docs site → product app as three layers in one monorepo.
  • Auth kit (middleware, login pages, composables) as a reusable layer.
  • Design system shared between projects, with app.config tokens.
  • Internal theme tailored to your company, consumed by every Nuxt repo.

Layers are where Nuxt stops being a framework and starts being a platform for your team.