mirror of https://github.com/vuejs/vitepress
commit
3dbbd80ec3
@ -1,8 +1,3 @@
|
||||
<script setup>
|
||||
import { useData } from 'vitepress'
|
||||
const { page } = useData()
|
||||
</script>
|
||||
|
||||
<!-- @content -->
|
||||
|
||||
<pre class="params">{{ page.params }}</pre>
|
||||
<pre class="params">{{ $params }}</pre>
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
# Foo
|
||||
|
||||
<!-- #region snippet -->
|
||||
## Region
|
||||
|
||||
this is region
|
||||
<!-- #endregion snippet -->
|
||||
@ -0,0 +1,178 @@
|
||||
# Markdown Extensions
|
||||
|
||||
## Links
|
||||
|
||||
### Internal Links
|
||||
|
||||
- [home](/)
|
||||
- [markdown-extensions](/markdown-extensions/)
|
||||
- [heading](./#internal-links)
|
||||
- [omit extension](./foo)
|
||||
- [.md extension](./foo.md)
|
||||
- [.html extension](./foo.html)
|
||||
|
||||
### External Links
|
||||
|
||||
[VitePress on GitHub](https://github.com/vuejs/vitepress)
|
||||
|
||||
## GitHub-Style Tables
|
||||
|
||||
| Tables | Are | Cool |
|
||||
| ------------- | :-----------: | -----: |
|
||||
| col 3 is | right-aligned | \$1600 |
|
||||
| col 2 is | centered | \$12 |
|
||||
| zebra stripes | are neat | \$1 |
|
||||
|
||||
## Emoji
|
||||
|
||||
- :tada:
|
||||
- :100:
|
||||
|
||||
## Table of Contents
|
||||
|
||||
[[toc]]
|
||||
|
||||
## Custom Containers
|
||||
|
||||
### Default Title
|
||||
|
||||
::: 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
|
||||
|
||||
::: danger STOP
|
||||
Danger zone, do not proceed
|
||||
:::
|
||||
|
||||
::: details Click me to view the code
|
||||
```js
|
||||
console.log('Hello, VitePress!')
|
||||
```
|
||||
:::
|
||||
|
||||
## Line Highlighting in Code Blocks
|
||||
|
||||
### Single Line
|
||||
|
||||
```js{4}
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
msg: 'Highlighted!'
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Multiple single lines, ranges
|
||||
|
||||
```js{1,4,6-8}
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
msg: `Highlighted!
|
||||
This line isn't highlighted,
|
||||
but this and the next 2 are.`,
|
||||
motd: 'VitePress is awesome',
|
||||
lorem: 'ipsum',
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Comment Highlight
|
||||
|
||||
```js
|
||||
export default { // [!code focus]
|
||||
data() { // [!code hl]
|
||||
return {
|
||||
msg: 'Removed' // [!code --]
|
||||
msg: 'Added' // [!code ++]
|
||||
msg: 'Error', // [!code error]
|
||||
msg: 'Warning' // [!code warning]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Line Numbers
|
||||
|
||||
```ts:line-numbers
|
||||
const line1 = 'This is line 1'
|
||||
const line2 = 'This is line 2'
|
||||
```
|
||||
|
||||
## Import Code Snippets
|
||||
|
||||
### Basic Code Snippet
|
||||
|
||||
<<< @/markdown-extensions/foo.md
|
||||
|
||||
### Specify Region
|
||||
|
||||
<<< @/markdown-extensions/foo.md#snippet
|
||||
|
||||
### With Other Features
|
||||
|
||||
<<< @/markdown-extensions/foo.md#snippet{1 ts:line-numbers} [snippet with region]
|
||||
|
||||
## Code Groups
|
||||
|
||||
### Basic Code Group
|
||||
|
||||
::: 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
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
### With Other Features
|
||||
|
||||
::: code-group
|
||||
|
||||
<<< @/markdown-extensions/foo.md
|
||||
|
||||
<<< @/markdown-extensions/foo.md#snippet{1 ts:line-numbers} [snippet with region]
|
||||
|
||||
:::
|
||||
|
||||
## Markdown File Inclusion
|
||||
|
||||
<!--@include: ./foo.md-->
|
||||
@ -0,0 +1,232 @@
|
||||
import type { Locator } from 'playwright-chromium'
|
||||
|
||||
const getClassList = async (locator: Locator) => {
|
||||
const className = await locator.getAttribute('class')
|
||||
return className?.split(' ').filter(Boolean) ?? []
|
||||
}
|
||||
|
||||
beforeEach(async () => {
|
||||
await goto('/markdown-extensions/')
|
||||
})
|
||||
|
||||
describe('Links', () => {
|
||||
test('render internal link', async () => {
|
||||
const targetMap = Object.entries({
|
||||
home: '/',
|
||||
'markdown-extensions': '/markdown-extensions/',
|
||||
heading: './#internal-links',
|
||||
'omit extension': './foo.html',
|
||||
'.md extension': './foo.html',
|
||||
'.html extension': './foo.html'
|
||||
})
|
||||
|
||||
const items = page.locator('#internal-links +ul a')
|
||||
const count = await items.count()
|
||||
expect(count).toBe(6)
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
const [text, href] = targetMap[i]
|
||||
expect(await items.nth(i).textContent()).toBe(text)
|
||||
expect(await items.nth(i).getAttribute('href')).toBe(href)
|
||||
}
|
||||
})
|
||||
|
||||
test('external link get target="_blank" and rel="noreferrer"', async () => {
|
||||
const link = page.locator('#external-links + p a')
|
||||
expect(await link.getAttribute('target')).toBe('_blank')
|
||||
expect(await link.getAttribute('rel')).toBe('noreferrer')
|
||||
})
|
||||
})
|
||||
|
||||
describe('GitHub-Style Tables', () => {
|
||||
test('render table', async () => {
|
||||
const table = page.locator('#github-style-tables + table')
|
||||
expect(table).toBeTruthy()
|
||||
})
|
||||
})
|
||||
|
||||
describe('Emoji', () => {
|
||||
test('render emoji', async () => {
|
||||
const emojis = ['🎉', '💯']
|
||||
|
||||
const items = page.locator('#emoji + ul li')
|
||||
const count = await items.count()
|
||||
expect(count).toBe(2)
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
expect(await items.nth(i).textContent()).toBe(emojis[i])
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('Table of Contents', () => {
|
||||
test('render toc', async () => {
|
||||
const items = page.locator('#table-of-contents + nav ul li')
|
||||
const count = await items.count()
|
||||
expect(count).toBe(23)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Custom Containers', () => {
|
||||
enum CustomBlocks {
|
||||
Info = 'INFO',
|
||||
Tip = 'TIP',
|
||||
Warning = 'WARNING',
|
||||
Danger = 'DANGER',
|
||||
Details = 'Details'
|
||||
}
|
||||
|
||||
const classnameMap = {
|
||||
[CustomBlocks.Info]: 'info',
|
||||
[CustomBlocks.Tip]: 'tip',
|
||||
[CustomBlocks.Warning]: 'warning',
|
||||
[CustomBlocks.Danger]: 'danger',
|
||||
[CustomBlocks.Details]: 'details'
|
||||
}
|
||||
|
||||
const getTitleText = (locator: Locator, type: CustomBlocks) => {
|
||||
if (type === CustomBlocks.Details) {
|
||||
return locator.locator('summary').textContent()
|
||||
} else {
|
||||
return locator.locator('.custom-block-title').textContent()
|
||||
}
|
||||
}
|
||||
|
||||
test('default title', async () => {
|
||||
const blocks = page.locator('#default-title ~ .custom-block')
|
||||
for (const [index, type] of Object.values(CustomBlocks).entries()) {
|
||||
const block = blocks.nth(index)
|
||||
const classList = await getClassList(block)
|
||||
expect(classList).contain(classnameMap[type as CustomBlocks])
|
||||
expect(await getTitleText(block, type)).toBe(type)
|
||||
}
|
||||
})
|
||||
|
||||
test('custom Title', async () => {
|
||||
const blocks = page.locator('#custom-title ~ .custom-block')
|
||||
expect(await getTitleText(blocks.nth(0), CustomBlocks.Danger)).toBe('STOP')
|
||||
expect(await getTitleText(blocks.nth(1), CustomBlocks.Details)).toBe(
|
||||
'Click me to view the code'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Line Highlighting in Code Blocks', () => {
|
||||
test('single line', async () => {
|
||||
const classList = await getClassList(
|
||||
page.locator('#single-line + div code > span').nth(3)
|
||||
)
|
||||
expect(classList).toContain('highlighted')
|
||||
})
|
||||
|
||||
test('multiple single lines, ranges', async () => {
|
||||
const lines = page.locator(
|
||||
'#multiple-single-lines-ranges + div code > span'
|
||||
)
|
||||
|
||||
for (const num of [1, 4, 6, 7, 8]) {
|
||||
expect(await getClassList(lines.nth(num - 1))).toContain('highlighted')
|
||||
}
|
||||
})
|
||||
|
||||
test('comment highlight', async () => {
|
||||
const lines = page.locator('#comment-highlight + div code > span')
|
||||
expect(await getClassList(lines.nth(0))).toContain('has-focus')
|
||||
|
||||
expect(await getClassList(lines.nth(1))).toContain('highlighted')
|
||||
|
||||
expect(await getClassList(lines.nth(3))).toContain('diff')
|
||||
expect(await getClassList(lines.nth(3))).toContain('remove')
|
||||
|
||||
expect(await getClassList(lines.nth(4))).toContain('diff')
|
||||
expect(await getClassList(lines.nth(4))).toContain('add')
|
||||
|
||||
expect(await getClassList(lines.nth(5))).toContain('highlighted')
|
||||
expect(await getClassList(lines.nth(5))).toContain('error')
|
||||
|
||||
expect(await getClassList(lines.nth(6))).toContain('highlighted')
|
||||
expect(await getClassList(lines.nth(6))).toContain('warning')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Line Numbers', () => {
|
||||
test('render line numbers', async () => {
|
||||
const div = page.locator('#line-numbers + div')
|
||||
expect(await getClassList(div)).toContain('line-numbers-mode')
|
||||
const lines = div.locator('.line-numbers-wrapper > span')
|
||||
expect(await lines.count()).toBe(2)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Import Code Snippets', () => {
|
||||
test('basic', async () => {
|
||||
const lines = page.locator('#basic-code-snippet + div code > span')
|
||||
expect(await lines.count()).toBe(7)
|
||||
})
|
||||
|
||||
test('specify region', async () => {
|
||||
const lines = page.locator('#specify-region + div code > span')
|
||||
expect(await lines.count()).toBe(3)
|
||||
})
|
||||
|
||||
test('with other features', async () => {
|
||||
const div = page.locator('#with-other-features + div')
|
||||
expect(await getClassList(div)).toContain('line-numbers-mode')
|
||||
const lines = div.locator('code > span')
|
||||
expect(await lines.count()).toBe(3)
|
||||
expect(await getClassList(lines.nth(0))).toContain('highlighted')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Code Groups', () => {
|
||||
test('basic', async () => {
|
||||
const div = page.locator('#basic-code-group + div')
|
||||
|
||||
// tabs
|
||||
const labels = div.locator('.tabs > label')
|
||||
const labelNames = ['config.js', 'config.ts']
|
||||
const count = await labels.count()
|
||||
expect(count).toBe(2)
|
||||
for (let i = 0; i < count; i++) {
|
||||
const text = await labels.nth(i).textContent()
|
||||
expect(text).toBe(labelNames[i])
|
||||
}
|
||||
|
||||
// blocks
|
||||
const blocks = div.locator('.blocks > div')
|
||||
expect(await getClassList(blocks.nth(0))).toContain('active')
|
||||
await labels.nth(1).click()
|
||||
expect(await getClassList(blocks.nth(1))).toContain('active')
|
||||
})
|
||||
|
||||
test('with other features', async () => {
|
||||
const div = page.locator('#with-other-features-1 + div')
|
||||
|
||||
// tabs
|
||||
const labels = div.locator('.tabs > label')
|
||||
const labelNames = ['foo.md', 'snippet with region']
|
||||
const count = await labels.count()
|
||||
expect(count).toBe(2)
|
||||
for (let i = 0; i < count; i++) {
|
||||
const text = await labels.nth(i).textContent()
|
||||
expect(text).toBe(labelNames[i])
|
||||
}
|
||||
|
||||
// blocks
|
||||
const blocks = div.locator('.blocks > div')
|
||||
expect(await blocks.nth(0).locator('code > span').count()).toBe(7)
|
||||
expect(await getClassList(blocks.nth(1))).toContain('line-numbers-mode')
|
||||
expect(await getClassList(blocks.nth(1))).toContain('language-ts')
|
||||
expect(await blocks.nth(1).locator('code > span').count()).toBe(3)
|
||||
expect(
|
||||
await getClassList(blocks.nth(1).locator('code > span').nth(0))
|
||||
).toContain('highlighted')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Markdown File Inclusion', () => {
|
||||
test('render markdown', async () => {
|
||||
const h1 = page.locator('#markdown-file-inclusion + h1')
|
||||
expect(await h1.getAttribute('id')).toBe('foo')
|
||||
})
|
||||
})
|
||||
@ -1,23 +1,20 @@
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
|
||||
const dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
import { defineLoader } from 'vitepress'
|
||||
|
||||
type Data = Record<string, boolean>[]
|
||||
export declare const data: Data
|
||||
|
||||
export default {
|
||||
export default defineLoader({
|
||||
watch: ['./data/*'],
|
||||
async load(): Promise<Data> {
|
||||
async load(files: string[]): Promise<Data> {
|
||||
const foo = fs.readFileSync(
|
||||
path.resolve(dirname, './data/foo.json'),
|
||||
files.find((f) => f.endsWith('foo.json'))!,
|
||||
'utf-8'
|
||||
)
|
||||
const bar = fs.readFileSync(
|
||||
path.resolve(dirname, './data/bar.json'),
|
||||
files.find((f) => f.endsWith('bar.json'))!,
|
||||
'utf-8'
|
||||
)
|
||||
return [JSON.parse(foo), JSON.parse(bar)]
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@ -1,192 +0,0 @@
|
||||
# Frontmatter Config
|
||||
|
||||
Frontmatter enables page based configuration. In every markdown file, you can use frontmatter config to override app-level or theme config options. Also, there are config options which you can only define in frontmatter.
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: Docs with VitePress
|
||||
editLink: true
|
||||
---
|
||||
```
|
||||
|
||||
You can access frontmatter by `$frontmatter` helper inside any markdown file.
|
||||
|
||||
```md
|
||||
{{ $frontmatter.title }}
|
||||
```
|
||||
|
||||
## title
|
||||
|
||||
- Type: `string`
|
||||
|
||||
Title for the page. It's same as [config.title](../config/app-config#title), and it overrides the app config.
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: VitePress
|
||||
---
|
||||
```
|
||||
|
||||
## titleTemplate
|
||||
|
||||
- Type: `string | boolean`
|
||||
|
||||
The suffix for the title. It's same as [config.titleTemplate](../config/app-config#titletemplate), and it overrides the app config.
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: VitePress
|
||||
titleTemplate: Vite & Vue powered static site generator
|
||||
---
|
||||
```
|
||||
|
||||
## description
|
||||
|
||||
- Type: `string`
|
||||
|
||||
Description for the page. It's same as [config.description](../config/app-config#description), and it overrides the app config.
|
||||
|
||||
```yaml
|
||||
---
|
||||
description: VitePress
|
||||
---
|
||||
```
|
||||
|
||||
## head
|
||||
|
||||
- Type: `HeadConfig[]`
|
||||
|
||||
Specify extra head tags to be injected:
|
||||
|
||||
```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]
|
||||
```
|
||||
|
||||
## lastUpdated
|
||||
|
||||
- Type: `boolean`
|
||||
- Default: `true`
|
||||
|
||||
Whether to display [Last Updated](../guide/theme-last-updated) text in the current page.
|
||||
|
||||
```yaml
|
||||
---
|
||||
lastUpdated: false
|
||||
---
|
||||
```
|
||||
|
||||
## layout
|
||||
|
||||
- Type: `doc | home | page`
|
||||
- Default: `doc`
|
||||
|
||||
Determines the layout of the page.
|
||||
|
||||
- `doc` - It applies default documentation styles to the markdown content.
|
||||
- `home` - Special layout for "Home Page". You may add extra options such as `hero` and `features` to rapidly create beautiful landing page.
|
||||
- `page` - Behave similar to `doc` but it applies no styles to the content. Useful when you want to create a fully custom page.
|
||||
|
||||
```yaml
|
||||
---
|
||||
layout: doc
|
||||
---
|
||||
```
|
||||
|
||||
## hero
|
||||
|
||||
- Type: `Hero`
|
||||
|
||||
This option only takes effect when `layout` is set to `home`.
|
||||
|
||||
It defines contents of home hero section.
|
||||
|
||||
```yaml
|
||||
---
|
||||
layout: home
|
||||
|
||||
hero:
|
||||
name: VitePress
|
||||
text: Vite & Vue powered static site generator.
|
||||
tagline: Lorem ipsum...
|
||||
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
|
||||
|
||||
// Action buttons to display in home hero section.
|
||||
actions?: HeroAction[]
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
```
|
||||
|
||||
## features
|
||||
|
||||
- Type: `Feature[]`
|
||||
|
||||
This option only takes effect when `layout` is set to `home`.
|
||||
|
||||
It defines items to display in features section.
|
||||
|
||||
You may learn more about it in [Theme: Home Page](../guide/theme-home-page).
|
||||
|
||||
## aside
|
||||
|
||||
- Type: `boolean`
|
||||
- Default: `true`
|
||||
|
||||
If you want the right aside component in `doc` layout not to be shown, set this option to `false`.
|
||||
|
||||
```yaml
|
||||
---
|
||||
aside: false
|
||||
---
|
||||
```
|
||||
|
||||
## outline
|
||||
|
||||
- Type: `number | [number, number] | 'deep' | false`
|
||||
- Default: `2`
|
||||
|
||||
The levels of header in the outline to display for the page. It's same as [config.themeConfig.outline](../config/theme-config#outline), and it overrides the theme config.
|
||||
@ -1,76 +0,0 @@
|
||||
# Introduction
|
||||
|
||||
Place your configuration file at `.vitepress/config.js`. This is where all VitePress-specific files will be placed.
|
||||
|
||||
```
|
||||
.
|
||||
├─ docs
|
||||
│ ├─ .vitepress
|
||||
│ │ └─ config.js
|
||||
│ └─ index.md
|
||||
└─ package.json
|
||||
```
|
||||
|
||||
::: tip
|
||||
You can also use any of `.ts`, `.cjs`, `.mjs`, `.cts`, `.mts` as the config file extension.
|
||||
:::
|
||||
|
||||
VitePress comes with 2 types of configuration. One is the [App Config](./app-config) which configures the site's fundamental features such as setting title of the site, or customize how markdown parser works. Second is the [Theme Config](./theme-config) which configures the theme of the site, for example, adding a sidebar, or add features such as "Edit this page on GitHub" link.
|
||||
|
||||
There's also another configuration you may do in [Frontmatter](./frontmatter-config). Frontmatter config can override global config defined in App Config or Theme Config for that specific page. However, there're several options that are only available at frontmatter as well.
|
||||
|
||||
Please refer to the corresponding config page to learn more.
|
||||
|
||||
## Config Intellisense
|
||||
|
||||
Since VitePress ships with TypeScript typings, you can leverage your IDE's intellisense with jsdoc type hints:
|
||||
|
||||
```js
|
||||
/**
|
||||
* @type {import('vitepress').UserConfig}
|
||||
*/
|
||||
const config = {
|
||||
// ...
|
||||
}
|
||||
|
||||
export default config
|
||||
```
|
||||
|
||||
Alternatively, you can use the `defineConfig` helper at which should provide intellisense without the need for jsdoc annotations:
|
||||
|
||||
```js
|
||||
import { defineConfig } from 'vitepress'
|
||||
|
||||
export default defineConfig({
|
||||
// ...
|
||||
})
|
||||
```
|
||||
|
||||
VitePress also directly supports TS config files. You can use `.vitepress/config.ts` with the `defineConfig` helper as well.
|
||||
|
||||
## Typed Theme Config
|
||||
|
||||
By default, `defineConfig` helper leverages the theme config type from default theme:
|
||||
|
||||
```ts
|
||||
import { defineConfig } from 'vitepress'
|
||||
|
||||
export default defineConfig({
|
||||
themeConfig: {
|
||||
// Type is `DefaultTheme.Config`
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
If you use a custom theme and want type checks for the theme config, you'll need to use `defineConfigWithTheme` instead, and pass the config type for your custom theme via a generic argument:
|
||||
|
||||
```ts
|
||||
import { defineConfigWithTheme } from 'vitepress'
|
||||
import { ThemeConfig } from 'your-theme'
|
||||
|
||||
export default defineConfigWithTheme<ThemeConfig>({
|
||||
themeConfig: {
|
||||
// Type is `ThemeConfig`
|
||||
}
|
||||
})
|
||||
```
|
||||
@ -0,0 +1,56 @@
|
||||
---
|
||||
outline: deep
|
||||
---
|
||||
|
||||
# Connecting to a CMS
|
||||
|
||||
## General Workflow
|
||||
|
||||
Connecting VitePress to a CMS will largely revolve around [Dynamic Routes](/guide/routing#dynamic-routes). Make sure to understand how it works before proceeding.
|
||||
|
||||
Since each CMS will work differently, here we can only provide a generic workflow that you will need to adapt to your specific scenario.
|
||||
|
||||
1. If your CMS requires authentication, create an `.env` file to store your API tokens and load it so:
|
||||
|
||||
```js
|
||||
// posts/[id].paths.js
|
||||
import { loadEnv } from 'vitepress'
|
||||
|
||||
const env = loadEnv('', process.cwd())
|
||||
```
|
||||
|
||||
2. Fetch the necessary data from the CMS and format it into proper paths data:
|
||||
|
||||
```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. Render the content in the page:
|
||||
|
||||
```md
|
||||
# {{ $params.title }}
|
||||
|
||||
- by {{ $params.author }} on {{ $params.date }}
|
||||
|
||||
<!-- @content -->
|
||||
```
|
||||
|
||||
## Integration Guides
|
||||
|
||||
If you have written a guide on integrating VitePress with a specific CMS, please use the "Edit this page" link below to submit it here!
|
||||
@ -1,27 +0,0 @@
|
||||
# Configuration
|
||||
|
||||
Without any configuration, the page is pretty minimal, and the user has no way to navigate around the site. To customize your site, let's first create a `.vitepress` directory inside your docs directory. This is where all VitePress-specific files will be placed. Your project structure is probably like this:
|
||||
|
||||
```
|
||||
.
|
||||
├─ docs
|
||||
│ ├─ .vitepress
|
||||
│ │ └─ config.js
|
||||
│ └─ index.md
|
||||
└─ package.json
|
||||
```
|
||||
|
||||
The essential file for configuring a VitePress site is `.vitepress/config.js`, which should export a JavaScript object:
|
||||
|
||||
```js
|
||||
export default {
|
||||
title: 'VitePress',
|
||||
description: 'Just playing around.'
|
||||
}
|
||||
```
|
||||
|
||||
In the above example, the site will have the title of `VitePress`, and `Just playing around.` as the description meta tag.
|
||||
|
||||
Learn everything about VitePress features at [Theme: Introduction](./customization-intro) to find how to configure specific features within this config file.
|
||||
|
||||
You may also find all configuration references at [Config Reference](../config/introduction).
|
||||
@ -0,0 +1,222 @@
|
||||
# Using a Custom Theme
|
||||
|
||||
## Theme Resolving
|
||||
|
||||
You can enable a custom theme by creating a `.vitepress/theme/index.js` or `.vitepress/theme/index.ts` file (the "theme entry file"):
|
||||
|
||||
```
|
||||
.
|
||||
├─ docs # project root
|
||||
│ ├─ .vitepress
|
||||
│ │ ├─ theme
|
||||
│ │ │ └─ index.js # theme entry
|
||||
│ │ └─ config.js # config file
|
||||
│ └─ index.md
|
||||
└─ package.json
|
||||
```
|
||||
|
||||
VitePress will always use the custom theme instead of the default theme when it detects presence of a theme entry file. You can, however, [extend the default theme](./extending-default-theme) to perform advanced customizations on top of it.
|
||||
|
||||
## Theme Interface
|
||||
|
||||
A VitePress custom theme is defined as an object with the following interface:
|
||||
|
||||
```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
|
||||
}
|
||||
```
|
||||
|
||||
The theme entry file should export the theme as its default export:
|
||||
|
||||
```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 }) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The default export is the only contract for a custom theme, and only the `Layout` property is required. So technically, a VitePress theme can be as simple as a single Vue component.
|
||||
|
||||
Inside your layout component, it works just like a normal Vite + Vue 3 application. Do note the theme also needs to be [SSR-compatible](./using-vue#browser-api-access-restrictions).
|
||||
|
||||
## Building a Layout
|
||||
|
||||
The most basic layout component needs to contain a [`<Content />`](/reference/runtime-api#content) component:
|
||||
|
||||
```vue
|
||||
<!-- .vitepress/theme/Layout.vue -->
|
||||
<template>
|
||||
<h1>Custom Layout!</h1>
|
||||
|
||||
<!-- this is where markdown content will be rendered -->
|
||||
<Content />
|
||||
</template>
|
||||
```
|
||||
|
||||
The above layout simply renders every page's markdown as HTML. The first improvement we can add is to handle 404 errors:
|
||||
|
||||
```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>
|
||||
```
|
||||
|
||||
The [`useData()`](/reference/runtime-api#usedata) helper provides us with all the runtime data we need to conditionally render different layouts. One of the other data we can access is the current page's frontmatter. We can leverage this to allow the end user to control the layout in each page. For example, the user can indicate the page should use a special home page layout with:
|
||||
|
||||
```md
|
||||
---
|
||||
layout: home
|
||||
---
|
||||
```
|
||||
|
||||
And we can adjust our theme to handle this:
|
||||
|
||||
```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>
|
||||
```
|
||||
|
||||
You can, of course, split the layout into more components:
|
||||
|
||||
```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>
|
||||
```
|
||||
|
||||
Consult the [Runtime API Reference](/reference/runtime-api) for everything available in theme components. In addition, you can leverage [Build-Time Data Loading](./data-loading) to generate data-driven layout - for example, a page that lists all blog posts in the current project.
|
||||
|
||||
## Distributing a Custom Theme
|
||||
|
||||
The easiest way to distribute a custom theme is by providing it as a [template repository on GitHub](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-template-repository).
|
||||
|
||||
If you wish to distribute the theme as an npm package, follow these steps:
|
||||
|
||||
1. Export the theme object as the default export in your package entry.
|
||||
|
||||
2. If applicable, export your theme config type definition as `ThemeConfig`.
|
||||
|
||||
3. If your theme requires adjusting the VitePress config, export that config under a package sub-path (e.g. `my-theme/config`) so the user can extend it.
|
||||
|
||||
4. Document the theme config options (both via config file and frontmatter).
|
||||
|
||||
5. Provide clear instructions on how to consume your theme (see below).
|
||||
|
||||
## Consuming a Custom Theme
|
||||
|
||||
To consume an external theme, import and re-export it from the custom theme entry:
|
||||
|
||||
```js
|
||||
// .vitepress/theme/index.js
|
||||
import Theme from 'awesome-vitepress-theme'
|
||||
|
||||
export default Theme
|
||||
```
|
||||
|
||||
If the theme needs to be extended:
|
||||
|
||||
```js
|
||||
// .vitepress/theme/index.js
|
||||
import Theme from 'awesome-vitepress-theme'
|
||||
|
||||
export default {
|
||||
extends: Theme,
|
||||
enhanceApp(ctx) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If the theme requires special VitePress config, you will need to also extend it in your own config:
|
||||
|
||||
```ts
|
||||
// .vitepress/theme/config.ts
|
||||
import baseConfig from 'awesome-vitepress-theme/config'
|
||||
|
||||
export default {
|
||||
// extend theme base config (if needed)
|
||||
extends: baseConfig
|
||||
}
|
||||
```
|
||||
|
||||
Finally, if the theme provides types for its theme config:
|
||||
|
||||
```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`
|
||||
}
|
||||
})
|
||||
```
|
||||
@ -1,228 +0,0 @@
|
||||
# Theme Introduction
|
||||
|
||||
VitePress comes with its default theme providing many features out of the box. Learn more about each feature on its dedicated page listed below.
|
||||
|
||||
- [Nav](./theme-nav)
|
||||
- [Sidebar](./theme-sidebar)
|
||||
- [Prev Next Link](./theme-prev-next-link)
|
||||
- [Edit Link](./theme-edit-link)
|
||||
- [Last Updated](./theme-last-updated)
|
||||
- [Layout](./theme-layout)
|
||||
- [Home Page](./theme-home-page)
|
||||
- [Team Page](./theme-team-page)
|
||||
- [Badge](./theme-badge)
|
||||
- [Footer](./theme-footer)
|
||||
- [Search](./theme-search)
|
||||
- [Carbon Ads](./theme-carbon-ads)
|
||||
|
||||
If you don't find the features you're looking for, or you would rather create your own theme, you may customize VitePress to fit your requirements. In the following sections, we'll go through each way of customizing the VitePress theme.
|
||||
|
||||
## Using a Custom Theme
|
||||
|
||||
You can enable a custom theme by adding the `.vitepress/theme/index.js` or `.vitepress/theme/index.ts` file (the "theme entry file").
|
||||
|
||||
```
|
||||
.
|
||||
├─ docs
|
||||
│ ├─ .vitepress
|
||||
│ │ ├─ theme
|
||||
│ │ │ └─ index.js
|
||||
│ │ └─ config.js
|
||||
│ └─ index.md
|
||||
└─ package.json
|
||||
```
|
||||
|
||||
A VitePress custom theme is simply an object containing four properties and is defined as follows:
|
||||
|
||||
```ts
|
||||
interface Theme {
|
||||
Layout: Component // Vue 3 component
|
||||
NotFound?: Component
|
||||
enhanceApp?: (ctx: EnhanceAppContext) => Awaitable<void>
|
||||
setup?: () => void
|
||||
}
|
||||
|
||||
interface EnhanceAppContext {
|
||||
app: App // Vue 3 app instance
|
||||
router: Router // VitePress router instance
|
||||
siteData: Ref<SiteData>
|
||||
}
|
||||
```
|
||||
|
||||
The theme entry file should export the theme as its default export:
|
||||
|
||||
```js
|
||||
// .vitepress/theme/index.js
|
||||
import Layout from './Layout.vue'
|
||||
|
||||
export default {
|
||||
// root component to wrap each page
|
||||
Layout,
|
||||
|
||||
// this is a Vue 3 functional component
|
||||
NotFound: () => 'custom 404',
|
||||
|
||||
enhanceApp({ app, router, siteData }) {
|
||||
// app is the Vue 3 app instance from `createApp()`.
|
||||
// router is VitePress' custom router. `siteData` is
|
||||
// a `ref` of current site-level metadata.
|
||||
},
|
||||
|
||||
setup() {
|
||||
// this function will be executed inside VitePressApp's
|
||||
// setup hook. all composition APIs are available here.
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
...where the `Layout` component could look like this:
|
||||
|
||||
```vue
|
||||
<!-- .vitepress/theme/Layout.vue -->
|
||||
<template>
|
||||
<h1>Custom Layout!</h1>
|
||||
|
||||
<!-- this is where markdown content will be rendered -->
|
||||
<Content />
|
||||
</template>
|
||||
```
|
||||
|
||||
The default export is the only contract for a custom theme. Inside your custom theme, it works just like a normal Vite + Vue 3 application. Do note the theme also needs to be [SSR-compatible](./using-vue#browser-api-access-restrictions).
|
||||
|
||||
To distribute a theme, simply export the object in your package entry. To consume an external theme, import and re-export it from the custom theme entry:
|
||||
|
||||
```js
|
||||
// .vitepress/theme/index.js
|
||||
import Theme from 'awesome-vitepress-theme'
|
||||
|
||||
export default Theme
|
||||
```
|
||||
|
||||
## Extending the Default Theme
|
||||
|
||||
If you want to extend and customize the default theme, you can import it from `vitepress/theme` and augment it in a custom theme entry. Here are some examples of common customizations:
|
||||
|
||||
### Registering Global Components
|
||||
|
||||
```js
|
||||
// .vitepress/theme/index.js
|
||||
import DefaultTheme from 'vitepress/theme'
|
||||
|
||||
export default {
|
||||
...DefaultTheme,
|
||||
enhanceApp(ctx) {
|
||||
// extend default theme custom behaviour.
|
||||
DefaultTheme.enhanceApp(ctx)
|
||||
|
||||
// register your custom global components
|
||||
ctx.app.component('MyGlobalComponent' /* ... */)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Since we are using Vite, you can also leverage Vite's [glob import feature](https://vitejs.dev/guide/features.html#glob-import) to auto register a directory of components.
|
||||
|
||||
### Customizing CSS
|
||||
|
||||
The default theme CSS is customizable by overriding root level CSS variables:
|
||||
|
||||
```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: #646cff;
|
||||
--vp-c-brand-light: #747bff;
|
||||
}
|
||||
```
|
||||
|
||||
See [default theme CSS variables](https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css) that can be overridden.
|
||||
|
||||
### Layout Slots
|
||||
|
||||
The default theme's `<Layout/>` component has a few slots that can be used to inject content at certain locations of the page. Here's an example of injecting a component into the before outline:
|
||||
|
||||
```js
|
||||
// .vitepress/theme/index.js
|
||||
import DefaultTheme from 'vitepress/theme'
|
||||
import MyLayout from './MyLayout.vue'
|
||||
|
||||
export default {
|
||||
...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>
|
||||
```
|
||||
|
||||
Or you could use render function as well.
|
||||
|
||||
```js
|
||||
// .vitepress/theme/index.js
|
||||
import { h } from 'vue'
|
||||
import DefaultTheme from 'vitepress/theme'
|
||||
import MyComponent from './MyComponent.vue'
|
||||
|
||||
export default {
|
||||
...DefaultTheme,
|
||||
Layout() {
|
||||
return h(DefaultTheme.Layout, null, {
|
||||
'aside-outline-before': () => h(MyComponent)
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Full list of slots available in the default theme layout:
|
||||
|
||||
- When `layout: 'doc'` (default) is enabled via frontmatter:
|
||||
- `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`
|
||||
- When `layout: 'home'` is enabled via frontmatter:
|
||||
- `home-hero-before`
|
||||
- `home-hero-info`
|
||||
- `home-hero-image`
|
||||
- `home-hero-after`
|
||||
- `home-features-before`
|
||||
- `home-features-after`
|
||||
- Always:
|
||||
- `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`
|
||||
@ -0,0 +1,138 @@
|
||||
# Extending the Default Theme
|
||||
|
||||
VitePress' default theme is optimized for documentation, and can be customized. Consult the [Default Theme Config Overview](/reference/default-theme-config) for a comprehensive list of options.
|
||||
|
||||
However, there are a number of cases where configuration alone won't be enough. For example:
|
||||
|
||||
1. You need to tweak the CSS styling;
|
||||
2. You need to modify the Vue app instance, for example to register global components;
|
||||
3. You need to inject custom content into the theme via layout slots.
|
||||
|
||||
These advanced customizations will require using a custom theme that "extends" the default theme.
|
||||
|
||||
:::tip
|
||||
Before proceeding, make sure to first read [Using a Custom Theme](./custom-theme) to understand how custom themes work.
|
||||
:::
|
||||
|
||||
## Customizing CSS
|
||||
|
||||
The default theme CSS is customizable by overriding root level CSS variables:
|
||||
|
||||
```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: #646cff;
|
||||
--vp-c-brand-light: #747bff;
|
||||
}
|
||||
```
|
||||
|
||||
See [default theme CSS variables](https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css) that can be overridden.
|
||||
|
||||
## Registering Global Components
|
||||
|
||||
```js
|
||||
// .vitepress/theme/index.js
|
||||
import DefaultTheme from 'vitepress/theme'
|
||||
|
||||
export default {
|
||||
extends: DefaultTheme,
|
||||
enhanceApp(ctx) {
|
||||
// register your custom global components
|
||||
ctx.app.component('MyGlobalComponent' /* ... */)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Since we are using Vite, you can also leverage Vite's [glob import feature](https://vitejs.dev/guide/features.html#glob-import) to auto register a directory of components.
|
||||
|
||||
## Layout Slots
|
||||
|
||||
The default theme's `<Layout/>` component has a few slots that can be used to inject content at certain locations of the page. Here's an example of injecting a component into the before outline:
|
||||
|
||||
```js
|
||||
// .vitepress/theme/index.js
|
||||
import DefaultTheme from 'vitepress/theme'
|
||||
import MyLayout from './MyLayout.vue'
|
||||
|
||||
export default {
|
||||
...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>
|
||||
```
|
||||
|
||||
Or you could use render function as well.
|
||||
|
||||
```js
|
||||
// .vitepress/theme/index.js
|
||||
import { h } from 'vue'
|
||||
import DefaultTheme from 'vitepress/theme'
|
||||
import MyComponent from './MyComponent.vue'
|
||||
|
||||
export default {
|
||||
...DefaultTheme,
|
||||
Layout() {
|
||||
return h(DefaultTheme.Layout, null, {
|
||||
'aside-outline-before': () => h(MyComponent)
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Full list of slots available in the default theme layout:
|
||||
|
||||
- When `layout: 'doc'` (default) is enabled via frontmatter:
|
||||
- `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`
|
||||
- When `layout: 'home'` is enabled via frontmatter:
|
||||
- `home-hero-before`
|
||||
- `home-hero-info`
|
||||
- `home-hero-image`
|
||||
- `home-hero-after`
|
||||
- `home-features-before`
|
||||
- `home-features-after`
|
||||
- Always:
|
||||
- `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`
|
||||
|
||||
@ -0,0 +1,23 @@
|
||||
# MPA Mode <Badge type="warning" text="experimental" />
|
||||
|
||||
MPA (Multi-Page Application) mode can be enabled via the command line via `vitepress build --mpa`, or via config through the `mpa: true` option.
|
||||
|
||||
In MPA mode, all pages are rendered without any JavaScript included by default. As a result, the production site will likely have a better initial visit performance score from audit tools.
|
||||
|
||||
However, due to the absence of SPA navigation, cross-page links will lead to full page reloads. Post-load navigations in MPA mode will not feel as instant as in SPA mode.
|
||||
|
||||
Also note that no-JS-by-default also means you are essentially using Vue purely as a server-side templating language - no event handlers will be attached in the browser, so there will be no interactivity. To load client-side JavaScript, you can do so by using the special `<script client>` tag (works in both `.md` and `.vue` files, but only in MPA mode):
|
||||
|
||||
```html
|
||||
<script client>
|
||||
document.querySelector('h1').addEventListener('click', () => {
|
||||
console.log('client side JavaScript!')
|
||||
})
|
||||
</script>
|
||||
|
||||
# Hello
|
||||
```
|
||||
|
||||
Client scripts in all theme components will be bundled together, while client script for a specific page will be split for that page only.
|
||||
|
||||
Notice that `<script client>` is **not evaluated as Vue component code**: it's processed as a plain JavaScript module. For this reason, MPA mode should only be used if your site requires absolutely minimal client-side interactivity.
|
||||
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 261 B |
@ -0,0 +1,74 @@
|
||||
# Command Line Interface
|
||||
|
||||
## `vitepress dev`
|
||||
|
||||
Start VitePress dev server using designated directory as root. Defaults to current directory. The `dev` command can also be omitted when running in current directory.
|
||||
|
||||
### Usage
|
||||
|
||||
```sh
|
||||
# start in current directory, omitting `dev`
|
||||
vitepress
|
||||
|
||||
# start in sub directory
|
||||
vitepress dev [root]
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
| Option | Description |
|
||||
| - | - |
|
||||
| `--open [path]` | Open browser on startup (`boolean \| string`) |
|
||||
| `--port <port>` | Specify port (`number`) |
|
||||
| `--base <path>` | Public base path (default: `/`) (`string`) |
|
||||
| `--cors` | Enable CORS |
|
||||
| `--strictPort` | Exit if specified port is already in use (`boolean`) |
|
||||
| `--force` | Force the optimizer to ignore the cache and re-bundle (`boolean`) |
|
||||
|
||||
## `vitepress build`
|
||||
|
||||
Build the VitePress site for production.
|
||||
|
||||
### Usage
|
||||
|
||||
```sh
|
||||
vitepress build [root]
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
| Option | Description |
|
||||
| - | - |
|
||||
| `--mpa` (experimental) | Build in [MPA mode](/guide/mpa-mode) without client-side hydration (`boolean`) |
|
||||
| `--base <path>` | Public base path (default: `/`) (`string`) |
|
||||
| `--target <target>` | Transpile target (default: `"modules"`) (`string`) |
|
||||
| `--outDir <dir>` | Output directory (default: `.vitepress/dist`) (`string`) |
|
||||
| `--minify [minifier]` | Enable/disable minification, or specify minifier to use (default: `"esbuild"`) (`boolean \| "terser" \| "esbuild"`) |
|
||||
| `--assetsInlineLimit <number>` | Static asset base64 inline threshold in bytes (default: `4096`) (`number`) |
|
||||
|
||||
## `vitepress preview`
|
||||
|
||||
Locally preview the production build.
|
||||
|
||||
### Usage
|
||||
|
||||
```sh
|
||||
vitepress preview [root]
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
| Option | Description |
|
||||
| - | - |
|
||||
| `--base <path>` | Public base path (default: `/`) (`string`) |
|
||||
| `--port <port>` | Specify port (`number`) |
|
||||
|
||||
## `vitepress init`
|
||||
|
||||
Start the [Setup Wizard](/guide/getting-started#setup-wizard) in current directory.
|
||||
|
||||
### Usage
|
||||
|
||||
```sh
|
||||
vitepress init
|
||||
```
|
||||
@ -1,4 +1,4 @@
|
||||
# Prev Next Link
|
||||
# Prev Next Links
|
||||
|
||||
You can customize the text and link for the previous and next pages (shown at doc footer). This is helpful if you want a different text there than what you have on your sidebar. Additionally, you may find it useful to disable the footer or link to a page that is not included in your sidebar.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# Sidebar
|
||||
|
||||
The sidebar is the main navigation block for your documentation. You can configure the sidebar menu in [`themeConfig.sidebar`](/config/theme-config#sidebar).
|
||||
The sidebar is the main navigation block for your documentation. You can configure the sidebar menu in [`themeConfig.sidebar`](/reference/default-theme-config#sidebar).
|
||||
|
||||
```js
|
||||
export default {
|
||||
@ -0,0 +1,145 @@
|
||||
---
|
||||
outline: deep
|
||||
---
|
||||
|
||||
# Frontmatter Config
|
||||
|
||||
Frontmatter enables page based configuration. In every markdown file, you can use frontmatter config to override site-level or theme-level config options. Also, there are config options which you can only define in frontmatter.
|
||||
|
||||
Example usage:
|
||||
|
||||
```md
|
||||
---
|
||||
title: Docs with VitePress
|
||||
editLink: true
|
||||
---
|
||||
```
|
||||
|
||||
You can access frontmatter data via the `$frontmatter` global in Vue expressions:
|
||||
|
||||
```md
|
||||
{{ $frontmatter.title }}
|
||||
```
|
||||
|
||||
## title
|
||||
|
||||
- Type: `string`
|
||||
|
||||
Title for the page. It's same as [config.title](/reference/site-config#title), and it overrides the site-level config.
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: VitePress
|
||||
---
|
||||
```
|
||||
|
||||
## titleTemplate
|
||||
|
||||
- Type: `string | boolean`
|
||||
|
||||
The suffix for the title. It's same as [config.titleTemplate](/reference/site-config#titletemplate), and it overrides the site-level config.
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: VitePress
|
||||
titleTemplate: Vite & Vue powered static site generator
|
||||
---
|
||||
```
|
||||
|
||||
## description
|
||||
|
||||
- Type: `string`
|
||||
|
||||
Description for the page. It's same as [config.description](/reference/site-config#description), and it overrides the site-level config.
|
||||
|
||||
```yaml
|
||||
---
|
||||
description: VitePress
|
||||
---
|
||||
```
|
||||
|
||||
## head
|
||||
|
||||
- Type: `HeadConfig[]`
|
||||
|
||||
Specify extra head tags to be injected for the current page. Will be appended after head tags injected by site-level config.
|
||||
|
||||
```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
|
||||
|
||||
The following frontmatter options are only applicable when using the default theme.
|
||||
|
||||
### layout <Badge type="info" text="default theme only" />
|
||||
|
||||
- Type: `doc | home | page`
|
||||
- Default: `doc`
|
||||
|
||||
Determines the layout of the page.
|
||||
|
||||
- `doc` - It applies default documentation styles to the markdown content.
|
||||
- `home` - Special layout for "Home Page". You may add extra options such as `hero` and `features` to rapidly create beautiful landing page.
|
||||
- `page` - Behave similar to `doc` but it applies no styles to the content. Useful when you want to create a fully custom page.
|
||||
|
||||
```yaml
|
||||
---
|
||||
layout: doc
|
||||
---
|
||||
```
|
||||
|
||||
### hero <Badge type="info" text="default theme only" /> <Badge type="info" text="Home page only" />
|
||||
|
||||
Defines contents of home hero section when `layout` is set to `home`. More details in [Default Theme: Home Page](/reference/default-theme-home-page).
|
||||
|
||||
### features <Badge type="info" text="default theme only" /> <Badge type="info" text="Home page only" />
|
||||
|
||||
Defines items to display in features section when `layout` is set to `home`. More details in [Default Theme: Home Page](/reference/default-theme-home-page).
|
||||
|
||||
### aside <Badge type="info" text="default theme only" />
|
||||
|
||||
- Type: `boolean`
|
||||
- Default: `true`
|
||||
|
||||
If you want the right aside component in `doc` layout not to be shown, set this option to `false`.
|
||||
|
||||
```yaml
|
||||
---
|
||||
aside: false
|
||||
---
|
||||
```
|
||||
|
||||
### outline <Badge type="info" text="default theme only" />
|
||||
|
||||
- Type: `number | [number, number] | 'deep' | false`
|
||||
- Default: `2`
|
||||
|
||||
The levels of header in the outline to display for the page. It's same as [config.themeConfig.outline](/reference/default-theme-config#outline), and it overrides the theme config.
|
||||
|
||||
### lastUpdated <Badge type="info" text="default theme only" />
|
||||
|
||||
- Type: `boolean`
|
||||
- Default: `true`
|
||||
|
||||
Whether to display [Last Updated](/reference/default-theme-last-updated) text in the current page.
|
||||
|
||||
```yaml
|
||||
---
|
||||
lastUpdated: false
|
||||
---
|
||||
```
|
||||
@ -1,20 +1,16 @@
|
||||
import { defineComponent, h, onUpdated } from 'vue'
|
||||
import { defineComponent, h } from 'vue'
|
||||
import { useRoute } from '../router.js'
|
||||
|
||||
export const Content = defineComponent({
|
||||
name: 'VitePressContent',
|
||||
props: {
|
||||
onContentUpdated: Function,
|
||||
as: { type: [Object, String], default: 'div' }
|
||||
},
|
||||
setup(props) {
|
||||
const route = useRoute()
|
||||
onUpdated(() => {
|
||||
props.onContentUpdated?.()
|
||||
})
|
||||
return () =>
|
||||
h(props.as, { style: { position: 'relative' } }, [
|
||||
route.component ? h(route.component) : null
|
||||
route.component ? h(route.component) : '404 Page Not Found'
|
||||
])
|
||||
}
|
||||
})
|
||||
|
||||
@ -1,28 +0,0 @@
|
||||
import { defineConfig } from 'vitepress'
|
||||
|
||||
// https://vitepress.vuejs.org/config/app-config
|
||||
export default defineConfig({
|
||||
title: <%= title %>,
|
||||
description: <%= description %><% if (defaultTheme) { %>,
|
||||
themeConfig: {
|
||||
// https://vitepress.vuejs.org/config/default-theme-config
|
||||
nav: [
|
||||
{ text: 'Home', link: '/' },
|
||||
{ text: 'Examples', link: '/markdown-examples' }
|
||||
],
|
||||
|
||||
sidebar: [
|
||||
{
|
||||
text: 'Examples',
|
||||
items: [
|
||||
{ text: 'Markdown Examples', link: '/markdown-examples' },
|
||||
{ text: 'Runtime API Examples', link: '/api-examples' }
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
socialLinks: [
|
||||
{ icon: 'github', link: 'https://github.com/vuejs/vitepress' }
|
||||
]
|
||||
}<% } %>
|
||||
})
|
||||
Loading…
Reference in new issue