mirror of https://github.com/vuejs/vitepress
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
374 lines
11 KiB
374 lines
11 KiB
2 years ago
|
---
|
||
|
outline: deep
|
||
|
---
|
||
|
|
||
2 years ago
|
# Routing
|
||
|
|
||
2 years ago
|
## File-Based Routing
|
||
2 years ago
|
|
||
2 years ago
|
VitePress uses file-based routing, which means the generated HTML pages are mapped from the directory structure of the source Markdown files. For example, given the following directory structure:
|
||
2 years ago
|
|
||
|
```
|
||
|
.
|
||
|
├─ guide
|
||
|
│ ├─ getting-started.md
|
||
|
│ └─ index.md
|
||
|
├─ index.md
|
||
|
└─ prologue.md
|
||
|
```
|
||
|
|
||
2 years ago
|
The generated HTML pages will be:
|
||
2 years ago
|
|
||
|
```
|
||
2 years ago
|
index.md --> /index.html (accessible as /)
|
||
2 years ago
|
prologue.md --> /prologue.html
|
||
2 years ago
|
guide/index.md --> /guide/index.html (accessible as /guide/)
|
||
2 years ago
|
guide/getting-started.md --> /guide/getting-started.html
|
||
2 years ago
|
```
|
||
|
|
||
2 years ago
|
The resulting HTML can be hosted on any web server that can serve static files.
|
||
|
|
||
|
## Root and Source Directory
|
||
|
|
||
|
There are two important concepts in the file structure of a VitePress project: the **project root** and the **source directory**.
|
||
2 years ago
|
|
||
2 years ago
|
### Project Root
|
||
2 years ago
|
|
||
2 years ago
|
Project root is where VitePress will try to look for the `.vitepress` special directory. The `.vitepress` directory is a reserved location for VitePress' config file, dev server cache, build output, and optional theme customization code.
|
||
|
|
||
|
When you run `vitepress dev` or `vitepress build` from the command line, VitePress will use the current working directory as project root. To specify a sub-directory as root, you will need to pass the relative path to the command. For example, if your VitePress project is located in `./docs`, you should run `vitepress dev docs`:
|
||
2 years ago
|
|
||
|
```
|
||
|
.
|
||
2 years ago
|
├─ docs # project root
|
||
|
│ ├─ .vitepress # config dir
|
||
2 years ago
|
│ ├─ getting-started.md
|
||
|
│ └─ index.md
|
||
|
└─ ...
|
||
|
```
|
||
|
|
||
2 years ago
|
```sh
|
||
2 years ago
|
vitepress dev docs
|
||
|
```
|
||
|
|
||
2 years ago
|
This is going to result in the following source-to-HTML mapping:
|
||
2 years ago
|
|
||
|
```
|
||
2 years ago
|
docs/index.md --> /index.html (accessible as /)
|
||
|
docs/getting-started.md --> /getting-started.html
|
||
2 years ago
|
```
|
||
|
|
||
2 years ago
|
### Source Directory
|
||
2 years ago
|
|
||
2 years ago
|
Source directory is where your Markdown source files live. By default, it is the same as the project root. However, you can configure it via the [`srcDir`](../reference/site-config#srcdir) config option.
|
||
2 years ago
|
|
||
|
The `srcDir` option is resolved relative to project root. For example, with `srcDir: 'src'`, your file structure will look like this:
|
||
|
|
||
|
```
|
||
2 years ago
|
. # project root
|
||
|
├─ .vitepress # config dir
|
||
|
└─ src # source dir
|
||
2 years ago
|
├─ getting-started.md
|
||
|
└─ index.md
|
||
|
```
|
||
|
|
||
|
The resulting source-to-HTML mapping:
|
||
|
|
||
|
```
|
||
|
src/index.md --> /index.html (accessible as /)
|
||
|
src/getting-started.md --> /getting-started.html
|
||
2 years ago
|
```
|
||
|
|
||
|
## Linking Between Pages
|
||
|
|
||
2 years ago
|
You can use both absolute and relative paths when linking between pages. Note that although both `.md` and `.html` extensions will work, the best practice is to omit file extensions so that VitePress can generate the final URLs based on your config.
|
||
2 years ago
|
|
||
|
```md
|
||
|
<!-- Do -->
|
||
2 years ago
|
[Getting Started](./getting-started)
|
||
2 years ago
|
[Getting Started](../guide/getting-started)
|
||
|
|
||
|
<!-- Don't -->
|
||
2 years ago
|
[Getting Started](./getting-started.md)
|
||
|
[Getting Started](./getting-started.html)
|
||
2 years ago
|
```
|
||
|
|
||
1 year ago
|
Learn more about linking to assets such images in [Asset Handling](./asset-handling).
|
||
|
|
||
|
### Linking to Non-VitePress Pages
|
||
|
|
||
|
If you want to link to a page in your site that is not generated by VitePress, you'll either need to use the full URL (opens in a new tab) or explicitly specify the target:
|
||
|
|
||
|
**Input**
|
||
|
|
||
|
```md
|
||
|
[Link to pure.html](/pure.html){target="_self"}
|
||
|
```
|
||
|
|
||
|
**Output**
|
||
|
|
||
|
[Link to pure.html](/pure.html){target="_self"}
|
||
|
|
||
|
::: tip Note
|
||
|
|
||
|
In Markdown links, the `base` is automatically prepended to the URL. This means that if you want to link to a page outside of your base, you'd need something like `../../pure.html` in the link (resolved relative to the current page by the browser).
|
||
|
|
||
|
Alternatively, you can directly use the anchor tag syntax:
|
||
|
|
||
|
```md
|
||
|
<a href="/pure.html" target="_self">Link to pure.html</a>
|
||
|
```
|
||
|
|
||
|
:::
|
||
2 years ago
|
|
||
2 years ago
|
## Generating Clean URL
|
||
2 years ago
|
|
||
1 year ago
|
::: warning Server Support Required
|
||
2 years ago
|
To serve clean URLs with VitePress, server-side support is required.
|
||
|
:::
|
||
|
|
||
2 years ago
|
By default, VitePress resolves inbound links to URLs ending with `.html`. However, some users may prefer "Clean URLs" without the `.html` extension - for example, `example.com/path` instead of `example.com/path.html`.
|
||
2 years ago
|
|
||
10 months ago
|
Some servers or hosting platforms (for example Netlify, Vercel, GitHub Pages) provide the ability to map a URL like `/foo` to `/foo.html` if it exists, without a redirect:
|
||
2 years ago
|
|
||
10 months ago
|
- Netlify and GitHub Pages support this by default.
|
||
2 years ago
|
- Vercel requires enabling the [`cleanUrls` option in `vercel.json`](https://vercel.com/docs/concepts/projects/project-configuration#cleanurls).
|
||
|
|
||
|
If this feature is available to you, you can then also enable VitePress' own [`cleanUrls`](../reference/site-config#cleanurls) config option so that:
|
||
|
|
||
|
- Inbound links between pages are generated without the `.html` extension.
|
||
|
- If current path ends with `.html`, the router will perform a client-side redirect to the extension-less path.
|
||
|
|
||
10 months ago
|
If, however, you cannot configure your server with such support, you will have to manually resort to the following directory structure:
|
||
2 years ago
|
|
||
|
```
|
||
|
.
|
||
|
├─ getting-started
|
||
|
│ └─ index.md
|
||
|
├─ installation
|
||
|
│ └─ index.md
|
||
|
└─ index.md
|
||
|
```
|
||
|
|
||
2 years ago
|
## Route Rewrites
|
||
2 years ago
|
|
||
2 years ago
|
You can customize the mapping between the source directory structure and the generated pages. It's useful when you have a complex project structure. For example, let's say you have a monorepo with multiple packages, and would like to place documentations along with the source files like this:
|
||
2 years ago
|
|
||
|
```
|
||
|
.
|
||
|
├─ packages
|
||
|
│ ├─ pkg-a
|
||
|
│ │ └─ src
|
||
|
│ │ ├─ pkg-a-code.ts
|
||
2 years ago
|
│ │ └─ pkg-a-docs.md
|
||
2 years ago
|
│ └─ pkg-b
|
||
|
│ └─ src
|
||
|
│ ├─ pkg-b-code.ts
|
||
2 years ago
|
│ └─ pkg-b-docs.md
|
||
2 years ago
|
```
|
||
|
|
||
2 years ago
|
And you want the VitePress pages to be generated like this:
|
||
2 years ago
|
|
||
|
```
|
||
2 years ago
|
packages/pkg-a/src/pkg-a-docs.md --> /pkg-a/index.html
|
||
|
packages/pkg-b/src/pkg-b-docs.md --> /pkg-b/index.html
|
||
2 years ago
|
```
|
||
|
|
||
2 years ago
|
You can achieve this by configuring the [`rewrites`](../reference/site-config#rewrites) option like this:
|
||
2 years ago
|
|
||
|
```ts
|
||
2 years ago
|
// .vitepress/config.js
|
||
2 years ago
|
export default {
|
||
|
rewrites: {
|
||
2 years ago
|
'packages/pkg-a/src/pkg-a-docs.md': 'pkg-a/index.md',
|
||
|
'packages/pkg-b/src/pkg-b-docs.md': 'pkg-b/index.md'
|
||
2 years ago
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
2 years ago
|
The `rewrites` option also supports dynamic route parameters. In the above example, it would be verbose to list all the paths if you have many packages. Given that they all have the same file structure, you can simplify the config like this:
|
||
2 years ago
|
|
||
|
```ts
|
||
|
export default {
|
||
|
rewrites: {
|
||
2 years ago
|
'packages/:pkg/src/(.*)': ':pkg/index.md'
|
||
2 years ago
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
2 years ago
|
The rewrite paths are compiled using the `path-to-regexp` package - consult [its documentation](https://github.com/pillarjs/path-to-regexp#parameters) for more advanced syntax.
|
||
2 years ago
|
|
||
1 year ago
|
::: warning Relative Links with Rewrites
|
||
2 years ago
|
|
||
2 years ago
|
When rewrites are enabled, **relative links should be based on the rewritten paths**. For example, in order to create a relative link from `packages/pkg-a/src/pkg-a-code.md` to `packages/pkg-b/src/pkg-b-code.md`, you should use:
|
||
2 years ago
|
|
||
|
```md
|
||
|
[Link to PKG B](../pkg-b/pkg-b-code)
|
||
|
```
|
||
2 years ago
|
:::
|
||
2 years ago
|
|
||
|
## Dynamic Routes
|
||
|
|
||
2 years ago
|
You can generate many pages using a single Markdown file and dynamic data. For example, you can create a `packages/[pkg].md` file that generates a corresponding page for every package in a project. Here, the `[pkg]` segment is a route **parameter** that differentiates each page from the others.
|
||
|
|
||
|
### Paths Loader File
|
||
|
|
||
|
Since VitePress is a static site generator, the possible page paths must be determined at build time. Therefore, a dynamic route page **must** be accompanied by a **paths loader file**. For `packages/[pkg].md`, we will need `packages/[pkg].paths.js` (`.ts` is also supported):
|
||
|
|
||
|
```
|
||
|
.
|
||
|
└─ packages
|
||
|
├─ [pkg].md # route template
|
||
|
└─ [pkg].paths.js # route paths loader
|
||
|
```
|
||
|
|
||
|
The paths loader should provide an object with a `paths` method as its default export. The `paths` method should return an array of objects with a `params` property. Each of these objects will generate a corresponding page.
|
||
|
|
||
|
Given the following `paths` array:
|
||
|
|
||
|
```js
|
||
|
// packages/[pkg].paths.js
|
||
|
export default {
|
||
|
paths() {
|
||
|
return [
|
||
|
{ params: { pkg: 'foo' }},
|
||
|
{ params: { pkg: 'bar' }}
|
||
|
]
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
The generated HTML pages will be:
|
||
|
|
||
|
```
|
||
|
.
|
||
|
└─ packages
|
||
|
├─ foo.html
|
||
|
└─ bar.html
|
||
|
```
|
||
|
|
||
|
### Multiple Params
|
||
|
|
||
|
A dynamic route can contain multiple params:
|
||
|
|
||
|
**File Structure**
|
||
|
|
||
|
```
|
||
|
.
|
||
|
└─ packages
|
||
|
├─ [pkg]-[version].md
|
||
|
└─ [pkg]-[version].paths.js
|
||
|
```
|
||
|
|
||
|
**Paths Loader**
|
||
|
|
||
|
```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' }}
|
||
|
]
|
||
|
}
|
||
|
```
|
||
|
|
||
|
**Output**
|
||
|
|
||
|
```
|
||
|
.
|
||
|
└─ packages
|
||
|
├─ foo-1.0.0.html
|
||
|
├─ foo-2.0.0.html
|
||
|
├─ bar-1.0.0.html
|
||
|
└─ bar-2.0.0.html
|
||
|
```
|
||
|
|
||
|
### Dynamically Generating Paths
|
||
|
|
||
|
The paths loader module is run in Node.js and only executed during build time. You can dynamically generate the paths array using any data, either local or remote.
|
||
|
|
||
|
Generating paths from local files:
|
||
|
|
||
|
```js
|
||
|
import fs from 'fs'
|
||
|
|
||
|
export default {
|
||
|
paths() {
|
||
|
return fs
|
||
|
.readdirSync('packages')
|
||
|
.map((pkg) => {
|
||
|
return { params: { pkg }}
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
Generating paths from remote data:
|
||
|
|
||
|
```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
|
||
|
|
||
|
You can use the params to pass additional data to each page. The Markdown route file can access the current page params in Vue expressions via the `$params` global property:
|
||
|
|
||
|
```md
|
||
|
- package name: {{ $params.pkg }}
|
||
|
- version: {{ $params.version }}
|
||
|
```
|
||
|
|
||
2 years ago
|
You can also access the current page's params via the [`useData`](../reference/runtime-api#usedata) runtime API. This is available in both Markdown files and Vue components:
|
||
2 years ago
|
|
||
|
```vue
|
||
|
<script setup>
|
||
|
import { useData } from 'vitepress'
|
||
|
|
||
|
// params is a Vue ref
|
||
|
const { params } = useData()
|
||
|
|
||
|
console.log(params.value)
|
||
|
</script>
|
||
|
```
|
||
|
|
||
|
### Rendering Raw Content
|
||
|
|
||
|
Params passed to the page will be serialized in the client JavaScript payload, so you should avoid passing heavy data in params, for example raw Markdown or HTML content fetched from a remote CMS.
|
||
|
|
||
|
Instead, you can pass such content to each page using the `content` property on each path object:
|
||
|
|
||
|
```js
|
||
|
export default {
|
||
1 year ago
|
async paths() {
|
||
|
const posts = await (await fetch('https://my-cms.com/blog-posts')).json()
|
||
2 years ago
|
|
||
1 year ago
|
return posts.map((post) => {
|
||
|
return {
|
||
|
params: { id: post.id },
|
||
|
content: post.content // raw Markdown or HTML
|
||
|
}
|
||
|
})
|
||
2 years ago
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
Then, use the following special syntax to render the content as part of the Markdown file itself:
|
||
|
|
||
|
```md
|
||
|
<!-- @content -->
|
||
|
```
|