docs: add Chinese translations (#2249)

---------

Co-authored-by: Xavi Lee <awxiaoxian2020@163.com>
Co-authored-by: shellRaining <shellRaining@gmail.com>
Co-authored-by: Xavi Lee <xavilee2002@outlook.com>
Co-authored-by: Divyansh Singh <40380293+brc-dd@users.noreply.github.com>
pull/3402/head
vanchKong 6 months ago committed by GitHub
parent 7735631597
commit 3052002b47
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -4,48 +4,11 @@ import { defineConfig, type DefaultTheme } from 'vitepress'
const require = createRequire(import.meta.url)
const pkg = require('vitepress/package.json')
export default defineConfig({
export const en = defineConfig({
lang: 'en-US',
title: 'VitePress',
description: 'Vite & Vue powered static site generator.',
lastUpdated: true,
cleanUrls: true,
markdown: {
math: true,
codeTransformers: [
// We use `[!!code` in demo to prevent transformation, here we revert it back.
{
postprocess(code) {
return code.replace(/\[\!\!code/g, '[!code')
}
}
]
},
sitemap: {
hostname: 'https://vitepress.dev',
transformItems(items) {
return items.filter((item) => !item.url.includes('migration'))
}
},
/* prettier-ignore */
head: [
['link', { rel: 'icon', type: 'image/svg+xml', href: '/vitepress-logo-mini.svg' }],
['link', { rel: 'icon', type: 'image/png', href: '/vitepress-logo-mini.png' }],
['meta', { name: 'theme-color', content: '#5f67ee' }],
['meta', { name: 'og:type', content: 'website' }],
['meta', { name: 'og:locale', content: 'en' }],
['meta', { name: 'og:site_name', content: 'VitePress' }],
['meta', { name: 'og:image', content: 'https://vitepress.dev/vitepress-og.jpg' }],
['script', { src: 'https://cdn.usefathom.com/script.js', 'data-site': 'AZBRSFGG', 'data-spa': 'auto', defer: '' }]
],
themeConfig: {
logo: { src: '/vitepress-logo-mini.svg', width: 24, height: 24 },
nav: nav(),
sidebar: {
@ -58,27 +21,9 @@ export default defineConfig({
text: 'Edit this page on GitHub'
},
socialLinks: [
{ icon: 'github', link: 'https://github.com/vuejs/vitepress' }
],
footer: {
message: 'Released under the MIT License.',
copyright: 'Copyright © 2019-present Evan You'
},
search: {
provider: 'algolia',
options: {
appId: '8J64VVRP8K',
apiKey: 'a18e2f4cc5665f6602c5631fd868adfd',
indexName: 'vitepress'
}
},
carbonAds: {
code: 'CEBDT27Y',
placement: 'vuejsorg'
}
}
})
@ -111,7 +56,6 @@ function nav(): DefaultTheme.NavItem[] {
]
}
/* prettier-ignore */
function sidebarGuide(): DefaultTheme.SidebarItem[] {
return [
{
@ -140,7 +84,10 @@ function sidebarGuide(): DefaultTheme.SidebarItem[] {
collapsed: false,
items: [
{ text: 'Using a Custom Theme', link: 'custom-theme' },
{ text: 'Extending the Default Theme', link: 'extending-default-theme' },
{
text: 'Extending the Default Theme',
link: 'extending-default-theme'
},
{ text: 'Build-Time Data Loading', link: 'data-loading' },
{ text: 'SSR Compatibility', link: 'ssr-compat' },
{ text: 'Connecting to a CMS', link: 'cms' }

@ -0,0 +1,66 @@
import { defineConfig } from 'vitepress'
import { en } from './en'
import { zh, search as zhSearch } from './zh'
export default defineConfig({
title: 'VitePress',
lastUpdated: true,
cleanUrls: true,
markdown: {
math: true,
codeTransformers: [
// We use `[!!code` in demo to prevent transformation, here we revert it back.
{
postprocess(code) {
return code.replace(/\[\!\!code/g, '[!code')
}
}
]
},
sitemap: {
hostname: 'https://vitepress.dev',
transformItems(items) {
return items.filter((item) => !item.url.includes('migration'))
}
},
/* prettier-ignore */
head: [
['link', { rel: 'icon', type: 'image/svg+xml', href: '/vitepress-logo-mini.svg' }],
['link', { rel: 'icon', type: 'image/png', href: '/vitepress-logo-mini.png' }],
['meta', { name: 'theme-color', content: '#5f67ee' }],
['meta', { name: 'og:type', content: 'website' }],
['meta', { name: 'og:locale', content: 'en' }],
['meta', { name: 'og:site_name', content: 'VitePress' }],
['meta', { name: 'og:image', content: 'https://vitepress.dev/vitepress-og.jpg' }],
['script', { src: 'https://cdn.usefathom.com/script.js', 'data-site': 'AZBRSFGG', 'data-spa': 'auto', defer: '' }]
],
themeConfig: {
logo: { src: '/vitepress-logo-mini.svg', width: 24, height: 24 },
socialLinks: [
{ icon: 'github', link: 'https://github.com/vuejs/vitepress' }
],
search: {
provider: 'algolia',
options: {
appId: '8J64VVRP8K',
apiKey: 'a18e2f4cc5665f6602c5631fd868adfd',
indexName: 'vitepress',
locales: { ...zhSearch }
}
},
carbonAds: { code: 'CEBDT27Y', placement: 'vuejsorg' }
},
locales: {
root: { label: 'English', ...en },
zh: { label: '简体中文', ...zh }
}
})

@ -0,0 +1,204 @@
import { createRequire } from 'module'
import { defineConfig, type DefaultTheme } from 'vitepress'
const require = createRequire(import.meta.url)
const pkg = require('vitepress/package.json')
export const zh = defineConfig({
lang: 'zh-Hans',
description: '由 Vite 和 Vue 驱动的静态站点生成器',
themeConfig: {
nav: nav(),
sidebar: {
'/zh/guide/': { base: '/zh/guide/', items: sidebarGuide() },
'/zh/reference/': { base: '/zh/reference/', items: sidebarReference() }
},
editLink: {
pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',
text: '在 GitHub 上编辑此页面'
},
footer: {
message: '根据 MIT 许可发布。',
copyright: '版权所有 © 2019 至今 尤雨溪'
},
docFooter: {
prev: '上一页',
next: '下一页'
},
outline: {
label: '页面导航'
},
lastUpdated: {
text: '最后更新于',
formatOptions: {
dateStyle: 'short',
timeStyle: 'medium'
}
},
langMenuLabel: '多语言',
returnToTopLabel: '回到顶部',
sidebarMenuLabel: '菜单',
darkModeSwitchLabel: '主题',
lightModeSwitchTitle: '切换到浅色模式',
darkModeSwitchTitle: '切换到深色模式'
}
})
function nav(): DefaultTheme.NavItem[] {
return [
{
text: '指南',
link: '/zh/guide/what-is-vitepress',
activeMatch: '/zh/guide/'
},
{
text: '参考',
link: '/zh/reference/site-config',
activeMatch: '/zh/reference/'
},
{
text: pkg.version,
items: [
{
text: '更新日志',
link: 'https://github.com/vuejs/vitepress/blob/main/CHANGELOG.md'
},
{
text: '参与贡献',
link: 'https://github.com/vuejs/vitepress/blob/main/.github/contributing.md'
}
]
}
]
}
function sidebarGuide(): DefaultTheme.SidebarItem[] {
return [
{
text: '简介',
collapsed: false,
items: [
{ text: '什么是 VitePress', link: 'what-is-vitepress' },
{ text: '快速开始', link: 'getting-started' },
{ text: '路由', link: 'routing' },
{ text: '部署', link: 'deploy' }
]
},
{
text: '写作',
collapsed: false,
items: [
{ text: 'Markdown 扩展', link: 'markdown' },
{ text: '资源处理', link: 'asset-handling' },
{ text: 'frontmatter', link: 'frontmatter' },
{ text: '在 Markdown 使用 Vue', link: 'using-vue' },
{ text: '国际化', link: 'i18n' }
]
},
{
text: '自定义',
collapsed: false,
items: [
{ text: '自定义主题', link: 'custom-theme' },
{ text: '扩展默认主题', link: 'extending-default-theme' },
{ text: '构建时数据加载', link: 'data-loading' },
{ text: 'SSR 兼容性', link: 'ssr-compat' },
{ text: '连接 CMS', link: 'cms' }
]
},
{
text: '实验性功能',
collapsed: false,
items: [
{ text: 'MPA 模式', link: 'mpa-mode' },
{ text: 'sitemap 生成', link: 'sitemap-generation' }
]
},
{ text: '配置和 API 参考', base: '/zh/reference/', link: 'site-config' }
]
}
function sidebarReference(): DefaultTheme.SidebarItem[] {
return [
{
text: '参考',
items: [
{ text: '站点配置', link: 'site-config' },
{ text: 'frontmatter 配置', link: 'frontmatter-config' },
{ text: '运行时 API', link: 'runtime-api' },
{ text: 'CLI', link: 'cli' },
{
text: '默认主题',
base: '/zh/reference/default-theme-',
items: [
{ text: '概览', link: 'config' },
{ text: '导航栏', link: 'nav' },
{ text: '侧边栏', link: 'sidebar' },
{ text: '主页', link: 'home-page' },
{ text: '页脚', link: 'footer' },
{ text: '布局', link: 'layout' },
{ text: '徽章', link: 'badge' },
{ text: '团队页', link: 'team-page' },
{ text: '上下页链接', link: 'prev-next-links' },
{ text: '编辑链接', link: 'edit-link' },
{ text: '最后更新时间戳', link: 'last-updated' },
{ text: '搜索', link: 'search' },
{ text: 'Carbon Ads', link: 'carbon-ads' }
]
}
]
}
]
}
export const search: DefaultTheme.AlgoliaSearchOptions['locales'] = {
zh: {
placeholder: '搜索文档',
translations: {
button: {
buttonText: '搜索文档',
buttonAriaLabel: '搜索文档'
},
modal: {
searchBox: {
resetButtonTitle: '清除查询条件',
resetButtonAriaLabel: '清除查询条件',
cancelButtonText: '取消',
cancelButtonAriaLabel: '取消'
},
startScreen: {
recentSearchesTitle: '搜索历史',
noRecentSearchesText: '没有搜索历史',
saveRecentSearchButtonTitle: '保存至搜索历史',
removeRecentSearchButtonTitle: '从搜索历史中移除',
favoriteSearchesTitle: '收藏',
removeFavoriteSearchButtonTitle: '从收藏中移除'
},
errorScreen: {
titleText: '无法获取结果',
helpText: '你可能需要检查你的网络连接'
},
footer: {
selectText: '选择',
navigateText: '切换',
closeText: '关闭',
searchByText: '搜索提供者'
},
noResultsScreen: {
noResultsText: '无法找到相关结果',
suggestedQueryText: '你可以尝试查询',
reportMissingResultsText: '你认为该查询应该有结果?',
reportMissingResultsLinkText: '点击反馈'
}
}
}
}
}

@ -75,25 +75,39 @@ However, VitePress won't redirect `/` to `/en/` by default. You'll need to confi
/* /en/:splat 302
```
**Pro tip:** If using the above approach, you can use `nf_lang` cookie to persist user's language choice. A very basic way to do this is register a watcher inside the [setup](./custom-theme#using-a-custom-theme) function of custom theme:
**Pro tip:** If using the above approach, you can use `nf_lang` cookie to persist user's language choice:
```ts
// docs/.vitepress/theme/index.ts
import DefaultTheme from 'vitepress/theme'
import Layout from './Layout.vue'
export default {
extends: DefaultTheme,
setup() {
const { lang } = useData()
watchEffect(() => {
if (inBrowser) {
document.cookie = `nf_lang=${lang.value}; expires=Mon, 1 Jan 2024 00:00:00 UTC; path=/`
}
})
}
Layout
}
```
```vue
<!-- docs/.vitepress/theme/Layout.vue -->
<script setup lang="ts">
import DefaultTheme from 'vitepress/theme'
import { useData } from 'vitepress'
import { watchEffect } from 'vue'
const { lang } = useData()
watchEffect(() => {
if (inBrowser) {
document.cookie = `nf_lang=${lang.value}; expires=Mon, 1 Jan 2030 00:00:00 UTC; path=/`
}
})
</script>
<template>
<DefaultTheme.Layout />
</template>
```
## RTL Support (Experimental)
For RTL support, specify `dir: 'rtl'` in config and use some RTLCSS PostCSS plugin like <https://github.com/MohammadYounes/rtlcss>, <https://github.com/vkalinichev/postcss-rtl> or <https://github.com/elchininet/postcss-rtlcss>. You'll need to configure your PostCSS plugin to use `:where([dir="ltr"])` and `:where([dir="rtl"])` as prefixes to prevent CSS specificity issues.

@ -0,0 +1,59 @@
# 资源处理 {#asset-handling}
## 引用静态资源 {#referencing-static-assets}
所有的 Markdown 文件都会被编译成 Vue 组件,并由 [Vite](https://vitejs.dev/guide/assets.html) 处理。可以,**并且应该**使用相对路径来引用资源:
```md
![An image](./image.png)
```
可以在 Markdown 文件、主题中的 `*.vue` 组件、样式和普通的 `.css` 文件中引用静态资源,通过使用绝对路径 (基于项目根目录) 或者相对路径 (基于文件系统)。后者类似于 Vite、Vue CLI 或者 webpack 的 `file-loader` 的行为。
常见的图像,媒体和字体文件会被自动检测并视作资源。
所有引用的资源,包括那些使用绝对路径的,都会在生产构建过程中被复制到输出目录,并使用哈希文件名。从未使用过的资源将不会被复制。小于 4kb 的图像资源将会采用 base64 内联——这可以通过 [`vite`](../reference/site-config#vite) 配置选项进行配置。
所有**静态**路径引用,包括绝对路径,都应基于你的工作目录的结构。
## public 目录 {#the-public-directory}
有时可能需要一些静态资源,但这些资源没有直接被 Markdown 或主题组件直接引用,或者你可能想以原始文件名提供某些文件,像 `robots.txt`favicons 和 PWA 图标这样的文件。
可以将这些文件放置在[源目录](./routing#source-directory)的 `public` 目录中。例如,如果项目根目录是 `./docs`,并且使用默认源目录位置,那么 public 目录将是 `./docs/public`
放置在 `public` 中的资源将按原样复制到输出目录的根目录中。
请注意,应使用根绝对路径来引用放置在 `public` 中的文件——例如,`public/icon.png` 应始终在源代码中作为 `/icon.png` 引用。
## 根 URL {#base-url}
如果站点没有部署在根 URL 上,则需要在 `.vitepress/config.js` 中设置 `base` 选项。例如,如果计划将站点部署到 `https://foo.github.io/bar/`,则 `base` 应设置为 `'/bar/'`(它应始终以斜杠开头和结尾)。
所有静态资源路径都会被自动处理,来适应不同的 `base` 配置值。例如,如果 markdown 中有一个对 `public` 中的资源的绝对引用:
```md
![An image](/image-inside-public.png)
```
在这种情况下,更改 `base` 配置值时,**无需**更新该引用。
但是如果你正在编写一个主题组件,它动态地链接到资源,例如一个图片,它的 `src` 基于主题配置值:
```vue
<img :src="theme.logoPath" />
```
在这种情况下,建议使用 VitePress 提供的 [`withBase` helper](../reference/runtime-api#withbase) 来包装路径:
```vue
<script setup>
import { withBase, useData } from 'vitepress'
const { theme } = useData()
</script>
<template>
<img :src="withBase(theme.logoPath)" />
</template>
```

@ -0,0 +1,56 @@
---
outline: deep
---
# 连接到 CMS {#connecting-to-a-cms}
## 一般的工作流 {#general-workflow}
将 VitePress 连接到 CMS 主要围绕[动态路由](./routing#dynamic-routes)展开。在继续阅读之前,请确保了解它的工作原理。
由于每个 CMS 的工作方式都不同,因此我们只能提供一个通用的工作流,你需要根据具体情况进行调整。
1. 如果你的 CMS 需要身份验证,请创建一个 `.env` 文件来存储你的 API token
```js
// posts/[id].paths.js
import { loadEnv } from 'vitepress'
const env = loadEnv('', process.cwd())
```
2. 从 CMS 获取必要的数据并将其格式调整为合适的路径数据:
```js
export default {
async paths() {
// use respective CMS client library if needed
const data = await (await fetch('https://my-cms-api', {
headers: {
// token if necessary
}
})).json()
return data.map(entry => {
return {
params: { id: entry.id, /* title, authors, date etc. */ },
content: entry.content
}
})
}
}
```
3. 在页面中渲染内容:
```md
# {{ $params.title }}
- by {{ $params.author }} on {{ $params.date }}
<!-- @content -->
```
## 整合指南 {#integration-guides}
如果你已经写了一篇关于如何将 VitePress 与特定 CMS 集成的指南,请点击下面的“在 GitHub 上编辑此页面”链接将它提交到这里!

@ -0,0 +1,222 @@
# 自定义主题 {#using-a-custom-theme}
## 解析主题 {#theme-resolving}
可以通过创建一个 `.vitepress/theme/index.js``.vitepress/theme/index.ts` 文件 (即“主题入口文件”) 来启用自定义主题:
```
.
├─ docs # project root
│ ├─ .vitepress
│ │ ├─ theme
│ │ │ └─ index.js # theme entry
│ │ └─ config.js # config file
│ └─ index.md
└─ package.json
```
当检测到存在主题入口文件时VitePress 总会使用自定义主题而不是默认主题。但你可以[拓展默认主题](./extending-default-theme)来在其基础上实现更高级的自定义。
## 主题接口 {#theme-interface}
VitePress 自定义主题是一个对象,该对象具有如下接口:
```ts
interface Theme {
/**
* Root layout component for every page
* @required
*/
Layout: Component
/**
* Enhance Vue app instance
* @optional
*/
enhanceApp?: (ctx: EnhanceAppContext) => Awaitable<void>
/**
* Extend another theme, calling its `enhanceApp` before ours
* @optional
*/
extends?: Theme
}
interface EnhanceAppContext {
app: App // Vue app instance
router: Router // VitePress router instance
siteData: Ref<SiteData> // Site-level metadata
}
```
主题入口文件需要将主题作为默认导出来导出:
```js
// .vitepress/theme/index.js
// You can directly import Vue files in the theme entry
// VitePress is pre-configured with @vitejs/plugin-vue.
import Layout from './Layout.vue'
export default {
Layout,
enhanceApp({ app, router, siteData }) {
// ...
}
}
```
默认导出是自定义主题的唯一方式,并且只有 `Layout` 属性是必须的。所以从技术上讲,一个 VitePress 主题可以是一个单独的 Vue 组件。
在组件内部,它的工作方式就像是一个普通的 Vite + Vue 3 应用。请注意,主题还需要保证 [SSR 兼容](./ssr-compat)。
## 构建布局 {#building-a-layout}
最基本的布局组件需要包含一个 [`<Content />`](../reference/runtime-api#content) 组件:
```vue
<!-- .vitepress/theme/Layout.vue -->
<template>
<h1>Custom Layout!</h1>
<!-- this is where markdown content will be rendered -->
<Content />
</template>
```
上面的布局只是将每个页面的 markdown 渲染为 HTML。我们添加的第一个改进是处理 404 错误:
```vue{1-4,9-12}
<script setup>
import { useData } from 'vitepress'
const { page } = useData()
</script>
<template>
<h1>Custom Layout!</h1>
<div v-if="page.isNotFound">
Custom 404 page!
</div>
<Content v-else />
</template>
```
[`useData()`](../reference/runtime-api#usedata) 为我们提供了所有的运行时数据,以便我们根据不同条件渲染不同的布局。我们可以访问的另一个数据是当前页面的 frontmatter。通过利用这个数据我们允许用户控制每个页面的布局。例如用户可以指定一个页面是否使用特殊的主页布局
```md
---
layout: home
---
```
并且我们可以调整我们的主题进行处理:
```vue{3,12-14}
<script setup>
import { useData } from 'vitepress'
const { page, frontmatter } = useData()
</script>
<template>
<h1>Custom Layout!</h1>
<div v-if="page.isNotFound">
Custom 404 page!
</div>
<div v-if="frontmatter.layout === 'home'">
Custom home page!
</div>
<Content v-else />
</template>
```
当然你可以将布局切分为不同的组件:
```vue{3-5,12-15}
<script setup>
import { useData } from 'vitepress'
import NotFound from './NotFound.vue'
import Home from './Home.vue'
import Page from './Page.vue'
const { page, frontmatter } = useData()
</script>
<template>
<h1>Custom Layout!</h1>
<NotFound v-if="page.isNotFound" />
<Home v-if="frontmatter.layout === 'home'" />
<Page v-else /> <!-- <Page /> renders <Content /> -->
</template>
```
请查看[运行时 API 参考](../reference/runtime-api)获取主题组件中所有可用内容。此外,可以利用[构建时数据加载](./data-loading)来生成数据驱动布局——例如,一个列出当前项目中所有博客文章的页面。
## 分发自定义主题 {#distributing-a-custom-theme}
分发自定义主题最简单的方式是通过将其作为 [GitHub 模版仓库](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-template-repository)。
如果你希望将主题作为 npm 包来分发,请按照下面的步骤操作:
1. 在包入口将主题对象作为默认导出来导出。
2. 如果合适的话,将主题配置类型定义作为 `ThemeConfig` 导出。
3. 如果主题需要调整 VitePress 配置,请在包的子路径下 (例如 `my-theme/config`) 下导出该配置,以便用户拓展。
4. 记录主题配置选项 (通过配置文件和 frontmatter)。
5. 提供清晰的说明,告诉用户如何使用主题 (见下文)。
## 使用自定义主题 {#consuming-a-custom-theme}
要使用外部主题,请导入它并重新导出:
```js
// .vitepress/theme/index.js
import Theme from 'awesome-vitepress-theme'
export default Theme
```
如果主题需要拓展:
```js
// .vitepress/theme/index.js
import Theme from 'awesome-vitepress-theme'
export default {
extends: Theme,
enhanceApp(ctx) {
// ...
}
}
```
如果主题需要特殊的 VitePress 配置,也需要在配置中拓展:
```ts
// .vitepress/theme/config.ts
import baseConfig from 'awesome-vitepress-theme/config'
export default {
// extend theme base config (if needed)
extends: baseConfig
}
```
最后,如果主题为其主题配置提供了类型:
```ts
// .vitepress/theme/config.ts
import baseConfig from 'awesome-vitepress-theme/config'
import { defineConfigWithTheme } from 'vitepress'
import type { ThemeConfig } from 'awesome-vitepress-theme'
export default defineConfigWithTheme<ThemeConfig>({
extends: baseConfig,
themeConfig: {
// Type is `ThemeConfig`
}
})
```

@ -0,0 +1,248 @@
# 构建时数据加载 {#build-time-data-loading}
VitePress 提供了**数据加载**的功能,它允许加载任意数据并从页面或组件中导入它。数据加载**只在构建时**执行:最终的数据将被序列化为 JavaScript 包中的 JSON。
数据加载可以被用于获取远程数据,也可以基于本地文件生成元数据。例如,可以使用数据加载来解析所有本地 API 页面并自动生成所有 API 入口的索引。
## 基本用法 {#basic-usage}
一个用于数据加载的文件必须以 `.data.js``.data.ts` 结尾。该文件应该提供一个默认导出的对象,该对象具有 `load()` 方法:
```js
// example.data.js
export default {
load() {
return {
hello: 'world'
}
}
}
```
数据加载模块只在 Node.js 中执行,因此可以按需导入 Node API 和 npm 依赖。
然后,可以在 `.md` 页面和 `.vue` 组件中使用 `data` 命名导出从该文件中导入数据:
```vue
<script setup>
import { data } from './example.data.js'
</script>
<pre>{{ data }}</pre>
```
输出:
```json
{
"hello": "world"
}
```
你会注意到数据加载本身并没有导出 `data`。这是因为 VitePress 在后台调用了 `load()` 方法,并通过名为 `data` 的命名导出隐式地暴露了结果。
即使它是异步的,这也是有效的:
```js
export default {
async load() {
// fetch remote data
return (await fetch('...')).json()
}
}
```
## 使用本地文件生成数据 {#data-from-local-files}
当需要基于本地文件生成数据时,应该在数据加载中使用 `watch` 选项,以便这些文件改动时可以触发热更新。
`watch` 选项也很方便,因为可以使用 [glob 模式](https://github.com/mrmlnc/fast-glob#pattern-syntax) 匹配多个文件。模式可以相对于数据加载文件本身,`load()` 函数将接收匹配文件的绝对路径。
下面的例子展示了如何使用 [csv-parse](https://github.com/adaltas/node-csv/tree/master/packages/csv-parse/) 加载 CSV 文件并将其转换为 JSON。因为此文件仅在构建时执行因此不会将 CSV 解析器发送到客户端!
```js
import fs from 'node:fs'
import { parse } from 'csv-parse/sync'
export default {
watch: ['./data/*.csv'],
load(watchedFiles) {
// watchedFiles will be an array of absolute paths of the matched files.
// generate an array of blog post metadata that can be used to render
// a list in the theme layout
return watchedFiles.map((file) => {
return parse(fs.readFileSync(file, 'utf-8'), {
columns: true,
skip_empty_lines: true
})
})
}
}
```
## `createContentLoader`
当构建一个内容为主的站点时,我们经常需要创建一个“档案”或“索引”页面:一个我们可以列出内容中的所有可用条目的页面,例如博客文章或 API 页面。我们**可以**直接使用数据加载 API 实现这一点但由于这是一个常见的用例VitePress 还提供了一个 `createContentLoader` 辅助函数来简化这个过程:
```js
// posts.data.js
import { createContentLoader } from 'vitepress'
export default createContentLoader('posts/*.md', /* options */)
```
该辅助函数接受一个相对于[项目根目录](./routing#project-root)的 glob 模式,并返回一个 `{ watch, load }` 数据加载对象,该对象可以用作数据加载文件中的默认导出。它还基于文件修改时间戳实现了缓存以提高开发性能。
请注意,数据加载仅适用于 Markdown 文件——匹配的非 Markdown 文件将被跳过。
加载的数据将是一个类型为 `ContentData[]` 的数组:
```ts
interface ContentData {
// mapped URL for the page. e.g. /posts/hello.html (does not include base)
// manually iterate or use custom `transform` to normalize the paths
url: string
// frontmatter data of the page
frontmatter: Record<string, any>
// the following are only present if relevant options are enabled
// we will discuss them below
src: string | undefined
html: string | undefined
excerpt: string | undefined
}
```
默认情况下只提供 `url``frontmatter`。这是因为加载的数据将作为 JSON 内联在客户端包中,我们需要谨慎考虑其大小。下面的例子展示了如何使用数据构建最小的博客索引页面:
```vue
<script setup>
import { data as posts } from './posts.data.js'
</script>
<template>
<h1>All Blog Posts</h1>
<ul>
<li v-for="post of posts">
<a :href="post.url">{{ post.frontmatter.title }}</a>
<span>by {{ post.frontmatter.author }}</span>
</li>
</ul>
</template>
```
### 选项 {#options}
默认数据可能不适合所有需求——可以选择使用选项转换数据:
```js
// posts.data.js
import { createContentLoader } from 'vitepress'
export default createContentLoader('posts/*.md', {
includeSrc: true, // include raw markdown source?
render: true, // include rendered full page HTML?
excerpt: true, // include excerpt?
transform(rawData) {
// map, sort, or filter the raw data as you wish.
// the final result is what will be shipped to the client.
return rawData.sort((a, b) => {
return +new Date(b.frontmatter.date) - +new Date(a.frontmatter.date)
}).map((page) => {
page.src // raw markdown source
page.html // rendered full page HTML
page.excerpt // rendered excerpt HTML (content above first `---`)
return {/* ... */}
})
}
})
```
查看它在 [Vue.js 博客](https://github.com/vuejs/blog/blob/main/.vitepress/theme/posts.data.ts)中是如何使用的。
`createContentLoader` API 也可以在[构建钩子](/reference/site-config#build-hooks)中使用:
```js
// .vitepress/config.js
export default {
async buildEnd() {
const posts = await createContentLoader('posts/*.md').load()
// generate files based on posts metadata, e.g. RSS feed
}
}
```
**类型**
```ts
interface ContentOptions<T = ContentData[]> {
/**
* Include src?
* @default false
*/
includeSrc?: boolean
/**
* Render src to HTML and include in data?
* @default false
*/
render?: boolean
/**
* If `boolean`, whether to parse and include excerpt? (rendered as HTML)
*
* If `function`, control how the excerpt is extracted from the content.
*
* If `string`, define a custom separator to be used for extracting the
* excerpt. Default separator is `---` if `excerpt` is `true`.
*
* @see https://github.com/jonschlinkert/gray-matter#optionsexcerpt
* @see https://github.com/jonschlinkert/gray-matter#optionsexcerpt_separator
*
* @default false
*/
excerpt?:
| boolean
| ((file: { data: { [key: string]: any }; content: string; excerpt?: string }, options?: any) => void)
| string
/**
* Transform the data. Note the data will be inlined as JSON in the client
* bundle if imported from components or markdown files.
*/
transform?: (data: ContentData[]) => T | Promise<T>
}
```
## 为数据加载器导出类型 {#typed-data-loaders}
当使用 TypeScript 时,可以像这样为 loader 和 `data` 导出类型:
```ts
import { defineLoader } from 'vitepress'
export interface Data {
// data type
}
declare const data: Data
export { data }
export default defineLoader({
// type checked loader options
watch: ['...'],
async load(): Promise<Data> {
// ...
}
})
```
## 配置 {#configuration}
要获取数据加载中的配置信息,可以使用如下代码:
```ts
import type { SiteConfig } from 'vitepress'
const config: SiteConfig = (globalThis as any).VITEPRESS_CONFIG
```

@ -0,0 +1,291 @@
---
outline: deep
---
# 部署 VitePress 站点 {#deploy-your-vitepress-site}
以下指南基于一些前提:
- VitePress 站点位于项目的 `docs` 目录中。
- 你使用的是默认的生成输出目录 `.vitepress/dist`)。
- VitePress 作为本地依赖项安装在项目中,并且你已在 `package.json` 中设置以下脚本:
```json
{
"scripts": {
"docs:build": "vitepress build docs",
"docs:preview": "vitepress preview docs"
}
}
```
## 本地构建与测试 {#build-and-test-locally}
1. 可以运行以下命令来构建文档:
```sh
$ npm run docs:build
```
2. 构建文档后,通过运行以下命令可以在本地预览它:
```sh
$ npm run docs:preview
```
`preview` 命令将启动一个本地静态 Web 服务器`http://localhost:4173`,该服务器以 `.vitepress/dist` 作为源文件。这是检查生产版本在本地环境中是否正常的一种简单方法。
3. 可以通过传递 `--port` 作为参数来配置服务器的端口。
```json
{
"scripts": {
"docs:preview": "vitepress preview docs --port 8080"
}
}
```
现在 `docs:preview` 方法将在 `http://localhost:8080` 启动服务器。
## 设定 public 根目录 {#setting-a-public-base-path}
默认情况下,我们假设站点将部署在域名 `/`)的根路径上。如果站点在子路径中提供服务,例如 `https://mywebsite.com/blog/`,则需要在 VitePress 配置中将 [`base`](../reference/site-config#base)选项设置为 `'/blog/'`
**例:** 如果你使用的是 Github或 GitLab页面并部署到 `user.github.io/repo/`,请将 `base` 设置为 `/repo/`
## HTTP 缓存标头 {#http-cache-headers}
如果可以控制生产服务器上的 HTTP 标头,则可以配置 `cache-control` 标头以在重复访问时获得更好的性能。
生产版本对静态资源 (JavaScript、CSS 和其他非 `public` 目录中的导入资源) 使用哈希文件名。如果你使用浏览器开发工具的网络选项卡查看生产预览,你将看到类似 `app.4f283b18.js` 的文件。
此哈希 `4f283b18` 是从此文件的内容生成的。相同的哈希 URL 保证提供相同的文件内容——如果内容更改URL 也会更改。这意味着你可以安全地为这些文件使用最强的缓存标头。所有此类文件都将放置在输出目录的 `assets/` 中,因此你可以为它们配置以下标头:
```
Cache-Control: max-age=31536000,immutable
```
::: details Netlify 示例 `_headers` 文件
```
/assets/*
cache-control: max-age=31536000
cache-control: immutable
```
注意:该 `_headers` 文件应放置在[public 目录](/guide/asset-handling#the-public-directory)中(在我们的例子中是 `docs/public/_headers`),以便将其逐字复制到输出目录。
[Netlify 自定义标头文档](https://docs.netlify.com/routing/headers/)
:::
::: details Vercel 配置示例 `vercel.json`
```json
{
"headers": [
{
"source": "/assets/(.*)",
"headers": [
{
"key": "Cache-Control",
"value": "max-age=31536000, immutable"
}
]
}
]
}
```
注意:`vercel.json` 文件应放在存储库的根目录中。
[Vercel 关于标头配置的文档](https://vercel.com/docs/concepts/projects/project-configuration#headers)
:::
## 各平台部署指南 {#platform-guides}
### Netlify / Vercel / Cloudflare Pages / AWS Amplify / Render
使用仪表板创建新项目并更改这些设置:
- **构建命令:** `npm run docs:build`
- **输出目录:** `docs/.vitepress/dist`
- **node 版本:** `18` (或更高版本)
::: warning
不要为 HTML 代码启用 _Auto Minify_ 等选项。它将从输出中删除对 Vue 有意义的注释。如果被删除,你可能会看到激活不匹配错误。
:::
### GitHub Pages
1. 在项目的 `.github/workflows` 目录中创建一个名为 `deploy.yml` 的文件,其中包含这样的内容:
```yaml
# Sample workflow for building and deploying a VitePress site to GitHub Pages
#
name: Deploy VitePress site to Pages
on:
# Runs on pushes targeting the `main` branch. Change this to `master` if you're
# using the `master` branch as the default branch.
push:
branches: [main]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
concurrency:
group: pages
cancel-in-progress: false
jobs:
# Build job
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0 # Not needed if lastUpdated is not enabled
# - uses: pnpm/action-setup@v2 # Uncomment this if you're using pnpm
# - uses: oven-sh/setup-bun@v1 # Uncomment this if you're using Bun
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 18
cache: npm # or pnpm / yarn
- name: Setup Pages
uses: actions/configure-pages@v3
- name: Install dependencies
run: npm ci # or pnpm install / yarn install / bun install
- name: Build with VitePress
run: |
npm run docs:build # or pnpm docs:build / yarn docs:build / bun run docs:build
touch docs/.vitepress/dist/.nojekyll
- name: Upload artifact
uses: actions/upload-pages-artifact@v2
with:
path: docs/.vitepress/dist
# Deployment job
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
needs: build
runs-on: ubuntu-latest
name: Deploy
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v2
```
::: warning
确保 VitePress 中的 `base` 选项配置正确。有关更多详细信息,请参阅[设置根路径](#setting-a-public-base-path)。
:::
2. 在存储库设置中的“Pages”菜单项下选择“Build and deployment > Source > GitHub Actions”。
3. 将更改推送到 `main` 分支并等待 GitHub Action 工作流完成。你应该看到站点部署到 `https://<username>.github.io/[repository]/``https://<custom-domain>/`,这取决于你的设置。你的站点将在每次推送到 `main` 分支时自动部署。
### GitLab Pages
1. 如果你想部署到 `https://<username> .gitlab.io/<repository> /`,将 VitePress 配置中的 `outDir` 设置为 `../public`。将 `base` 选项配置为 `'/<repository>/'`
2. 在项目的根目录中创建一个名为 `.gitlab-ci.yml` 的文件,其中包含以下内容。每当你更改内容时,这都会构建和部署你的站点:
```yaml
image: node:18
pages:
cache:
paths:
- node_modules/
script:
# - apk add git # Uncomment this if you're using small docker images like alpine and have lastUpdated enabled
- npm install
- npm run docs:build
artifacts:
paths:
- public
only:
- main
```
### Azure 静态 web 应用 {#azure-static-web-apps}
1. 参考[官方文档](https://docs.microsoft.com/en-us/azure/static-web-apps/build-configuration)。
2. 在配置文件中设置这些值 (并删除不需要的值,如 `api_location`)
- **`app_location`**: `/`
- **`output_location`**: `docs/.vitepress/dist`
- **`app_build_command`**: `npm run docs:build`
### Firebase {#firebase}
1. 在项目的根目录下创建 `firebase.json``.firebaserc`
`firebase.json`:
```json
{
"hosting": {
"public": "docs/.vitepress/dist",
"ignore": []
}
}
```
`.firebaserc`:
```json
{
"projects": {
"default": "<YOUR_FIREBASE_ID>"
}
}
```
2. 运行 `npm run docs:build` 后,运行此命令进行部署:
```sh
firebase deploy
```
### Surge
1. 运行 `npm run docs:build` 后,运行此命令进行部署:
```sh
npx surge docs/.vitepress/dist
```
### Heroku
1. 参考 [`heroku-buildpack-static`](https://elements.heroku.com/buildpacks/heroku/heroku-buildpack-static) 中给出的文档和指南。
2. 使用以下内容在项目的根目录中创建一个名为 `static.json` 的文件:
```json
{
"root": "docs/.vitepress/dist"
}
```
### Edgio
请参阅[创建并部署 VitePress 应用程序到 Edgio](https://docs.edg.io/guides/vitepress)。
### Kinsta 静态站点托管 {#kinsta-static-site-hosting}
你可以按照这些[说明](https://kinsta.com/docs/vitepress-static-site-example/) 在 [Kinsta](https://kinsta.com/static-site-hosting/) 上部署 Vitepress 站点。

@ -0,0 +1,338 @@
---
outline: deep
---
# 扩展默认主题 {#extending-the-default-theme}
VitePress 默认的主题已经针对文档进行了优化,并且可以进行自定义。请参考[默认主题配置概览](../reference/default-theme-config)获取完整的选项列表。
但是有一些情况仅靠配置是不够的。例如:
1. 需要调整 CSS 样式;
2. 需要修改 Vue 应用实例,例如注册全局组件;
3. 需要通过 layout 插槽将自定义内容注入到主题中;
这些高级自定义配置将需要使用自定义主题来“拓展”默认主题。
:::tip
在继续之前,请确保首先阅读[自定义主题](./custom-theme)以了解其工作原理。
:::
## 自定义 CSS {#customizing-css}
可以通过覆盖根级别的 CSS 变量来自定义默认主题的 CSS
```js
// .vitepress/theme/index.js
import DefaultTheme from 'vitepress/theme'
import './custom.css'
export default DefaultTheme
```
```css
/* .vitepress/theme/custom.css */
:root {
--vp-c-brand-1: #646cff;
--vp-c-brand-2: #747bff;
}
```
查看[默认主题 CSS 变量](https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css)来获取可以被覆盖的变量。
## 使用自定义字体 {#using-different-fonts}
VitePress 使用 [Inter](https://rsms.me/inter/) 作为默认字体,并且将其包含在生成的输出中。该字体在生产环境中也会自动预加载。但是如果要使用不同的字体,这可能不是很好。
为了避免在生成后的输出中包含 Inter 字体,请从 `vitepress/theme-without-fonts` 中导入主题:
```js
// .vitepress/theme/index.js
import DefaultTheme from 'vitepress/theme-without-fonts'
import './my-fonts.css'
export default DefaultTheme
```
```css
/* .vitepress/theme/custom.css */
:root {
--vp-font-family-base: /* normal text font */
--vp-font-family-mono: /* code font */
}
```
::: warning
如果你在使用像是[团队页](/reference/default-theme-team-page)这样的组件,请确保也从 `vitepress/theme-without-fonts` 中导入它们!
:::
如果字体是通过 `@font-face` 引用的本地文件,它将会被作为资源被包含在 `.vitepress/dist/asset` 目录下,并且使用哈希后的文件名。为了预加载这个文件,请使用 [transformHead](/reference/site-config#transformhead) 构建钩子:
```js
// .vitepress/config.js
export default {
transformHead({ assets }) {
// adjust the regex accordingly to match your font
const myFontFile = assets.find(file => /font-name\.\w+\.woff2/)
if (myFontFile) {
return [
[
'link',
{
rel: 'preload',
href: myFontFile,
as: 'font',
type: 'font/woff2',
crossorigin: ''
}
]
]
}
}
}
```
## 注册全局组件 {#registering-global-components}
```js
// .vitepress/theme/index.js
import DefaultTheme from 'vitepress/theme'
/** @type {import('vitepress').Theme} */
export default {
extends: DefaultTheme,
enhanceApp({ app }) {
// register your custom global components
app.component('MyGlobalComponent' /* ... */)
}
}
```
如果使用 TypeScript:
```ts
// .vitepress/theme/index.ts
import type { Theme } from 'vitepress'
import DefaultTheme from 'vitepress/theme'
export default {
extends: DefaultTheme,
enhanceApp({ app }) {
// register your custom global components
app.component('MyGlobalComponent' /* ... */)
}
} satisfies Theme
```
因为我们使用 Vite还可以利用 Vite 的 [glob 导入功能](https://cn.vitejs.dev/guide/features.html#glob-import)来自动注册一个组件目录。
## 布局插槽 {#layout-slots}
默认主题的 `<Layout/>` 组件有一些插槽,能够被用来在页面的特定位置注入内容。下面这个例子展示了将一个组件注入到 outline 之前:
```js
// .vitepress/theme/index.js
import DefaultTheme from 'vitepress/theme'
import MyLayout from './MyLayout.vue'
export default {
extends: DefaultTheme,
// override the Layout with a wrapper component that
// injects the slots
Layout: MyLayout
}
```
```vue
<!--.vitepress/theme/MyLayout.vue-->
<script setup>
import DefaultTheme from 'vitepress/theme'
const { Layout } = DefaultTheme
</script>
<template>
<Layout>
<template #aside-outline-before>
My custom sidebar top content
</template>
</Layout>
</template>
```
也可以使用渲染函数。
```js
// .vitepress/theme/index.js
import { h } from 'vue'
import DefaultTheme from 'vitepress/theme'
import MyComponent from './MyComponent.vue'
export default {
extends: DefaultTheme,
Layout() {
return h(DefaultTheme.Layout, null, {
'aside-outline-before': () => h(MyComponent)
})
}
}
```
默认主题布局的全部可用插槽如下:
- 当 `layout: 'doc'` (默认) 在 frontmatter 中被启用时:
- `doc-top`
- `doc-bottom`
- `doc-footer-before`
- `doc-before`
- `doc-after`
- `sidebar-nav-before`
- `sidebar-nav-after`
- `aside-top`
- `aside-bottom`
- `aside-outline-before`
- `aside-outline-after`
- `aside-ads-before`
- `aside-ads-after`
- 当 `layout: 'home'` 在 frontmatter 中被启用时:
- `home-hero-before`
- `home-hero-info`
- `home-hero-image`
- `home-hero-after`
- `home-features-before`
- `home-features-after`
- 当 `layout: 'page'` 在 frontmatter 中被启用时:
- `page-top`
- `page-bottom`
- 当未找到页面 (404) 时:
- `not-found`
- 总是启用:
- `layout-top`
- `layout-bottom`
- `nav-bar-title-before`
- `nav-bar-title-after`
- `nav-bar-content-before`
- `nav-bar-content-after`
- `nav-screen-content-before`
- `nav-screen-content-after`
## Using View Transitions API
### 关于外观切换 {#on-appearance-toggle}
可以扩展默认主题以在切换颜色模式时提供自定义过渡动画。例如:
```vue
<!-- .vitepress/theme/Layout.vue -->
<script setup lang="ts">
import { useData } from 'vitepress'
import DefaultTheme from 'vitepress/theme'
import { nextTick, provide } from 'vue'
const { isDark } = useData()
const enableTransitions = () =>
'startViewTransition' in document &&
window.matchMedia('(prefers-reduced-motion: no-preference)').matches
provide('toggle-appearance', async ({ clientX: x, clientY: y }: MouseEvent) => {
if (!enableTransitions()) {
isDark.value = !isDark.value
return
}
const clipPath = [
`circle(0px at ${x}px ${y}px)`,
`circle(${Math.hypot(
Math.max(x, innerWidth - x),
Math.max(y, innerHeight - y)
)}px at ${x}px ${y}px)`
]
await document.startViewTransition(async () => {
isDark.value = !isDark.value
await nextTick()
}).ready
document.documentElement.animate(
{ clipPath: isDark.value ? clipPath.reverse() : clipPath },
{
duration: 300,
easing: 'ease-in',
pseudoElement: `::view-transition-${isDark.value ? 'old' : 'new'}(root)`
}
)
})
</script>
<template>
<DefaultTheme.Layout />
</template>
<style>
::view-transition-old(root),
::view-transition-new(root) {
animation: none;
mix-blend-mode: normal;
}
::view-transition-old(root),
.dark::view-transition-new(root) {
z-index: 1;
}
::view-transition-new(root),
.dark::view-transition-old(root) {
z-index: 9999;
}
.VPSwitchAppearance {
width: 22px !important;
}
.VPSwitchAppearance .check {
transform: none !important;
}
</style>
```
Result (**warning!**: flashing colors, sudden movements, bright lights):
<details>
<summary>Demo</summary>
![Appearance Toggle Transition Demo](/appearance-toggle-transition.webp)
</details>
有关视图过渡动画的更多详细信息,请参阅 [Chrome 文档](https://developer.chrome.com/docs/web-platform/view-transitions/)。
### 路由切换时 {#on-route-change}
即将到来。
## 重写内部组件 {#overriding-internal-components}
可以使用 Vite 的 [aliases](https://vitejs.dev/config/shared-options.html#resolve-alias) 来用自定义组件替换默认主题的组件:
```ts
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vitepress'
export default defineConfig({
vite: {
resolve: {
alias: [
{
find: /^.*\/VPNavBar\.vue$/,
replacement: fileURLToPath(
new URL('./components/CustomNavBar.vue', import.meta.url)
)
}
]
}
}
})
```
想要了解组件的确切名称请参考我们的[源代码](https://github.com/vuejs/vitepress/tree/main/src/client/theme-default/components)。因为组件是内部的,因此在小版本更迭中,它们名字改动的可能性很小。

@ -0,0 +1,48 @@
# frontmatter
## 用法 {#usage}
VitePress 支持在所有 Markdown 文件中使用 YAML frontmatter并使用 [gray-matter](https://github.com/jonschlinkert/gray-matter) 解析。frontmatter 必须位于 Markdown 文件的顶部 (在任何元素之前,包括 `<script>` 标签),并且需要在三条虚线之间的采用有效的 YAML 格式。例如:
```md
---
title: Docs with VitePress
editLink: true
---
```
许多站点或默认主题配置选项在 frontmatter 中都有相应的选项。可以使用 frontmatter 来覆盖当前页面的特定行为。详细信息请参见 [frontmatter 配置参考](../reference/frontmatter-config)。
还可以定义自己的 frontmatter 数据,以在页面上的动态 Vue 表达式中使用。
## 访问 frontmatter 数据 {#accessing-frontmatter-data}
frontmatter 数据可以通过特殊的 `$frontmatter` 全局变量来访问:
下面的例子展示了应该如何在 Markdown 文件中使用它:
```md
---
title: Docs with VitePress
editLink: true
---
# {{ $frontmatter.title }}
Guide content
```
还可以使用 [`useData()`](../reference/runtime-api#usedata) 辅助函数在 `<script setup>` 中访问当前页面的 frontmatter。
## 其他 frontmatter 格式 {#alternative-frontmatter-formats}
VitePress 也支持 JSON 格式的 frontmatter以花括号开始和结束
```json
---
{
"title": "Blogging Like a Hacker",
"editLink": true
}
---
```

@ -0,0 +1,208 @@
# 快速开始 {#getting-started}
## 在线尝试 {#try-it-online}
可以直接在 [StackBlitz](https://vitepress.new) 上进行在线尝试。
## 安装 {#installation}
### 前置准备 {#prerequisites}
- [Node.js](https://nodejs.org/) 18 及以上版本。
- 通过命令行界面 (CLI) 访问 VitePress 的终端。
- 支持 [Markdown](https://en.wikipedia.org/wiki/Markdown) 语法的编辑器。
- 推荐 [VSCode](https://code.visualstudio.com/) 及其[官方 Vue 扩展](https://marketplace.visualstudio.com/items?itemName=Vue.volar)。
VitePress 可以单独使用,也可以安装到现有项目中。在这两种情况下,都可以使用以下方式安装它:
::: code-group
```sh [npm]
$ npm add -D vitepress
```
```sh [pnpm]
$ pnpm add -D vitepress
```
```sh [yarn]
$ yarn add -D vitepress
```
```sh [bun]
$ bun add -D vitepress
```
:::
::: details 遇到了 missing peer deps 警告?
如果使用 PNPM会注意到对 `@docsearch/js` 的 missing peer deps 警告。这不会影响 VitePress 运行。如果希望禁止显示此警告,请将以下内容添加到 `package.json`
```json
"pnpm": {
"peerDependencyRules": {
"ignoreMissing": [
"@algolia/client-search",
"search-insights"
]
}
}
```
:::
::: tip 注意
VitePress 是仅 ESM 的软件包。不要使用 `require()` 导入它,并确保最新的 `package.json` 包含 `"type": "module"`,或者更改相关文件的文件扩展名,例如 `.vitepress/config.js``.mjs`/`.mts`。更多详情请参考 [Vite 故障排除指南](http://vitejs.dev/guide/troubleshooting.html#this-package-is-esm-only)。此外,在异步 CJS 上下文中,可以使用 `await import('vitepress')` 代替。
:::
### 安装向导 {#setup-wizard}
VitePress 附带一个命令行设置向导,可以帮助你构建一个基本项目。安装后,通过运行以下命令启动向导:
::: code-group
```sh [npm]
$ npx vitepress init
```
```sh [pnpm]
$ pnpm vitepress init
```
```sh [bun]
$ bunx vitepress init
```
:::
将需要回答几个简单的问题:
<<< @/snippets/init.ansi
:::tip Vue 作为 peer dependency
如果打算使用 Vue 组件或 API 进行自定义,还应该明确地将 `vue` 安装为 peer dependency。
:::
## 文件结构 {#file-structure}
如果正在构建一个独立的 VitePress 站点,可以在当前目录 (`./`) 中搭建站点。但是,如果在现有项目中与其他源代码一起安装 VitePress建议将站点搭建在嵌套目录 (例如 `./docs`) 中,以便它与项目的其余部分分开。
假设选择在 `./docs` 中搭建 VitePress 项目,生成的文件结构应该是这样的:
```
.
├─ docs
│ ├─ .vitepress
│ │ └─ config.js
│ ├─ api-examples.md
│ ├─ markdown-examples.md
│ └─ index.md
└─ package.json
```
`docs` 目录作为 VitePress 站点的项目**根目录**。`.vitepress` 目录是 VitePress 配置文件、开发服务器缓存、构建输出和可选主题自定义代码的位置。
:::tip
默认情况下VitePress 将其开发服务器缓存存储在 `.vitepress/cache` 中,并将生产构建输出存储在 `.vitepress/dist` 中。如果使用 Git应该将它们添加到 `.gitignore` 文件中。也可以手动[配置](../reference/site-config#outdir)这些位置。
:::
### 配置文件 {#the-config-file}
配置文件 (`.vitepress/config.js`) 让你能够自定义 VitePress 站点的各个方面,最基本的选项是站点的标题和描述:
```js
// .vitepress/config.js
export default {
// site-level options
title: 'VitePress',
description: 'Just playing around.',
themeConfig: {
// theme-level options
}
}
```
还可以通过 `themeConfig` 选项配置主题的行为。有关所有配置选项的完整详细信息,请参见[配置参考](../reference/site-config)。
### 源文件 {#source-files}
`.vitepress` 目录之外的 Markdown 文件被视为**源文件**。
VitePress 使用 **基于文件的路由**:每个 `.md` 文件将在相同的路径被编译成为 `.html` 文件。例如,`index.md` 将会被编译成 `index.html`,可以在生成的 VitePress 站点的根路径 `/` 进行访问。
VitePress 还提供了生成简洁 URL、重写路径和动态生成页面的能力。这些将在[路由指南](./routing)中进行介绍。
## 启动并运行 {#up-and-running}
该工具还应该将以下 npm 脚本注入到 `package.json` 中:
```json
{
...
"scripts": {
"docs:dev": "vitepress dev docs",
"docs:build": "vitepress build docs",
"docs:preview": "vitepress preview docs"
},
...
}
```
`docs:dev` 脚本将启动具有即时热更新的本地开发服务器。使用以下命令运行它:
::: code-group
```sh [npm]
$ npm run docs:dev
```
```sh [pnpm]
$ pnpm run docs:dev
```
```sh [yarn]
$ yarn docs:dev
```
```sh [bun]
$ bun run docs:dev
```
:::
除了 npm 脚本,还可以直接调用 VitePress
::: code-group
```sh [npm]
$ npx vitepress dev docs
```
```sh [pnpm]
$ pnpm exec vitepress dev docs
```
```sh [bun]
$ bunx vitepress dev docs
```
:::
更多的命令行用法请参见 [CLI 参考](../reference/cli)。
开发服务应该会运行在 `http://localhost:5173` 上。在浏览器中访问 URL 以查看新站点的运行情况吧!
## 下一步 {#what-s-next}
- 想要进一步了解 Markdown 文件是怎么映射到对应的 HTML请继续阅读[路由指南](./routing)。
- 要了解有关可以在页面上执行的操作的更多信息,例如编写 Markdown 内容或使用 Vue 组件,请参见指南的“编写”部分。一个很好的起点是了解 [Markdown 扩展](./markdown)。
- 要探索默认文档主题提供的功能,请查看[默认主题配置参考](../reference/default-theme-config)。
- 如果想进一步自定义站点的外观,参见[扩展默认主题](./extending-default-theme)或者[构建自定义主题](./custom-theme)。
- 文档成形以后,务必阅读[部署指南](./deploy)。

@ -0,0 +1,113 @@
# 国际化 {#internationalization}
要使用内置的 i18n (国际化) 功能,需要创建类似于下面的目录结构:
```
docs/
├─ es/
│ ├─ foo.md
├─ fr/
│ ├─ foo.md
├─ foo.md
```
然后在 `docs/.vitepress/config.ts` 中:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
// shared properties and other top-level stuff...
locales: {
root: {
label: 'English',
lang: 'en'
},
fr: {
label: 'French',
lang: 'fr', // optional, will be added as `lang` attribute on `html` tag
link: '/fr/guide' // default /fr/ -- shows on navbar translations menu, can be external
// other locale specific properties...
}
}
})
```
下面的属性能够被每个 locale 覆盖 (包括 root)
```ts
interface LocaleSpecificConfig<ThemeConfig = any> {
lang?: string
dir?: string
title?: string
titleTemplate?: string | boolean
description?: string
head?: HeadConfig[] // will be merged with existing head entries, duplicate meta tags are automatically removed
themeConfig?: ThemeConfig // will be shallow merged, common stuff can be put in top-level themeConfig entry
}
```
有关自定义默认主题的文本占位符的信息,请参考 [`DefaultTheme.Config`](https://github.com/vuejs/vitepress/blob/main/types/default-theme.d.ts) 接口。不要在 locale 级别覆盖 `themeConfig.algolia``themeConfig.carbonAds`。想获取多语言搜索的信息,请参考 [Algolia 文档](../reference/default-theme-search#i18n)。
**提示**:配置文件也可以是 `docs/.vitepress/config/index.ts`。通过为每个语言环境创建一个配置文件,然后从 `index.ts` 合并并导出它们,可以更好的组织文件。
## 为本地化设置子目录 {#separate-directory-for-each-locale}
下面是一个组织良好的结构:
```
docs/
├─ en/
│ ├─ foo.md
├─ es/
│ ├─ foo.md
├─ fr/
├─ foo.md
```
但是VitePress 默认不会将 `/` 重定向到 `/en/`。需要配置服务器来实现这一点。例如,在使用 Netlify 时,可以添加一个 `docs/public/_redirects` 文件,如下所示:
```
/* /es/:splat 302 Language=es
/* /fr/:splat 302 Language=fr
/* /en/:splat 302
```
**提示:** 如果使用上述的方法,可以使用`nf_lang` cookie 来保存用户的语言选择。例如,可以在主题中添加以下代码:
```ts
// docs/.vitepress/theme/index.ts
import DefaultTheme from 'vitepress/theme'
import Layout from './Layout.vue'
export default {
extends: DefaultTheme,
Layout
}
```
```vue
<!-- docs/.vitepress/theme/Layout.vue -->
<script setup lang="ts">
import DefaultTheme from 'vitepress/theme'
import { useData } from 'vitepress'
import { watchEffect } from 'vue'
const { lang } = useData()
watchEffect(() => {
if (inBrowser) {
document.cookie = `nf_lang=${lang.value}; expires=Mon, 1 Jan 2030 00:00:00 UTC; path=/`
}
})
</script>
<template>
<DefaultTheme.Layout />
</template>
```
## RTL 支持 (实验性功能) {#rtl-support-experimental}
支持 RTL 需要在配置中指定 `dir: 'rtl'` 并且使用一些 RTLCSS PostCSS 插件,例如 <https://github.com/MohammadYounes/rtlcss>, <https://github.com/vkalinichev/postcss-rtl> 或者 <https://github.com/elchininet/postcss-rtlcss>。需要配置 PostCSS 插件,使用 `:where([dir="ltr"])``:where([dir="rtl"])` 作为前缀,以防止 CSS 特异性问题。

@ -0,0 +1,895 @@
# Markdown 拓展 {#markdown-extensions}
VitePress 带有内置的 Markdown 拓展。
## 标题锚点 {#header-anchors}
标题会自动应用锚点。可以使用 `markdown.anchor` 选项配置锚点的渲染。
### 自定义锚点 {#custom-anchors}
要为标题指定自定义锚点而不是使用自动生成的锚点,请向标题添加后缀:
```
# 使用自定义锚点 {#my-anchor}
```
这允许将标题链接为 `#my-anchor`,而不是默认的 `#使用自定义锚点`
## 链接 {#links}
内部和外部链接都会被特殊处理。
### 内部链接 {#internal-links}
内部链接将转换为单页导航的路由链接。此外,子目录中包含的每个 `index.md` 都会自动转换为 `index.html`,并带有相应的 URL `/`
例如,给定以下目录结构:
```
.
├─ index.md
├─ foo
│ ├─ index.md
│ ├─ one.md
│ └─ two.md
└─ bar
├─ index.md
├─ three.md
└─ four.md
```
假设现在处于 `foo/one.md` 文件中:
```md
[Home](/) <!-- sends the user to the root index.md -->
[foo](/foo/) <!-- sends the user to index.html of directory foo -->
[foo heading](./#heading) <!-- anchors user to a heading in the foo index file -->
[bar - three](../bar/three) <!-- you can omit extension -->
[bar - three](../bar/three.md) <!-- you can append .md -->
[bar - four](../bar/four.html) <!-- or you can append .html -->
```
### 页面后缀 {#page-suffix}
默认情况下,生成的页面和内部链接带有 `.html` 后缀。
### 外部链接 {#external-links}
外部链接带有 `target="_blank" rel="noreferrer"`
- [vuejs.org](https://vuejs.org)
- [VitePress on GitHub](https://github.com/vuejs/vitepress)
## frontmatter {#frontmatter}
[YAML 格式的 frontmatter](https://jekyllrb.com/docs/front-matter/) 开箱即用:
```yaml
---
title: Blogging Like a Hacker
lang: en-US
---
```
此数据将可用于页面的其余部分,以及所有自定义和主题组件。
更多信息,参见 [frontmatter](../reference/frontmatter-config)。
## GitHub 风格的表格 {#github-style-tables}
**输入**
```
| Tables | Are | Cool |
| ------------- | :-----------: | ----: |
| col 3 is | right-aligned | $1600 |
| col 2 is | centered | $12 |
| zebra stripes | are neat | $1 |
```
**输出**
| Tables | Are | Cool |
| ------------- | :-----------: | -----: |
| col 3 is | right-aligned | \$1600 |
| col 2 is | centered | \$12 |
| zebra stripes | are neat | \$1 |
## Emoji :tada:
**输入**
```
:tada: :100:
```
**输出**
:tada: :100:
这里可以找到[所有支持的 emoji 列表](https://github.com/markdown-it/markdown-it-emoji/blob/master/lib/data/full.mjs)。
## 目录表 (TOC) {#table-of-contents}
**输入**
```
[[toc]]
```
**输出**
[[toc]]
可以使用 `markdown.toc` 选项配置 TOC 的呈现效果。
## 自定义容器 {#custom-containers}
自定义容器可以通过它们的类型、标题和内容来定义。
### 默认标题 {#default-title}
**输入**
```md
::: info
This is an info box.
:::
::: tip
This is a tip.
:::
::: warning
This is a warning.
:::
::: danger
This is a dangerous warning.
:::
::: details
This is a details block.
:::
```
**输出**
::: info
This is an info box.
:::
::: tip
This is a tip.
:::
::: warning
This is a warning.
:::
::: danger
This is a dangerous warning.
:::
::: details
This is a details block.
:::
### 自定义标题 {#custom-title}
可以通过在容器的 "type" 之后附加文本来设置自定义标题。
**输入**
````md
::: danger STOP
危险区域,请勿继续
:::
::: details 点我查看代码
```js
console.log('Hello, VitePress!')
```
:::
````
**输出**
::: danger STOP
危险区域,请勿继续
:::
::: details 点我查看代码
```js
console.log('Hello, VitePress!')
```
:::
此外,可以通过在站点配置中添加以下内容来全局设置自定义标题,如果不是用英语书写,这会很有帮助:
```ts
// config.ts
export default defineConfig({
// ...
markdown: {
container: {
tipLabel: '提示',
warningLabel: '警告',
dangerLabel: '危险',
infoLabel: '信息',
detailsLabel: '详细信息'
}
}
// ...
})
```
### `raw`
这是一个特殊的容器,可以用来防止与 VitePress 的样式和路由冲突。这在记录组件库时特别有用。可能还想查看 [whyframe](https://whyframe.dev/docs/integrations/vitepress) 以获得更好的隔离。
**语法**
```md
::: raw
Wraps in a <div class="vp-raw">
:::
```
`vp-raw` class 也可以直接用于元素。样式隔离目前是可选的:
- 使用喜欢的包管理器来安装需要的依赖项:
```sh
$ npm add -D postcss
```
- 创建 `docs/.postcssrc.cjs` 并将以下内容
```js
import { postcssIsolateStyles } from 'vitepress'
export default {
plugins: [postcssIsolateStyles()]
}
```
It uses [`postcss-prefix-selector`](https://github.com/postcss/postcss-load-config) under the hood. You can pass its options like this:
```js
postcssIsolateStyles({
includeFiles: [/vp-doc\.css/] // defaults to /base\.css/
})
```
## 代码块中的语法高亮 {#syntax-highlighting-in-code-blocks}
VitePress 使用 [Shikiji](https://github.com/antfu/shikiji) ([Shiki](https://shiki.matsu.io/) 的改进版本) 在 Markdown 代码块中使用彩色文本实现语法高亮。Shiki 支持多种编程语言。需要做的就是将有效的语言别名附加到代码块的开头:
**输入**
````
```js
export default {
name: 'MyComponent',
// ...
}
```
````
````
```html
<ul>
<li v-for="todo in todos" :key="todo.id">
{{ todo.text }}
</li>
</ul>
```
````
**输出**
```js
export default {
name: 'MyComponent'
// ...
}
```
```html
<ul>
<li v-for="todo in todos" :key="todo.id">
{{ todo.text }}
</li>
</ul>
```
在 Shikiji 的代码仓库中,可以找到[合法的编程语言列表](https://github.com/antfu/shikiji/blob/main/docs/languages.md)。
还可以全局配置中自定义语法高亮主题。有关详细信息,参见 [`markdown` 选项](../reference/site-config#markdown)得到更多信息。
## 在代码块中实现行高亮 {#line-highlighting-in-code-blocks}
**输入**
````
```js{4}
export default {
data () {
return {
msg: 'Highlighted!'
}
}
}
```
````
**输出**
```js{4}
export default {
data () {
return {
msg: 'Highlighted!'
}
}
}
```
除了单行之外,还可以指定多个单行、多行,或两者均指定:
- 多行:例如 `{5-8}`、`{3-10}`、`{10-17}`
- 多个单行:例如 `{4,7,9}`
- 多行与单行:例如 `{4,7-13,16,23-27,40}`
**输入**
````
```js{1,4,6-8}
export default { // Highlighted
data () {
return {
msg: `Highlighted!
This line isn't highlighted,
but this and the next 2 are.`,
motd: 'VitePress is awesome',
lorem: 'ipsum'
}
}
}
```
````
**输出**
```js{1,4,6-8}
export default { // Highlighted
data () {
return {
msg: `Highlighted!
This line isn't highlighted,
but this and the next 2 are.`,
motd: 'VitePress is awesome',
lorem: 'ipsum',
}
}
}
```
也可以使用 `// [!code hl]` 注释实现行高亮。
**输入**
````
```js
export default {
data () {
return {
msg: 'Highlighted!' // [!code hl]
}
}
}
```
````
**输出**
```js
export default {
data() {
return {
msg: 'Highlighted!' // [!code hl]
}
}
}
```
## 代码块中聚焦 {#focus-in-code-blocks}
在某一行上添加 `// [!code focus]` 注释将聚焦它并模糊代码的其他部分。
此外,可以使用 `// [!code focus:<lines>]` 定义要聚焦的行数。
**输入**
`!code` 后面只需要一个空格,为了展示原始的代码而不被实际渲染,这里有两个空格:
````
```js
export default {
data () {
return {
msg: 'Focused!' // [!code focus]
}
}
}
```
````
**输出**
```js
export default {
data() {
return {
msg: 'Focused!' // [!code focus]
}
}
}
```
## 代码块中的颜色差异 {#colored-diffs-in-code-blocks}
在某一行添加 `// [!code --]``// [!code ++]` 注释将会为该行创建 diff同时保留代码块的颜色。
**输入**
`!code` 后面只需要一个空格,为了展示原始的代码而不被实际渲染,这里有两个空格。
````
```js
export default {
data () {
return {
msg: 'Removed' // [!code --]
msg: 'Added' // [!code ++]
}
}
}
```
````
**输出**
```js
export default {
data () {
return {
msg: 'Removed' // [!code --]
msg: 'Added' // [!code ++]
}
}
}
```
## 高亮“错误”和“警告” {#errors-and-warnings-in-code-blocks}
在某一行添加 `// [!code warning]``// [!code error]` 注释将会为该行相应的着色。
**输入**
`!code` 后面只需要一个空格,为了展示原始的代码而不被实际渲染,这里有两个空格。
````
```js
export default {
data () {
return {
msg: 'Error', // [!code error]
msg: 'Warning' // [!code warning]
}
}
}
```
````
**输出**
```js
export default {
data() {
return {
msg: 'Error', // [!code error]
msg: 'Warning' // [!code warning]
}
}
}
```
## 行号 {#line-numbers}
可以通过以下配置为每个代码块启用行号:
```js
export default {
markdown: {
lineNumbers: true
}
}
```
查看 [`markdown` 选项](../reference/site-config#markdown) 获取更多信息。
可以在代码块中添加 `:line-numbers` / `:no-line-numbers` 标记来覆盖在配置中的设置。
**输入**
````md
```ts {1}
// line-numbers is disabled by default
const line2 = 'This is line 2'
const line3 = 'This is line 3'
```
```ts:line-numbers {1}
// line-numbers is enabled
const line2 = 'This is line 2'
const line3 = 'This is line 3'
```
```ts:line-numbers=2 {1}
// line-numbers is enabled and start from 2
const line3 = 'This is line 3'
const line4 = 'This is line 4'
```
````
**输出**
```ts {1}
// line-numbers is disabled by default
const line2 = 'This is line 2'
const line3 = 'This is line 3'
```
```ts:line-numbers {1}
// line-numbers is enabled
const line2 = 'This is line 2'
const line3 = 'This is line 3'
```
```ts:line-numbers=2 {1}
// line-numbers is enabled and start from 2
const line3 = 'This is line 3'
const line4 = 'This is line 4'
```
## 导入代码片段 {#import-code-snippets}
可以通过下面的语法来从现有文件中导入代码片段:
```md
<<< @/filepath
```
此语法同时支持[行高亮](#line-highlighting-in-code-blocks)
```md
<<< @/filepath{highlightLines}
```
**输入**
```md
<<< @/snippets/snippet.js{2}
```
**Code file**
<<< @/snippets/snippet.js
**输出**
<<< @/snippets/snippet.js
::: tip
`@` 的值对应于源代码根目录,默认情况下是 VitePress 项目根目录,除非配置了 `srcDir`。或者也可以从相对路径导入:
```md
<<< ../snippets/snippet.js
```
:::
也可以使用 [VS Code region](https://code.visualstudio.com/docs/editor/codebasics#_folding) 来只包含代码文件的相应部分。可以在文件目录后面的 `#` 符号后提供一个自定义的区域名:
**输入**
```md
<<< @/snippets/snippet-with-region.js#snippet{1}
```
**Code file**
<<< @/snippets/snippet-with-region.js
**输出**
<<< @/snippets/snippet-with-region.js#snippet{1}
也可以像这样在大括号内(`{}`)指定语言:
```md
<<< @/snippets/snippet.cs{c#}
<!-- with line highlighting: -->
<<< @/snippets/snippet.cs{1,2,4-6 c#}
<!-- with line numbers: -->
<<< @/snippets/snippet.cs{1,2,4-6 c#:line-numbers}
```
如果无法从文件拓展名推测出源语言,这将会很有帮助
## 代码组 {#code-groups}
可以像这样对多个代码块进行分组:
**输入**
````md
::: code-group
```js [config.js]
/**
* @type {import('vitepress').UserConfig}
*/
const config = {
// ...
}
export default config
```
```ts [config.ts]
import type { UserConfig } from 'vitepress'
const config: UserConfig = {
// ...
}
export default config
```
:::
````
**输出**
::: code-group
```js [config.js]
/**
* @type {import('vitepress').UserConfig}
*/
const config = {
// ...
}
export default config
```
```ts [config.ts]
import type { UserConfig } from 'vitepress'
const config: UserConfig = {
// ...
}
export default config
```
:::
也可以在代码组中[导入代码片段](#import-code-snippets)
**输入**
```md
::: code-group
<!-- filename is used as title by default -->
<<< @/snippets/snippet.js
<!-- you can provide a custom one too -->
<<< @/snippets/snippet-with-region.js#snippet{1,2 ts:line-numbers} [snippet with region]
:::
```
**输出**
::: code-group
<<< @/snippets/snippet.js
<<< @/snippets/snippet-with-region.js#snippet{1,2 ts:line-numbers} [snippet with region]
:::
## 包含 markdown 文件 {#markdown-file-inclusion}
可以像这样在一个 markdown 文件中包含另一个 markdown 文件,甚至是内嵌的。
::: tip
也可以使用 `@`,它的值对应于源代码根目录,默认情况下是 VitePress 项目根目录,除非配置了 `srcDir`
:::
例如,可以这样用相对路径包含 Markdown 文件:
**输入**
```md
# Docs
## Basics
<!--@include: ./parts/basics.md-->
```
**Part file** (`parts/basics.md`)
```md
Some getting started stuff.
### Configuration
Can be created using `.foorc.json`.
```
**等价代码**
```md
# Docs
## Basics
Some getting started stuff.
### Configuration
Can be created using `.foorc.json`.
```
它还支持选择行范围:
**输入**
```md
# Docs
## Basics
<!--@include: ./parts/basics.md{3,}-->
```
**Part file** (`parts/basics.md`)
```md
Some getting started stuff.
### Configuration
Can be created using `.foorc.json`.
```
**等价代码**
```md
# Docs
## Basics
### Configuration
Can be created using `.foorc.json`.
```
所选行范围的格式可以是: `{3,}``{,10}`、`{1,10}`
::: warning
如果指定的文件不存在,这将不会产生错误。因此,在使用这个功能的时候请保证内容按预期呈现。
:::
## 数学方程 {#math-equations}
现在这是可选的。要启用它, 需要安装 `markdown-it-mathjax3`,在配置文件中设置`markdown.math` 为 `true`
```sh
npm add -D markdown-it-mathjax3
```
```ts
// .vitepress/config.ts
export default {
markdown: {
math: true
}
}
```
**输入**
```md
When $a \ne 0$, there are two solutions to $(ax^2 + bx + c = 0)$ and they are
$$ x = {-b \pm \sqrt{b^2-4ac} \over 2a} $$
**Maxwell's equations:**
| equation | description |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| $\nabla \cdot \vec{\mathbf{B}} = 0$ | divergence of $\vec{\mathbf{B}}$ is zero |
| $\nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} = \vec{\mathbf{0}}$ | curl of $\vec{\mathbf{E}}$ is proportional to the rate of change of $\vec{\mathbf{B}}$ |
| $\nabla \times \vec{\mathbf{B}} -\, \frac1c\, \frac{\partial\vec{\mathbf{E}}}{\partial t} = \frac{4\pi}{c}\vec{\mathbf{j}} \nabla \cdot \vec{\mathbf{E}} = 4 \pi \rho$ | _wha?_ |
```
**输出**
When $a \ne 0$, there are two solutions to $(ax^2 + bx + c = 0)$ and they are
$$ x = {-b \pm \sqrt{b^2-4ac} \over 2a} $$
**Maxwell's equations:**
| equation | description |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| $\nabla \cdot \vec{\mathbf{B}} = 0$ | divergence of $\vec{\mathbf{B}}$ is zero |
| $\nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} = \vec{\mathbf{0}}$ | curl of $\vec{\mathbf{E}}$ is proportional to the rate of change of $\vec{\mathbf{B}}$ |
| $\nabla \times \vec{\mathbf{B}} -\, \frac1c\, \frac{\partial\vec{\mathbf{E}}}{\partial t} = \frac{4\pi}{c}\vec{\mathbf{j}} \nabla \cdot \vec{\mathbf{E}} = 4 \pi \rho$ | _wha?_ |
## 图片懒加载 {#image-lazy-loading}
You can enable lazy loading for each image added via markdown by setting `lazyLoading` to `true` in your config file:
```js
export default {
markdown: {
image: {
// image lazy loading is disabled by default
lazyLoading: true
}
}
}
```
## 高级配置 {#advanced-configuration}
VitePress 使用 [markdown-it](https://github.com/markdown-it/markdown-it) 作为 Markdown 渲染器。上面提到的很多拓展功能都是通过自定义插件实现的。可以使用 `.vitepress/config.js` 中的 `markdown` 选项来进一步自定义 `markdown-it` 实例。
```js
import { defineConfig } from 'vitepress'
import markdownItAnchor from 'markdown-it-anchor'
import markdownItFoo from 'markdown-it-foo'
export default defineConfig({
markdown: {
// options for markdown-it-anchor
// https://github.com/valeriangalliat/markdown-it-anchor#usage
anchor: {
permalink: markdownItAnchor.permalink.headerLink()
},
// options for @mdit-vue/plugin-toc
// https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-toc#options
toc: { level: [1, 2] },
config: (md) => {
// use more markdown-it plugins!
md.use(markdownItFoo)
}
}
})
```
请查看[配置参考:站点配置](../reference/site-config#markdown)来获取完整的可配置属性列表。

@ -0,0 +1,23 @@
# 从 VitePress 0.x 迁移 {#migration-from-vitepress-0-x}
如果你来自 VitePress 0.x 版本VitePress 有了一些重大更改。请按照本指南了解如何将应用程序迁移到最新的 VitePress。
## 应用配置 {#app-config}
- 国际化功能尚未实现。
## 主题配置 {#theme-config}
- `sidebar` 选项改变了它的结构。
- `children` 现在命名为 `items`
- 顶级侧边栏不包含 `link`。我们打算把它改回来。
- 删除了 `repo`、`repoLabel`、`docsDir`、`docsBranch`、`editLinks`、`editLinkText`以支持更灵活的api。
- 要将带有图标的 GitHub 链接添加到导航,请使用 [社交链接](../reference/default-theme-config#nav) 功能。
- 要添加“编辑此页面”功能,请使用 [编辑链接](../reference/default-theme-edit-link) 功能。
- `lastUpdated` 选项现在分为` config.lastUpdated` 和 `themeConfig.lastUpdatedText`
- `carbonAds.carbon` 更改为 `carbonAds.code`.
## frontmatter 配置 {#frontmatter-config}
- `home: true` 选项已更改为 `layout: home`。此外,还修改了许多与主页相关的设置以提供附加功能。详情请参阅 [主页指南](../reference/default-theme-home-page)。
- `footer` 选项移至 [`themeConfig.footer`](../reference/default-theme-footer).

@ -0,0 +1,30 @@
# 从 VuePress 迁移 {#migration-from-vuepress}
## 配置 {#config}
### 侧边栏 {#sidebar}
侧边栏不再从 frontmatter 中自动获取。你可以自行阅读 [`frontmatter`](https://github.com/vuejs/vitepress/issues/572#issuecomment-1170116225) 来动态填充侧边栏。[迁移工具](https://github.com/vuejs/vitepress/issues/96)将来可能会提供。
## Markdown {#markdown}
### 图片 {#images}
与 VuePress 不同在使用静态图片时VitePress 会根据配置自动处理这些 [`base`](./asset-handling#base-url)。
因此,现在可以在没有 `img` 标签的情况下渲染图像。
```diff
- <img :src="$withBase('/foo.png')" alt="foo">
+ ![foo](/foo.png)
```
::: warning
对于动态图像,仍然需要 `withBase`,如 [Base URL](./asset-handling#base-url) 中所示。
:::
使用 `<img.*withBase\('(.*)'\).*alt="([^"]*)".*>` 正则表达式查找并替换为 `![$2]($1)``![](...)` 语法替换所有图像。
---
更多请继续关注...

@ -0,0 +1,23 @@
# MPA 模式 <Badge type="warning" text="experimental" /> {#mpa-mode}
可以通过命令行输入 `vitepress build --mpa` 或在配置文件中指定 `mpa: true` 配置选项来启用 MPA (Multi-Page Application) 模式。
在 MPA 模式下,所有页面都会默认不包含任何 JavaScript。因此站点可能评估工具中获得更好的初始访问性能分数。
但是,由于 SPA 导航的缺失跨页面链接将导致重新加载整个页面。MPA 模式下的导航不会像 SPA 模式那样立即响应。
同时请注意,默认情况下不使用 JavaScript 意味着你实际上只是将 Vue 作为服务器端模板语言。浏览器不会附加任何事件处理程序,因此将不会有任何交互性。要加载客户端 JavaScript需要使用特殊的 `<script client>` 标签:
```html
<script client>
document.querySelector('h1').addEventListener('click', () => {
console.log('client side JavaScript!')
})
</script>
# Hello
```
`<script client>` 是 VitePress 独有的功能,而不是 Vue 的功能。它可以在 `.md``.vue` 文件中使用,但只能在 MPA 模式下使用。所有主题组件中的客户端脚本将被打包在一起,而特定页面的客户端脚本将会分开处理。
请注意,`<script client>` **不会被视为 Vue 组件代码**:它会看做普通的 JavaScript 模块来处理。因此,只有在站点需要绝对最小的客户端交互性时,才应该使用 MPA 模式。

@ -0,0 +1,373 @@
---
outline: deep
---
# 路由 {#routing}
## 基于文件的路由 {#file-based-routing}
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 可以托管在任何可以提供静态文件的 Web 服务器上。
## 根目录和源目录 {#root-and-source-directory}
VitePress 项目的文件结构中有两个重要的概念:项目根目录 (**project root**) 和源目录 (**source directory**)。
### 项目根目录 {#project-root}
项目根目录是 VitePress 将尝试寻找 `.vitepress` 特殊目录的地方。`.vitepress` 目录是 VitePress 配置文件、开发服务器缓存、构建输出和可选主题自定义代码的预留位置。
当从命令行运行 `vitepress dev``vitepress build`VitePress 将使用当前工作目录作为项目根目录。要将子目录指定为根目录,需要将相对路径传递给命令。例如,如果 VitePress 项目位于 `./docs`,应该运行 `vitepress dev docs`
```
.
├─ docs # project root
│ ├─ .vitepress # config dir
│ ├─ getting-started.md
│ └─ index.md
└─ ...
```
```sh
vitepress dev docs
```
这将导致以下源代码到 HTML 的映射:
```
docs/index.md --> /index.html (可以通过 / 访问)
docs/getting-started.md --> /getting-started.html
```
### 源目录 {#source-directory}
源目录是 Markdown 源文件所在的位置。默认情况下,它与项目根目录相同。但是,可以通过 [`srcDir`](../reference/site-config#srcdir) 配置选项对其进行配置。
`srcDir` 选项是相对于项目根目录解析的。例如,对于 `srcDir: 'src'`,文件结构将如下所示:
```
. # project root
├─ .vitepress # config dir
└─ src # source dir
├─ getting-started.md
└─ index.md
```
生成的源代码到 HTML 的映射:
```
src/index.md --> /index.html (可以通过 / 访问)
src/getting-started.md --> /getting-started.html
```
## 链接页面 {#linking-between-pages}
在页面之间链接时,可以使用绝对路径和相对路径。请注意,虽然 `.md``.html` 扩展名都可以使用,但最佳做法是省略文件扩展名,以便 VitePress 可以根据配置生成最终 URL。
```md
<!-- Do -->
[Getting Started](./getting-started)
[Getting Started](../guide/getting-started)
<!-- Don't -->
[Getting Started](./getting-started.md)
[Getting Started](./getting-started.html)
```
在[资源处理](./asset-handling)中了解有关链接到资源(例如图像)的更多信息。
### 链接到非 vitepress 页面 {#linking-to-non-vitepress-pages}
如果想链接到站点中不是由 VitePress 生成的页面,需要使用完整的 URL在新选项卡中打开或明确指定 target
**输入**
```md
[Link to pure.html](/pure.html){target="_self"}
```
**输出**
[Link to pure.html](/pure.html){target="_self"}
::: tip 注意
在 Markdown 链接中,`base` 会自动添加到 URL 前面。这意味着,如果想链接到 `base` 之外的页面,则链接中需要类似 `../../pure.html` 的内容(由浏览器相对于当前页面解析)。
或者,可以直接使用锚标记语法:
```md
<a href="/pure.html" target="_self">Link to pure.html</a>
```
:::
## 生成简洁的 URL {#generating-clean-url}
:::warning 需要服务器支持
要使用 VitePress 提供简洁 URL需要服务器端支持。
:::
默认情况下VitePress 将入站链接解析为以 `.html` 结尾的 URL。但是一些用户可能更喜欢没有 .html 扩展名的“简洁 URL”——例如`example.com/path` 而不是 `example.com/path.html`
某些服务器或托管平台(例如 Netlify 或 Vercel提供将 `/foo` 之类的 URL 映射到 `/foo.html`(如果存在)的功能,而无需重定向:
- Netlify 默认支持这个。
- Vercel 需要在 [vercel.json 中启用 cleanUrls 选项](https://vercel.com/docs/concepts/projects/project-configuration#cleanurls)。
如果可以使用此功能,还可以启用 VitePress 自己的 [`cleanUrls`](../reference/site-config#cleanurls) 配置选项,以便:
- 页面之间的入站链接是在没有 `.html` 扩展名的情况下生成的。
- 如果当前路径以 `.html` 结尾,路由器将执行客户端重定向到无扩展路径。
但是,如果无法为服务器配置此类支持(例如 GitHub 页面),则必须手动采用以下目录结构:
```
.
├─ getting-started
│ └─ index.md
├─ installation
│ └─ index.md
└─ index.md
```
## 路由重写 {#route-rewrites}
可以自定义源目录结构和生成页面之间的映射。当有一个复杂的项目结构时,它很有用。例如,假设有一个包含多个包的 monorepo并且希望将文档与源文件一起放置如下所示
```
.
├─ packages
│ ├─ pkg-a
│ │ └─ src
│ │ ├─ pkg-a-code.ts
│ │ └─ pkg-a-docs.md
│ └─ pkg-b
│ └─ src
│ ├─ pkg-b-code.ts
│ └─ pkg-b-docs.md
```
希望像这样生成 VitePress 页面:
```
packages/pkg-a/src/pkg-a-docs.md --> /pkg-a/index.html
packages/pkg-b/src/pkg-b-docs.md --> /pkg-b/index.html
```
可以通过像这样配置 [`rewrites`](../reference/site-config#rewrites) 选项来实现此目的:
```ts
// .vitepress/config.js
export default {
rewrites: {
'packages/pkg-a/src/pkg-a-docs.md': 'pkg-a/index.md',
'packages/pkg-b/src/pkg-b-docs.md': 'pkg-b/index.md'
}
}
```
`rewrites` 选项还支持动态路由参数。在上面的示例中,如果有很多包,则列出所有路径会很冗长。鉴于它们都具有相同的文件结构,可以像这样简化配置:
```ts
export default {
rewrites: {
'packages/:pkg/src/(.*)': ':pkg/index.md'
}
}
```
重写路径是使用 `path-to-regexp` 包编译的——请参阅其[文档](https://github.com/pillarjs/path-to-regexp#parameters)以获取更高级的语法。
::: warning 开启重写功能时使用相对链接
启用重写后,**相对链接应基于重写的路径**。例如,为了创建从 `packages/pkg-a/src/pkg-a-code.md``packages/pkg-b/src/pkg-b-code.md` 的相对链接,应该使用:
```md
[Link to PKG B](../pkg-b/pkg-b-code)
```
:::
## 动态路由 {#dynamic-routes}
可以使用单个 Markdown 文件和动态数据生成许多页面。例如,可以创建一个 `packages/[pkg].md` 文件,为项目中的每个包生成相应的页面。这里,`[pkg]` 段是一个路由参数,用于区分每个页面。
### 路径加载文件 {#paths-loader-file}
由于 VitePress 是静态站点生成器,因此**必须**在构建时确定可能的页面路径。因此,动态路由页面必须伴随**路径加载文件**。对于 `packages/[pkg].md`,我们需要 `packages/[pkg].paths.js`(也支持 `.ts`
```
.
└─ packages
├─ [pkg].md # route template
└─ [pkg].paths.js # route paths loader
```
路径加载器应该提供一个带有 `paths` 方法的对象作为其默认导出。`paths` 方法应返回具有 `params` 属性的对象数组。这些对象中的每一个都将生成一个相应的页面。
给定以下 `paths` 数组:
```js
// packages/[pkg].paths.js
export default {
paths() {
return [
{ params: { pkg: 'foo' }},
{ params: { pkg: 'bar' }}
]
}
}
```
生成的 HTML 页面将会是:
```
.
└─ packages
├─ foo.html
└─ bar.html
```
### 多参数 {#multiple-params}
动态路由可以包含多个参数:
**File Structure**
```
.
└─ packages
├─ [pkg]-[version].md
└─ [pkg]-[version].paths.js
```
**路径加载器**
```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
```
### 动态生成路径 {#dynamically-generating-paths}
路径加载器模块在 Node.js 中运行,并且仅在构建期间执行。可以使用本地或远程的任何数据动态生成路径数组。
从本地文件生成路径:
```js
import fs from 'fs'
export default {
paths() {
return fs
.readdirSync('packages')
.map((pkg) => {
return { params: { pkg }}
})
}
}
```
从远程数据生成路径:
```js
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
}
}
})
}
}
```
### 访问页面中的参数 {#accessing-params-in-page}
可以使用参数将附加数据传递到每个页面。Markdown 路由文件可以通过 `$params` 全局属性访问 Vue 表达式中的当前页面参数:
```md
- package name: {{ $params.pkg }}
- version: {{ $params.version }}
```
还可以通过 [`useData`](../reference/runtime-api#usedata) runtime API 访问当前页面的参数。这在 Markdown 文件和 Vue 组件中都可用:
```vue
<script setup>
import { useData } from 'vitepress'
// params is a Vue ref
const { params } = useData()
console.log(params.value)
</script>
```
### 渲染原始内容 {#rendering-raw-content}
传递给页面的参数将在客户端 JavaScript payload 中序列化,因此应该避免在参数中传递大量数据,例如从远程 CMS 获取的原始 Markdown 或 HTML 内容。
相反,可以使用每个路径对象上的 `content` 属性将此类内容传递到每个页面:
```js
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 // raw Markdown or HTML
}
})
}
}
```
然后,使用以下特殊语法将内容呈现为 Markdown 文件本身的一部分:
```md
<!-- @content -->
```

@ -0,0 +1,53 @@
# 生成 sitemap {#sitemap-generation}
VitePress 提供开箱即用的配置,为站点生成 `sitemap.xml` 文件。要启用它,请将以下内容添加到 `.vitepress/config.js` 中:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
sitemap: {
hostname: 'https://example.com'
}
})
```
要在 `sitemap.xml` 中包含 `<lastmod>` 标签,可以启用 [`lastUpdated`](../reference/default-theme-last-updated) 选项。
## 选项 {#options}
VitePress 的 sitemap 由 [`sitemap`](https://www.npmjs.com/package/sitemap) 模块提供支持。可以将该模块支持的选项传递给配置文件中的 `sitemap` 选项。这些选项将直接传递给 `SitemapStream` 构造函数。有关更多详细信息,请参阅 [`sitemap` 文档](https://www.npmjs.com/package/sitemap#options-you-can-pass)。例如:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
sitemap: {
hostname: 'https://example.com',
lastmodDateOnly: false
}
})
```
## `transformItems` Hook
在将 sitemap 写入 `sitemap.xml` 文件之前,可以使用 `sitemap.transformItems` 钩子来修改 sitemap。使用 sitemap 调用该钩子,应返回 sitemap 数组。例如:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
sitemap: {
hostname: 'https://example.com',
transformItems: (items) => {
// add new items or modify/filter existing items
items.push({
url: '/extra-page',
changefreq: 'monthly',
priority: 0.8
})
return items
}
}
})
```

@ -0,0 +1,136 @@
---
outline: deep
---
# SSR 兼容性 {#ssr-compatibility}
通过使用 Vue 的服务器端渲染 (SSR) 功能VitePress 能够在生产构建期间在 Node.js 中预渲染应用程序。这意味着主题组件中的所有自定义代码都需要考虑 SSR 兼容性。
[Vue 官方文档的 SSR 部分](https://cn.vuejs.org/guide/scaling-up/ssr.html)提供了更多有关 SSR 是什么SSR / SSG 之间的关系以及编写 SSR 友好代码的常见注意事项等信息。原则上只在 Vue 组件的 `beforeMount``mounted` 钩子中访问 browser / DOM API。
## `<ClientOnly>`
如果正在使用或演示不支持 SSR 的组件 (例如,包含自定义指令),则可以将它们包装在内置的 `<ClientOnly>` 组件中:
```md
<ClientOnly>
<NonSSRFriendlyComponent />
</ClientOnly>
```
## 在导入时访问浏览器 API 的库 {#libraries-that-access-browser-api-on-import}
一些组件或库在**导入时**访问浏览器 API。要使用假定在导入时处于浏览器环境的代码需要动态导入它们。
### 在 mounted 钩子中导入 {#importing-in-mounted-hook}
```vue
<script setup>
import { onMounted } from 'vue'
onMounted(() => {
import('./lib-that-access-window-on-import').then((module) => {
// use code
})
})
</script>
```
### 条件导入 {#conditional-import}
也可以使用 `import.meta.env.SSR` 标志 ([Vite 环境变量](https://cn.vitejs.dev/guide/env-and-mode.html#env-变量)的一部分) 来有条件地导入依赖项:
```js
if (!import.meta.env.SSR) {
import('./lib-that-access-window-on-import').then((module) => {
// use code
})
}
```
因为 [`Theme.enhanceApp`](/guide/custom-theme#theme-interface) 可以是异步的,所以可以有条件地导入并注册访问浏览器 API 的 Vue 插件:
```js
// .vitepress/theme/index.js
/** @type {import('vitepress').Theme} */
export default {
// ...
async enhanceApp({ app }) {
if (!import.meta.env.SSR) {
const plugin = await import('plugin-that-access-window-on-import')
app.use(plugin.default)
}
}
}
```
如果使用 TypeScript:
```ts
// .vitepress/theme/index.ts
import type { Theme } from 'vitepress'
export default {
// ...
async enhanceApp({ app }) {
if (!import.meta.env.SSR) {
const plugin = await import('plugin-that-access-window-on-import')
app.use(plugin.default)
}
}
} satisfies Theme
```
### `defineClientComponent`
VitePress 为导入 Vue 组件提供了一个方便的辅助函数,该组件可以在导入时访问浏览器 API。
```vue
<script setup>
import { defineClientComponent } from 'vitepress'
const ClientComp = defineClientComponent(() => {
return import('component-that-access-window-on-import')
})
</script>
<template>
<ClientComp />
</template>
```
还可以将 props/children/slots 传递给目标组件:
```vue
<script setup>
import { ref } from 'vue'
import { defineClientComponent } from 'vitepress'
const clientCompRef = ref(null)
const ClientComp = defineClientComponent(
() => import('component-that-access-window-on-import'),
// args are passed to h() - https://vuejs.org/api/render-function.html#h
[
{
ref: clientCompRef
},
{
default: () => 'default slot',
foo: () => h('div', 'foo'),
bar: () => [h('span', 'one'), h('span', 'two')]
}
],
// callback after the component is loaded, can be async
() => {
console.log(clientCompRef.value)
}
)
</script>
<template>
<ClientComp />
</template>
```
目标组件将仅在 wrapper 组件的 mounted 钩子中导入。

@ -0,0 +1,256 @@
# 在 Markdown 使用 Vue {#using-vue-in-markdown}
在 VitePress 中,每个 Markdown 文件都被编译成 HTML而且将其作为 [Vue 单文件组件](https://cn.vuejs.org/guide/scaling-up/sfc.html)处理。这意味着可以在 Markdown 中使用任何 Vue 功能,包括动态模板、使用 Vue 组件或通过添加 `<script>` 标签为页面的 Vue 组件添加逻辑。
值得注意的是VitePress 利用 Vue 的编译器自动检测和优化 Markdown 内容的纯静态部分。静态内容被优化为单个占位符节点,并从页面的 JavaScript 负载中删除以供初始访问。在客户端激活期间也会跳过它们。简而言之,只需注意任何给定页面上的动态部分。
::: tip SSR 兼容性
所有的 Vue 用法都需要兼容 SSR。参见 [SSR 兼容性](./ssr-compat)获得更多信息和常见的解决方案。
:::
## 模板化 {#templating}
### 插值语法 {#interpolation}
每个 Markdown 文件首先被编译成 HTML然后作为 Vue 组件传递给 Vite 流程管道。这意味着可以在文本中使用 Vue 的插值语法:
**输入**
```md
{{ 1 + 1 }}
```
**输出**
<div class="language-text"><pre><code>{{ 1 + 1 }}</code></pre></div>
### 指令 {#directives}
也可以使用指令 (请注意,根据设计,原始 HTML 在 Markdown 中也有效):
**输入**
```html
<span v-for="i in 3">{{ i }}</span>
```
**输出**
<div class="language-text"><pre><code><span v-for="i in 3">{{ i }} </span></code></pre></div>
## `<script>``<style>` {#script-and-style}
Markdown 文件中的根级 `<script>``<style>` 标签与 Vue SFC 中的一样,包括 `<script setup>`、`<style module>` 等。这里的主要区别是没有 `<template>` 标签:所有其他根级内容都是 Markdown。另请注意所有标签都应放在 frontmatter **之后**
```html
---
hello: world
---
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
## Markdown Content
The count is: {{ count }}
<button :class="$style.button" @click="count++">Increment</button>
<style module>
.button {
color: red;
font-weight: bold;
}
</style>
```
:::warning 避免在 Markdown 中使用 `<style scoped>`
在 Markdown 中使用时,`<style scoped>` 需要为当前页面的每个元素添加特殊属性,这将显著增加页面的大小。当我们需要局部范围的样式时 `<style module>` 是首选。
:::
还可以访问 VitePress 的运行时 API例如 [`useData` 辅助函数](../reference/runtime-api#usedata),它提供了当前页面的元数据:
**输入**
```html
<script setup>
import { useData } from 'vitepress'
const { page } = useData()
</script>
<pre>{{ page }}</pre>
```
**输出**
```json
{
"path": "/using-vue.html",
"title": "Using Vue in Markdown",
"frontmatter": {},
...
}
```
## 使用组件 {#using-components}
可以直接在 Markdown 文件中导入和使用 Vue 组件。
### 在 Markdown 中导入组件 {#importing-in-markdown}
如果一个组件只被几个页面使用,建议在使用它们的地方显式导入它们。这使它们可以正确地进行代码拆分,并且仅在显示相关页面时才加载:
```md
<script setup>
import CustomComponent from '../../components/CustomComponent.vue'
</script>
# Docs
这是一个使用自定义组件的 .md
<CustomComponent />
## More docs
...
```
### 注册全局组件 {#registering-components-globally}
如果一个组件要在大多数页面上使用,可以通过自定义 Vue 实例来全局注册它们。有关示例,请参见[扩展默认主题](./extending-default-theme#registering-global-components)中的相关部分。
::: warning 重要
确保自定义组件的名称包含连字符或采用 PascalCase。否则它将被视为内联元素并包裹在 `<p>` 标签内,这将导致激活不匹配,因为 `<p>` 不允许将块元素放置在其中。
:::
### 在标题中使用组件 <ComponentInHeader /> {#using-components-in-headers}
可以在标题中使用 Vue 组件,但请注意以下语法之间的区别:
| Markdown | 输出的 HTML | 被解析的标题 |
| ------------------------------------------------------- | ----------------------------------------- | ------------- |
| <pre v-pre><code> # text &lt;Tag/&gt; </code></pre> | `<h1>text <Tag/></h1>` | `text` |
| <pre v-pre><code> # text \`&lt;Tag/&gt;\` </code></pre> | `<h1>text <code>&lt;Tag/&gt;</code></h1>` | `text <Tag/>` |
`<code>` 包裹的 HTML 将按原样显示,只有未包裹的 HTML 才会被 Vue 解析。
::: tip
输出 HTML 由 [Markdown-it](https://github.com/Markdown-it/Markdown-it) 完成,而解析的标题由 VitePress 处理 (并用于侧边栏和文档标题)。
:::
## 转义 {#escaping}
可以通过使用 `v-pre` 指令将它们包裹在 `<span>` 或其他元素中来转义 Vue 插值:
**输入**
```md
This <span v-pre>{{ will be displayed as-is }}</span>
```
**输出**
<div class="escape-demo">
<p>This <span v-pre>{{ will be displayed as-is }}</span></p>
</div>
也可以将整个段落包装在 `v-pre` 自定义容器中:
```md
::: v-pre
{{ This will be displayed as-is }}`
:::
```
**输出**
<div class="escape-demo">
::: v-pre
{{ This will be displayed as-is }}
:::
</div>
## 代码块中不转义 {#unescape-in-code-blocks}
默认情况下,代码块是受到保护的,都会自动使用 `v-pre` 包装,因此内部不会处理任何 Vue 语法。要在代码块内启用 Vue 插值语法,可以在代码语言后附加 `-vue` 后缀,例如 `js-vue`
**输入**
````md
```js-vue
Hello {{ 1 + 1 }}
```
````
**输出**
```js-vue
Hello {{ 1 + 1 }}
```
请注意,这可能会让某些字符不能正确地进行语法高亮显示。
## 使用 CSS 预处理器 {#using-css-pre-processors}
VitePress [内置支持](https://cn.vitejs.dev/guide/features.html#css-pre-processors) CSS 预处理器:`.scss`、`.sass`、.`less`、`.styl` 和 `.stylus` 文件。无需为它们安装 Vite 专用插件,但必须安装相应的预处理器:
```
# .scss and .sass
npm install -D sass
# .less
npm install -D less
# .styl and .stylus
npm install -D stylus
```
然后可以在 Markdown 和主题组件中使用以下内容:
```vue
<style lang="sass">
.title
font-size: 20px
</style>
```
## 使用 teleport 传递组件内容 {#using-teleports}
Vitepress 目前只有使用 teleport 传送到 body 的 SSG 支持。对于其他地方,可以将它们包裹在内置的 `<ClientOnly>` 组件中,或者通过 [postRender 钩子](../reference/site-config#postrender)将 teleport 标签注入到最终页面 HTML 中的正确位置。
<ModalDemo />
::: details
<<< @/components/ModalDemo.vue
:::
```md
<ClientOnly>
<Teleport to="#modal">
<div>
// ...
</div>
</Teleport>
</ClientOnly>
```
<script setup>
import ModalDemo from '../../components/ModalDemo.vue'
import ComponentInHeader from '../../components/ComponentInHeader.vue'
</script>
<style>
.escape-demo {
border: 1px solid var(--vp-c-border);
border-radius: 8px;
padding: 0 20px;
}
</style>

@ -0,0 +1,57 @@
# VitePress 是什么? {#what-is-vitepress}
VitePress 是一个[静态站点生成器](https://en.wikipedia.org/wiki/Static_site_generator) (SSG)专为构建快速、以内容为中心的站点而设计。简而言之VitePress 获取用 Markdown 编写的源内容,对其应用主题,并生成可以轻松部署到任何地方的静态 HTML 页面。
<div class="tip custom-block" style="padding-top: 8px">
只是想尝试一下?跳到[快速开始](./getting-started)。
</div>
## 使用场景 {#use-cases}
- **文档**
VitePress 附带一个专为技术文档设计的默认主题,尤其是那些需要嵌入交互式演示的主题。它支持你正在阅读的这个页面,以及 [Vite](https://vitejs.dev/)、[Pinia](https://pinia.vuejs.org/)、[VueUse](https://vueuse.org/)、[Mermaid](https://mermaid.js.org/)、[Wikimedia Codex](https://doc.wikimedia.org/codex/latest/) 等文档。
[Vue.js 官方文档](https://vuejs.org/)也是基于 VitePress 的。但是为了可以在不同的翻译文档之间共享,它自定义了自己的主题
- **博客、档案和营销网站**
VitePress 支持[完全的自定义主题](./custom-theme),具有标准 Vite + Vue 应用程序的开发体验。基于 Vite 构建还意味着可以直接利用其丰富生态系统中的 Vite 插件。此外VitePress 提供了灵活的 API 来[加载数据](./data-loading) (本地或远程),也可以[动态生成路由](./routing#dynamic-routes)。只要可以在构建时确定数据,就可以使用它来构建几乎任何东西。
[Vue.js 官方博客](https://blog.vuejs.org/)是一个简单的博客页面,它根据本地内容生成其索引页面。
## 开发体验 {#developer-experience}
VitePress 旨在使用 Markdown 生成内容时提供出色的开发体验。
- **[Vite 驱动](https://cn.vitejs.dev/)**:即时服务器启动,始终立即反映(<100ms)编辑变化,无需重新加载页面。
- **[内置 Markdown 扩展](./markdown)**frontmatter、表格、语法高亮……应有尽有。具体来说VitePress 提供了许多用于处理代码块的高级功能,使其真正成为技术文档的理想选择。
- **[Vue 增强的 Markdown](./using-vue)**:每个 Markdown 页面都是 Vue [单文件组件](https://cn.vuejs.org/guide/scaling-up/sfc.html),这要归功于 Vue 模板与 HTML 的 100% 语法兼容性。可以使用 Vue 模板语法或导入的 Vue 组件在静态内容中嵌入交互性。
## 性能 {#performance}
与许多传统的 SSG 不同VitePress 生成的站点实际上是一个[单页应用程序](https://en.wikipedia.org/wiki/Single-page_application) (SPA)。
- **快速初始加载**
对任何页面的初次访问都将提供静态的、预呈现的 HTML以实现极快的加载速度和最佳的 SEO。然后页面加载一个 JavaScript 包,将页面变成 Vue SPA (这被称为“激活”)。激活是非常快的:在 [PageSpeed Insights](https://pagespeed.web.dev/report?url=https%3A%2F%2Fvitepress.dev%2F) 上,典型的 VitePress 站点即使在网络速度较慢的低端移动设备上也能获得近乎完美的性能分数。
- **加载完成后可以快速切换**
更重要的是SPA 模型在首次加载后能够提升用户体验。用户在站点内导航时不会再触发整个页面的刷新。而是通过获取并动态更新新页面的内容来实现切换。VitePress还会自动预加载视口范围内链接对应的页面片段。这样一来大部分情况下用户在加载完成后就能立即浏览新页面。
- **高效的交互**
为了能够嵌入静态 Markdown 中的动态 Vue 部分,每个 Markdown 页面都被处理为 Vue 组件并编译成 JavaScript。这听起来可能效率低下但 Vue 编译器足够聪明,可以将静态和动态部分分开,从而最大限度地减少激活成本和有效负载大小。对于初始页面加载,静态部分会自动从 JavaScript 有效负载中删除,并在激活期间跳过。
## VuePress 又是什么? {#what-about-vuepress}
VitePress 灵感来源于 VuePress。最初的 VuePress 基于 Vue 2 和 webpack。借助 Vue 3 和 ViteVitePress 提供了更好的开发体验、更好的生产性能、更精美的默认主题和更灵活的自定义 API。
VitePress 和 VuePress 之间的 API 区别主要在于主题和自定义。如果使用的是带有默认主题的 VuePress 1迁移到 VitePress 应该相对简单。
VuePress 2 也投入了精力,它也支持 Vue 3 和 Vite与 VuePress 1 的兼容性更好。但是,并行维护两个 SSG 是难以持续的,因此 Vue 团队决定将重点放在 VitePress作为长期的主要 SSG 选择推荐。

@ -0,0 +1,56 @@
---
layout: home
title: VitePress
titleTemplate: 由 Vite 和 Vue 驱动的静态站点生成器
hero:
name: VitePress
text: 由 Vite 和 Vue 驱动的静态站点生成器
tagline: 简单、强大、快速。就是你想要的现代 SSG 框架!
actions:
- theme: brand
text: 快速开始
link: /zh/guide/getting-started
- theme: alt
text: GitHub
link: https://github.com/vuejs/vitepress
image:
src: /vitepress-logo-large.webp
alt: VitePress
features:
- icon: 📝
title: 专注内容
details: 只需 Markdown 即可轻松创建美观的文档站点。
- icon: <svg xmlns="http://www.w3.org/2000/svg" width="30" viewBox="0 0 256 256.32"><defs><linearGradient id="a" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"/><stop offset="100%" stop-color="#BD34FE"/></linearGradient><linearGradient id="b" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"/><stop offset="8.333%" stop-color="#FFDD35"/><stop offset="100%" stop-color="#FFA800"/></linearGradient></defs><path fill="url(#a)" d="M255.153 37.938 134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"/><path fill="url(#b)" d="M185.432.063 96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028 72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"/></svg>
title: 享受 Vite 无可比拟的体验
details: 服务器即时启动,闪电般的热更新,还可以使用基于 Vite 生态的插件。
- icon: <svg xmlns="http://www.w3.org/2000/svg" width="30" viewBox="0 0 256 220.8"><path fill="#41B883" d="M204.8 0H256L128 220.8 0 0h97.92L128 51.2 157.44 0h47.36Z"/><path fill="#41B883" d="m0 0 128 220.8L256 0h-51.2L128 132.48 50.56 0H0Z"/><path fill="#35495E" d="M50.56 0 128 133.12 204.8 0h-47.36L128 51.2 97.92 0H50.56Z"/></svg>
title: 使用 Vue 自定义
details: 直接在 Markdown 中使用 Vue 语法和组件,或者使用 Vue 组件构建自定义主题。
- icon: 🚀
title: 速度真的很快!
details: 采用静态 HTML 实现快速的页面初次加载,使用客户端路由实现快速的页面切换导航。
---
<style>
:root {
--vp-home-hero-name-color: transparent;
--vp-home-hero-name-background: -webkit-linear-gradient(120deg, #bd34fe 30%, #41d1ff);
--vp-home-hero-image-background-image: linear-gradient(-45deg, #bd34fe 50%, #47caff 50%);
--vp-home-hero-image-filter: blur(44px);
}
@media (min-width: 640px) {
:root {
--vp-home-hero-image-filter: blur(56px);
}
}
@media (min-width: 960px) {
:root {
--vp-home-hero-image-filter: blur(68px);
}
}
</style>

@ -0,0 +1,74 @@
# 命令行接口 {#command-line-interface}
## `vitepress dev`
使用指定目录作为根目录来启动 VitePress 开发服务器。默认为当前目录。在当前目录下运行时也可以省略 `dev` 命令。
### 用法
```sh
# start in current directory, omitting `dev`
vitepress
# start in sub directory
vitepress dev [root]
```
### 选项 {#options}
| 选项 | 说明 |
| --------------- | ------------------------------------------ |
| `--open [path]` | 启动时打开浏览器 (`boolean \| string`) |
| `--port <port>` | 指定端口 (`number`) |
| `--base <path>` | public base URL (默认值: `/`) (`string`) |
| `--cors` | 启用 CORS |
| `--strictPort` | 如果指定的端口已被占用则退出 (`boolean`) |
| `--force` | 强制优化程序忽略缓存并重新绑定 (`boolean`) |
## `vitepress build`
构建用于生产环境的 VitePress 站点。
### 用法
```sh
vitepress build [root]
```
### 选项\
| 选项 | 说明 |
| ------------------------------ | ------------------------------------------------------------------------------------------------- |
| `--mpa` (experimental) | [MPA 模式](../guide/mpa-mode) 下构建,无需客户端激活 (`boolean`) |
| `--base <path>` | public base URL (默认值: `/`) (`string`) |
| `--target <target>` | 转译目标 (默认值:`"modules"`) (`string`) |
| `--outDir <dir>` | 输出目录 (默认值:`.vitepress/dist`) (`string`) |
| `--minify [minifier]` | 启用/禁用压缩,或指定要使用的压缩程序 (默认值:`"esbuild"`) (`boolean \| "terser" \| "esbuild"`) |
| `--assetsInlineLimit <number>` | 静态资源 base64 内联阈值(以字节为单位)(默认值:`4096`) (`number`) |
## `vitepress preview`
在本地预览生产版本。
### 用法
```sh
vitepress preview [root]
```
### 选项
| 选项 | 说明 |
| --------------- | -------------------------------------- |
| `--base <path>` | public base URL (默认值: `/`) (`string`) |
| `--port <port>` | 指定端口 (`number`) |
## `vitepress init`
在当前目录中启动[安装向导](../guide/getting-started#setup-wizard)。
### 用法
```sh
vitepress init
```

@ -0,0 +1,69 @@
# 徽标 {#badge}
徽标可让你为标题添加状态。例如,指定部分的类型或支持的版本可能很有用。
## 用法 {#usage}
可以使用全局组件 `Badge`
```html
### Title <Badge type="info" text="default" />
### Title <Badge type="tip" text="^1.9.0" />
### Title <Badge type="warning" text="beta" />
### Title <Badge type="danger" text="caution" />
```
上面的代码渲染如下:
### Title <Badge type="info" text="default" />
### Title <Badge type="tip" text="^1.9.0" />
### Title <Badge type="warning" text="beta" />
### Title <Badge type="danger" text="caution" />
## 自定义子节点 {#custom-children}
`<Badge>` 接受 `children`,这将显示在徽标中。
```html
### Title <Badge type="info">custom element</Badge>
```
### Title <Badge type="info">custom element</Badge>
## 自定义不同类型徽标的背景色 {#customize-type-color}
可以通过覆盖 css 来自定义不同类型 `<Badge />` 的样式。以下是默认值。
```css
:root {
--vp-badge-info-border: transparent;
--vp-badge-info-text: var(--vp-c-text-2);
--vp-badge-info-bg: var(--vp-c-default-soft);
--vp-badge-tip-border: transparent;
--vp-badge-tip-text: var(--vp-c-brand-1);
--vp-badge-tip-bg: var(--vp-c-brand-soft);
--vp-badge-warning-border: transparent;
--vp-badge-warning-text: var(--vp-c-warning-1);
--vp-badge-warning-bg: var(--vp-c-warning-soft);
--vp-badge-danger-border: transparent;
--vp-badge-danger-text: var(--vp-c-danger-1);
--vp-badge-danger-bg: var(--vp-c-danger-soft);
}
```
## `<Badge>`
`<Badge>` 组件接受以下属性:
```ts
interface Props {
// When `<slot>` is passed, this value gets ignored.
text?: string
// Defaults to `tip`.
type?: 'info' | 'tip' | 'warning' | 'danger'
}
```

@ -0,0 +1,22 @@
# Carbon Ads {#carbon-ads}
VitePress 内置了对 [Carbon Ads](https://www.carbonads.net/) 的原生支持。通过在配置中定义 Carbon Ads 凭据VitePress 将在页面上显示广告。
```js
export default {
themeConfig: {
carbonAds: {
code: 'your-carbon-code',
placement: 'your-carbon-placement'
}
}
}
```
这些值用于调用 carbon CDN 脚本,如下所示。
```js
`//cdn.carbonads.com/carbon.js?serve=${code}&placement=${placement}`
```
要了解有关 Carbon Ads 配置的更多信息,请访问 [Carbon Ads 站点](https://www.carbonads.net/)。

@ -0,0 +1,449 @@
# 默认主题配置 {#default-theme-config}
主题配置可让自定义主题。可以通过将 `themeConfig` 添加到配置文件来定义主题配置:
```ts
export default {
lang: 'en-US',
title: 'VitePress',
description: 'Vite & Vue powered static site generator.',
// Theme related configurations.
themeConfig: {
logo: '/logo.svg',
nav: [...],
sidebar: { ... }
}
}
```
**此页面上记录的选项仅适用于默认主题**。不同的主题需要不同的主题配置。使用自定义主题时,主题配置对象将传递给主题,以便主题可以基于它作出不同表现。
## i18nRouting
- 类型:`boolean`
将本地语言更改为 `zh` 会将 URL 从 `/foo`(或 `/en/foo/`)更改为 `/zh/foo`。可以通过将 `themeConfig.i18nRouting` 设置为 `false` 来禁用此行为。
## logo
- 类型:`ThemeableImage`
导航栏上显示的 Logo位于站点标题右侧。可以接受一个路径字符串或者一个对象来设置在浅色/深色模式下不同的 Logo。
```ts
export default {
themeConfig: {
logo: '/logo.svg'
}
}
```
```ts
type ThemeableImage =
| string
| { src: string; alt?: string }
| { light: string; dark: string; alt?: string }
```
## siteTitle
- 类型:`string | false`
可以自定义此项以替换导航中的默认站点标题(应用配置中的 `title`)。当设置为 `false` 时,导航中的标题将被禁用。这在当 `logo` 已经包含站点标题文本时很有用。
```ts
export default {
themeConfig: {
siteTitle: 'Hello World'
}
}
```
## nav
- 类型:`NavItem`
导航菜单项的配置。可以在[默认主题: 导航栏](./default-theme-nav#navigation-links) 了解更多详情。
```ts
export default {
themeConfig: {
nav: [
{ text: 'Guide', link: '/guide' },
{
text: 'Dropdown Menu',
items: [
{ text: 'Item A', link: '/item-1' },
{ text: 'Item B', link: '/item-2' },
{ text: 'Item C', link: '/item-3' }
]
}
]
}
}
```
```ts
type NavItem = NavItemWithLink | NavItemWithChildren
interface NavItemWithLink {
text: string
link: string
activeMatch?: string
target?: string
rel?: string
}
interface NavItemChildren {
text?: string
items: NavItemWithLink[]
}
interface NavItemWithChildren {
text?: string
items: (NavItemChildren | NavItemWithLink)[]
activeMatch?: string
}
```
## sidebar
- 类型:`Sidebar`
侧边栏菜单项的配置。可以在[默认主题: 侧边栏](./default-theme-sidebar) 了解更多详情。
```ts
export default {
themeConfig: {
sidebar: [
{
text: 'Guide',
items: [
{ text: 'Introduction', link: '/introduction' },
{ text: 'Getting Started', link: '/getting-started' },
...
]
}
]
}
}
```
```ts
export type Sidebar = SidebarItem[] | SidebarMulti
export interface SidebarMulti {
[path: string]: SidebarItem[]
}
export type SidebarItem = {
/**
* The text label of the item.
*/
text?: string
/**
* The link of the item.
*/
link?: string
/**
* The children of the item.
*/
items?: SidebarItem[]
/**
* If not specified, group is not collapsible.
*
* If `true`, group is collapsible and collapsed by default
*
* If `false`, group is collapsible but expanded by default
*/
collapsed?: boolean
}
```
## aside
- 类型:`boolean | 'left'`
- 默认值:`true`
- 每个页面可以通过 [frontmatter](./frontmatter-config#aside) 覆盖
将此值设置为 `false` 可禁用 aside(大纲) 容器。\
将此值设置为 `true` 将在页面右侧渲染。\
将此值设置为 `left` 将在页面左侧渲染。
如果想对所有页面禁用它,应该使用 `outline: false`
## outline
- 类型:`Outline | Outline['level'] | false`
- 每个页面可以通过 [frontmatter](./frontmatter-config#outline) 覆盖层级
将此值设置为 `false` 可禁止渲染大纲容器。更多详情请参考该接口:
```ts
interface Outline {
/**
* The levels of headings to be displayed in the outline.
* Single number means only headings of that level will be displayed.
* If a tuple is passed, the first number is the minimum level and the second number is the maximum level.
* `'deep'` is same as `[2, 6]`, which means all headings from `<h2>` to `<h6>` will be displayed.
*
* @default 2
*/
level?: number | [number, number] | 'deep'
/**
* The title to be displayed on the outline.
*
* @default 'On this page'
*/
label?: string
}
```
## socialLinks
- 类型:`SocialLink[]`
可以定义此选项以在导航栏中展示带有图标的社交帐户链接。
```ts
export default {
themeConfig: {
socialLinks: [
{ icon: 'github', link: 'https://github.com/vuejs/vitepress' },
{ icon: 'twitter', link: '...' },
// You can also add custom icons by passing SVG as string:
{
icon: {
svg: '<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Dribbble</title><path d="M12...6.38z"/></svg>'
},
link: '...',
// You can include a custom label for accessibility too (optional but recommended):
ariaLabel: 'cool link'
}
]
}
}
```
```ts
interface SocialLink {
icon: SocialLinkIcon
link: string
ariaLabel?: string
}
type SocialLinkIcon =
| 'discord'
| 'facebook'
| 'github'
| 'instagram'
| 'linkedin'
| 'mastodon'
| 'slack'
| 'twitter'
| 'youtube'
| { svg: string }
```
## footer
- 类型:`Footer`
- 可以通过 [frontmatter](./frontmatter-config#footer) 进行覆盖。
页脚配置。可以添加 message 和 copyright。由于设计原因仅当页面不包含侧边栏时才会显示页脚。
```ts
export default {
themeConfig: {
footer: {
message: 'Released under the MIT License.',
copyright: 'Copyright © 2019-present Evan You'
}
}
}
```
```ts
export interface Footer {
message?: string
copyright?: string
}
```
## editLink
- 类型:`EditLink`
- 每个页面可以通过 [frontmatter](./frontmatter-config#editlink) 覆盖
编辑链接可让显示链接以编辑 Git 管理服务(例如 GitHub 或 GitLab上的页面。有关详细信息请参阅 [默认主题:编辑链接](./default-theme-edit-link)。
```ts
export default {
themeConfig: {
editLink: {
pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',
text: 'Edit this page on GitHub'
}
}
}
```
```ts
export interface EditLink {
pattern: string
text?: string
}
```
## lastUpdated
- 类型:`LastUpdatedOptions`
允许自定义上次更新的文本和日期格式。
```ts
export default {
themeConfig: {
lastUpdated: {
text: 'Updated at',
formatOptions: {
dateStyle: 'full',
timeStyle: 'medium'
}
}
}
}
```
```ts
export interface LastUpdatedOptions {
/**
* @default 'Last updated'
*/
text?: string
/**
* @default
* { dateStyle: 'short', timeStyle: 'short' }
*/
formatOptions?: Intl.DateTimeFormatOptions & { forceLocale?: boolean }
}
```
## algolia
- 类型:`AlgoliaSearch`
支持使用 [Algolia DocSearch](https://docsearch.algolia.com/docs/what-is-docsearch) 搜索站点文档。在 [默认主题:搜索](./default-theme-search) 中了解更多信息。
```ts
export interface AlgoliaSearchOptions extends DocSearchProps {
locales?: Record<string, Partial<DocSearchProps>>
}
```
在[这里](https://github.com/vuejs/vitepress/blob/main/types/docsearch.d.ts)查看完整配置。
## carbonAds {#carbon-ads}
- 类型:`CarbonAdsOptions`
一个配置即可展示 [Carbon Ads](https://www.carbonads.net/)。
```ts
export default {
themeConfig: {
carbonAds: {
code: 'your-carbon-code',
placement: 'your-carbon-placement'
}
}
}
```
```ts
export interface CarbonAdsOptions {
code: string
placement: string
}
```
Learn more in [Default Theme: Carbon Ads](./default-theme-carbon-ads)
## docFooter
- 类型:`DocFooter`
可用于自定义出现在上一页和下一页链接上方的文本。如果不是用英语编写文档,这很有帮助。也可用于全局禁用上一页/下一页链接。如果想有选择地启用/禁用上一个/下一个链接,可以使用 [frontmatter](./default-theme-prev-next-links)。
```ts
export default {
themeConfig: {
docFooter: {
prev: 'Pagina prior',
next: 'Proxima pagina'
}
}
}
```
```ts
export interface DocFooter {
prev?: string | false
next?: string | false
}
```
## darkModeSwitchLabel
- 类型:`string`
- 默认值:`Appearance`
Can be used to customize the dark mode switch label. This label is only displayed in the mobile view.
## lightModeSwitchTitle
- 类型:`string`
- 默认值:`Switch to light theme`
Can be used to customize the light mode switch title that appears on hovering.
## darkModeSwitchTitle
- 类型:`string`
- 默认值:`Switch to dark theme`
Can be used to customize the dark mode switch title that appears on hovering.
## sidebarMenuLabel
- 类型:`string`
- 默认值:`Menu`
Can be used to customize the sidebar menu label. This label is only displayed in the mobile view.
## returnToTopLabel
- 类型:`string`
- 默认值:`Return to top`
Can be used to customize the label of the return to top button. This label is only displayed in the mobile view.
## langMenuLabel
- 类型:`string`
- 默认值:`Change language`
Can be used to customize the aria-label of the language toggle button in navbar. This is only used if you're using [i18n](../guide/i18n).
## externalLinkIcon
- 类型:`boolean`
- 默认值:`false`
Whether to show an external link icon next to external links in markdown.

@ -0,0 +1,60 @@
# 编辑链接 {#edit-link}
## 站点级配置 {#site-level-config}
编辑链接让你可以显示一个链接,以在 GitHub 或 GitLab 等 Git 管理服务上编辑页面。要启用它,请将 `themeConfig.editLink` 选项添加到配置中。
```js
export default {
themeConfig: {
editLink: {
pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path'
}
}
}
```
`pattern` 选项定义链接的 URL 结构,并且 `:path` 将被替换为页面路径。
你还可以放置一个接受 [`PageData`](./runtime-api#usedata) 作为参数并返回 URL 字符串的纯函数。
```js
export default {
themeConfig: {
editLink: {
pattern: ({ filePath }) => {
if (filePath.startsWith('packages/')) {
return `https://github.com/acme/monorepo/edit/main/${filePath}`
} else {
return `https://github.com/acme/monorepo/edit/main/docs/${filePath}`
}
}
}
}
}
```
它不应该有副作用,也不应该访问其范围之外的任何东西,因为它将在浏览器中被序列化和执行。
默认情况下这将在文档页面底部添加链接文本“Edit this page”。可以通过定义 `text` 选项来自定义此文本。
```js
export default {
themeConfig: {
editLink: {
pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',
text: 'Edit this page on GitHub'
}
}
}
```
## frontmatter 配置 {#frontmatter-config}
可以使用 frontmatter 上的 `editLink` 选项单独禁用某个页面的编辑链接:
```yaml
---
editLink: false
---
```

@ -0,0 +1,53 @@
# 页脚 {#footer}
配置好 `themeConfig.footer`VitePress 将在全局页面底部显示页脚。
```ts
export default {
themeConfig: {
footer: {
message: 'Released under the MIT License.',
copyright: 'Copyright © 2019-present Evan You'
}
}
}
```
```ts
export interface Footer {
// The message shown right before copyright.
message?: string
// The actual copyright text.
copyright?: string
}
```
上面的配置也支持 HTML 字符串。所以,例如,如果想配置页脚文本有一些链接,可以调整配置如下:
```ts
export default {
themeConfig: {
footer: {
message: 'Released under the <a href="https://github.com/vuejs/vitepress/blob/main/LICENSE">MIT License</a>.',
copyright: 'Copyright © 2019-present <a href="https://github.com/yyx990803">Evan You</a>'
}
}
}
```
::: warning
只有内联元素可以在 `message``copyright` 中使用,因为它们渲染在 `<p>` 元素中。如果想添加块元素,请考虑使用 [`layout-bottom`](../guide/extending-default-theme#layout-slots) 插槽。
:::
请注意,当[侧边栏](./default-theme-sidebar)可见时,不会显示页脚。
## frontmatter 配置 {#frontmatter-config}
可以使用 frontmatter 上的 `footer` 选项在单独页面上禁用此功能:
```yaml
---
footer: false
---
```

@ -0,0 +1,159 @@
# 主页 {#home-page}
VitePress 默认主题提供了一个首页布局,也可以在[此站点首页](../)看到。可以通过 [frontmatter](./frontmatter-config) 指定 `layout: home` 在任何页面上使用它
```yaml
---
layout: home
---
```
但是,仅此选项不会有太大作用。可以通过设置其他选项(例如 `hero``features`)向主页添加几个不同的预模板化。
## Hero 部分 {#hero-section}
Hero section 位于主页顶部。以下是配置 Hero 的方法。
```yaml
---
layout: home
hero:
name: VitePress
text: Vite & Vue powered static site generator.
tagline: Lorem ipsum...
image:
src: /logo.png
alt: VitePress
actions:
- theme: brand
text: Get Started
link: /guide/what-is-vitepress
- theme: alt
text: View on GitHub
link: https://github.com/vuejs/vitepress
---
```
```ts
interface Hero {
// The string shown top of `text`. Comes with brand color
// and expected to be short, such as product name.
name?: string
// The main text for the hero section. This will be defined
// as `h1` tag.
text: string
// Tagline displayed below `text`.
tagline?: string
// The image is displayed next to the text and tagline area.
image?: ThemeableImage
// Action buttons to display in home hero section.
actions?: HeroAction[]
}
type ThemeableImage =
| string
| { src: string; alt?: string }
| { light: string; dark: string; alt?: string }
interface HeroAction {
// Color theme of the button. Defaults to `brand`.
theme?: 'brand' | 'alt'
// Label of the button.
text: string
// Destination link of the button.
link: string
}
```
### 自定义 name 的颜色 {#customizing-the-name-color}
VitePress 通过 (`--vp-c-brand-1`) 设置 `name` 的颜色 .但是,可以通过覆盖 `--vp-home-hero-name-color` 变量来自定义此颜色。
```css
:root {
--vp-home-hero-name-color: blue;
}
```
也可以通过组合 `--vp-home-hero-name-background` 来进一步自定义 `name` 为渐变色。
```css
:root {
--vp-home-hero-name-color: transparent;
--vp-home-hero-name-background: -webkit-linear-gradient(120deg, #bd34fe, #41d1ff);
}
```
## Features 部分 {#features-section}
在 Features section可以在 Hero section 之后列出任意数量的 Features。可以在 frontmatter 中配置 `features`
可以为每个 feature 提供一个图标可以是表情符号或任何类型的图像。当配置的图标是图片svg, png, jpeg...)时,必须提供合适的宽度和高度的图标;还可以在需要时配置其描述、固有大小以及深色和浅色主题下的不同表现。
```yaml
---
layout: home
features:
- icon: 🛠️
title: Simple and minimal, always
details: Lorem ipsum...
- icon:
src: /cool-feature-icon.svg
title: Another cool feature
details: Lorem ipsum...
- icon:
dark: /dark-feature-icon.svg
light: /light-feature-icon.svg
title: Another cool feature
details: Lorem ipsum...
---
```
```ts
interface Feature {
// Show icon on each feature box.
icon?: FeatureIcon
// Title of the feature.
title: string
// Details of the feature.
details: string
// Link when clicked on feature component. The link can
// be both internal or external.
//
// e.g. `guide/reference/default-theme-home-page` or `https://example.com`
link?: string
// Link text to be shown inside feature component. Best
// used with `link` option.
//
// e.g. `Learn more`, `Visit page`, etc.
linkText?: string
// Link rel attribute for the `link` option.
//
// e.g. `external`
rel?: string
}
type FeatureIcon =
| string
| { src: string; alt?: string; width?: string; height: string }
| {
light: string
dark: string
alt?: string
width?: string
height: string
}
```

@ -0,0 +1,27 @@
# 最后更新于 {#last-updated}
最近一条内容的更新时间会显示在页面右下角。要启用它,请将 `lastUpdated` 选项添加到配置中。
::: tip
你必须提交 markdown 文件才能看到最近更新时间。
:::
## 全局配置 {#site-level-config}
```js
export default {
lastUpdated: true
}
```
## frontmatter 配置 {#frontmatter-config}
可以使用 frontmatter 上的 `lastUpdated` 选项单独禁用某个页面的最后更新展示:
```yaml
---
lastUpdated: false
---
```
另请参阅[默认主题:最近更新时间](./default-theme-config#lastupdated) 了解更多详细信息。主题级别的任何 [truthy](https://developer.mozilla.org/zh-CN/docs/Glossary/Truthy) 值也将启用该功能,除非在站点或页面级别明确禁用。

@ -0,0 +1,62 @@
# 布局 {#layout}
可以通过设置页面 [frontmatter](./frontmatter-config) 选项来选择页面布局。有 3 种布局选项 `doc`、`page` 和 `home`。如果未指定任何内容,则该页面将被视为 `doc` 页面。
```yaml
---
layout: doc
---
```
## doc 布局 {#doc-layout}
`doc` 是默认布局,它将整个 Markdown 内容设置为“documentation”外观。它的工作原理是将整个内容包装在 css `vp-doc` 类中,并将样式应用于它下面的元素。
几乎所有通用元素,例如 `p`, 或 `h2` 都有特殊的样式。因此,请记住,如果在 Markdown 内容中添加任何自定义 HTML这些内容也会受到这些样式的影响。
它还提供下面列出的文档特定功能。这些功能仅在此布局中启用。
- [编辑链接](./default-theme-edit-link)
- [上下页链接](./default-theme-prev-next-links)
- [大纲](./default-theme-config#outline)
- [Carbon Ads](./default-theme-carbon-ads)
## page 布局 {#page-layout}
`page` 被视为“空白页”。Markdown 仍然会被解析,所有的 [Markdown 拓展](../guide/markdown) 都和 `doc` 布局一样运行,但它没有任何默认样式。
`page` 布局将使可以自行设计所有内容,而不会受 VitePress 主题影响。当想要创建自己的自定义页面时,这很有用。
请注意,即使在此布局中,如果页面具有匹配的侧边栏配置,侧边栏仍会显示。
## home 布局 {#home-layout}
`home` 将生成模板化的“主页”。在此布局中,可以设置额外的选项,例如 `hero``features` 以进一步自定义内容。请访问[默认主题: 主页](./default-theme-home-page)了解更多详情。
## 无布局 {#no-layout}
如果不想要任何布局,可以通过 frontmatter 传递 `layout: false`。如果想要一个完全可自定义的登录页面(默认情况下没有任何侧边栏、导航栏或页脚),此选项很有用。
## 自定义布局 {#custom-layout}
也可以使用自定义布局:
```md
---
layout: foo
---
```
这将在上下文中查找注册名为 `foo` 的组件。例如,可以在 `.vitepress/theme/index.ts`中全局注册组件:
```ts
import DefaultTheme from 'vitepress/theme'
import Foo from './Foo.vue'
export default {
extends: DefaultTheme,
enhanceApp({ app }) {
app.component('foo', Foo)
}
}
```

@ -0,0 +1,162 @@
# 导航栏 {#nav}
Nav 是显示在页面顶部的导航栏。它包含站点标题、全局菜单链接等。
## 站点标题和图标 {#site-title-and-logo}
默认情况下nav 显示 [`config.title`](./site-config#title) 作为站点的标题。如果想更改导航栏上显示的内容,可以在 `themeConfig.siteTitle` 选项中定义自定义文本。
```js
export default {
themeConfig: {
siteTitle: 'My Custom Title'
}
}
```
如果站点有图标,则可以通过传递图片路径来显示它。应该将图标直接放在 `public` 中,并赋值该绝对路径。
```js
export default {
themeConfig: {
logo: '/my-logo.svg'
}
}
```
添加图标时,它会与站点标题一起显示。如果只需要图标并且想要隐藏站点标题文本,请将 `siteTitle` 选项设置为 `false`
```js
export default {
themeConfig: {
logo: '/my-logo.svg',
siteTitle: false
}
}
```
如果想添加 `alt` 属性或根据暗/亮模式自定义它,还可以将图标作为对象传递。有关详细信息,请参阅 [`themeConfig.logo`](./default-theme-config#logo)。
## 导航链接 {#navigation-links}
可以定义 `themeConfig.nav` 选项以将链接添加到导航栏。
```js
export default {
themeConfig: {
nav: [
{ text: 'Guide', link: '/guide' },
{ text: 'Config', link: '/config' },
{ text: 'Changelog', link: 'https://github.com/...' }
]
}
}
```
`text` 是 nav 中显示的实际文本,而 `link` 是单击文本时将导航到的链接。对于链接,将路径设置为不带 `.md` 后缀的实际文件,并且始终以 `/` 开头。
导航链接也可以是下拉菜单。为此,请替换 `link` 选项,设置 `items` 数组。
```js
export default {
themeConfig: {
nav: [
{ text: 'Guide', link: '/guide' },
{
text: 'Dropdown Menu',
items: [
{ text: 'Item A', link: '/item-1' },
{ text: 'Item B', link: '/item-2' },
{ text: 'Item C', link: '/item-3' }
]
}
]
}
}
```
请注意,下拉菜单标题(上例中的 `下拉菜单`)不能具有 `link` 属性,因为它是打开下拉对话框的按钮。
还可以通过传入更多嵌套项来进一步向下拉菜单项添加“sections”。
```js
export default {
themeConfig: {
nav: [
{ text: 'Guide', link: '/guide' },
{
text: 'Dropdown Menu',
items: [
{
// 该部分的标题
text: 'Section A Title',
items: [
{ text: 'Section A Item A', link: '...' },
{ text: 'Section B Item B', link: '...' }
]
}
]
},
{
text: 'Dropdown Menu',
items: [
{
// 也可以省略标题
items: [
{ text: 'Section A Item A', link: '...' },
{ text: 'Section B Item B', link: '...' }
]
}
]
}
]
}
}
```
### 自定义链接的路由匹配状态 {#customize-link-s-active-state}
当前页面位于匹配路径下时,导航菜单项将突出显示。如果 想自定义要匹配的路径,请将 `activeMatch` 属性和正则表达式定义为字符串值。
```js
export default {
themeConfig: {
nav: [
// This link gets active state when the user is
// on `/config/` path.
{
text: 'Guide',
link: '/guide',
activeMatch: '/config/'
}
]
}
}
```
::: warning
`activeMatch` 应为正则表达式字符串,但必须将其定义为字符串。我们不能在这里使用实际的 RegExp 对象,因为它在构建期间不可序列化。
:::
### 自定义链接的“target”和“rel”属性 {#customize-link-s-target-and-rel-attributes}
默认情况下VitePress 会根据链接是否为外部链接自动判断 `target``rel` 属性。但如果愿意,也可以自定义它们。
```js
export default {
themeConfig: {
nav: [
{
text: 'Merchandise',
link: 'https://www.thegithubshop.com/',
target: '_self',
rel: 'sponsored'
}
]
}
}
```
## 社交链接 {#social-links}
参考 [`socialLinks`](./default-theme-config#sociallinks)。

@ -0,0 +1,43 @@
# 上下页链接 {#prev-next-links}
可以自定义上一页和下一页的文本和链接 (显示在文档页脚处)。如果要使其与侧边栏上的文本不同,这会很有帮助。此外,你可能会发现,要禁用未包含在侧边栏中的页面的页脚或链接时,这很有用。
## prev
- 类型:`string | false | { text?: string; link?: string }`
- 说明:
指定要在指向上一页的链接上显示的文本/链接。如果没有在 frontmatter 中设置它,文本/链接将从侧边栏配置中推断出来。
- 示例:
- 仅自定义文本:
```yaml
---
prev: 'Get Started | Markdown'
---
```
- 自定义文本和链接:
```yaml
---
prev:
text: 'Markdown'
link: '/guide/markdown'
---
```
- 隐藏上一页:
```yaml
---
prev: false
---
```
## next
`prev` 相同,但用于下一页。

@ -0,0 +1,379 @@
---
outline: deep
---
# 搜索 {#search}
## 本地搜索 {#local-search}
得益于 [minisearch](https://github.com/lucaong/minisearch/)VitePress 支持使用浏览器内索引进行模糊全文搜索。要启用此功能,只需在 `.vitepress/config.ts` 文件中将 `themeConfig.search.provider` 选项设置为 `'local'` 即可:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
themeConfig: {
search: {
provider: 'local'
}
}
})
```
示例结果:
![搜索弹窗截图](/search.png)
或者,你可以使用 [Algolia DocSearch](#algolia-search) 或一些社区插件,例如:<https://www.npmjs.com/package/vitepress-plugin-search> 或者 <https://www.npmjs.com/package/vitepress-plugin-pagefind>
### i18n {#local-search-i18n}
你可以使用这样的配置来使用多语言搜索:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
themeConfig: {
search: {
provider: 'local',
options: {
locales: {
zh: {
translations: {
button: {
buttonText: '搜索文档',
buttonAriaLabel: '搜索文档'
},
modal: {
noResultsText: '无法找到相关结果',
resetButtonTitle: '清除查询条件',
footer: {
selectText: '选择',
navigateText: '切换'
}
}
}
}
}
}
}
}
})
```
### MiniSearch 配置项 {#mini-search-options}
你可以像这样配置 MiniSearch
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
themeConfig: {
search: {
provider: 'local',
options: {
miniSearch: {
/**
* @type {Pick<import('minisearch').Options, 'extractField' | 'tokenize' | 'processTerm'>}
*/
options: {
/* ... */
},
/**
* @type {import('minisearch').SearchOptions}
* @default
* { fuzzy: 0.2, prefix: true, boost: { title: 4, text: 2, titles: 1 } }
*/
searchOptions: {
/* ... */
}
}
}
}
}
})
```
参阅 [MiniSearch 文档](https://lucaong.github.io/minisearch/classes/MiniSearch.MiniSearch.html)了解更多信息。
### 自定义渲染内容 {#custom-content-renderer}
可以在索引之前自定义用于渲染 Markdown 内容的函数:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
themeConfig: {
search: {
provider: 'local',
options: {
/**
* @param {string} src
* @param {import('vitepress').MarkdownEnv} env
* @param {import('markdown-it')} md
*/
_render(src, env, md) {
// return html string
}
}
}
}
})
```
该函数将从客户端站点数据中剥离,因此你可以在其中使用 Node.js API。
#### 示例:从搜索中排除页面 {#example-excluding-pages-from-search}
你可以通过将 `search: false` 添加到页面的 `frontmatter` 来从搜索中排除页面。或者:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
themeConfig: {
search: {
provider: 'local',
options: {
_render(src, env, md) {
const html = md.render(src, env)
if (env.frontmatter?.search === false) return ''
if (env.relativePath.startsWith('some/path')) return ''
return html
}
}
}
}
})
```
::: warning 注意
如果提供了自定义的 `_render` 函数,你需要自己处理 `search: false` 的 frontmatter。此外在调用 `md.render` 之前,`env` 对象不会完全填充,因此对可选 `env` 属性(如 `frontmatter` )的任何检查都应该在此之后完成。
:::
#### 示例:转换内容-添加锚点{#example-transforming-content-adding-anchors}
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
themeConfig: {
search: {
provider: 'local',
options: {
_render(src, env, md) {
const html = md.render(src, env)
if (env.frontmatter?.title)
return md.render(`# ${env.frontmatter.title}`) + html
return html
}
}
}
}
})
```
## Algolia Search {#algolia-search}
VitePress 支持使用 [Algolia DocSearch](https://docsearch.algolia.com/docs/what-is-docsearch) 搜索文档站点。请参阅他们的入门指南。在你的 `.vitepress/config.ts` 中,你至少需要提供以下内容才能使其正常工作:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
themeConfig: {
search: {
provider: 'algolia',
options: {
appId: '...',
apiKey: '...',
indexName: '...'
}
}
}
})
```
### i18n {#algolia-search-i18n}
你可以使用这样的配置来使用多语言搜索:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
themeConfig: {
search: {
provider: 'algolia',
options: {
appId: '...',
apiKey: '...',
indexName: '...',
locales: {
zh: {
placeholder: '搜索文档',
translations: {
button: {
buttonText: '搜索文档',
buttonAriaLabel: '搜索文档'
},
modal: {
searchBox: {
resetButtonTitle: '清除查询条件',
resetButtonAriaLabel: '清除查询条件',
cancelButtonText: '取消',
cancelButtonAriaLabel: '取消'
},
startScreen: {
recentSearchesTitle: '搜索历史',
noRecentSearchesText: '没有搜索历史',
saveRecentSearchButtonTitle: '保存至搜索历史',
removeRecentSearchButtonTitle: '从搜索历史中移除',
favoriteSearchesTitle: '收藏',
removeFavoriteSearchButtonTitle: '从收藏中移除'
},
errorScreen: {
titleText: '无法获取结果',
helpText: '你可能需要检查你的网络连接'
},
footer: {
selectText: '选择',
navigateText: '切换',
closeText: '关闭',
searchByText: '搜索提供者'
},
noResultsScreen: {
noResultsText: '无法找到相关结果',
suggestedQueryText: '你可以尝试查询',
reportMissingResultsText: '你认为该查询应该有结果?',
reportMissingResultsLinkText: '点击反馈'
}
}
}
}
}
}
}
}
})
```
[这些选项](https://github.com/vuejs/vitepress/blob/main/types/docsearch.d.ts)可以被覆盖。请参阅 Algolia 官方文档以了解更多信息。
### 爬虫配置 {#crawler-config}
以下是基于此站点使用的示例配置:
```ts
new Crawler({
appId: '...',
apiKey: '...',
rateLimit: 8,
startUrls: ['https://vitepress.dev/'],
renderJavaScript: false,
sitemaps: [],
exclusionPatterns: [],
ignoreCanonicalTo: false,
discoveryPatterns: ['https://vitepress.dev/**'],
schedule: 'at 05:10 on Saturday',
actions: [
{
indexName: 'vitepress',
pathsToMatch: ['https://vitepress.dev/**'],
recordExtractor: ({ $, helpers }) => {
return helpers.docsearch({
recordProps: {
lvl1: '.content h1',
content: '.content p, .content li',
lvl0: {
selectors: '',
defaultValue: 'Documentation'
},
lvl2: '.content h2',
lvl3: '.content h3',
lvl4: '.content h4',
lvl5: '.content h5'
},
indexHeadings: true
})
}
}
],
initialIndexSettings: {
vitepress: {
attributesForFaceting: ['type', 'lang'],
attributesToRetrieve: ['hierarchy', 'content', 'anchor', 'url'],
attributesToHighlight: ['hierarchy', 'hierarchy_camel', 'content'],
attributesToSnippet: ['content:10'],
camelCaseAttributes: ['hierarchy', 'hierarchy_radio', 'content'],
searchableAttributes: [
'unordered(hierarchy_radio_camel.lvl0)',
'unordered(hierarchy_radio.lvl0)',
'unordered(hierarchy_radio_camel.lvl1)',
'unordered(hierarchy_radio.lvl1)',
'unordered(hierarchy_radio_camel.lvl2)',
'unordered(hierarchy_radio.lvl2)',
'unordered(hierarchy_radio_camel.lvl3)',
'unordered(hierarchy_radio.lvl3)',
'unordered(hierarchy_radio_camel.lvl4)',
'unordered(hierarchy_radio.lvl4)',
'unordered(hierarchy_radio_camel.lvl5)',
'unordered(hierarchy_radio.lvl5)',
'unordered(hierarchy_radio_camel.lvl6)',
'unordered(hierarchy_radio.lvl6)',
'unordered(hierarchy_camel.lvl0)',
'unordered(hierarchy.lvl0)',
'unordered(hierarchy_camel.lvl1)',
'unordered(hierarchy.lvl1)',
'unordered(hierarchy_camel.lvl2)',
'unordered(hierarchy.lvl2)',
'unordered(hierarchy_camel.lvl3)',
'unordered(hierarchy.lvl3)',
'unordered(hierarchy_camel.lvl4)',
'unordered(hierarchy.lvl4)',
'unordered(hierarchy_camel.lvl5)',
'unordered(hierarchy.lvl5)',
'unordered(hierarchy_camel.lvl6)',
'unordered(hierarchy.lvl6)',
'content'
],
distinct: true,
attributeForDistinct: 'url',
customRanking: [
'desc(weight.pageRank)',
'desc(weight.level)',
'asc(weight.position)'
],
ranking: [
'words',
'filters',
'typo',
'attribute',
'proximity',
'exact',
'custom'
],
highlightPreTag: '<span class="algolia-docsearch-suggestion--highlight">',
highlightPostTag: '</span>',
minWordSizefor1Typo: 3,
minWordSizefor2Typos: 7,
allowTyposOnNumericTokens: false,
minProximity: 1,
ignorePlurals: true,
advancedSyntax: true,
attributeCriteriaComputedByMinProximity: true,
removeWordsIfNoResults: 'allOptional'
}
}
})
```
<style>
img[src="/search.png"] {
width: 100%;
aspect-ratio: 1 / 1;
}
</style>

@ -0,0 +1,215 @@
# 侧边栏 {#sidebar}
侧边栏是文档的主要导航块。可以在 [`themeConfig.sidebar`](./default-theme-config#sidebar) 中配置侧边栏菜单。
```js
export default {
themeConfig: {
sidebar: [
{
text: 'Guide',
items: [
{ text: 'Introduction', link: '/introduction' },
{ text: 'Getting Started', link: '/getting-started' },
...
]
}
]
}
}
```
## 基本用法 {#the-basics}
侧边栏菜单的最简单形式是传入一个链接数组。第一级项目定义侧边栏的“部分”。它应该包含作为小标题的 `text` 和作为实际导航链接的 `items`
```js
export default {
themeConfig: {
sidebar: [
{
text: 'Section Title A',
items: [
{ text: 'Item A', link: '/item-a' },
{ text: 'Item B', link: '/item-b' },
...
]
},
{
text: 'Section Title B',
items: [
{ text: 'Item C', link: '/item-c' },
{ text: 'Item D', link: '/item-d' },
...
]
}
]
}
}
```
每个 `link` 都应指定以 `/` 开头的实际文件的路径。如果在链接末尾添加斜杠,它将显示相应目录的 `index.md`
```js
export default {
themeConfig: {
sidebar: [
{
text: 'Guide',
items: [
// This shows `/guide/index.md` page.
{ text: 'Introduction', link: '/guide/' }
]
}
]
}
}
```
可以进一步将侧边栏项目嵌入到 6 级深度,从根级别上计数。请注意,深度超过 6 级将被忽略,并且不会在侧边栏上显示。
```js
export default {
themeConfig: {
sidebar: [
{
text: 'Level 1',
items: [
{
text: 'Level 2',
items: [
{
text: 'Level 3',
items: [
...
]
}
]
}
]
}
]
}
}
```
## 多侧边栏 {#multiple-sidebars}
可能会根据页面路径显示不同的侧边栏。例如,如本站点所示,可能希望在文档中创建单独的侧边栏,例如“指南”页面和“配置参考”页面。
为此,首先将你的页面组织到每个所需部分的目录中:
```
.
├─ guide/
│ ├─ index.md
│ ├─ one.md
│ └─ two.md
└─ config/
├─ index.md
├─ three.md
└─ four.md
```
然后,更新配置以定义每个部分的侧边栏。这一次,应该传递一个对象而不是数组。
```js
export default {
themeConfig: {
sidebar: {
// This sidebar gets displayed when a user
// is on `guide` directory.
'/guide/': [
{
text: 'Guide',
items: [
{ text: 'Index', link: '/guide/' },
{ text: 'One', link: '/guide/one' },
{ text: 'Two', link: '/guide/two' }
]
}
],
// This sidebar gets displayed when a user
// is on `config` directory.
'/config/': [
{
text: 'Config',
items: [
{ text: 'Index', link: '/config/' },
{ text: 'Three', link: '/config/three' },
{ text: 'Four', link: '/config/four' }
]
}
]
}
}
}
```
## 可折叠的侧边栏组 {#collapsible-sidebar-groups}
通过向侧边栏组添加 `collapsed` 选项,它会显示一个切换按钮来隐藏/显示每个部分。
```js
export default {
themeConfig: {
sidebar: [
{
text: 'Section Title A',
collapsed: false,
items: [...]
}
]
}
}
```
默认情况下,所有部分都是“打开”的。如果 希望它们在初始页面加载时“关闭”,请将 `collapsed` 选项设置为 `true`
```js
export default {
themeConfig: {
sidebar: [
{
text: 'Section Title A',
collapsed: true,
items: [...]
}
]
}
}
```
## `useSidebar` <Badge type="info" text="composable" />
返回侧边栏相关数据。返回的对象具有以下类型:
```ts
export interface DocSidebar {
isOpen: Ref<boolean>
sidebar: ComputedRef<DefaultTheme.SidebarItem[]>
sidebarGroups: ComputedRef<DefaultTheme.SidebarItem[]>
hasSidebar: ComputedRef<boolean>
hasAside: ComputedRef<boolean>
leftAside: ComputedRef<boolean>
isSidebarEnabled: ComputedRef<boolean>
open: () => void
close: () => void
toggle: () => void
}
```
**示例:**
```vue
<script setup>
import { useSidebar } from 'vitepress/theme'
const { hasSidebar } = useSidebar()
</script>
<template>
<div v-if="hasSidebar">Only show when sidebar exists</div>
</template>
```

@ -0,0 +1,258 @@
<script setup>
import { VPTeamMembers } from 'vitepress/theme'
const members = [
{
avatar: 'https://github.com/yyx990803.png',
name: 'Evan You',
title: 'Creator',
links: [
{ icon: 'github', link: 'https://github.com/yyx990803' },
{ icon: 'twitter', link: 'https://twitter.com/youyuxi' }
]
},
{
avatar: 'https://github.com/kiaking.png',
name: 'Kia King Ishii',
title: 'Developer',
links: [
{ icon: 'github', link: 'https://github.com/kiaking' },
{ icon: 'twitter', link: 'https://twitter.com/KiaKing85' }
]
}
]
</script>
# 团队页 {#team-page}
如果你想介绍你的团队,你可以使用 Team components 来构建团队页面。有两种使用这些组件的方法。一种是将其嵌入文档页面,另一种是创建完整的团队页面。
## 在页面中显示团队成员 {#show-team-members-in-a-page}
你可以在任何页面上使用从 `vitepress/theme` 暴露出的公共组件 `<VPTeamMembers>` 显示团队成员。
```html
<script setup>
import { VPTeamMembers } from 'vitepress/theme'
const members = [
{
avatar: 'https://www.github.com/yyx990803.png',
name: 'Evan You',
title: 'Creator',
links: [
{ icon: 'github', link: 'https://github.com/yyx990803' },
{ icon: 'twitter', link: 'https://twitter.com/youyuxi' }
]
},
...
]
</script>
# Our Team
Say hello to our awesome team.
<VPTeamMembers size="small" :members="members" />
```
以上将在卡片外观元素中显示团队成员。它应该显示类似于下面的内容。
<VPTeamMembers size="small" :members="members" />
`<VPTeamMembers>` 组件有 2 种不同的尺寸,`small` 和 `medium`。虽然它取决于你的偏好,但通常尺寸在文档页面中使用时 `small` 应该更适合。此外,你可以为每个成员添加更多属性,例如添加“描述”或“赞助”按钮。在 [`<VPTeamMembers>`](#vpteammembers)中了解更多信息。
在文档页面中嵌入团队成员对于小型团队来说非常有用,某种情况下,完整的贡献团队可能太大了,可以引入部分成员作为文档上下文的参考。
如果你有大量成员,或者只是想有更多空间来展示团队成员,请考虑[创建一个完整的团队页面](#create-a-full-team-page)。
## 创建一个完整的团队页面 {#create-a-full-team-page}
除了将团队成员添加到 doc 页面,你还可以创建一个完整的团队页面,类似于创建自定义[默认主题:主页](./default-theme-home-page)的方式。
要创建团队页面,首先,创建一个新的 md 文件。文件名无所谓,这里我们就叫它 `team.md` 吧。在这个文件中,在 frontmatter 设置 `layout: page`,然后你可以使用 `TeamPage` 组件来组成页面结构。
```html
---
layout: page
---
<script setup>
import {
VPTeamPage,
VPTeamPageTitle,
VPTeamMembers
} from 'vitepress/theme'
const members = [
{
avatar: 'https://www.github.com/yyx990803.png',
name: 'Evan You',
title: 'Creator',
links: [
{ icon: 'github', link: 'https://github.com/yyx990803' },
{ icon: 'twitter', link: 'https://twitter.com/youyuxi' }
]
},
...
]
</script>
<VPTeamPage>
<VPTeamPageTitle>
<template #title>
Our Team
</template>
<template #lead>
The development of VitePress is guided by an international
team, some of whom have chosen to be featured below.
</template>
</VPTeamPageTitle>
<VPTeamMembers
:members="members"
/>
</VPTeamPage>
```
创建完整的团队页面时,请记住用 `<VPTeamPage>` 组件包装所有团队相关组件,以获得正确的布局结构,如间距。
`<VPPageTitle>` 组件添加页面标题部分。标题是 `<h1>` 标题。使用 `#title``#lead` 插槽来介绍你的团队。
`<VPMembers>` 和在 doc 页面中使用时一样。它将显示成员列表。
### 添加分段以划分团队成员 {#add-sections-to-divide-team-members}
你可以将“分段”添加到团队页面。例如,你可能有不同类型的团队成员,例如核心团队成员和社区合作伙伴。你可以将这些成员分成几个部分,以更好地解释每组的角色。
为此,将 `<VPTeamPageSection>` 组件添加到我们之前创建的 `team.md` 文件中。
```html
---
layout: page
---
<script setup>
import {
VPTeamPage,
VPTeamPageTitle,
VPTeamMembers,
VPTeamPageSection
} from 'vitepress/theme'
const coreMembers = [...]
const partners = [...]
</script>
<VPTeamPage>
<VPTeamPageTitle>
<template #title>Our Team</template>
<template #lead>...</template>
</VPTeamPageTitle>
<VPTeamMembers size="medium" :members="coreMembers" />
<VPTeamPageSection>
<template #title>Partners</template>
<template #lead>...</template>
<template #members>
<VPTeamMembers size="small" :members="partners" />
</template>
</VPTeamPageSection>
</VPTeamPage>
```
`<VPTeamPageSection>` 组件可以有类似于 `VPTeamPageTitle` 组件的 `#title``#lead` 插槽,还有用于显示团队成员的 `#members` 插槽。
请记住将 `<VPTeamMembers>` 组件放入 `#members` 插槽中。
## `<VPTeamMembers>`
`<VPTeamMembers>` 组件显示给定的成员列表。
```html
<VPTeamMembers
size="medium"
:members="[
{ avatar: '...', name: '...' },
{ avatar: '...', name: '...' },
...
]"
/>
```
```ts
interface Props {
// Size of each members. Defaults to `medium`.
size?: 'small' | 'medium'
// List of members to display.
members: TeamMember[]
}
interface TeamMember {
// Avatar image for the member.
avatar: string
// Name of the member.
name: string
// Title to be shown below member's name.
// e.g. Developer, Software Engineer, etc.
title?: string
// Organization that the member belongs.
org?: string
// URL for the organization.
orgLink?: string
// Description for the member.
desc?: string
// Social links. e.g. GitHub, Twitter, etc. You may pass in
// the Social Links object here.
// See: https://vitepress.dev/reference/default-theme-config.html#sociallinks
links?: SocialLink[]
// URL for the sponsor page for the member.
sponsor?: string
// Text for the sponsor link. Defaults to 'Sponsor'.
actionText?: string
}
```
## `<VPTeamPage>`
创建完整团队页面时的根组件。它只接受一个插槽。它将设置所有传入的团队相关组件的样式。
## `<VPTeamPageTitle>`
添加页面的标题。最好在一开始就在 `<VPTeamPage>` 下使用。它接受 `#title``#lead` 插槽。
```html
<VPTeamPage>
<VPTeamPageTitle>
<template #title>
Our Team
</template>
<template #lead>
The development of VitePress is guided by an international
team, some of whom have chosen to be featured below.
</template>
</VPTeamPageTitle>
</VPTeamPage>
```
## `<VPTeamPageSection>`
在团队页面中创建一个“分段”。它接受 `#title`、`#lead` 和 `#members` 插槽。你可以在 `<VPTeamPage>` 中添加任意数量的分段。
```html
<VPTeamPage>
...
<VPTeamPageSection>
<template #title>Partners</template>
<template #lead>Lorem ipsum...</template>
<template #members>
<VPTeamMembers :members="data" />
</template>
</VPTeamPageSection>
</VPTeamPage>
```

@ -0,0 +1,221 @@
---
outline: deep
---
# frontmatter 配置 {#frontmatter-config}
frontmatter 支持基于页面的配置。在每个 markdown 文件中,可以使用 frontmatter 配置来覆盖站点级别或主题级别的配置选项。此外,还有一些配置选项只能在 frontmatter 中定义。
示例用法:
```md
---
title: Docs with VitePress
editLink: true
---
```
可以通过 Vue 表达式中的 `$frontmatter` 全局变量访问 frontmatter 数据:
```md
{{ $frontmatter.title }}
```
## title
- 类型:`string`
页面的标题。它与 [config.title](./site-config#title) 相同,并且覆盖站点级配置。
```yaml
---
title: VitePress
---
```
## titleTemplate
- 类型:`string | boolean`
标题的后缀。它与 [config.titleTemplate](./site-config#titletemplate) 相同,它会覆盖站点级别的配置。
```yaml
---
title: VitePress
titleTemplate: Vite & Vue powered static site generator
---
```
## description
- 类型:`string`
页面的描述。它与 [config.description](./site-config#description) 相同,它会覆盖站点级别的配置。
```yaml
---
description: VitePress
---
```
## head
- 类型:`HeadConfig[]`
指定要为当前页面注入的额外 head 标签。将附加在站点级配置注入的头部标签之后。
```yaml
---
head:
- - meta
- name: description
content: hello
- - meta
- name: keywords
content: super duper SEO
---
```
```ts
type HeadConfig =
| [string, Record<string, string>]
| [string, Record<string, string>, string]
```
## 仅默认主题 {#default-theme-only}
以下 frontmatter 选项仅在使用默认主题时适用。
### layout
- 类型:`doc | home | page`
- 默认值:`doc`
指定页面的布局。
- `doc`——它将默认文档样式应用于 markdown 内容。
- `home`——“主页”的特殊布局。可以添加额外的选项,例如 `hero``features`,以快速创建漂亮的落地页。
- `page`——表现类似于 `doc`,但它不对内容应用任何样式。当想创建一个完全自定义的页面时很有用。
```yaml
---
layout: doc
---
```
### hero <Badge type="info" text="home page only" />
`layout` 设置为 `home` 时,定义主页 hero 部分的内容。更多详细信息:[默认主题:主页](./default-theme-home-page)。
### features <Badge type="info" text="home page only" />
定义当`layout` 设置为 `home` 时要在 features 部分中显示的项目。更多详细信息:[默认主题:主页](./default-theme-home-page)。
### navbar
- 类型:`boolean`
- 默认值:`true`
是否显示[导航栏](./default-theme-nav)。
```yaml
---
navbar: false
---
```
### sidebar
- 类型:`boolean`
- 默认值:`true`
是否显示 [侧边栏](./default-theme-sidebar).
```yaml
---
sidebar: false
---
```
### aside
- 类型:`boolean | 'left'`
- 默认值:`true`
定义侧边栏组件在 `doc` 布局中的位置。
将此值设置为 `false` 可禁用侧边栏容器。\
将此值设置为 `true` 会将侧边栏渲染到右侧。\
将此值设置为 `left` 会将侧边栏渲染到左侧。
```yaml
---
aside: false
---
```
### outline
- 类型:`number | [number, number] | 'deep' | false`
- 默认值:`2`
大纲中显示的标题级别。它与 [config.themeConfig.outline.level](./default-theme-config#outline) 相同,它会覆盖站点级的配置。
### lastUpdated
- 类型:`boolean | Date`
- 默认值:`true`
是否在当前页面的页脚中显示[最近更新时间](./default-theme-last-updated)的文本。如果指定了日期时间,则会显示该日期时间而不是上次 git 修改的时间戳。
```yaml
---
lastUpdated: false
---
```
### editLink
- 类型:`boolean`
- 默认值:`true`
是否在当前页的页脚显示[编辑链接](./default-theme-edit-link)。
```yaml
---
editLink: false
---
```
### footer
- 类型:`boolean`
- 默认值:`true`
是否显示[页脚](./default-theme-footer)。
```yaml
---
footer: false
---
```
### pageClass
- 类型:`string`
将额外的类名称添加到特定页面。
```yaml
---
pageClass: custom-page-class
---
```
然后可以在 `.vitepress/theme/custom.css` 文件中自定义该特定页面的样式:
```css
.custom-page-class {
  /* page-specific styles */
}
```

@ -0,0 +1,165 @@
# 运行时 API {#runtime-api}
VitePress 提供了几个内置的 API 来让你访问应用程序数据。VitePress 还附带了一些可以在全局范围内使用的内置组件。
辅助函数可从 `vitepress` 全局导入,通常用于自定义主题 Vue 组件。但是,它们也可以在 `.md` 页面内使用,因为 markdown 文件被编译成 Vue [单文件组件](https://vuejs.org/guide/scaling-up/sfc.html)。
`use*` 开头的方法表示它是一个 [Vue 3 Composition API](https://vuejs.org/guide/introduction.html#composition-api) 函数“Composable(可组合)”),只能在 `setup()``<script setup>` 中使用。
## `useData` <Badge type="info" text="composable" />
返回特定页面的数据。返回的对象具有以下类型:
```ts
interface VitePressData<T = any> {
/**
* Site-level metadata
*/
site: Ref<SiteData<T>>
/**
* themeConfig from .vitepress/config.js
*/
theme: Ref<T>
/**
* Page-level metadata
*/
page: Ref<PageData>
/**
* Page frontmatter
*/
frontmatter: Ref<PageData['frontmatter']>
/**
* Dynamic route params
*/
params: Ref<PageData['params']>
title: Ref<string>
description: Ref<string>
lang: Ref<string>
isDark: Ref<boolean>
dir: Ref<string>
localeIndex: Ref<string>
}
interface PageData {
title: string
titleTemplate?: string | boolean
description: string
relativePath: string
filePath: string
headers: Header[]
frontmatter: Record<string, any>
params?: Record<string, any>
isNotFound?: boolean
lastUpdated?: number
}
```
**示例:**
```vue
<script setup>
import { useData } from 'vitepress'
const { theme } = useData()
</script>
<template>
<h1>{{ theme.footer.copyright }}</h1>
</template>
```
## `useRoute` <Badge type="info" text="composable" />
返回具有以下类型的当前路由对象:
```ts
interface Route {
path: string
data: PageData
component: Component | null
}
```
## `useRouter` <Badge type="info" text="composable" />
返回 VitePress 路由实例,以便可以以编程方式导航到另一个页面。
```ts
interface Router {
/**
* Current route.
*/
route: Route
/**
* Navigate to a new URL.
*/
go: (to?: string) => Promise<void>
/**
* Called before the route changes. Return `false` to cancel the navigation.
*/
onBeforeRouteChange?: (to: string) => Awaitable<void | boolean>
/**
* Called before the page component is loaded (after the history state is
* updated). Return `false` to cancel the navigation.
*/
onBeforePageLoad?: (to: string) => Awaitable<void | boolean>
/**
* Called after the route changes.
*/
onAfterRouteChanged?: (to: string) => Awaitable<void>
}
```
## `withBase` <Badge type="info" text="helper" />
- **Type**: `(path: string) => string`
将配置的 [`base`](./site-config#base) 追加到给定的 URL 路径。另请参阅 [Base URL](../guide/asset-handling#base-url)。
## `<Content />` <Badge type="info" text="component" />
`<Content />` 组件显示渲染的 markdown 内容。在[创建自己的主题时](../guide/custom-theme)很有用。
```vue
<template>
<h1>Custom Layout!</h1>
<Content />
</template>
```
## `<ClientOnly />` <Badge type="info" text="component" />
`<ClientOnly />` 组件仅在客户端渲染其插槽。
由于 VitePress 应用程序在生成静态构建时是在 Node.js 中服务器渲染的,因此任何 Vue 使用都必须符合通用代码要求。简而言之,确保仅在 beforeMount 或 mounted 钩子中访问 Browser/DOM API。
如果正在使用或演示对 SSR 不友好的组件 (例如,包含自定义指令),可以将它们包装在 `ClientOnly` 组件中。
```vue-html
<ClientOnly>
<NonSSRFriendlyComponent />
</ClientOnly>
```
- 相关文档:[SSR 兼容性](../guide/ssr-compat)
## `$frontmatter` <Badge type="info" text="template global" />
在 Vue 表达式中直接访问当前页面的 [frontmatter](../guide/frontmatter) 数据。
```md
---
title: Hello
---
# {{ $frontmatter.title }}
```
## `$params` <Badge type="info" text="template global" />
在 Vue 表达式中直接访问当前页面的[动态路由参数](../guide/routing#dynamic-routes)。
```md
- package name: {{ $params.pkg }}
- version: {{ $params.version }}
```

@ -0,0 +1,695 @@
---
outline: deep
---
# 站点配置 {#site-config}
站点配置可以定义站点的全局设置。应用配置选项适用于每个 VitePress 站点,无论它使用什么主题。例如根目录或站点的标题。
## 概览 {#overview}
### 配置解析 {#config-resolution}
配置文件总是从 `<root>/.vitepress/config.[ext]` 解析,其中 `<root>` 是 VitePress [项目根目录](../guide/routing#root-and-source-directory)`[ext]` 是支持的文件扩展名之一。开箱即用地支持 TypeScript。支持的扩展名包括 `.js`、`.ts`、`.mjs` 和 `.mts`
建议在配置文件中使用 ES 模块语法。配置文件应该默认导出一个对象:
```ts
export default {
// app level config options
lang: 'en-US',
title: 'VitePress',
description: 'Vite & Vue powered static site generator.',
...
}
```
:::details 异步的动态配置
如果需要动态生成配置,也可以默认导出一个函数,例如:
```ts
import { defineConfig } from 'vitepress'
export default async () => defineConfig({
const posts = await (await fetch('https://my-cms.com/blog-posts')).json()
return {
// app level config options
lang: 'en-US',
title: 'VitePress',
description: 'Vite & Vue powered static site generator.',
// theme level config options
themeConfig: {
sidebar: [
...posts.map((post) => ({
text: post.name,
link: `/posts/${post.name}`
}))
]
}
}
})
```
也可以在最外层使用 `await`。例如:
```ts
import { defineConfig } from 'vitepress'
const posts = await (await fetch('https://my-cms.com/blog-posts')).json()
export default defineConfig({
// app level config options
lang: 'en-US',
title: 'VitePress',
description: 'Vite & Vue powered static site generator.',
// theme level config options
themeConfig: {
sidebar: [
...posts.map((post) => ({
text: post.name,
link: `/posts/${post.name}`
}))
]
}
})
```
:::
### 配置智能提示 {#config-intellisense}
使用 `defineConfig` 辅助函数将为配置选项提供 TypeScript 支持的智能提示。假设 IDE 支持它,那么智能提示在 JavaScript 和 TypeScript 中都将触发。
```js
import { defineConfig } from 'vitepress'
export default defineConfig({
// ...
})
```
### 主题类型提示 {#typed-theme-config}
默认情况下,`defineConfig` 辅助函数期望默认主题的主题配置数据类型:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
themeConfig: {
// Type is `DefaultTheme.Config`
}
})
```
如果使用自定义主题并希望对主题配置进行类型检查,则需要改用 `defineConfigWithTheme`,并通过通用参数传递自定义主题的配置类型:
```ts
import { defineConfigWithTheme } from 'vitepress'
import type { ThemeConfig } from 'your-theme'
export default defineConfigWithTheme<ThemeConfig>({
themeConfig: {
// Type is `ThemeConfig`
}
})
```
### Vite、Vue 和 Markdown 配置
- **Vite**
可以使用 VitePress 配置中的 [vite](#vite) 选项配置底层 Vite 实例。无需创建单独的 Vite 配置文件。
- **Vue**
VitePress 已经包含 Vite 的官方 Vue 插件([@vitejs/plugin-vue](https://github.com/vitejs/vite-plugin-vue))。可以配置 VitePress 中的 [vue](#vue) 选项。
- **Markdown**
可以使用 VitePress 配置中的 [markdown](#markdown) 选项配置底层的 [Markdown-It](https://github.com/markdown-it/markdown-it) 实例。
## 站点元数据 {#site-metadata}
### title
- 类型:`string`
- 默认值: `VitePress`
- 每个页面可以通过 [frontmatter](./frontmatter-config#title) 覆盖
站点的标题。使用默认主题时,这将显示在导航栏中。
它还将用作所有单独页面标题的默认后缀,除非定义了 [`titleTemplate`](#titletemplate)。单个页面的最终标题将是其第一个 `<h1>` 标题的文本内容加上的全局 `title`。例如使用以下配置和页面内容:
```ts
export default {
title: 'My Awesome Site'
}
```
```md
# Hello
```
页面标题就是 `Hello | My Awesome Site`.
### titleTemplate
- 类型:`string | boolean`
- 每个页面可以通过 [frontmatter](./frontmatter-config#titletemplate) 覆盖
允许自定义每个页面的标题后缀或整个标题。例如:
```ts
export default {
title: 'My Awesome Site',
titleTemplate: 'Custom Suffix'
}
```
```md
# Hello
```
页面标题就是 `Hello | Custom Suffix`.
要完全自定义标题的呈现方式,可以在 `titleTemplate` 中使用 `:title` 标识符:
```ts
export default {
titleTemplate: ':title - Custom Suffix'
}
```
这里的 `:title` 将替换为从页面的第一个 `<h1>` 标题推断出的文本。上一个示例页面的标题将是 `Hello - Custom Suffix`
该选项可以设置为 `false` 以禁用标题后缀。
### description
- 类型:`string`
- 默认值: `A VitePress site`
- 每个页面可以通过 [frontmatter](./frontmatter-config#description) 覆盖
站点的描述。这将呈现为页面 HTML 中的 `<meta>` 标签。
```ts
export default {
description: 'A VitePress site'
}
```
### head
- 类型:`HeadConfig[]`
- 默认值: `[]`
- 每个页面可以通过 [frontmatter](./frontmatter-config#head) 添加
要在页面 HTML 的 `<head>` 标记中呈现的其他元素。用户添加的标签在结束 `head` 标签之前呈现,在 VitePress 标签之后。
```ts
type HeadConfig =
| [string, Record<string, string>]
| [string, Record<string, string>, string]
```
#### 示例:添加一个图标 {#example-adding-a-favicon}
```ts
export default {
head: [['link', { rel: 'icon', href: '/favicon.ico' }]]
} // put favicon.ico in public directory, if base is set, use /base/favicon.ico
/* Would render:
<link rel="icon" href="/favicon.ico">
*/
```
#### 示例:添加谷歌字体 {#example-adding-google-fonts}
```ts
export default {
head: [
[
'link',
{ rel: 'preconnect', href: 'https://fonts.googleapis.com' }
],
[
'link',
{ rel: 'preconnect', href: 'https://fonts.gstatic.com', crossorigin: '' }
],
[
'link',
{ href: 'https://fonts.googleapis.com/css2?family=Roboto&display=swap', rel: 'stylesheet' }
]
]
}
/* Would render:
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto&display=swap" rel="stylesheet">
*/
```
#### 示例:添加一个 serviceWorker {#example-registering-a-service-worker}
```ts
export default {
head: [
[
'script',
{ id: 'register-sw' },
`;(() => {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
}
})()`
]
]
}
/* Would render:
<script id="register-sw">
;(() => {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
}
})()
</script>
*/
```
#### 示例:使用谷歌分析 {#example-using-google-analytics}
```ts
export default {
head: [
[
'script',
{ async: '', src: 'https://www.googletagmanager.com/gtag/js?id=TAG_ID' }
],
[
'script',
{},
`window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'TAG_ID');`
]
]
}
/* Would render:
<script async src="https://www.googletagmanager.com/gtag/js?id=TAG_ID"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'TAG_ID');
</script>
*/
```
### lang
- 类型:`string`
- 默认值: `en-US`
站点的 lang 属性。这将呈现为页面 HTML 中的 `<html lang="en-US">` 标签。
```ts
export default {
lang: 'en-US'
}
```
### base
- 类型:`string`
- 默认值: `/`
站点将部署到的 base URL。如果计划在子路径例如 GitHub 页面)下部署站点,则需要设置此项。如果计划将站点部署到 `https://foo.github.io/bar/`,那么应该将 `base` 设置为 `“/bar/”`。它应该始终以 `/`开头和结尾。
base 会自动添加到其他选项中以 `/` 开头的所有 URL 前面,因此只需指定一次。
```ts
export default {
base: '/base/'
}
```
## 路由 {#routing}
### cleanUrls
- 类型:`boolean`
- 默认值: `false`
当设置为 `true`VitePress 将从 URL 中删除 `.html` 后缀。另请参阅[生成简洁的 URL](../guide/routing#generating-clean-url)。
::: warning 需要服务器支持
要启用此功能,可能需要在托管平台上进行额外配置。要使其正常工作,服务器必须能够在**不重定向的情况下**访问 `/foo` 时提供 `/foo.html`
:::
### rewrites
- 类型:`Record<string, string>`
自定义目录 &lt;-&gt; URL 映射。详细信息请参阅[路由:路由重写](../guide/routing#route-rewrites)。
```ts
export default {
rewrites: {
'source/:page': 'destination/:page'
}
}
```
## 构建 {#build}
### srcDir
- 类型:`string`
- 默认值: `.`
markdown 页面的目录,相对于项目根目录。另请参阅[根目录和源目录](../guide/routing#root-and-source-directory)。
```ts
export default {
srcDir: './src'
}
```
### srcExclude
- 类型:`string`
- 默认值: `undefined`
用于匹配应作为源内容输出的 markdown 文件的 [全局模式](https://github.com/mrmlnc/fast-glob#pattern-syntax)。
```ts
export default {
srcExclude: ['**/README.md', '**/TODO.md']
}
```
### outDir
- 类型:`string`
- 默认值: `./.vitepress/dist`
项目的构建输出位置,相对于[项目根目录](../guide/routing#root-and-source-directory)。
```ts
export default {
outDir: '../public'
}
```
### assetsDir
- 类型:`string`
- 默认值: `assets`
指定放置生成的静态资源的目录。该路径应位于 [`outDir`](#outdir) 内,并相对于它进行解析。
```ts
export default {
assetsDir: 'static'
}
```
### cacheDir
- 类型:`string`
- 默认值: `./.vitepress/cache`
缓存文件的目录,相对于[项目根目录](../guide/routing#root-and-source-directory)。另请参阅:[cacheDir](https://vitejs.dev/config/shared-options.html#cachedir)。
```ts
export default {
cacheDir: './.vitepress/.vite'
}
```
### ignoreDeadLinks
- 类型:`boolean | 'localhostLinks' | (string | RegExp | ((link: string) => boolean))[]`
- 默认值: `false`
当设置为 `true`VitePress 不会因为死链而导致构建失败。
当设置为 `'localhostLinks'` ,出现死链时构建将失败,但不会检查 `localhost` 链接。
```ts
export default {
ignoreDeadLinks: true
}
```
它也可以是一组精确的 url 字符串、正则表达式模式或自定义过滤函数。
```ts
export default {
ignoreDeadLinks: [
// ignore exact url "/playground"
'/playground',
// ignore all localhost links
/^https?:\/\/localhost/,
// ignore all links include "/repl/""
/\/repl\//,
// custom function, ignore all links include "ignore"
(url) => {
return url.toLowerCase().includes('ignore')
}
]
}
```
### mpa <Badge type="warning" text="experimental" />
- 类型:`boolean`
- 默认值: `false`
设置为 `true` 时,生产应用程序将在 [MPA 模式](../guide/mpa-mode)下构建。MPA 模式默认提供 零 JavaScript 支持,代价是禁用客户端导航,并且需要明确选择加入才能进行交互。
## 主题 {#theming}
### appearance
- 类型:`boolean | 'dark' | 'force-dark' | import('@vueuse/core').UseDarkOptions`
- 默认值: `true`
是否启用深色模式(通过将 `.dark` 类添加到 `<html>` 元素)。
- 如果该选项设置为 `true`,则默认主题将由用户的首选配色方案决定。
- 如果该选项设置为 `dark`,则默认情况下主题将是深色的,除非用户手动切换它。
- 如果该选项设置为 `false`,用户将无法切换主题。
此选项注入一个内联脚本,使用 `vitepress-theme-appearance` key 从本地存储恢复用户设置。这确保在呈现页面之前应用 `.dark` 类以避免闪烁。
`appearance.initialValue` 只能是 `'dark' | undefined`。 不支持 Refs 或 getters。
### lastUpdated
- 类型:`boolean`
- 默认值: `false`
是否使用 Git 获取每个页面的最后更新时间戳。时间戳将包含在每个页面的页面数据中,可通过 [`useData`](./runtime-api#usedata) 访问。
使用默认主题时,启用此选项将显示每个页面的最后更新时间。可以通过 [`themeConfig.lastUpdatedText`](./default-theme-config#lastupdatedtext) 选项自定义文本。
## 自定义 {#customization}
### markdown
- 类型:`MarkdownOption`
配置 Markdown 解析器选项。VitePress 使用 [Markdown-it](https://github.com/markdown-it/markdown-it) 作为解析器,使用[Shikiji](https://github.com/antfu/shikiji) ([Shiki](https://shiki.matsu.io/) 的改进版本) 来高亮不同语言语法。在此选项中,可以传递各种 Markdown 相关选项以满足的需要。
```js
export default {
markdown: {...}
}
```
查看[类型声明和 jsdocs](https://github.com/vuejs/vitepress/blob/main/src/node/markdown/markdown.ts) 以获得所有可配置的选项。
### vite
- 类型:`import('vite').UserConfig`
将原始 [Vite 配置](https://vitejs.dev/config/)传递给内部 Vite 开发服务器 / bundler。
```js
export default {
vite: {
// Vite config options
}
}
```
### vue
- 类型:`import('@vitejs/plugin-vue').Options`
将原始的 [@vitejs/plugin-vue 选项](https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue#options)传递给内部插件实例。
```js
export default {
vue: {
// @vitejs/plugin-vue options
}
}
```
## 构建钩子 {#build-hooks}
VitePress 构建钩子允许向站点添加新功能和行为:
- Sitemap
- Search Indexing
- PWA
- Teleport
### buildEnd
- 类型:`(siteConfig: SiteConfig) => Awaitable<void>`
`buildEnd` 是一个构建 CLI 钩子它将在构建SSG完成后但在 VitePress CLI 进程退出之前运行。
```ts
export default {
async buildEnd(siteConfig) {
// ...
}
}
```
### postRender
- 类型:`(context: SSGContext) => Awaitable<SSGContext | void>`
`postRender` 是一个构建钩子,在 SSG 渲染完成时调用。它将允许在 SSG 期间处理传递的内容。
```ts
export default {
async postRender(context) {
// ...
}
}
```
```ts
interface SSGContext {
content: string
teleports?: Record<string, string>
[key: string]: any
}
```
### transformHead
- 类型:`(context: TransformContext) => Awaitable<HeadConfig[]>`
`transformHead` 是一个构建钩子,用于在生成每个页面之前转换 head。它将允许添加无法静态添加到 VitePress 配置中的 head entries。只需要返回额外的 entries它们将自动与现有 entries 合并。
::: warning
不要改变 `context` 中的任何东西。
:::
```ts
export default {
async transformHead(context) {
// ...
}
}
```
```ts
interface TransformContext {
page: string // e.g. index.md (relative to srcDir)
assets: string[] // all non-js/css assets as fully resolved public URL
siteConfig: SiteConfig
siteData: SiteData
pageData: PageData
title: string
description: string
head: HeadConfig[]
content: string
}
```
请注意,仅在静态生成站点时才会调用此挂钩。在开发期间不会调用它。如果需要在开发期间添加动态头条目,可以使用 [`transformPageData`](#transformpagedata) 钩子来替代:
```ts
export default {
transformPageData(pageData) {
pageData.frontmatter.head ??= []
pageData.frontmatter.head.push([
'meta',
{
name: 'og:title',
content:
pageData.frontmatter.layout === 'home'
? `VitePress`
: `${pageData.title} | VitePress`
}
])
}
}
```
### transformHtml
- 类型:`(code: string, id: string, context: TransformContext) => Awaitable<string | void>`
`transformHtml` 是一个构建钩子,用于在保存到磁盘之前转换每个页面的内容。
::: warning
不要改变 `context` 中的任何东西。另外,修改 html 内容可能会导致运行时出现激活问题。
:::
```ts
export default {
async transformHtml(code, id, context) {
// ...
}
}
```
### transformPageData
- 类型:`(pageData: PageData, context: TransformPageContext) => Awaitable<Partial<PageData> | { [key: string]: any } | void>`
`transformPageData` 是一个钩子,用于转换每个页面的 `pageData`。可以直接改变 `pageData` 或返回将合并到 `PageData` 中的更改值。
::: warning
不要改变 `context` 中的任何东西。请注意,这可能会影响开发服务器的性能,特别是当在钩子中有一些网络请求或大量计算(例如生成图像)时。可以通过判断 `process.env.NODE_ENV === 'production'` 匹配符合条件的情况。
:::
```ts
export default {
async transformPageData(pageData, { siteConfig }) {
pageData.contributors = await getPageContributors(pageData.relativePath)
}
// or return data to be merged
async transformPageData(pageData, { siteConfig }) {
return {
contributors: await getPageContributors(pageData.relativePath)
}
}
}
```
```ts
interface TransformPageContext {
siteConfig: SiteConfig
}
```

@ -100,9 +100,9 @@
"focus-trap": "^7.5.4",
"mark.js": "8.11.1",
"minisearch": "^6.3.0",
"shikiji": "^0.9.15",
"shikiji-core": "^0.9.15",
"shikiji-transformers": "^0.9.15",
"shikiji": "^0.9.16",
"shikiji-core": "^0.9.16",
"shikiji-transformers": "^0.9.16",
"vite": "^5.0.10",
"vue": "^3.4.3"
},
@ -194,7 +194,7 @@
"sitemap": "^7.1.1",
"supports-color": "^9.4.0",
"typescript": "^5.3.3",
"vitest": "^1.1.0",
"vitest": "^1.1.1",
"vue-tsc": "^1.8.27",
"wait-on": "^7.2.0"
},

@ -42,14 +42,14 @@ importers:
specifier: ^6.3.0
version: 6.3.0
shikiji:
specifier: ^0.9.15
version: 0.9.15
specifier: ^0.9.16
version: 0.9.16
shikiji-core:
specifier: ^0.9.15
version: 0.9.15
specifier: ^0.9.16
version: 0.9.16
shikiji-transformers:
specifier: ^0.9.15
version: 0.9.15
specifier: ^0.9.16
version: 0.9.16
vite:
specifier: ^5.0.10
version: 5.0.10(@types/node@20.10.6)
@ -283,8 +283,8 @@ importers:
specifier: ^5.3.3
version: 5.3.3
vitest:
specifier: ^1.1.0
version: 1.1.0(@types/node@20.10.6)(supports-color@9.4.0)
specifier: ^1.1.1
version: 1.1.1(@types/node@20.10.6)(supports-color@9.4.0)
vue-tsc:
specifier: ^1.8.27
version: 1.8.27(typescript@5.3.3)
@ -1301,38 +1301,38 @@ packages:
vue: 3.4.3(typescript@5.3.3)
dev: false
/@vitest/expect@1.1.0:
resolution: {integrity: sha512-9IE2WWkcJo2BR9eqtY5MIo3TPmS50Pnwpm66A6neb2hvk/QSLfPXBz2qdiwUOQkwyFuuXEUj5380CbwfzW4+/w==}
/@vitest/expect@1.1.1:
resolution: {integrity: sha512-Qpw01C2Hyb3085jBkOJLQ7HRX0Ncnh2qV4p+xWmmhcIUlMykUF69zsnZ1vPmAjZpomw9+5tWEGOQ0GTfR8U+kA==}
dependencies:
'@vitest/spy': 1.1.0
'@vitest/utils': 1.1.0
'@vitest/spy': 1.1.1
'@vitest/utils': 1.1.1
chai: 4.3.10
dev: true
/@vitest/runner@1.1.0:
resolution: {integrity: sha512-zdNLJ00pm5z/uhbWF6aeIJCGMSyTyWImy3Fcp9piRGvueERFlQFbUwCpzVce79OLm2UHk9iwaMSOaU9jVHgNVw==}
/@vitest/runner@1.1.1:
resolution: {integrity: sha512-8HokyJo1SnSi3uPFKfWm/Oq1qDwLC4QDcVsqpXIXwsRPAg3gIDh8EbZ1ri8cmQkBxdOu62aOF9B4xcqJhvt4xQ==}
dependencies:
'@vitest/utils': 1.1.0
'@vitest/utils': 1.1.1
p-limit: 5.0.0
pathe: 1.1.1
dev: true
/@vitest/snapshot@1.1.0:
resolution: {integrity: sha512-5O/wyZg09V5qmNmAlUgCBqflvn2ylgsWJRRuPrnHEfDNT6tQpQ8O1isNGgo+VxofISHqz961SG3iVvt3SPK/QQ==}
/@vitest/snapshot@1.1.1:
resolution: {integrity: sha512-WnMHjv4VdHLbFGgCdVVvyRkRPnOKN75JJg+LLTdr6ah7YnL75W+7CTIMdzPEPzaDxA8r5yvSVlc1d8lH3yE28w==}
dependencies:
magic-string: 0.30.5
pathe: 1.1.1
pretty-format: 29.7.0
dev: true
/@vitest/spy@1.1.0:
resolution: {integrity: sha512-sNOVSU/GE+7+P76qYo+VXdXhXffzWZcYIPQfmkiRxaNCSPiLANvQx5Mx6ZURJ/ndtEkUJEpvKLXqAYTKEY+lTg==}
/@vitest/spy@1.1.1:
resolution: {integrity: sha512-hDU2KkOTfFp4WFFPWwHFauddwcKuGQ7gF6Un/ZZkCogoAiTMN7/7YKvUDbywPZZ754iCQGjdUmXN3t4k0jm1IQ==}
dependencies:
tinyspy: 2.2.0
dev: true
/@vitest/utils@1.1.0:
resolution: {integrity: sha512-z+s510fKmYz4Y41XhNs3vcuFTFhcij2YF7F8VQfMEYAAUfqQh0Zfg7+w9xdgFGhPf3tX3TicAe+8BDITk6ampQ==}
/@vitest/utils@1.1.1:
resolution: {integrity: sha512-E9LedH093vST/JuBSyHLFMpxJKW3dLhe/flUSPFedoyj4wKiFX7Jm8gYLtOIiin59dgrssfmFv0BJ1u8P/LC/A==}
dependencies:
diff-sequences: 29.6.3
loupe: 2.3.7
@ -1685,7 +1685,7 @@ packages:
/axios@1.6.3(debug@4.3.4):
resolution: {integrity: sha512-fWyNdeawGam70jXSVlKl+SUNVcL6j6W79CuSIPfi6HnDUmSCH6gyUys/HrqHeA/wU0Az41rRgean494d0Jb+ww==}
dependencies:
follow-redirects: 1.15.3(debug@4.3.4)
follow-redirects: 1.15.4(debug@4.3.4)
form-data: 4.0.0
proxy-from-env: 1.1.0
transitivePeerDependencies:
@ -2434,8 +2434,8 @@ packages:
tabbable: 6.2.0
dev: false
/follow-redirects@1.15.3(debug@4.3.4):
resolution: {integrity: sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==}
/follow-redirects@1.15.4(debug@4.3.4):
resolution: {integrity: sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==}
engines: {node: '>=4.0'}
peerDependencies:
debug: '*'
@ -3980,20 +3980,20 @@ packages:
resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==}
dev: true
/shikiji-core@0.9.15:
resolution: {integrity: sha512-7hqIcUKS15OMs/61Qp2GvO1fSajBB36bDqi8vexIg5kp80V6v6SGtBrlq+nLlo7erMG2d1kvIuTIq1bwKI6fEg==}
/shikiji-core@0.9.16:
resolution: {integrity: sha512-eJIK8/IpzvAGnbckCE2Qf/fOSfpjVLSosUfI3pQAnbphGXagEqiRcT/gyVtL4llqmBh0nexqRdJKMFZF3A6ayw==}
dev: false
/shikiji-transformers@0.9.15:
resolution: {integrity: sha512-k0sQ6tX26/cdb8QV9CCwwr7QjRp6/AVP9C0oNIXNld3of+xCrpf74kD74piybG6vMfzBoHGsz/s60RVBJOUaYQ==}
/shikiji-transformers@0.9.16:
resolution: {integrity: sha512-DcvhYtLc3Xtme070vgyyeHX0XrNK0zHrKIiPk8wcptFbFUuS65qYDd/UFl68+R8KhdoSFTM9EXlBa9MhrGlbaw==}
dependencies:
shikiji: 0.9.15
shikiji: 0.9.16
dev: false
/shikiji@0.9.15:
resolution: {integrity: sha512-+inN4cN+nY7b0uCPOiqFHAk+cn2DEdM3AIQgPhAV7QKqhww/o7OGS5xvLh3SNnjke9C/HispALqGOQGYHVq7KQ==}
/shikiji@0.9.16:
resolution: {integrity: sha512-QeSwiW88gHke9deQ5Av1f6CEVPGW/riRMPT3vMDGPnASCOhBZK4TYk5ZRoa2qYLncPZS5kXKwcggccQvg3+U7Q==}
dependencies:
shikiji-core: 0.9.15
shikiji-core: 0.9.16
dev: false
/side-channel@1.0.4:
@ -4430,8 +4430,8 @@ packages:
engines: {node: '>= 0.8'}
dev: true
/vite-node@1.1.0(@types/node@20.10.6)(supports-color@9.4.0):
resolution: {integrity: sha512-jV48DDUxGLEBdHCQvxL1mEh7+naVy+nhUUUaPAZLd3FJgXuxQiewHcfeZebbJ6onDqNGkP4r3MhQ342PRlG81Q==}
/vite-node@1.1.1(@types/node@20.10.6)(supports-color@9.4.0):
resolution: {integrity: sha512-2bGE5w4jvym5v8llF6Gu1oBrmImoNSs4WmRVcavnG2me6+8UQntTqLiAMFyiAobp+ZXhj5ZFhI7SmLiFr/jrow==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
dependencies:
@ -4486,8 +4486,8 @@ packages:
optionalDependencies:
fsevents: 2.3.3
/vitest@1.1.0(@types/node@20.10.6)(supports-color@9.4.0):
resolution: {integrity: sha512-oDFiCrw7dd3Jf06HoMtSRARivvyjHJaTxikFxuqJjO76U436PqlVw1uLn7a8OSPrhSfMGVaRakKpA2lePdw79A==}
/vitest@1.1.1(@types/node@20.10.6)(supports-color@9.4.0):
resolution: {integrity: sha512-Ry2qs4UOu/KjpXVfOCfQkTnwSXYGrqTbBZxw6reIYEFjSy1QUARRg5pxiI5BEXy+kBVntxUYNMlq4Co+2vD3fQ==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
peerDependencies:
@ -4512,11 +4512,11 @@ packages:
optional: true
dependencies:
'@types/node': 20.10.6
'@vitest/expect': 1.1.0
'@vitest/runner': 1.1.0
'@vitest/snapshot': 1.1.0
'@vitest/spy': 1.1.0
'@vitest/utils': 1.1.0
'@vitest/expect': 1.1.1
'@vitest/runner': 1.1.1
'@vitest/snapshot': 1.1.1
'@vitest/spy': 1.1.1
'@vitest/utils': 1.1.1
acorn-walk: 8.3.1
cac: 6.7.14
chai: 4.3.10
@ -4531,7 +4531,7 @@ packages:
tinybench: 2.5.1
tinypool: 0.8.1
vite: 5.0.10(@types/node@20.10.6)
vite-node: 1.1.0(@types/node@20.10.6)(supports-color@9.4.0)
vite-node: 1.1.1(@types/node@20.10.6)(supports-color@9.4.0)
why-is-node-running: 2.2.2
transitivePeerDependencies:
- less

@ -0,0 +1,12 @@
import { inBrowser } from '../../shared'
import { ref } from 'vue'
const hashRef = ref(inBrowser ? location.hash : '')
if (inBrowser) {
window.addEventListener('hashchange', () => {
hashRef.value = location.hash
})
}
export { hashRef }

@ -1,6 +1,7 @@
import { computed } from 'vue'
import { useData } from './data'
import { ensureStartingSlash } from '../support/utils'
import { useData } from './data'
import { hashRef } from './hash'
export function useLangs({
removeCurrent = true,
@ -20,12 +21,15 @@ export function useLangs({
? []
: {
text: value.label,
link: normalizeLink(
value.link || (key === 'root' ? '/' : `/${key}/`),
theme.value.i18nRouting !== false && correspondingLink,
page.value.relativePath.slice(currentLang.value.link.length - 1),
!site.value.cleanUrls
)
link:
normalizeLink(
value.link || (key === 'root' ? '/' : `/${key}/`),
theme.value.i18nRouting !== false && correspondingLink,
page.value.relativePath.slice(
currentLang.value.link.length - 1
),
!site.value.cleanUrls
) + hashRef.value
}
)
)

@ -11,13 +11,14 @@ import {
type ComputedRef,
type Ref
} from 'vue'
import { inBrowser, isActive } from '../../shared'
import { isActive } from '../../shared'
import {
hasActiveLink as containsActiveLink,
getSidebar,
getSidebarGroups
} from '../support/sidebar'
import { useData } from './data'
import { hashRef } from './hash'
export interface SidebarControl {
collapsed: Ref<boolean>
@ -134,13 +135,6 @@ export function useCloseSidebarOnEscape(
}
}
const hashRef = ref(inBrowser ? location.hash : '')
if (inBrowser) {
window.addEventListener('hashchange', () => {
hashRef.value = location.hash
})
}
export function useSidebarControl(
item: ComputedRef<DefaultTheme.SidebarItem>
): SidebarControl {

@ -157,7 +157,11 @@ export async function createVitePressPlugin(
},
optimizeDeps: {
// force include vue to avoid duplicated copies when linked + optimized
include: ['vue', 'vitepress > @vue/devtools-api'],
include: [
'vue',
'vitepress > @vue/devtools-api',
'vitepress > @vueuse/core'
],
exclude: ['@docsearch/js', 'vitepress']
},
server: {

Loading…
Cancel
Save