Merge remote-tracking branch 'origin/main' into chgeo-main

pull/4067/head
Divyansh Singh 11 months ago
commit 3de723a98a

@ -1,3 +1,22 @@
# [1.4.0](https://github.com/vuejs/vitepress/compare/v1.3.4...v1.4.0) (2024-10-07)
### Bug Fixes
- `vueRE` conflicting with `lineNoRE` ([#4247](https://github.com/vuejs/vitepress/issues/4247)) ([2ac64b8](https://github.com/vuejs/vitepress/commit/2ac64b8d4180f2a7c54fda57df7f3a0a52488d62))
- hmr not updating page data in rewritten paths and file path is wrong in mdit for dynamic routes ([c46e4b7](https://github.com/vuejs/vitepress/commit/c46e4b784ddb9ce3bd1cfcc3de1d1d676535cb5b)), closes [#4172](https://github.com/vuejs/vitepress/issues/4172)
- remove font synthesis in webfont mode, google fonts now support italic axis in inter ([1628918](https://github.com/vuejs/vitepress/commit/1628918f30b5602b83c51a2a8f4ec5e773cf7445))
- **theme:** change the order of CSS rules of `VPFlyout` ([#4225](https://github.com/vuejs/vitepress/issues/4225)) ([68150a6](https://github.com/vuejs/vitepress/commit/68150a6f3349c1741ed5683e3010d9ecea02f3a8)), closes [#4224](https://github.com/vuejs/vitepress/issues/4224)
- **theme:** respect custom tag prop in VPButton component ([#4185](https://github.com/vuejs/vitepress/issues/4185)) ([9c5d348](https://github.com/vuejs/vitepress/commit/9c5d348c034eb6773562c93cad699d287051aa7b))
### Features
- add `data-title` attribute for code group label tag ([#4152](https://github.com/vuejs/vitepress/issues/4152)) ([bc7271d](https://github.com/vuejs/vitepress/commit/bc7271d258047feb8a39c97ebc5e2a16bf899bb5))
- allow ignoring certain headers and their subtrees completely in outline ([3e11b6a](https://github.com/vuejs/vitepress/commit/3e11b6abf5fbe80c2bc733f590ab57c7b2cc06f2)), closes [#4171](https://github.com/vuejs/vitepress/issues/4171)
- **client:** add `onAfterPageLoad` hook in router ([#4126](https://github.com/vuejs/vitepress/issues/4126)) ([315c220](https://github.com/vuejs/vitepress/commit/315c22004993f6f1cbdbb59178e46745d8e505a6))
- support adding extra attributes to snippet imports (useful for twoslash) ([#4100](https://github.com/vuejs/vitepress/issues/4100)) ([e8f7dd1](https://github.com/vuejs/vitepress/commit/e8f7dd16f6139fdfd129b86caff4b6613dd1e887))
- **theme:** expose theme default VPLink & VPSocialLink(s) component ([#4178](https://github.com/vuejs/vitepress/issues/4178)) ([615e33b](https://github.com/vuejs/vitepress/commit/615e33bb24d5005574af971ffcf1f41d751a855c))
- trigger `onContentUpdated` on frontmatter-only changes too ([0db269a](https://github.com/vuejs/vitepress/commit/0db269a4c5d90ecf69f0219982cdf8f335e787ce))
## [1.3.4](https://github.com/vuejs/vitepress/compare/v1.3.3...v1.3.4) (2024-08-24) ## [1.3.4](https://github.com/vuejs/vitepress/compare/v1.3.3...v1.3.4) (2024-08-24)
### Bug Fixes ### Bug Fixes

@ -60,7 +60,7 @@ export const shared = defineConfig({
provider: 'algolia', provider: 'algolia',
options: { options: {
appId: '8J64VVRP8K', appId: '8J64VVRP8K',
apiKey: 'a18e2f4cc5665f6602c5631fd868adfd', apiKey: '52f578a92b88ad6abde815aae2b0ad7c',
indexName: 'vitepress', indexName: 'vitepress',
locales: { locales: {
...zhSearch, ...zhSearch,

@ -156,22 +156,24 @@ You can customize the mapping between the source directory structure and the gen
``` ```
. .
─ packages ─ packages
├─ pkg-a ├─ pkg-a
│ └─ src │ └─ src
│ │ ├─ pkg-a-code.ts │ ├─ foo.md
│ │ └─ pkg-a-docs.md │ └─ index.md
└─ pkg-b └─ pkg-b
└─ src └─ src
│ ├─ pkg-b-code.ts ├─ bar.md
│ └─ pkg-b-docs.md └─ index.md
``` ```
And you want the VitePress pages to be generated like this: And you want the VitePress pages to be generated like this:
``` ```
packages/pkg-a/src/pkg-a-docs.md --> /pkg-a/index.html packages/pkg-a/src/index.md --> /pkg-a/index.html
packages/pkg-b/src/pkg-b-docs.md --> /pkg-b/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
``` ```
You can achieve this by configuring the [`rewrites`](../reference/site-config#rewrites) option like this: You can achieve this by configuring the [`rewrites`](../reference/site-config#rewrites) option like this:
@ -180,8 +182,10 @@ You can achieve this by configuring the [`rewrites`](../reference/site-config#re
// .vitepress/config.js // .vitepress/config.js
export default { export default {
rewrites: { rewrites: {
'packages/pkg-a/src/pkg-a-docs.md': 'pkg-a/index.md', 'packages/pkg-a/src/index.md': 'pkg-a/index.md',
'packages/pkg-b/src/pkg-b-docs.md': 'pkg-b/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'
} }
} }
``` ```
@ -191,12 +195,22 @@ The `rewrites` option also supports dynamic route parameters. In the above examp
```ts ```ts
export default { export default {
rewrites: { rewrites: {
'packages/:pkg/src/(.*)': ':pkg/index.md' 'packages/:pkg/src/:slug*': ':pkg/:slug*'
} }
} }
``` ```
The rewrite paths are compiled using the `path-to-regexp` package - consult [its documentation](https://github.com/pillarjs/path-to-regexp#parameters) for more advanced syntax. The rewrite paths are compiled using the `path-to-regexp` package - consult [its documentation](https://github.com/pillarjs/path-to-regexp/tree/6.x#parameters) for more advanced syntax.
`rewrites` can also be a function that receives the original path and returns the new path:
```ts
export default {
rewrites(id) {
return id.replace(/^packages\/([^/]+)\/src\//, '$1/')
}
}
```
::: warning Relative Links with Rewrites ::: warning Relative Links with Rewrites

@ -296,7 +296,7 @@ new Crawler({
lvl1: '.content h1', lvl1: '.content h1',
content: '.content p, .content li', content: '.content p, .content li',
lvl0: { lvl0: {
selectors: '', selectors: 'section.has-active div h2',
defaultValue: 'Documentation' defaultValue: 'Documentation'
}, },
lvl2: '.content h2', lvl2: '.content h2',

@ -103,8 +103,8 @@ interface Router {
*/ */
onBeforeRouteChange?: (to: string) => Awaitable<void | boolean> onBeforeRouteChange?: (to: string) => Awaitable<void | boolean>
/** /**
* Called before the page component is loaded (after the history state is * Called before the page component is loaded (after the history state is updated).
* updated). Return `false` to cancel the navigation. * Return `false` to cancel the navigation.
*/ */
onBeforePageLoad?: (to: string) => Awaitable<void | boolean> onBeforePageLoad?: (to: string) => Awaitable<void | boolean>
/** /**

@ -289,7 +289,7 @@ new Crawler({
lvl1: '.content h1', lvl1: '.content h1',
content: '.content p, .content li', content: '.content p, .content li',
lvl0: { lvl0: {
selectors: '', selectors: 'section.has-active div h2',
defaultValue: 'Documentation' defaultValue: 'Documentation'
}, },
lvl2: '.content h2', lvl2: '.content h2',

@ -296,7 +296,7 @@ new Crawler({
lvl1: '.content h1', lvl1: '.content h1',
content: '.content p, .content li', content: '.content p, .content li',
lvl0: { lvl0: {
selectors: '', selectors: 'section.has-active div h2',
defaultValue: 'Documentation' defaultValue: 'Documentation'
}, },
lvl2: '.content h2', lvl2: '.content h2',

@ -289,7 +289,7 @@ new Crawler({
lvl1: '.content h1', lvl1: '.content h1',
content: '.content p, .content li', content: '.content p, .content li',
lvl0: { lvl0: {
selectors: '', selectors: 'section.has-active div h2',
defaultValue: 'Documentation' defaultValue: 'Documentation'
}, },
lvl2: '.content h2', lvl2: '.content h2',

@ -10,7 +10,7 @@
Вы можете ссылаться на статические ресурсы в ваших файлах разметки, компоненты `*.vue` в теме, стили и обычные файлы `.css`, используя абсолютные пути (основанные на корне проекта) или относительные пути (основанные на вашей файловой системе). Последнее похоже на поведение, к которому вы привыкли, если использовали Vite, Vue CLI или `file-loader` в webpack. Вы можете ссылаться на статические ресурсы в ваших файлах разметки, компоненты `*.vue` в теме, стили и обычные файлы `.css`, используя абсолютные пути (основанные на корне проекта) или относительные пути (основанные на вашей файловой системе). Последнее похоже на поведение, к которому вы привыкли, если использовали Vite, Vue CLI или `file-loader` в webpack.
Распространенные типы файлов изображений, мультимедиа и шрифтов определяются и включаются в качестве ресурсов автоматически. Распространённые типы файлов изображений, мультимедиа и шрифтов определяются и включаются в качестве ресурсов автоматически.
::: tip Связанные файлы не рассматриваются как ресурсы ::: tip Связанные файлы не рассматриваются как ресурсы
PDF-файлы или другие документы, на которые есть ссылки в файлах с разметкой, не рассматриваются автоматически как ресурсы. Чтобы сделать связанные файлы доступными, вы должны вручную поместить их в каталог [`public`](#the-public-directory) вашего проекта. PDF-файлы или другие документы, на которые есть ссылки в файлах с разметкой, не рассматриваются автоматически как ресурсы. Чтобы сделать связанные файлы доступными, вы должны вручную поместить их в каталог [`public`](#the-public-directory) вашего проекта.

@ -175,7 +175,7 @@ export default {
} }
``` ```
**Types** **Типы**
```ts ```ts
interface ContentOptions<T = ContentData[]> { interface ContentOptions<T = ContentData[]> {
@ -226,7 +226,7 @@ interface ContentOptions<T = ContentData[]> {
## Загрузчики типизированных данных {#typed-data-loaders} ## Загрузчики типизированных данных {#typed-data-loaders}
При использовании TypeScript вы можете ввести свой загрузчик и экспортировать `data` следующим образом: При использовании TypeScript можно ввести свой загрузчик и экспортировать `data` следующим образом:
```ts ```ts
import { defineLoader } from 'vitepress' import { defineLoader } from 'vitepress'

@ -4,7 +4,7 @@ outline: deep
# Развёртывание вашего сайта VitePress {#deploy-your-vitepress-site} # Развёртывание вашего сайта VitePress {#deploy-your-vitepress-site}
Следующие руководства основаны на некоторых общих предположениях: Следующие инструкции основаны на некоторых общих предположениях:
- Сайт VitePress находится в директории `docs` вашего проекта. - Сайт VitePress находится в директории `docs` вашего проекта.
- Вы используете выходной каталог сборки по умолчанию (`.vitepress/dist`). - Вы используете выходной каталог сборки по умолчанию (`.vitepress/dist`).
@ -19,7 +19,7 @@ outline: deep
} }
``` ```
## Создание и локальное тестирование {#build-and-test-locally} ## Сборка и локальное тестирование {#build-and-test-locally}
1. Выполните эту команду, чтобы собрать документацию: 1. Выполните эту команду, чтобы собрать документацию:
@ -33,9 +33,9 @@ outline: deep
$ npm run docs:preview $ npm run docs:preview
``` ```
Команда `preview` загрузит локальный статический веб-сервер, который будет обслуживать выходной каталог `.vitepress/dist` по адресу `http://localhost:4173`. Вы можете использовать это, чтобы убедиться, что всё выглядит хорошо, прежде чем отправлять в производство. Команда `preview` загрузит локальный статический веб-сервер, который будет обслуживать выходной каталог `.vitepress/dist` по адресу `http://localhost:4173`. Вы можете использовать его для теста, чтобы убедиться, что всё выглядит хорошо, прежде чем отправлять в производство.
3. Вы можете настроить порт сервера, передав `--port` в качестве аргумента. 3. Можно указать порт сервера, передав `--port` в качестве аргумента.
```json ```json
{ {
@ -55,11 +55,11 @@ outline: deep
## Заголовки кэша HTTP {#http-cache-headers} ## Заголовки кэша HTTP {#http-cache-headers}
Если вы контролируете HTTP-заголовки на своем рабочем сервере, вы можете настроить заголовки `cache-control` для достижения лучшей производительности при повторных посещениях. Если вы контролируете HTTP-заголовки на своем рабочем сервере, можно настроить заголовки `cache-control` для достижения лучшей производительности при повторных посещениях.
В производственной сборке используются хэшированные имена файлов для статических ресурсов (JavaScript, CSS и другие импортированные ресурсы, не находящиеся в `public`). Если вы просмотрите предварительную версию с помощью сетевой вкладки devtools вашего браузера, вы увидите файлы типа `app.4f283b18.js`. В производственной сборке используются хэшированные имена файлов для статических ресурсов (JavaScript, CSS и другие импортированные ресурсы, не находящиеся в `public`). Если вы просмотрите предварительную версию с помощью вкладки «Network» («Сеть») инструментов разработчика вашего браузера, вы увидите файлы типа `app.4f283b18.js`.
Этот хэш `4f283b18` генерируется из содержимого этого файла. Один и тот же хэшированный URL гарантированно обслуживает одно и то же содержимое файла — если содержимое меняется, то и URL тоже. Это означает, что вы можете смело использовать самые сильные заголовки кэша для этих файлов. Все такие файлы будут помещены в каталог `assets/` в выходном каталоге, поэтому вы можете настроить для них следующий заголовок: Этот хэш `4f283b18` генерируется из содержимого этого файла. Один и тот же хэшированный URL гарантированно обслуживает одно и то же содержимое файла — если содержимое меняется, то и URL тоже. Это означает, что можно смело использовать самые сильные настройки кэширования для этих файлов. Все такие файлы будут помещены в каталог `assets/` в выходном каталоге, поэтому вы можете настроить для них следующий заголовок:
``` ```
Cache-Control: max-age=31536000,immutable Cache-Control: max-age=31536000,immutable
@ -198,7 +198,7 @@ Cache-Control: max-age=31536000,immutable
### GitLab Pages {#gitlab-pages} ### GitLab Pages {#gitlab-pages}
1. Установите значение `../public` для параметра `outDir` в конфигурации VitePress. Настройте опцию `base` на `'/<репозиторий>/'`, если вы хотите развернуть ваш проект по адресу `https://<имя пользователя>.gitlab.io/<репозиторий>/`. Вам не нужна опция `base`, если вы выполняете развёртывание на личном домене, страницах пользователя или группы или если в GitLab включен параметр «Использовать уникальный домен». 1. Установите значение `../public` для параметра `outDir` в конфигурации VitePress. Настройте опцию `base` на `'/<репозиторий>/'`, если вы хотите развернуть ваш проект по адресу `https://<имя пользователя>.gitlab.io/<репозиторий>/`. Вам не нужна опция `base`, если вы выполняете развёртывание на личном домене, страницах пользователя или группы, или если в GitLab включен параметр «Использовать уникальный домен».
2. Создайте файл с именем `.gitlab-ci.yml` в корне вашего проекта с приведённым ниже содержимым. Это позволит создавать и развёртывать ваш сайт каждый раз, когда вы вносите изменения в его содержимое: 2. Создайте файл с именем `.gitlab-ci.yml` в корне вашего проекта с приведённым ниже содержимым. Это позволит создавать и развёртывать ваш сайт каждый раз, когда вы вносите изменения в его содержимое:

@ -4,7 +4,7 @@ outline: deep
# Расширение темы по умолчанию {#extending-the-default-theme} # Расширение темы по умолчанию {#extending-the-default-theme}
Тема VitePress по умолчанию оптимизирована для документации и может быть настроена по своему усмотрению. Полный список опций можно найти в главе [Настройки темы по умолчанию](../reference/default-theme-config). Тема VitePress по умолчанию оптимизирована для документации и может быть настроена по вашему усмотрению. Полный список опций можно найти в главе [Настройки темы по умолчанию](../reference/default-theme-config).
Однако есть ряд случаев, когда одной лишь конфигурации будет недостаточно. Например: Однако есть ряд случаев, когда одной лишь конфигурации будет недостаточно. Например:
@ -12,7 +12,7 @@ outline: deep
2. Вам нужно изменить экземпляр приложения Vue, например, чтобы зарегистрировать глобальные компоненты; 2. Вам нужно изменить экземпляр приложения Vue, например, чтобы зарегистрировать глобальные компоненты;
3. Вам нужно внедрить пользовательский контент в тему через слоты макета. 3. Вам нужно внедрить пользовательский контент в тему через слоты макета.
Эти расширенные настройки потребуют использования пользовательской темы, которая «расширяет» тема по умолчанию. Эти расширенные настройки потребуют использования пользовательской темы, которая «расширяет» тему по умолчанию.
::: tip СОВЕТ ::: tip СОВЕТ
Прежде чем приступить к работе, обязательно прочитайте главу [Пользовательская тема](./custom-theme), чтобы понять, как работают пользовательские темы. Прежде чем приступить к работе, обязательно прочитайте главу [Пользовательская тема](./custom-theme), чтобы понять, как работают пользовательские темы.
@ -124,7 +124,7 @@ export default {
} satisfies Theme } satisfies Theme
``` ```
Поскольку мы используем Vite, вы также можете использовать [глобальную функцию импорта](https://vitejs.dev/guide/features.html#glob-import) Vite для автоматической регистрации каталога компонентов. Поскольку мы используем Vite, можно применять [глобальную функцию импорта](https://vitejs.dev/guide/features.html#glob-import) Vite для автоматической регистрации каталога компонентов.
## Слоты макета {#layout-slots} ## Слоты макета {#layout-slots}

@ -11,7 +11,7 @@ editLink: true
--- ---
``` ```
Многие параметры конфигурации сайта или темы по умолчанию имеют соответствующие опции в блоке метаданных. Вы можете использовать метаданные, чтобы переопределить определённое поведение только для текущей страницы. Подробности см. в [Справочнике по настройке метаданных](../reference/frontmatter-config). Многие параметры конфигурации сайта или темы по умолчанию имеют соответствующие опции в блоке метаданных. Вы можете использовать метаданные, чтобы переопределить заданное поведение только для текущей страницы. Подробности см. в [Справочнике по настройке метаданных](../reference/frontmatter-config).
Вы также можете определить собственные метаданные, которые будут использоваться в динамических выражениях Vue на странице. Вы также можете определить собственные метаданные, которые будут использоваться в динамических выражениях Vue на странице.

@ -63,7 +63,7 @@ VitePress — это пакет, предназначенный только д
### Мастер настройки {#setup-wizard} ### Мастер настройки {#setup-wizard}
VitePress поставляется с мастером настройки командной строки, который поможет вам создать базовый проект. После установки запустите мастер, запустив его: VitePress поставляется с мастером настройки командной строки, который поможет вам создать базовый проект. После установки запустите мастер, выполнив команду:
::: code-group ::: code-group
@ -133,13 +133,13 @@ export default {
} }
``` ```
Вы также можете настроить поведение темы с помощью опции `themeConfig`. Загляните в главу [Настройка сайта](../reference/site-config) для получения подробной информации обо всех параметрах конфигурации. Вы также можете настроить поведение темы с помощью опции `themeConfig`. Загляните в главу [Конфигурация сайта](../reference/site-config) для получения подробной информации обо всех настраиваемых параметрах.
### Исходные файлы {#source-files} ### Исходные файлы {#source-files}
Файлы Markdown за пределами директории `.vitepress` считаются **исходными файлами**. Файлы Markdown за пределами директории `.vitepress` считаются **исходными файлами**.
VitePress использует **маршрутизацию на основе файлов**: Каждый файл `.md` компилируется в соответствующий файл `.html` с тем же путем. Например, `index.md` будет скомпилирован в `index.html`, и его можно будет посетить по корневому пути `/` результирующего сайта VitePress. VitePress использует **маршрутизацию на основе файлов**: Каждый файл `.md` компилируется в соответствующий файл `.html` с тем же путём. Например, `index.md` будет скомпилирован в `index.html`, и его можно будет посетить по корневому пути `/` результирующего сайта VitePress.
VitePress также предоставляет возможность генерировать чистые URL-адреса, переписывать пути и динамически генерировать страницы. Всё это будет рассмотрено в [Руководстве по маршрутизации](./routing). VitePress также предоставляет возможность генерировать чистые URL-адреса, переписывать пути и динамически генерировать страницы. Всё это будет рассмотрено в [Руководстве по маршрутизации](./routing).
@ -159,7 +159,7 @@ VitePress также предоставляет возможность гене
} }
``` ```
Скрипт `docs:dev` запустит локальный dev-сервер с мгновенными горячими обновлениями. Запустите его с помощью следующей команды: Скрипт `docs:dev` запустит локальный dev-сервер с мгновенными горячими обновлениями. Выполните следующую команду:
::: code-group ::: code-group

@ -210,7 +210,7 @@ console.log('Привет, VitePress!')
::: :::
Кроме того, вы можете установить пользовательские заголовки глобально, добавив следующее содержимое в конфигурацию сайта, полезное, если вы пишете не на английском языке: Кроме того, можно установить пользовательские заголовки глобально, добавив следующее содержимое в конфигурацию сайта, полезное, если вы пишете не на английском языке:
```ts ```ts
// config.ts // config.ts
@ -269,7 +269,7 @@ export default defineConfig({
## Оповещения в стиле GitHub {#github-flavored-alerts} ## Оповещения в стиле GitHub {#github-flavored-alerts}
VitePress также поддерживает [Оповещения в стиле GitHub](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts) для отображения в виде призывов. Они будут отображаться так же, как и [пользовательские контейнеры](#custom-containers). VitePress также поддерживает [Оповещения в стиле GitHub](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts) для отображения в виде вставок. Они будут отображаться так же, как и [пользовательские контейнеры](#custom-containers).
```md ```md
> [!NOTE] > [!NOTE]
@ -305,7 +305,7 @@ VitePress также поддерживает [Оповещения в стил
## Подсветка синтаксиса в блоках кода {#syntax-highlighting-in-code-blocks} ## Подсветка синтаксиса в блоках кода {#syntax-highlighting-in-code-blocks}
VitePress использует [Shiki](https://github.com/shikijs/shiki) для выделения синтаксиса языка в блоках кода Markdown с помощью цветного текста. Shiki поддерживает широкий спектр языков программирования. Всё, что вам нужно сделать, это добавить правильный псевдоним языка к начальным значкам блока кода: VitePress использует [Shiki](https://github.com/shikijs/shiki) для выделения синтаксиса языка в блоках кода Markdown с помощью цветного текста. Shiki поддерживает широкий спектр языков программирования. Всё, что вам нужно сделать, это добавить правильный псевдоним языка к начальным обратным кавычкам блока кода:
**Разметка** **Разметка**
@ -375,7 +375,7 @@ export default {
} }
``` ```
Помимо одной строки, вы можете указать несколько отдельных строк, диапазонов или и то, и другое: Помимо одной строки, можно указать несколько отдельных строк, диапазонов или и то, и другое:
- Диапазоны строк, например: `{5-8}`, `{3-10}`, `{10-17}` - Диапазоны строк, например: `{5-8}`, `{3-10}`, `{10-17}`
- Несколько одиночных строк, например: `{4,7,9}` - Несколько одиночных строк, например: `{4,7,9}`
@ -477,7 +477,7 @@ export default {
## Подсветка различий в блоках кода {#colored-diffs-in-code-blocks} ## Подсветка различий в блоках кода {#colored-diffs-in-code-blocks}
Добавление в строку комментариев `// [!code --]` или `// [!code ++]` создаст diff этой строки, сохраняя цвета блока кода. Добавление в строку комментариев `// [!code --]` или `// [!code ++]` подсветит различие этой строки от другой, сохраняя цвета блока кода.
**Разметка** **Разметка**
@ -553,9 +553,9 @@ export default {
Более подробную информацию см. в секции [`markdown`](../reference/site-config#markdown). Более подробную информацию см. в секции [`markdown`](../reference/site-config#markdown).
Вы можете добавить метки `:line-numbers` / `:no-line-numbers` в ваши ограждённые блоки кода, чтобы переопределить значение, установленное в конфиге. Вы можете добавить метки `:line-numbers` / `:no-line-numbers` в ваши изолированные блоки кода, чтобы переопределить значение, установленное в конфиге.
Вы также можете настроить номер начальной строки, добавив `=` после `:line-numbers`. Например, `:line-numbers=2` означает, что номера строк в блоках кода будут начинаться с `2`. Вы также можете настроить номер начальной строки, добавив `=` после `:line-numbers`. Например, `:line-numbers=2` означает, что нумерация строк в блоках кода будет начинаться с `2`.
**Разметка** **Разметка**
@ -628,7 +628,7 @@ const line4 = 'Строка 4'
<<< @/snippets/snippet.js{2} <<< @/snippets/snippet.js{2}
::: tip СОВЕТ ::: tip СОВЕТ
Значение `@` соответствует корню источника. По умолчанию это корень проекта VitePress, если не настроен `srcDir`. Альтернативно вы также можете импортировать из относительных путей: Значение `@` соответствует корню источника. По умолчанию это корень проекта VitePress, если не настроен параметр `srcDir`. Альтернативно вы также можете импортировать из относительных путей:
```md ```md
<<< ../snippets/snippet.js <<< ../snippets/snippet.js
@ -652,7 +652,7 @@ const line4 = 'Строка 4'
<<< @/snippets/snippet-with-region.js#snippet{1} <<< @/snippets/snippet-with-region.js#snippet{1}
Вы также можете указать язык внутри фигурных скобок (`{}`) следующим образом: Кроме того, можно указать язык внутри фигурных скобок (`{}`) следующим образом:
```md ```md
<<< @/snippets/snippet.cs{c#} <<< @/snippets/snippet.cs{c#}
@ -670,7 +670,7 @@ const line4 = 'Строка 4'
## Группы кодов {#code-groups} ## Группы кодов {#code-groups}
Вы можете сгруппировать несколько блоков кода следующим образом: Можно сгруппировать несколько блоков кода следующим образом:
**Разметка** **Разметка**

@ -6,7 +6,7 @@
Однако из-за отсутствия навигации SPA межстраничные ссылки будут приводить к полной перезагрузке страницы. После загрузки навигация в режиме MPA будет не такой мгновенной, как в режиме SPA. Однако из-за отсутствия навигации SPA межстраничные ссылки будут приводить к полной перезагрузке страницы. После загрузки навигация в режиме MPA будет не такой мгновенной, как в режиме SPA.
Также обратите внимание, что «no-JS-by-default» («без JS по умолчанию») означает, что вы используете Vue исключительно как серверный язык шаблонов. Никаких обработчиков событий в браузере не будет, поэтому интерактивности не будет. Чтобы загрузить JavaScript со стороны клиента, вам нужно использовать специальный тег `<script client>`: Также обратите внимание, что «no-JS-by-default» («без JS по умолчанию») означает, что вы используете Vue исключительно как серверный язык шаблонов. Никаких обработчиков событий в браузере не будет, как и интерактивности. Чтобы загрузить JavaScript со стороны клиента, вам нужно использовать специальный тег `<script client>`:
```html ```html
<script client> <script client>

@ -188,7 +188,7 @@ export default {
} }
``` ```
Опция `rewrites` также поддерживает динамические параметры маршрута. В приведенном выше примере, если у вас много пакетов, перечислять все пути было бы скучно. Учитывая, что все они имеют одинаковую структуру файлов, вы можете упростить конфигурацию следующим образом: Опция `rewrites` также поддерживает динамические параметры маршрута. В приведённом выше примере, если у вас много пакетов, перечислять все пути было бы скучно. Учитывая, что все они имеют одинаковую структуру файлов, можно упростить конфигурацию следующим образом:
```ts ```ts
export default { export default {
@ -345,7 +345,7 @@ console.log(params.value)
### Рендеринг необработанного содержимого {#rendering-raw-content} ### Рендеринг необработанного содержимого {#rendering-raw-content}
Параметры, передаваемые странице, будут сериализованы в полезной нагрузке клиентского JavaScript, поэтому вам следует избегать передачи в параметрах больших объемов данных, например, необработанного Markdown или HTML-контента, полученного из удаленной CMS. Параметры, передаваемые странице, будут сериализованы в полезной нагрузке клиентского JavaScript, поэтому вам следует избегать передачи в параметрах больших объемов данных, например, необработанного Markdown или HTML-контента, полученного из удалённой CMS.
Вместо этого вы можете передавать такое содержимое на каждую страницу с помощью свойства `content` каждого объекта path: Вместо этого вы можете передавать такое содержимое на каждую страницу с помощью свойства `content` каждого объекта path:

@ -123,7 +123,7 @@ import CustomComponent from '../components/CustomComponent.vue'
Если компонент будет использоваться на большинстве страниц, его можно зарегистрировать глобально, настроив экземпляр приложения Vue. Пример смотрите в соответствующей главе [Расширение темы по умолчанию](./extending-default-theme#registering-global-components). Если компонент будет использоваться на большинстве страниц, его можно зарегистрировать глобально, настроив экземпляр приложения Vue. Пример смотрите в соответствующей главе [Расширение темы по умолчанию](./extending-default-theme#registering-global-components).
::: warning ВАЖНО ::: warning ВАЖНО
Убедитесь, что имя пользовательского компонента содержит дефис или написано в PascalCase. В противном случае он будет рассматриваться как встроенный элемент и заключен в тег `<p>`, что приведет к несоответствию гидратации, поскольку `<p>` не позволяет размещать внутри него блочные элементы. Убедитесь, что имя пользовательского компонента содержит дефис или написано в PascalCase. В противном случае он будет рассматриваться как встроенный элемент и заключен в тег `<p>`, что приведёт к несоответствию гидратации, поскольку `<p>` не позволяет размещать внутри него блочные элементы.
::: :::
### Использование компонентов в заголовках <ComponentInHeader /> {#using-components-in-headers} ### Использование компонентов в заголовках <ComponentInHeader /> {#using-components-in-headers}
@ -177,7 +177,7 @@ HTML, обёрнутый `<code>`, будет отображаться как е
## Unescape в блоках кода {#unescape-in-code-blocks} ## Unescape в блоках кода {#unescape-in-code-blocks}
По умолчанию все изолированные блоки кода автоматически оборачиваются `v-pre`, поэтому внутри них не будет обрабатываться синтаксис Vue. Чтобы включить интерполяцию в стиле Vue внутри фигурных скобок, вы можете добавить к языку суффикс `-vue`, например `js-vue`: По умолчанию все изолированные блоки кода автоматически оборачиваются `v-pre`, поэтому внутри них не будет обрабатываться синтаксис Vue. Чтобы включить интерполяцию в стиле Vue внутри фигурных скобок, можно добавить к языку суффикс `-vue`, например `js-vue`:
**Разметка** **Разметка**

@ -1,6 +1,6 @@
# Carbon Ads {#carbon-ads} # Carbon Ads {#carbon-ads}
В VitePress встроена встроенная поддержка [Carbon Ads](https://www.carbonads.net/). Определив в конфиге учётные данные Carbon Ads, VitePress будет отображать рекламу на странице. VitePress имеет встроенную поддержку [Carbon Ads](https://www.carbonads.net/). Определив в конфиге учётные данные Carbon Ads, VitePress будет отображать рекламу на странице.
```js ```js
export default { export default {
@ -13,10 +13,10 @@ export default {
} }
``` ```
Эти значения используются для вызова сценария carbon CDN, как показано ниже: Эти значения используются для вызова сценария Carbon CDN, как показано ниже:
```js ```js
;`//cdn.carbonads.com/carbon.js?serve=${code}&placement=${placement}` ;`//cdn.carbonads.com/carbon.js?serve=${code}&placement=${placement}`
``` ```
Чтобы узнать больше о конфигурации Carbon Ads, посетите [веб-сайт Carbon Ads](https://www.carbonads.net/). Чтобы узнать больше о настройке Carbon Ads, посетите [веб-сайт Carbon Ads](https://www.carbonads.net/).

@ -299,7 +299,7 @@ new Crawler({
lvl1: '.content h1', lvl1: '.content h1',
content: '.content p, .content li', content: '.content p, .content li',
lvl0: { lvl0: {
selectors: '', selectors: 'section.has-active div h2',
defaultValue: 'Documentation' defaultValue: 'Documentation'
}, },
lvl2: '.content h2', lvl2: '.content h2',

@ -161,6 +161,12 @@ aside: false
Уровни заголовков в оглавлении для отображения на странице. Это то же самое, что и [config.themeConfig.outline.level](./default-theme-config#outline), и оно переопределяет значение, установленное в конфигурации сайта. Уровни заголовков в оглавлении для отображения на странице. Это то же самое, что и [config.themeConfig.outline.level](./default-theme-config#outline), и оно переопределяет значение, установленное в конфигурации сайта.
```yaml
---
outline: [2, 4]
---
```
### lastUpdated {#lastupdated} ### lastUpdated {#lastupdated}
- Тип: `boolean | Date` - Тип: `boolean | Date`

@ -80,7 +80,7 @@ interface HeroAction {
### 自定义 name 的颜色 {#customizing-the-name-color} ### 自定义 name 的颜色 {#customizing-the-name-color}
VitePress 通过 (`--vp-c-brand-1`) 设置 `name` 的颜色 .但是,可以通过覆盖 `--vp-home-hero-name-color` 变量来自定义此颜色。 VitePress 通过 (`--vp-c-brand-1`) 设置 `name` 的颜色但是,可以通过覆盖 `--vp-home-hero-name-color` 变量来自定义此颜色。
```css ```css
:root { :root {

@ -289,7 +289,7 @@ new Crawler({
lvl1: '.content h1', lvl1: '.content h1',
content: '.content p, .content li', content: '.content p, .content li',
lvl0: { lvl0: {
selectors: '', selectors: 'section.has-active div h2',
defaultValue: 'Documentation' defaultValue: 'Documentation'
}, },
lvl2: '.content h2', lvl2: '.content h2',

@ -1,6 +1,6 @@
{ {
"name": "vitepress", "name": "vitepress",
"version": "1.3.4", "version": "1.4.0",
"description": "Vite & Vue powered static site generator", "description": "Vite & Vue powered static site generator",
"keywords": [ "keywords": [
"vite", "vite",
@ -98,22 +98,23 @@
"*": "prettier --write --ignore-unknown" "*": "prettier --write --ignore-unknown"
}, },
"dependencies": { "dependencies": {
"@docsearch/css": "^3.6.1", "@docsearch/css": "^3.6.2",
"@docsearch/js": "^3.6.1", "@docsearch/js": "^3.6.2",
"@shikijs/core": "^1.15.2", "@shikijs/core": "^1.22.0",
"@shikijs/transformers": "^1.15.2", "@shikijs/transformers": "^1.22.0",
"@shikijs/types": "^1.22.0",
"@types/markdown-it": "^14.1.2", "@types/markdown-it": "^14.1.2",
"@vitejs/plugin-vue": "^5.1.3", "@vitejs/plugin-vue": "^5.1.4",
"@vue/devtools-api": "^7.3.9", "@vue/devtools-api": "^7.4.6",
"@vue/shared": "^3.4.38", "@vue/shared": "^3.5.11",
"@vueuse/core": "^11.0.3", "@vueuse/core": "^11.1.0",
"@vueuse/integrations": "^11.0.3", "@vueuse/integrations": "^11.1.0",
"focus-trap": "^7.5.4", "focus-trap": "^7.6.0",
"mark.js": "8.11.1", "mark.js": "8.11.1",
"minisearch": "^7.1.0", "minisearch": "^7.1.0",
"shiki": "^1.15.2", "shiki": "^1.22.0",
"vite": "^5.4.2", "vite": "^5.4.8",
"vue": "^3.4.38" "vue": "^3.5.11"
}, },
"devDependencies": { "devDependencies": {
"@clack/prompts": "^0.7.0", "@clack/prompts": "^0.7.0",
@ -124,12 +125,12 @@
"@mdit-vue/plugin-title": "^2.1.3", "@mdit-vue/plugin-title": "^2.1.3",
"@mdit-vue/plugin-toc": "^2.1.3", "@mdit-vue/plugin-toc": "^2.1.3",
"@mdit-vue/shared": "^2.1.3", "@mdit-vue/shared": "^2.1.3",
"@polka/compression": "^1.0.0-next.26", "@polka/compression": "^1.0.0-next.28",
"@rollup/plugin-alias": "^5.1.0", "@rollup/plugin-alias": "^5.1.1",
"@rollup/plugin-commonjs": "^26.0.1", "@rollup/plugin-commonjs": "^28.0.0",
"@rollup/plugin-json": "^6.1.0", "@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-node-resolve": "^15.3.0",
"@rollup/plugin-replace": "^5.0.7", "@rollup/plugin-replace": "^6.0.1",
"@types/cross-spawn": "^6.0.6", "@types/cross-spawn": "^6.0.6",
"@types/debug": "^4.1.12", "@types/debug": "^4.1.12",
"@types/fs-extra": "^11.0.4", "@types/fs-extra": "^11.0.4",
@ -140,23 +141,23 @@
"@types/markdown-it-emoji": "^3.0.1", "@types/markdown-it-emoji": "^3.0.1",
"@types/micromatch": "^4.0.9", "@types/micromatch": "^4.0.9",
"@types/minimist": "^1.2.5", "@types/minimist": "^1.2.5",
"@types/node": "^22.5.1", "@types/node": "^22.7.4",
"@types/postcss-prefix-selector": "^1.16.3", "@types/postcss-prefix-selector": "^1.16.3",
"@types/prompts": "^2.4.9", "@types/prompts": "^2.4.9",
"chokidar": "^3.6.0", "chokidar": "^3.6.0",
"conventional-changelog-cli": "^5.0.0", "conventional-changelog-cli": "^5.0.0",
"cross-spawn": "^7.0.3", "cross-spawn": "^7.0.3",
"debug": "^4.3.6", "debug": "^4.3.7",
"esbuild": "^0.23.1", "esbuild": "^0.24.0",
"execa": "^9.3.1", "execa": "^9.4.0",
"fs-extra": "^11.2.0", "fs-extra": "^11.2.0",
"get-port": "^7.1.0", "get-port": "^7.1.0",
"gray-matter": "^4.0.3", "gray-matter": "^4.0.3",
"lint-staged": "^15.2.9", "lint-staged": "^15.2.10",
"lodash.template": "^4.5.0", "lodash.template": "^4.5.0",
"lru-cache": "^11.0.0", "lru-cache": "^11.0.1",
"markdown-it": "^14.1.0", "markdown-it": "^14.1.0",
"markdown-it-anchor": "^9.1.0", "markdown-it-anchor": "^9.2.0",
"markdown-it-attrs": "^4.2.0", "markdown-it-attrs": "^4.2.0",
"markdown-it-container": "^4.0.0", "markdown-it-container": "^4.0.0",
"markdown-it-emoji": "^3.0.0", "markdown-it-emoji": "^3.0.0",
@ -166,17 +167,17 @@
"nanoid": "^5.0.7", "nanoid": "^5.0.7",
"ora": "^8.1.0", "ora": "^8.1.0",
"p-map": "^7.0.2", "p-map": "^7.0.2",
"path-to-regexp": "^6.2.2", "path-to-regexp": "^6.3.0",
"picocolors": "^1.0.1", "picocolors": "^1.1.0",
"pkg-dir": "^8.0.0", "pkg-dir": "^8.0.0",
"playwright-chromium": "^1.46.1", "playwright-chromium": "^1.47.2",
"polka": "^1.0.0-next.25", "polka": "^1.0.0-next.28",
"postcss-prefix-selector": "^1.16.1", "postcss-prefix-selector": "^2.0.0",
"prettier": "^3.3.3", "prettier": "^3.3.3",
"prompts": "^2.4.2", "prompts": "^2.4.2",
"punycode": "^2.3.1", "punycode": "^2.3.1",
"rimraf": "^6.0.1", "rimraf": "^6.0.1",
"rollup": "^4.21.2", "rollup": "^4.24.0",
"rollup-plugin-dts": "^6.1.1", "rollup-plugin-dts": "^6.1.1",
"rollup-plugin-esbuild": "^6.1.1", "rollup-plugin-esbuild": "^6.1.1",
"semver": "^7.6.3", "semver": "^7.6.3",
@ -184,11 +185,11 @@
"sirv": "^2.0.4", "sirv": "^2.0.4",
"sitemap": "^8.0.0", "sitemap": "^8.0.0",
"supports-color": "^9.4.0", "supports-color": "^9.4.0",
"tinyglobby": "^0.2.5", "tinyglobby": "^0.2.9",
"typescript": "^5.5.4", "typescript": "^5.6.2",
"vitest": "^2.0.5", "vitest": "^2.1.2",
"vue-tsc": "^2.1.4", "vue-tsc": "^2.1.6",
"wait-on": "^8.0.0" "wait-on": "^8.0.1"
}, },
"peerDependencies": { "peerDependencies": {
"markdown-it-mathjax3": "^4", "markdown-it-mathjax3": "^4",
@ -202,7 +203,7 @@
"optional": true "optional": true
} }
}, },
"packageManager": "pnpm@9.9.0", "packageManager": "pnpm@9.12.0",
"pnpm": { "pnpm": {
"peerDependencyRules": { "peerDependencyRules": {
"ignoreMissing": [ "ignoreMissing": [

File diff suppressed because it is too large Load Diff

@ -87,7 +87,7 @@ function createHeadElement([tag, attrs, innerHTML]: HeadConfig) {
if (innerHTML) { if (innerHTML) {
el.innerHTML = innerHTML el.innerHTML = innerHTML
} }
if (tag === 'script' && !attrs.async) { if (tag === 'script' && attrs.async == null) {
// async is true by default for dynamically created scripts // async is true by default for dynamically created scripts
;(el as HTMLScriptElement).async = false ;(el as HTMLScriptElement).async = false
} }

@ -1,5 +1,5 @@
import siteData from '@siteData' import siteData from '@siteData'
import { useDark } from '@vueuse/core' import { useDark, usePreferredDark } from '@vueuse/core'
import { import {
computed, computed,
inject, inject,
@ -79,13 +79,15 @@ export function initData(route: Route): VitePressData {
const isDark = const isDark =
appearance === 'force-dark' appearance === 'force-dark'
? ref(true) ? ref(true)
: appearance : appearance === 'force-auto'
? useDark({ ? usePreferredDark()
storageKey: APPEARANCE_KEY, : appearance
initialValue: () => (appearance === 'dark' ? 'dark' : 'auto'), ? useDark({
...(typeof appearance === 'object' ? appearance : {}) storageKey: APPEARANCE_KEY,
}) initialValue: () => (appearance === 'dark' ? 'dark' : 'auto'),
: ref(false) ...(typeof appearance === 'object' ? appearance : {})
})
: ref(false)
const hashRef = ref(inBrowser ? location.hash : '') const hashRef = ref(inBrowser ? location.hash : '')

@ -78,6 +78,12 @@ function onBlur() {
color: var(--vp-c-brand-2); color: var(--vp-c-brand-2);
} }
.button[aria-expanded="false"] + .menu {
opacity: 0;
visibility: hidden;
transform: translateY(0);
}
.VPFlyout:hover .menu, .VPFlyout:hover .menu,
.button[aria-expanded="true"] + .menu { .button[aria-expanded="true"] + .menu {
opacity: 1; opacity: 1;
@ -85,12 +91,6 @@ function onBlur() {
transform: translateY(0); transform: translateY(0);
} }
.button[aria-expanded="false"] + .menu {
opacity: 0;
visibility: hidden;
transform: translateY(0);
}
.button { .button {
display: flex; display: flex;
align-items: center; align-items: center;

@ -440,10 +440,20 @@ function formMarkRegex(terms: Set<string>) {
<input <input
ref="searchInput" ref="searchInput"
v-model="filterText" v-model="filterText"
:placeholder="buttonText" :aria-activedescendant="selectedIndex > -1 ? ('localsearch-item-' + selectedIndex) : undefined"
id="localsearch-input" aria-autocomplete="both"
:aria-controls="results?.length ? 'localsearch-list' : undefined"
aria-labelledby="localsearch-label" aria-labelledby="localsearch-label"
autocapitalize="off"
autocomplete="off"
autocorrect="off"
class="search-input" class="search-input"
id="localsearch-input"
enterkeyhint="go"
maxlength="64"
:placeholder="buttonText"
spellcheck="false"
type="search"
/> />
<div class="search-actions"> <div class="search-actions">
<button <button
@ -482,8 +492,9 @@ function formMarkRegex(terms: Set<string>) {
<li <li
v-for="(p, index) in results" v-for="(p, index) in results"
:key="p.id" :key="p.id"
role="option" :id="'localsearch-item-' + index"
:aria-selected="selectedIndex === index ? 'true' : 'false'" :aria-selected="selectedIndex === index ? 'true' : 'false'"
role="option"
> >
<a <a
:href="p.id" :href="p.id"

@ -1,9 +1,5 @@
/* webfont-marker-begin */ /* webfont-marker-begin */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap');
html body {
font-synthesis: style;
}
/* webfont-marker-end */ /* webfont-marker-end */
@font-face { @font-face {

@ -19,13 +19,12 @@ import MarkdownIt from 'markdown-it'
import anchorPlugin from 'markdown-it-anchor' import anchorPlugin from 'markdown-it-anchor'
import attrsPlugin from 'markdown-it-attrs' import attrsPlugin from 'markdown-it-attrs'
import { full as emojiPlugin } from 'markdown-it-emoji' import { full as emojiPlugin } from 'markdown-it-emoji'
import type { BuiltinTheme, Highlighter } from 'shiki'
import type { import type {
BuiltinTheme,
Highlighter,
LanguageInput, LanguageInput,
ShikiTransformer, ShikiTransformer,
ThemeRegistrationAny ThemeRegistrationAny
} from 'shiki' } from '@shikijs/types'
import type { Logger } from 'vite' import type { Logger } from 'vite'
import { containerPlugin, type ContainerOptions } from './plugins/containers' import { containerPlugin, type ContainerOptions } from './plugins/containers'
import { gitHubAlertsPlugin } from './plugins/githubAlerts' import { gitHubAlertsPlugin } from './plugins/githubAlerts'

@ -90,7 +90,7 @@ export async function highlight(
} }
] ]
const vueRE = /-vue$/ const vueRE = /-vue(?=:|$)/
const lineNoStartRE = /=(\d*)/ const lineNoStartRE = /=(\d*)/
const lineNoRE = /:(no-)?line-numbers(=\d*)?$/ const lineNoRE = /:(no-)?line-numbers(=\d*)?$/
const mustacheRE = /\{\{.*?\}\}/g const mustacheRE = /\{\{.*?\}\}/g

@ -63,14 +63,14 @@ export async function createMarkdownToVueRenderFn(
const dynamicRoutes = new Map( const dynamicRoutes = new Map(
siteConfig?.dynamicRoutes?.routes.map((r) => [ siteConfig?.dynamicRoutes?.routes.map((r) => [
r.fullPath, r.fullPath,
path.join(srcDir, r.route) slash(path.join(srcDir, r.route))
]) || [] ]) || []
) )
const rewrites = new Map( const rewrites = new Map(
Object.entries(siteConfig?.rewrites.map || {}).map(([key, value]) => [ Object.entries(siteConfig?.rewrites.map || {}).map(([key, value]) => [
path.join(srcDir, key), slash(path.join(srcDir, key)),
path.join(srcDir, value!) slash(path.join(srcDir, value!))
]) || [] ]) || []
) )

@ -6,22 +6,35 @@ export function resolveRewrites(
pages: string[], pages: string[],
userRewrites: UserConfig['rewrites'] userRewrites: UserConfig['rewrites']
) { ) {
const rewriteRules = Object.entries(userRewrites || {}).map(([from, to]) => ({
toPath: compile(`/${to}`, { validate: false }),
matchUrl: match(from.startsWith('^') ? new RegExp(from) : from)
}))
const pageToRewrite: Record<string, string> = {} const pageToRewrite: Record<string, string> = {}
const rewriteToPage: Record<string, string> = {} const rewriteToPage: Record<string, string> = {}
if (rewriteRules.length) {
if (typeof userRewrites === 'function') {
for (const page of pages) { for (const page of pages) {
for (const { matchUrl, toPath } of rewriteRules) { const dest = userRewrites(page)
const res = matchUrl(page) if (dest && dest !== page) {
if (res) { pageToRewrite[page] = dest
const dest = toPath(res.params).slice(1) rewriteToPage[dest] = page
pageToRewrite[page] = dest }
rewriteToPage[dest] = page }
break } else if (typeof userRewrites === 'object') {
const rewriteRules = Object.entries(userRewrites || {}).map(
([from, to]) => ({
toPath: compile(`/${to}`, { validate: false }),
matchUrl: match(from.startsWith('^') ? new RegExp(from) : from)
})
)
if (rewriteRules.length) {
for (const page of pages) {
for (const { matchUrl, toPath } of rewriteRules) {
const res = matchUrl(page)
if (res) {
const dest = toPath(res.params).slice(1)
pageToRewrite[page] = dest
rewriteToPage[dest] = page
break
}
} }
} }
} }

@ -162,7 +162,7 @@ export interface UserConfig<ThemeConfig = any>
* *
* source -> destination * source -> destination
*/ */
rewrites?: Record<string, string> rewrites?: Record<string, string> | ((id: string) => string)
/** /**
* @experimental * @experimental

Loading…
Cancel
Save