Pages
Pages — это сущность, определяющая существующие страницы на сайте. Это самостоятельные сущности, которые никто больше не может переиспользовать (даже App импортирует их только для построения роутера).
Также важно отметить, что pages может быть частью модуля, но не обязательно. И в этом случае pages в модуле соблюдает все правила pages из FEOD. Более того вариант с pages в модуле является более предпочтительным и правильным. В это время вы можете оставить pages для страниц которые мучительно тяжело отнести к какому-либо модулю, например 404, about us и прочие на верхнем уровне.
Важно
Несмотря на сходство pages из FEOD и pages из FSD, они имеют определенные отличия.
Важность уровня
Данный уровень важен: в нём можно изучить, какие URL доступны на сайте и куда они ведут. Стоит отметить, что модули могут определять свои URL, поэтому это не единственный источник истины. Зато даже если вынести все страницы в модули, то в pages могут остаться страницы, которые мучительно тяжело отнести к какому-либо модулю, например 404, about us и прочие. Также выделение уровня страниц как самостоятельного важно потому, что это даёт нам возможность сформировать особые требования по работе с роутами. В базовой реализации речь идёт о файловом роутинге. Кроме того, pages, которые находятся в модулях, следуют тем же правилам, что и основной уровень, что даёт определённый уровень стандартизации.
Возможное альтернативное название:
views— привычнее для пользователей Vue Routerroutes— тоже неплохо объясняет суть: маршруты приложения. Неплохо подходит для использования на бэкенде
Роль Pages в FEOD
Pages играют ключевую роль в структуре FEOD:
- Определяют маршруты приложения — каждая страница соответствует конкретному URL
- Являются точками входа — страницы связывают URL с компонентами
- Изолированы от бизнес-логики — страницы не содержат сложной логики, они используют модули
- Не переиспользуются — страницы уникальны и не импортируются в других местах
Принцип работы
Если что-то имеет URL, то этот URL заводится здесь. Структура файлов в папке pages напрямую соответствует структуре URL-адресов приложения. Это делает навигацию по проекту интуитивно понятной — разработчик может легко найти страницу, зная её URL.
Правила заведения страниц
Важно
Использование файлового роутинга не является обязательным.
Также любые конвенции по именованию файлов не являются обязательными. Вы можете использовать любые имена файлов и папок, которые вам удобны. Здесь лишь дан пример как это можно сделать на основе существующих конвенций для Vue Router.
1. Соответствие файловой системы и роутинга
Страница располагается по принципам совпадения файловой системы и роутинга. Путь к файлу соответствует URL-адресу.
Примеры:
- URL:
/main/home→ Файл:pages/main/home.vue - URL:
/about→ Файл:pages/about.vue - URL:
/products/categories→ Файл:pages/products/categories.vue
2. Индексные страницы
Если URL оканчивается на /, то используется файл index.vue:
- URL:
/main/home/→ Файл:pages/main/home/index.vue - URL:
/→ Файл:pages/index.vue - URL:
/products/→ Файл:pages/products/index.vue
3. Динамические параметры
Если URL требует наличия параметра, то имя параметра берётся в квадратные скобки []:
- URL:
/posts/123445→ Файл:pages/posts/[id].vue - URL:
/users/42→ Файл:pages/users/[id].vue - URL:
/products/category/item-123→ Файл:pages/products/category/[itemId].vue
4. Множественные параметры
Если параметров несколько, то все они берутся в [] и разделяются подчёркиванием:
- URL:
/posts/12342_12123→ Файл:pages/posts/[userId]_[postId].vue - URL:
/users/42/posts/123→ Файл:pages/users/[userId]/posts/[postId].vue
5. Catch-all маршруты
Если нужно захватить все возможные продолжения, используется [...param]:
- URL:
/docs/guide/getting-started→ Файл:pages/docs/[...path].vue - URL:
/any/deep/nested/path→ Файл:pages/[...all].vue - URL:
/404или любой несуществующий → Файл:pages/[...404].vue
6. Named views (множественные компоненты)
Если нужно использовать несколько компонентов для одного роута (named views), то файлы именуются с точкой и именем view:
- URL:
/login→ Файлы:pages/login.form.vue(идёт в<router-view name="form">)pages/login.content.vue(идёт в<router-view name="content">)
7. Приватные модули страниц
Опционально
Данный пункт не является обязательным для реализации и остаётся на усмотрение разработчика.
Можно создавать приватные модули конкретной страницы с префиксом _:
- Для
/pages/home.vue→/pages/_home/index.ts—_homeстановится приватным модулем для страницы/pages/home - Для
/pages/home/→/pages/home/_home/index.ts—_homeстановится приватным модулем для страниц внутри/pages/home
Стоит отметить, что приватные модули более уместны для фреймворков с однофайловыми компонентами, где дробление на компоненты в рамках является затруднительным. Для остальных случаев лучше использовать обычные модули.
Старайтесь не злоупотреблять приватными модулями, так как они могут сделать код более запутанным и сложным для понимания. Вместо этого лучше использовать pages внутри модуля и свободно использовать части модуля на странице.
Структура Pages
Примеры реализации
Единый пример показывает все типы страниц в одном дереве и с одним набором файлов.
Выберите файл в дереве слева
Лучшие практики
1. Минимизируйте логику в страницах
Страницы должны быть тонкими и использовать модули для бизнес-логики:
<!-- OK Хорошо -->
<template>
<div>
<ProductList :products="products" />
</div>
</template>
<script setup lang="ts">
import { useProducts } from '@/modules/Products'
const { products } = useProducts()
</script>2. Используйте композаблы для переиспользуемой логики
Если логика может быть переиспользована, вынесите её в композабл модуля:
<script setup lang="ts">
import { usePost } from '@/modules/Posts'
import { useRoute } from 'vue-router'
const route = useRoute()
const { post, loading, error } = usePost(route.params.id as string)
</script>3. Обрабатывайте состояния загрузки и ошибок
Всегда обрабатывайте состояния загрузки и ошибок:
<template>
<div v-if="loading">Загрузка...</div>
<div v-else-if="error">{{ error }}</div>
<div v-else>
<!-- контент -->
</div>
</template>4. Используйте константы для роутов
Выносите имена роутов в /common/constants/routes.ts:
export const ROUTES = {
HOME: '/',
ABOUT: '/about',
PRODUCTS: {
LIST: '/products',
DETAIL: (id: string) => `/products/${id}`,
CATEGORY: (categoryId: string) => `/products/categories/${categoryId}`
}
}FAQ
Можно ли не создавать Pages вообще?
Если ваше приложение чётко бьётся на модули без проблем и позволяет очертить зоны ответственности, то решение убрать уровень Pages и использовать его только внутри соответствующих модулей имеет смысл и будет полностью корректным.
Как организовать вложенные маршруты?
Используйте структуру папок, соответствующую вложенности URL:
- URL:
/users/42/posts/123→pages/users/[userId]/posts/[postId].vue
Можно ли использовать layout в страницах?
Layouts должны быть определены в app/layouts и выбираться в роутере. Страницы не должны содержать логику выбора layout, если только вы не используете файловый роутинг и не имеете возможности выбрать layout прямо здесь.
Как обрабатывать 404?
Создайте catch-all маршрут pages/[...404].vue, который будет обрабатывать все несуществующие маршруты.