Авторство слоёв Nuxt

Nuxt предоставляет мощную систему расширения файлов по умолчанию, конфигурации и многого другого.

Слои Nuxt — мощный инструмент для совместного использования и повторного применения частей Nuxt-приложения в монорепозитории, из git-репозитория или npm-пакета. Структура слоя почти совпадает со структурой обычного Nuxt-приложения, поэтому их удобно писать и поддерживать.

Узнать больше Docs > 4 X > Getting Started > Layers.

Минимальная директория слоя Nuxt должна содержать файл nuxt.config.ts, чтобы Nuxt распознал её как слой.

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

Кроме того, отдельные другие файлы в директории слоя автоматически сканируются и подключаются Nuxt для проекта, который расширяет этот слой.

  • app/components/* — расширяют компоненты по умолчанию
  • app/composables/* — расширяют композаблы по умолчанию
  • app/layouts/* — расширяют макеты по умолчанию
  • app/middleware/* — расширяют middleware по умолчанию
  • app/pages/* — расширяют страницы по умолчанию
  • app/plugins/* — расширяют плагины по умолчанию
  • app/utils/* — расширяют утилиты по умолчанию
  • app/app.config.ts — расширяют конфиг приложения по умолчанию
  • server/* — расширяют серверные эндпоинты и middleware по умолчанию
  • nuxt.config.ts- расширяют конфиг 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-репозиторий

Слой Nuxt можно вынести в git-репозиторий. Примеры:

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> с токеном доступа.
Для self-hosted GitHub или GitLab укажите URL через GIGET_GITHUB_URL=<url> или GIGET_GITLAB_URL=<url> — либо настройте напрямую опцией auth в nuxt.config.
Если слой подключается как удалённый источник, его зависимости вне 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. Затем укажите имя модуля в extends:

nuxt.config.ts
export default defineNuxtConfig({
  extends: [
    // Node-модуль со scope
    '@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 и можете скачать модуль.

Советы

Именованные алиасы слоёв

У автосканируемых слоёв (из ~~/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'),
  ],
})

Отключение модулей из слоёв

Расширяя слой, иногда нужно отключить входящие в него модули. Задайте для ключа конфигурации модуля значение false в конфиге Nuxt.

nuxt.config.ts
export default defineNuxtConfig({
  extends: ['./base-layer'],
  // Отключение модулей слоя: ключ конфига модуля = false
  image: false, // отключает @nuxt/image
  pinia: false, // отключает @pinia/nuxt
})
Ключ задаёт каждый модуль. Частые примеры: image для @nuxt/image, pinia для @pinia/nuxt, content для @nuxt/content. Смотрите документацию модуля.

Это полезно, когда:

  • в слое есть модули, которые вам не нужны
  • вы хотите другую реализацию, чем даёт слой
  • нужно отключить аналитику или другие модули в отдельных окружениях
Так же можно отключать модули в своём проекте, не только из слоёв. Ключ false останавливает setup-функцию модуля, но типы для модуля по-прежнему генерируются.

Поддержка нескольких слоёв в модулях Nuxt

Для своей логики работы со слоями используйте утилиту getLayerDirectories из Nuxt Kit.

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}`)
      // ... другие каталоги
    }
  },
})

Замечания:

  • Ранние элементы массива имеют более высокий приоритет и переопределяют последующие
  • Проект пользователя — первый элемент массива

Углубление

Загрузка конфигурации и extends обрабатываются unjs/c12, слияние — unjs/defu, удалённые git-источники — unjs/giget. Подробности — в документации и исходниках.

Следите за развитием поддержки слоёв на GitHub.