Маршрутизация
Маршрутизация на основе файлов
VitePress использует маршрутизацию на основе файлов, что означает, что сгенерированные HTML-страницы отображаются на основе структуры папок исходных файлов Markdown. Например, при следующей структуре папок:
.
├─ guide
│ ├─ getting-started.md
│ └─ index.md
├─ index.md
└─ prologue.md
Сгенерированные HTML-страницы будут выглядеть так:
index.md --> /index.html (доступна по адресу /)
prologue.md --> /prologue.html
guide/index.md --> /guide/index.html (доступна по адресу /guide/)
guide/getting-started.md --> /guide/getting-started.html
Полученный HTML можно разместить на любом веб-сервере, который может обслуживать статические файлы.
Корневая директория и директория с исходными файлами
В файловой структуре проекта VitePress есть два важных понятия: корень проекта и директория с исходными файлами.
Корень проекта
Корень проекта — это место, где VitePress будет пытаться искать специальный каталог .vitepress
. Директория .vitepress
— это зарезервированное место для конфигурационного файла VitePress, кэша dev-сервера, результатов сборки и дополнительного кода настройки темы.
Когда вы запускаете vitepress dev
или vitepress build
из командной строки, VitePress будет использовать текущий рабочий каталог в качестве корня проекта. Чтобы указать подкаталог в качестве корневого, нужно передать команде относительный путь. Например, если ваш проект VitePress находится в папке ./docs
, вам следует выполнить команду vitepress dev docs
:
.
├─ docs # корень проекта
│ ├─ .vitepress # директория с настройками
│ ├─ getting-started.md
│ └─ index.md
└─ ...
vitepress dev docs
В результате получится следующее сопоставление источника с HTML:
docs/index.md --> /index.html (доступна по адресу /)
docs/getting-started.md --> /getting-started.html
Директория с исходными файлами
Директория с исходными файлами — это место, где хранятся ваши исходные файлы Markdown. По умолчанию она совпадает с корнем проекта. Однако вы можете настроить её с помощью параметра srcDir
.
Опция srcDir
разрешается относительно корня проекта. Например, с помощью srcDir: 'src'
, ваша файловая структура будет выглядеть следующим образом:
. # корень проекта
├─ .vitepress # директория с настройками
└─ src # директория с исходными файлами
├─ getting-started.md
└─ index.md
Итоговое сопоставление исходного кода с HTML:
src/index.md --> /index.html (доступна по адресу /)
src/getting-started.md --> /getting-started.html
Связи между страницами
При создании ссылок между страницами можно использовать как абсолютные, так и относительные пути. Обратите внимание, что хотя расширения .md
и .html
будут работать, лучше всего опускать расширения файлов, чтобы VitePress мог генерировать конечные URL на основе вашего конфига.
<!-- Будут работать -->
[Первые шаги](./getting-started)
[Первые шаги](../guide/getting-started)
<!-- Не будут работать -->
[Первые шаги](./getting-started.md)
[Первые шаги](./getting-started.html)
Узнайте больше о ссылках на такие ресурсы, как изображения, в главе Обработка ресурсов.
Ссылки на страницы, не принадлежащие VitePress
Если вы хотите создать ссылку на страницу вашего сайта, которая не создана VitePress, вам нужно будет либо использовать полный URL-адрес (откроется в новой вкладке), либо явно указать цель:
Разметка
[Ссылка на pure.html](/pure.html){target="_self"}
Результат
Примечание
В ссылках Markdown к URL-адресу автоматически добавляется значение параметра base
. Это означает, что если вы хотите создать ссылку на страницу за пределами base
, вам понадобится что-то вроде ../../pure.html
в ссылке (разрешаемой браузером относительно текущей страницы).
Альтернативно можно напрямую использовать синтаксис тега ссылки:
<a href="/pure.html" target="_self">Ссылка на pure.html</a>
Создание чистого URL-адреса
Требуется поддержка сервера
Для обслуживания чистых URL-адресов с помощью VitePress требуется поддержка на стороне сервера.
По умолчанию VitePress разрешает входящие ссылки на URL-адреса, заканчивающиеся на .html
. Однако некоторые пользователи могут предпочесть «Чистые URL-адреса» без расширения .html
— например, example.com/path
вместо example.com/path.html
.
Некоторые серверы или хостинговые платформы (например, Netlify, Vercel, GitHub Pages) предоставляют возможность сопоставлять URL-адрес типа /foo
с /foo.html
, если он существует, без перенаправления:
- Страницы Netlify и GitHub поддерживают это по умолчанию.
- Vercel требует включить опцию
cleanUrls
вvercel.json
.
Если эта функция вам доступна, вы также можете включить собственную опцию конфигурации VitePress cleanUrls
, чтобы обеспечить следующее поведение:
- Входящие ссылки между страницами генерируются без расширения
.html
. - Если текущий путь заканчивается на
.html
, маршрутизатор выполнит перенаправление на стороне клиента на путь без расширений.
Однако если вы не можете настроить свой сервер с такой поддержкой, вам придётся вручную прибегнуть к следующей структуре каталогов:
.
├─ getting-started
│ └─ index.md
├─ installation
│ └─ index.md
└─ index.md
Перезапись маршрутов
Вы можете настроить сопоставление между структурой исходного каталога и создаваемыми страницами. Это полезно, когда у вас сложная структура проекта. Допустим, у вас есть монорепо с несколькими пакетами, и вы хотите поместить документацию вместе с исходными файлами, как это сделано здесь:
.
├─ packages
│ ├─ pkg-a
│ │ └─ src
│ │ ├─ foo.md
│ │ └─ index.md
│ └─ pkg-b
│ └─ src
│ ├─ bar.md
│ └─ index.md
И вы хотите, чтобы страницы VitePress генерировались следующим образом:
packages/pkg-a/src/index.md --> /pkg-a/index.html
packages/pkg-a/src/foo.md --> /pkg-a/foo.html
packages/pkg-b/src/index.md --> /pkg-b/index.html
packages/pkg-b/src/bar.md --> /pkg-b/bar.html
Этого можно добиться, настроив опцию rewrites
следующим образом:
// .vitepress/config.js
export default {
rewrites: {
'packages/pkg-a/src/index.md': 'pkg-a/index.md',
'packages/pkg-a/src/foo.md': 'pkg-a/foo.md',
'packages/pkg-b/src/index.md': 'pkg-b/index.md',
'packages/pkg-b/src/bar.md': 'pkg-b/bar.md'
}
}
Опция rewrites
также поддерживает динамические параметры маршрута. В приведённом выше примере, если у вас много пакетов, перечислять все пути было бы скучно. Учитывая, что все они имеют одинаковую структуру файлов, можно упростить конфигурацию следующим образом:
export default {
rewrites: {
'packages/:pkg/src/:slug*': ':pkg/:slug*'
}
}
Пути перезаписи компилируются с помощью пакета path-to-regexp
— обратитесь к его документации за более сложным синтаксисом.
Пути перезаписи компилируются с помощью пакета path-to-regexp
— обратитесь к его документации за более сложным синтаксисом.
rewrites
также может быть функцией, которая получает исходный путь и возвращает новый:
export default {
rewrites(id) {
return id.replace(/^packages\/([^/]+)\/src\//, '$1/')
}
}
Относительные ссылки с переписыванием
Когда переписывание включено, относительные ссылки должны быть основаны на переписанных путях. Например, чтобы создать относительную ссылку с packages/pkg-a/src/pkg-a-code.md
на packages/pkg-b/src/pkg-b-code.md
, нужно использовать:
[Ссылка на PKG B](../pkg-b/pkg-b-code)
Динамические маршруты
Вы можете создать множество страниц, используя один файл Markdown и динамические данные. Например, вы можете создать файл packages/[pkg].md
, который будет генерировать соответствующую страницу для каждого пакета в проекте. Здесь сегмент [pkg]
является параметром маршрута, который отличает каждую страницу от других.
Файл загрузчика путей
Поскольку VitePress — это генератор статических сайтов, возможные пути страниц должны быть определены во время сборки. Поэтому динамическая маршрутная страница должна сопровождаться файлом загрузчика путей. Для packages/[pkg].md
нам понадобится packages/[pkg].paths.js
(.ts
также поддерживается):
.
└─ packages
├─ [pkg].md # шаблон маршрута
└─ [pkg].paths.js # загрузчик путей маршрута
Загрузчик путей должен предоставлять объект с методом paths
в качестве экспорта по умолчанию. Метод paths
должен возвращать массив объектов со свойством params
. Для каждого из этих объектов будет создана соответствующая страница.
Дан следующий массив paths
:
// packages/[pkg].paths.js
export default {
paths() {
return [{ params: { pkg: 'foo' } }, { params: { pkg: 'bar' } }]
}
}
Сгенерированные HTML-страницы будут выглядеть так:
.
└─ packages
├─ foo.html
└─ bar.html
Несколько параметров
Динамический маршрут может содержать несколько параметров:
Структура файлов
.
└─ packages
├─ [pkg]-[version].md
└─ [pkg]-[version].paths.js
Загрузчик путей
export default {
paths: () => [
{ params: { pkg: 'foo', version: '1.0.0' } },
{ params: { pkg: 'foo', version: '2.0.0' } },
{ params: { pkg: 'bar', version: '1.0.0' } },
{ params: { pkg: 'bar', version: '2.0.0' } }
]
}
Результат
.
└─ packages
├─ foo-1.0.0.html
├─ foo-2.0.0.html
├─ bar-1.0.0.html
└─ bar-2.0.0.html
Динамически генерируемые пути
Модуль загрузчика путей запускается в Node.js и выполняется только во время сборки. Вы можете динамически генерировать массив путей, используя любые данные, как локальные, так и удалённые.
Генерация путей из локальных файлов:
import fs from 'fs'
export default {
paths() {
return fs.readdirSync('packages').map((pkg) => {
return { params: { pkg } }
})
}
}
Генерация путей из удалённых данных:
export default {
async paths() {
const pkgs = await (await fetch('https://my-api.com/packages')).json()
return pkgs.map((pkg) => {
return {
params: {
pkg: pkg.name,
version: pkg.version
}
}
})
}
}
Доступ к параметрам на странице
Вы можете использовать параметры для передачи дополнительных данных на каждую страницу. Файл маршрута Markdown может получить доступ к параметрам текущей страницы в выражениях Vue через глобальное свойство $params
:
- package name: {{ $params.pkg }}
- version: {{ $params.version }}
Вы также можете получить доступ к параметрам текущей страницы через Runtime API useData
. Это доступно как в файлах Markdown, так и в компонентах Vue:
<script setup>
import { useData } from 'vitepress'
// params — это ref-ссылка Vue
const { params } = useData()
console.log(params.value)
</script>
Рендеринг необработанного содержимого
Параметры, передаваемые странице, будут сериализованы в полезной нагрузке клиентского JavaScript, поэтому вам следует избегать передачи в параметрах больших объемов данных, например, необработанного Markdown или HTML-контента, полученного из удалённой CMS.
Вместо этого вы можете передавать такое содержимое на каждую страницу с помощью свойства content
каждого объекта path:
export default {
async paths() {
const posts = await (await fetch('https://my-cms.com/blog-posts')).json()
return posts.map((post) => {
return {
params: { id: post.id },
content: post.content // необработанный Markdown или HTML
}
})
}
}
Затем используйте следующий специальный синтаксис, чтобы отобразить содержимое как часть самого файла Markdown:
<!-- @content -->