Nuxt 3: ручная маршрутизация и иерархическая структура

Nuxt 3 теперь доступен для бета-тестирования, и мне не терпится познакомиться с его новыми функциями. Интересно, как там обстоят дела с одной очень важной вещью — иерархической структурой проекта.

Конечно, стандартная структура проекта хорошо подходит для простых проектов, но когда ваш проект растет и ваша команда растет, становится сложно управлять структурой стандартным способом. Папка ваших страниц становится большой, папка вашего компонента становится грязной.

Лучший способ справиться с такими проблемами — организовать проект иерархически. Основная идея проста — каждая папка имеет дело с одной частью домена вашего приложения, удерживая его страницы и компоненты, связанные вместе. Вы можете разделить папки вашего домена (которые мы называем модулями в нашей компании) на поддомены в зависимости от того, какой уровень детализации вам нужен.

К сожалению, по умолчанию Nuxt не допускает такого поведения.

Во второй версии мы использовали раздел router в nuxt.config.js, чтобы переопределить автоматическое сопоставление папок страниц, но похоже, что эта функция была удалена в третьей версии.

Или просто немного изменился.

Беглое изучение исходного кода показывает, что интерфейс NuxtHooks в схеме конфигурации nuxt включает два подозрительных хука: build:extendRoutes и pages:extend. Похоже, что один из них именно то, что мы ищем.

Сначала я попробовал «build:extendRoutes», но безрезультатно. Похоже, его вообще не вызывали.

Затем я взломал «pages:extend». Он получает список страниц нашего приложения в качестве первого аргумента, и каждая запись включает имя маршрута, строку URL и путь к файлу с компонентом. Что, если мы попытаемся добавить в этот список дополнительные записи?

export default defineNuxtConfig({
  hooks: {
    'pages:extend': (pages: any) => {
      routes.push({
        name: 'module-e-page',
        path: '/module-e/:id?',
        file: __dirname + '/modules/SomeModule/index.vue'
      })
    }
  }
})

И, наконец, это работает!

Теперь нам нужно кое-что сделать, чтобы сделать проект аккуратным и аккуратным.

Во-первых, я объявил интерфейс Route, так как пакет nuxt3 не имеет экспортированного члена для определения типа страниц (внутренне он использует NuxtPage).

export default interface Route {
  name: string,
  path: string,
  file: string
}

Во-вторых, я написал изолированный маршрутизатор для каждого модуля в проекте. Например, modules/ModuleE/router.ts:

import { Route } from '@/core'
export default function routes (routes: Route[]) {
  routes.push({
    name: 'module-e-index',
    path: '/module-e',
    file: __dirname + '/index.vue'
  })
  
  routes.push({
    name: 'module-e-page',
    path: '/module-e/:id?',
    file: __dirname + '/index.vue'
  })
}

Затем я создал router.ts прямо в корневой папке моего проекта. Здесь можно импортировать и вызывать маршрутизаторы из каждого модуля^

import { Route } from './core/'
import ModuleERoutes from './modules/ModuleE/router'
import ModuleYRoutes from './modules/ModuleY/router'
export default function router (routes: Route[]) {
  ModuleERoutes(routes)
  ModuleYRoutes(routes)
}

И, наконец, вызовите их все в nuxt.config.ts.

import { defineNuxtConfig } from 'nuxt3'
import { Route } from './core'
import routes from './router'
export default defineNuxtConfig({
  hooks: {
    'pages:extend': (pages: Route[]) => {
       routes(pages)
     }
  }
})

Таким образом, мы можем получить любую структуру проекта, какую захотим, несмотря на ограничения Nuxt.