Merge branch 'main' into feat/public-path

pull/2467/head
nilennoct 1 month ago committed by GitHub
commit fc2baec39e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -23,7 +23,7 @@ Hi! We're really excited that you are interested in contributing to VitePress. B
## Development Setup
You will need [pnpm](https://pnpm.io)
You will need [Node.js](https://nodejs.org) v20 or higher and [pnpm](https://pnpm.io).
After cloning the repo, run:

@ -9,6 +9,7 @@ on:
types: [opened, synchronize, labeled, ready_for_review]
paths-ignore:
- '.github/**'
- '!.github/workflows/cr.yml'
- '__tests__/**'
- 'art/**'
- 'docs/**'
@ -17,6 +18,7 @@ on:
branches: [main]
paths-ignore:
- '.github/**'
- '!.github/workflows/cr.yml'
- '__tests__/**'
- 'art/**'
- 'docs/**'

@ -1,12 +1,14 @@
name: Close stale issues and PRs
on:
schedule:
- cron: '0 12 1,15 * *'
workflow_dispatch:
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v9
- uses: actions/stale@v10
with:
days-before-stale: 30
days-before-close: -1

@ -18,7 +18,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
node_version: [18, 20, 22]
node_version: [20, 22, latest]
include:
- os: windows-latest
node_version: 22

@ -1,2 +0,0 @@
shell-emulator=true
auto-install-peers=false

@ -1,3 +1,146 @@
## [2.0.0-alpha.12](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.11...v2.0.0-alpha.12) (2025-08-20)
### Bug Fixes
- **hmr:** don't load config twice on server restart ([d1a8061](https://github.com/vuejs/vitepress/commit/d1a8061eb438c730ccc62ce2d7158dbe89cc5292))
- **hmr:** no need for server restart on theme change ([d3a1567](https://github.com/vuejs/vitepress/commit/d3a15673bd0846c7837bcc4ff5a2e3239a02f1f9))
- **hmr:** hmr not working for snippet imports in dynamic routes ([914467e](https://github.com/vuejs/vitepress/commit/914467e17fb759a9722951a3fd7568eb3bc4d4e6))
- **theme:** fix local nav alignment and increase touch area ([43b36c0](https://github.com/vuejs/vitepress/commit/43b36c0c19c2b4696f8c38fdaf4318786ea7ae8e))
- **theme:** nav background doesn't extend fully and gap after sidebar with non-overlay scrollbars ([7df3052](https://github.com/vuejs/vitepress/commit/7df30525121a28a46cc6c802f3155ccff8effaca)), closes [#4653](https://github.com/vuejs/vitepress/issues/4653)
- **theme:** use clipboard-check instead of clipboard-copy for code copied icon ([1c8815d](https://github.com/vuejs/vitepress/commit/1c8815d53ed2d56b07938260df6566f1514f4bfc))
### Features
- add markdown-it-cjk-friendly ([9fc8462](https://github.com/vuejs/vitepress/commit/9fc8462726ccf1cdb78b6171c9f1f5964e79ca22)), closes [#3762](https://github.com/vuejs/vitepress/issues/3762) [#4752](https://github.com/vuejs/vitepress/issues/4752)
- make postcssIsolateStyles idempotent ([0944777](https://github.com/vuejs/vitepress/commit/094477789328b80cff45cd973efa16b6a4db0a27))
### BREAKING CHANGES
- [markdown-it-cjk-friendly](https://www.npmjs.com/package/markdown-it-cjk-friendly) is enabled by default. This intentionally deviates from the official commonmark spec for the benefit of CJK users. **For most users, no change is required.** If you were using hacks to patch `scanDelims`, you can remove those. To disable the plugin, set `markdown: { cjkFriendly: false }` in your vitepress config.
- `includeFiles` option in `postcssIsolateStyles` now defaults to `[/vp-doc\.css/, /base\.css/]`. You can remove explicit `includeFiles` if you were using it just to run it on `vp-doc.css`. To revert back to older behavior pass `includeFiles: [/base\.css/]`. The underlying implementation is changed and `transform` and `exclude` options are no longer supported. Use `postcss-prefix-selector` directly if you've advanced use cases.
## [2.0.0-alpha.11](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.10...v2.0.0-alpha.11) (2025-08-14)
### Bug Fixes
- hmr working only once for markdown files ([8d8a5ac](https://github.com/vuejs/vitepress/commit/8d8a5ac281f090cd097bece792d9dd3ef00e5545)), closes [#4909](https://github.com/vuejs/vitepress/issues/4909)
- html entities encoded twice in toc plugin ([8abbe29](https://github.com/vuejs/vitepress/commit/8abbe298d545de17d34a9bc1eb72af4c5a4b41b8)), closes [#4908](https://github.com/vuejs/vitepress/issues/4908)
## [2.0.0-alpha.10](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.9...v2.0.0-alpha.10) (2025-08-11)
### Bug Fixes
- **client:** base not stripped from relativePath in 404 pages ([b840877](https://github.com/vuejs/vitepress/commit/b840877aa83a5a24ffc1222e8a5a3dbf3e5105e8)), closes [#4850](https://github.com/vuejs/vitepress/issues/4850)
- hmr of style blocks in dynamic routes ([#4903](https://github.com/vuejs/vitepress/issues/4903)) ([3d0fafb](https://github.com/vuejs/vitepress/commit/3d0fafba545f4b5028cf43d86027dd44dab14421))
- make paths in `watchedFiles` absolute as mentioned in the docs ([318c14f](https://github.com/vuejs/vitepress/commit/318c14fa7c9fb949d74b7d9fae416e917766cf05))
- module graph causing unnecessary route regeneration on every update ([fc267ae](https://github.com/vuejs/vitepress/commit/fc267ae6b787e163d41666e090089821377ead43))
- preserve externally added dynamic routes and pages ([fc267ae](https://github.com/vuejs/vitepress/commit/fc267ae6b787e163d41666e090089821377ead43))
- **search:** input placeholder being cut off in smaller viewports ([162c6a6](https://github.com/vuejs/vitepress/commit/162c6a69bf56945daa20d126aa034c59ee0c8a2e))
- **search:** style tweaks for when searches are empty ([8b23217](https://github.com/vuejs/vitepress/commit/8b232171cc321bd3dc86b4357622815269f0b6f4))
- **types:** externalize markdown-it types ([5bf835b](https://github.com/vuejs/vitepress/commit/5bf835b5074e9567852d552bfb5115c6456026e8))
- **types:** pass generics deeply to user config ([777e2ca](https://github.com/vuejs/vitepress/commit/777e2caaacd93ce41b046f6c9d5ba80cc43ba37c))
### Features
- add source param to the deadlink check fn ([#4870](https://github.com/vuejs/vitepress/issues/4870)) ([8c027c2](https://github.com/vuejs/vitepress/commit/8c027c2a7c443074fd0d4890f7736b444f9254aa))
- **theme:** add `rel="me"` to social links by default ([#4873](https://github.com/vuejs/vitepress/issues/4873)) ([34886c6](https://github.com/vuejs/vitepress/commit/34886c667d1305a79d64c957f8c52931ea122f47))
## [2.0.0-alpha.9](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.8...v2.0.0-alpha.9) (2025-07-26)
### Bug Fixes
- **md:** pass container option to gitHubAlertsPlugin ([#4848](https://github.com/vuejs/vitepress/issues/4848)) ([52f0eaa](https://github.com/vuejs/vitepress/commit/52f0eaa0849344aa45efbf7258a6287597e55a9a))
- **theme:** remove duplicate text in sponsors grid ([3c51b22](https://github.com/vuejs/vitepress/commit/3c51b22ac98a12f193081d23799cb9f3f2ecf682)), closes [#4854](https://github.com/vuejs/vitepress/issues/4854)
### Features
- **search:** upgrade search to DocSearch v4-beta ([#4843](https://github.com/vuejs/vitepress/issues/4843)) ([ac61abe](https://github.com/vuejs/vitepress/commit/ac61abe7d7be5ef8b6939f18192896538eba1b8c))
### BREAKING CHANGES
- **search:** Uses DocSearch v4 beta. No change is required if you're not customizing the styles of navbar search button or modal. DocSearch AI features are in private beta, you can apply for them at https://forms.gle/iyfb5pC2CiiwszUKA
## [2.0.0-alpha.8](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.7...v2.0.0-alpha.8) (2025-07-08)
### Bug Fixes
- adjust glob logic to always resolve glob relative to base ([5d41785](https://github.com/vuejs/vitepress/commit/5d41785ff7b016b08f587f1ef3318fc18d58f6ab)), closes [#4822](https://github.com/vuejs/vitepress/issues/4822)
- **build:** ignore escaped `:` when splitting selector in `postcssIsolateStyles` ([#4830](https://github.com/vuejs/vitepress/issues/4830)) ([a629b03](https://github.com/vuejs/vitepress/commit/a629b03f0ee8a29d73a18481399d7de1c992faf2))
- font preload not being generated in rolldown-vite ([ed387e8](https://github.com/vuejs/vitepress/commit/ed387e89d42a08c15a9f45c9c5e11c6750245490))
- **theme:** remove extra slash when concatenating base with sidebar links ([c8fc80e](https://github.com/vuejs/vitepress/commit/c8fc80e438fffd98feaf7c72263bc3077792c4a2))
## [2.0.0-alpha.7](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.6...v2.0.0-alpha.7) (2025-06-24)
### Bug Fixes
- **local-search:** parse headings with non-anchor `a` tags as titles properly ([#4809](https://github.com/vuejs/vitepress/issues/4809)) ([5359903](https://github.com/vuejs/vitepress/commit/53599039a01af6d8e17a6a6e9cea5c222cc5948c))
- resolve pages after setting global vitepress config ([56ba65e](https://github.com/vuejs/vitepress/commit/56ba65e1301454df88f9a3856fa1a70dc052d314)), closes [#4803](https://github.com/vuejs/vitepress/issues/4803)
### Features
- **router:** add `replace` option to `useRouter` for history management ([#4788](https://github.com/vuejs/vitepress/issues/4788)) ([23541b4](https://github.com/vuejs/vitepress/commit/23541b4f83726cdac09ffcaf9141bba871cda690)), closes [#4787](https://github.com/vuejs/vitepress/issues/4787)
- consistent glob options across content, data, and path loaders ([#4808](https://github.com/vuejs/vitepress/issues/4808)) ([7619521](https://github.com/vuejs/vitepress/commit/76195212596cd54095240246b7e78075ac3cbc27)), closes [#4807](https://github.com/vuejs/vitepress/issues/4807)
- bump to vite 7 ([2ecd607](https://github.com/vuejs/vitepress/commit/2ecd607af15222eeddf0b888a72d0f913f5a3cd2))
### Performance Improvements
- render pages in contentLoader asynchronously ([36148a0](https://github.com/vuejs/vitepress/commit/36148a0bcf3a73d1fe3f0c5f33337b679f700053))
### BREAKING CHANGES
- Only `cwd`, `ignore`, `dot` and `debug` are supported in `globOptions` of `createContentLoader`. If you want to pass other options, you still can but you might need to suppress type errors.
- Uses vite 7. See [vite migration guide](https://vite.dev/guide/migration.html) for more info. For most of the users no change is required. VitePress should work same as earlier, except for maybe some type mismatches if you're using third-party plugins. You can suppress them using `@ts-expect-error` or `as any` and report the issues at respective repositories.
## [2.0.0-alpha.6](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.5...v2.0.0-alpha.6) (2025-06-12)
### Bug Fixes
- allow AdditionalConfigLoader to return void ([906a44a](https://github.com/vuejs/vitepress/commit/906a44a3ad488a46804757326af95cfb8cac6b75))
- **build:** avoiding creating separate chunks for vite public assets ([21f24b9](https://github.com/vuejs/vitepress/commit/21f24b9994ea4807ac7e0be38408e9aaa3abe8a9))
- **build:** emit lean chunks after vite has done processing ([26cb685](https://github.com/vuejs/vitepress/commit/26cb685adf54f07fe3e9fd7bfd49a0ff79956923)), closes [#4737](https://github.com/vuejs/vitepress/issues/4737)
- **client:** properly skip removed lines when copying code blocks ([c128baf](https://github.com/vuejs/vitepress/commit/c128baf0c41d5113c1b876f691e0185201b1f500))
- disable appearance scripts in zero-js mode ([e7f9d05](https://github.com/vuejs/vitepress/commit/e7f9d05c3e2ef4f4c1db3b2c17e586f0fc26a6f6)), closes [#4766](https://github.com/vuejs/vitepress/issues/4766)
- don't preload dynamic imports ([801648a](https://github.com/vuejs/vitepress/commit/801648a4c9d91e7f96302932ac9247d5bdd64ef7)), closes [#4770](https://github.com/vuejs/vitepress/issues/4770)
- gather additional config files even if root .vitepress/config is not present ([26f178c](https://github.com/vuejs/vitepress/commit/26f178cfaa330a017bb69b1ec6bd482d63a100a9))
- set `preserveEntrySignatures` for rolldown-vite ([#4784](https://github.com/vuejs/vitepress/issues/4784)) ([4351bc0](https://github.com/vuejs/vitepress/commit/4351bc0b831277401e08b350d7d7c0ab9ea0c9ed))
- skip fields not supported by rolldown for rolldown-vite ([#4747](https://github.com/vuejs/vitepress/issues/4747)) ([4e3fce4](https://github.com/vuejs/vitepress/commit/4e3fce40c9bab261f3c5e31833475c3e2c6ba0cf))
- **theme/regression:** code blocks not aligned properly in rtl layouts ([a643347](https://github.com/vuejs/vitepress/commit/a64334753079a5b874a482508d9ee255d2a0ea38))
- **theme:** hide native search input cancel button ([#4723](https://github.com/vuejs/vitepress/issues/4723)) ([2c4944f](https://github.com/vuejs/vitepress/commit/2c4944f06ccf46fcf58fb18a1819fd167c9533cc))
- **theme:** prevent error in handleSearchHotKey method ([#4782](https://github.com/vuejs/vitepress/issues/4782)) ([21fcecc](https://github.com/vuejs/vitepress/commit/21fcecce0581d0c461bc15e03429f61ff444a655))
- use v-pre for mathjax instead of isCustomElement ([c9b8928](https://github.com/vuejs/vitepress/commit/c9b89282f3573998cfc4103bbddbd73d2529cb66))
### Features
- use `oxc-minify` instead of `transformWithEsbuild` when rolldown-vite is used ([#4748](https://github.com/vuejs/vitepress/issues/4748)) ([7c1dc48](https://github.com/vuejs/vitepress/commit/7c1dc48b2fd08e128f7bbe26690fb6534dfb4b95))
## [2.0.0-alpha.5](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.4...v2.0.0-alpha.5) (2025-04-21)
### Bug Fixes
- don't remove shiki styles from `pre` and remove unnecessary transformers (#4652) ([db58af5](https://github.com/vuejs/vitepress/commit/db58af5c66e563e7663084057a9853d8f2da984c)), closes [#4652](https://github.com/vuejs/vitepress/issues/4652)
- normalize url fragments in internal links to correctly resolve to anchors ([#4628](https://github.com/vuejs/vitepress/issues/4628)) ([e25d080](https://github.com/vuejs/vitepress/commit/e25d0805505db2f1116e99d38a488d5cb39ed426)), closes [#4605](https://github.com/vuejs/vitepress/issues/4605)
- **theme-default:** ensure proper sizing of SVG hero images ([#4639](https://github.com/vuejs/vitepress/issues/4639)) ([7d94481](https://github.com/vuejs/vitepress/commit/7d9448192079e59493aa5c1e86cdf6d6deae8e36))
### Features
- add `isHome` frontmatter option (#4673) ([544cd81](https://github.com/vuejs/vitepress/commit/544cd8125985b9e3af7fee68ea9592d159799e01)), closes [#4673](https://github.com/vuejs/vitepress/issues/4673)
- add `custom-block-title-default` class when default title is used for containers ([#4643](https://github.com/vuejs/vitepress/issues/4643)) ([63079bf](https://github.com/vuejs/vitepress/commit/63079bff03b15861d174199f7361a2aff84380e0))
- add `dir=ltr` by default on code block pre elements instead of relying on css ([19faa16](https://github.com/vuejs/vitepress/commit/19faa16169b44f52bedf1401b4a97b2a8ffdeacb))
- **default-theme:** make VPButton slottable ([#4689](https://github.com/vuejs/vitepress/issues/4689)) ([0b70397](https://github.com/vuejs/vitepress/commit/0b7039719782e85119ad22be5c89ef3d233ffaae))
- support distributed config files ([#4660](https://github.com/vuejs/vitepress/issues/4660)) ([c5e2e4d](https://github.com/vuejs/vitepress/commit/c5e2e4db818c06f3c1b458753f22fb6ec1609628))
- **theme:** make "Take me home" button's link customizable ([#4658](https://github.com/vuejs/vitepress/issues/4658)) ([0267dca](https://github.com/vuejs/vitepress/commit/0267dcafa20beea24ef359d24bb1fa99e1ffda49))
### Performance Improvements
- call `module.enableCompileCache()` ([70de34c](https://github.com/vuejs/vitepress/commit/70de34c0387d9668ada3ea9a795f9ebee3535f5b))
- hoist expensive operations in useLayout ([e5ab067](https://github.com/vuejs/vitepress/commit/e5ab0676a9a8dc607e213eb691439b2e4ee472b7))
### BREAKING CHANGES
- `useLocalNav` and `useSidebar` are removed in favor of `useLayout`. To migrate, just do find and replace. Sidebar controls are no longer exported, but we didn't find any usage on GitHub. If there is demand, we can export respective composables later. `DefaultTheme.DocSidebar` and `DefaultTheme.DocLocalNav` types are also removed.
- `vp-adaptive-theme` class is no longer added to code blocks when there is single theme. Theme authors supporting single code theme can use `.shiki:not(.shiki-themes)` as selector. Alternatively, it might be better to use the bg/fg variables set on the `.shiki` block to keep things generic.
- `vp-code` class is no longer added to code blocks. Use `.shiki` or `pre.shiki` or `[class*='language-'] pre` instead. People not customizing their themes are not affected.
## [2.0.0-alpha.4](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.3...v2.0.0-alpha.4) (2025-03-09)
### Bug Fixes
@ -2198,7 +2341,6 @@ This version uses Vue 3.2.0.
### BREAKING CHANGES
- Some config options have changed.
- `vueOptions` renamed to `vue`
- `alias` option has been removed. Use `vite.resovle.alias` instead.
@ -2216,7 +2358,6 @@ This version uses Vue 3.2.0.
### BREAKING CHANGES
- The following methods are removed.
- `useSiteData`
- `useSiteDataByRoute`
- `usePageData`

@ -1,7 +1,7 @@
# VitePress 📝💨
[![test](https://github.com/vuejs/vitepress/workflows/Test/badge.svg)](https://github.com/vuejs/vitepress/actions)
[![npm](https://img.shields.io/npm/v/vitepress)](https://www.npmjs.com/package/vitepress)
[![test](https://github.com/vuejs/vitepress/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/vuejs/vitepress/actions/workflows/test.yml)
[![npm](https://img.shields.io/npm/v/vitepress/next)](https://www.npmjs.com/package/vitepress/v/next)
[![nightly releases](https://img.shields.io/badge/nightly-releases-orange)](https://nightly.akryum.dev/vuejs/vitepress)
[![chat](https://img.shields.io/badge/chat-discord-blue?logo=discord)](https://chat.vuejs.org)

@ -30,7 +30,7 @@ function removeSpaces(str: string) {
<input
type="radio"
:id="option.key"
:name="name"
:name
:value="option.value"
v-model="selected"
/>

@ -52,9 +52,7 @@ describe('static data file support in vite 3', () => {
await page.waitForFunction(
() =>
document.querySelector('pre#basic')?.textContent ===
JSON.stringify([{ a: false }, { b: true }], null, 2),
undefined,
{ timeout: 3000 }
JSON.stringify([{ a: false }, { b: true }], null, 2)
)
} finally {
await fs.writeFile(a, JSON.stringify({ a: true }, null, 2) + '\n')
@ -67,9 +65,7 @@ describe('static data file support in vite 3', () => {
await page.waitForFunction(
() =>
document.querySelector('pre#basic')?.textContent ===
JSON.stringify([{ a: true }], null, 2),
undefined,
{ timeout: 3000 }
JSON.stringify([{ a: true }], null, 2)
)
err = false
} finally {
@ -83,9 +79,7 @@ describe('static data file support in vite 3', () => {
await page.waitForFunction(
() =>
document.querySelector('pre#basic')?.textContent ===
JSON.stringify([{ a: true }, { b: false }], null, 2),
undefined,
{ timeout: 3000 }
JSON.stringify([{ a: true }, { b: false }], null, 2)
)
} finally {
await fs.writeFile(b, JSON.stringify({ b: true }, null, 2) + '\n')

@ -6,7 +6,7 @@ export default defineRoutes({
// console.log('watchedFiles', watchedFiles)
return paths
},
watch: ['**/data-loading/**/*.json'],
watch: ['../data-loading/**/*.json'],
async transformPageData(pageData) {
// console.log('transformPageData', pageData.filePath)
pageData.title += ' - transformed'

@ -0,0 +1,77 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`node/postcss/isolateStyles > transforms selectors and skips keyframes 1`] = `
"
/* simple classes */
.example:not(:where(.vp-raw, .vp-raw *)) { color: red; }
.class-a:not(:where(.vp-raw, .vp-raw *)) { color: coral; }
.class-b:not(:where(.vp-raw, .vp-raw *)) { color: deepskyblue; }
/* escaped colon in class */
.baz\\:not\\(.bar\\):not(:where(.vp-raw, .vp-raw *)) { display: block; }
.disabled\\:opacity-50:not(:where(.vp-raw, .vp-raw *)):disabled { opacity: .5; }
/* pseudos (class + element) */
.button:not(:where(.vp-raw, .vp-raw *)):hover { color: pink; }
.button:not(:where(.vp-raw, .vp-raw *)):focus:hover { color: hotpink; }
.item:not(:where(.vp-raw, .vp-raw *))::before { content: '•'; }
:not(:where(.vp-raw, .vp-raw *))::first-letter { color: pink; }
:not(:where(.vp-raw, .vp-raw *))::before { content: ''; }
/* universal + :not */
*:not(:where(.vp-raw, .vp-raw *)) { background-color: red; }
*:not(:where(.vp-raw, .vp-raw *)):not(.b) { text-transform: uppercase; }
/* combinators */
.foo:hover .bar:not(:where(.vp-raw, .vp-raw *)) { background: blue; }
ul > li.active:not(:where(.vp-raw, .vp-raw *)) { color: green; }
a + b ~ c:not(:where(.vp-raw, .vp-raw *)) { color: orange; }
/* ids + attribute selectors */
#wow:not(:where(.vp-raw, .vp-raw *)) { color: yellow; }
[data-world] .d:not(:where(.vp-raw, .vp-raw *)) { padding: 10px 20px; }
/* :root and chained tags */
:not(:where(.vp-raw, .vp-raw *)):root { --bs-blue: #0d6efd; }
:root .a:not(:where(.vp-raw, .vp-raw *)) { --bs-green: #bada55; }
html:not(:where(.vp-raw, .vp-raw *)) { margin: 0; }
body:not(:where(.vp-raw, .vp-raw *)) { padding: 0; }
html body div:not(:where(.vp-raw, .vp-raw *)) { color: blue; }
/* grouping with commas */
.a:not(:where(.vp-raw, .vp-raw *)), .b:not(:where(.vp-raw, .vp-raw *)) { color: red; }
/* multiple repeated groups to ensure stability */
.a:not(:where(.vp-raw, .vp-raw *)), .b:not(:where(.vp-raw, .vp-raw *)) { color: coral; }
.a:not(:where(.vp-raw, .vp-raw *)) { animation: glow 1s linear infinite alternate; }
/* nested blocks */
.foo:not(:where(.vp-raw, .vp-raw *)) {
svg:not(:where(.vp-raw, .vp-raw *)) { display: none; }
.bar:not(:where(.vp-raw, .vp-raw *)) { display: inline; }
}
/* standalone pseudos */
:not(:where(.vp-raw, .vp-raw *)):first-child { color: pink; }
:not(:where(.vp-raw, .vp-raw *)):hover { color: blue; }
:not(:where(.vp-raw, .vp-raw *)):active { color: red; }
/* keyframes (should be ignored) */
@keyframes fade {
from { opacity: 0; }
to { opacity: 1; }
}
@-webkit-keyframes glow {
from { color: coral; }
to { color: red; }
}
@-moz-keyframes glow {
from { color: coral; }
to { color: red; }
}
@-o-keyframes glow {
from { color: coral; }
to { color: red; }
}
"
`;

@ -0,0 +1,93 @@
import { postcssIsolateStyles } from 'node/postcss/isolateStyles'
import postcss from 'postcss'
const INPUT_CSS = `
/* simple classes */
.example { color: red; }
.class-a { color: coral; }
.class-b { color: deepskyblue; }
/* escaped colon in class */
.baz\\:not\\(.bar\\) { display: block; }
.disabled\\:opacity-50:disabled { opacity: .5; }
/* pseudos (class + element) */
.button:hover { color: pink; }
.button:focus:hover { color: hotpink; }
.item::before { content: '•'; }
::first-letter { color: pink; }
::before { content: ''; }
/* universal + :not */
* { background-color: red; }
*:not(.b) { text-transform: uppercase; }
/* combinators */
.foo:hover .bar { background: blue; }
ul > li.active { color: green; }
a + b ~ c { color: orange; }
/* ids + attribute selectors */
#wow { color: yellow; }
[data-world] .d { padding: 10px 20px; }
/* :root and chained tags */
:root { --bs-blue: #0d6efd; }
:root .a { --bs-green: #bada55; }
html { margin: 0; }
body { padding: 0; }
html body div { color: blue; }
/* grouping with commas */
.a, .b { color: red; }
/* multiple repeated groups to ensure stability */
.a, .b { color: coral; }
.a { animation: glow 1s linear infinite alternate; }
/* nested blocks */
.foo {
svg { display: none; }
.bar { display: inline; }
}
/* standalone pseudos */
:first-child { color: pink; }
:hover { color: blue; }
:active { color: red; }
/* keyframes (should be ignored) */
@keyframes fade {
from { opacity: 0; }
to { opacity: 1; }
}
@-webkit-keyframes glow {
from { color: coral; }
to { color: red; }
}
@-moz-keyframes glow {
from { color: coral; }
to { color: red; }
}
@-o-keyframes glow {
from { color: coral; }
to { color: red; }
}
`
describe('node/postcss/isolateStyles', () => {
test('transforms selectors and skips keyframes', () => {
const out = run(INPUT_CSS)
expect(out.css).toMatchSnapshot()
})
test('idempotent (running twice produces identical CSS)', () => {
const first = run(INPUT_CSS).css
const second = run(first).css
expect(second).toBe(first)
})
})
function run(css: string, from = 'src/styles/vp-doc.css') {
return postcss([postcssIsolateStyles()]).process(css, { from })
}

@ -1,2 +1,16 @@
#!/usr/bin/env node
// @ts-check
import module from 'node:module'
// https://github.com/vitejs/vite/blob/6c8a5a27e645a182f5b03a4ed6aa726eab85993f/packages/vite/bin/vite.js#L48-L63
try {
module.enableCompileCache?.()
setTimeout(() => {
try {
module.flushCompileCache?.()
} catch {}
}, 10 * 1000).unref()
} catch {}
import('../dist/node/cli.js')

@ -1,17 +1,18 @@
import { defineConfig } from 'vitepress'
import {
defineConfig,
resolveSiteDataByRoute,
type HeadConfig
} from 'vitepress'
import {
groupIconMdPlugin,
groupIconVitePlugin,
localIconLoader
} from 'vitepress-plugin-group-icons'
import { search as esSearch } from './es'
import { search as faSearch } from './fa'
import { search as koSearch } from './ko'
import { search as ptSearch } from './pt'
import { search as ruSearch } from './ru'
import { search as zhSearch } from './zh'
import llmstxt from 'vitepress-plugin-llms'
const prod = !!process.env.NETLIFY
export const shared = defineConfig({
export default defineConfig({
title: 'VitePress',
rewrites: {
@ -51,6 +52,8 @@ export const shared = defineConfig({
return 'Скопировать код'
case 'zh':
return '复制代码'
case 'ja':
return 'コードをコピー'
default:
return 'Copy code'
}
@ -71,18 +74,35 @@ export const shared = defineConfig({
}
},
/* 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' }],
[
'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', { property: 'og:type', content: 'website' }],
['meta', { property: 'og:locale', content: 'en' }],
['meta', { property: 'og:title', content: 'VitePress | Vite & Vue Powered Static Site Generator' }],
['meta', { property: 'og:site_name', content: 'VitePress' }],
['meta', { property: 'og:image', content: 'https://vitepress.dev/vitepress-og.jpg' }],
[
'meta',
{
property: 'og:image',
content: 'https://vitepress.dev/vitepress-og.jpg'
}
],
['meta', { property: 'og:url', content: 'https://vitepress.dev/' }],
['script', { src: 'https://cdn.usefathom.com/script.js', 'data-site': 'AZBRSFGG', 'data-spa': 'auto', defer: '' }]
[
'script',
{
src: 'https://cdn.usefathom.com/script.js',
'data-site': 'AZBRSFGG',
'data-spa': 'auto',
defer: ''
}
]
],
themeConfig: {
@ -98,30 +118,57 @@ export const shared = defineConfig({
appId: '8J64VVRP8K',
apiKey: '52f578a92b88ad6abde815aae2b0ad7c',
indexName: 'vitepress',
locales: {
...zhSearch,
...ptSearch,
...ruSearch,
...esSearch,
...koSearch,
...faSearch
}
askAi: 'YaVSonfX5bS8'
}
},
carbonAds: { code: 'CEBDT27Y', placement: 'vuejsorg' }
},
locales: {
root: { label: 'English', lang: 'en-US', dir: 'ltr' },
zh: { label: '简体中文', lang: 'zh-Hans', dir: 'ltr' },
pt: { label: 'Português', lang: 'pt-BR', dir: 'ltr' },
ru: { label: 'Русский', lang: 'ru-RU', dir: 'ltr' },
es: { label: 'Español', lang: 'es', dir: 'ltr' },
ko: { label: '한국어', lang: 'ko-KR', dir: 'ltr' },
fa: { label: 'فارسی', lang: 'fa-IR', dir: 'rtl' },
ja: { label: '日本語', lang: 'ja', dir: 'ltr' }
},
vite: {
plugins: [
groupIconVitePlugin({
customIcon: {
vitepress: localIconLoader(
import.meta.url,
'../../public/vitepress-logo-mini.svg'
'../public/vitepress-logo-mini.svg'
),
firebase: 'logos:firebase'
}
})
]
}
}),
prod &&
llmstxt({
workDir: 'en',
ignoreFiles: ['index.md']
})
],
experimental: {
enableNativePlugin: true
}
},
transformPageData: prod
? (pageData, ctx) => {
const site = resolveSiteDataByRoute(
ctx.siteConfig.site,
pageData.relativePath
)
const title = `${pageData.title || site.title} | ${pageData.description || site.description}`
;((pageData.frontmatter.head ??= []) as HeadConfig[]).push(
['meta', { property: 'og:locale', content: site.lang }],
['meta', { property: 'og:title', content: title }]
)
}
: undefined
})

@ -1,22 +0,0 @@
import { defineConfig } from 'vitepress'
import { shared } from './shared'
import { en } from './en'
import { zh } from './zh'
import { pt } from './pt'
import { ru } from './ru'
import { es } from './es'
import { ko } from './ko'
import { fa } from './fa'
export default defineConfig({
...shared,
locales: {
root: { label: 'English', ...en },
zh: { label: '简体中文', ...zh },
pt: { label: 'Português', ...pt },
ru: { label: 'Русский', ...ru },
es: { label: 'Español', ...es },
ko: { label: '한국어', ...ko },
fa: { label: 'فارسی', ...fa }
}
})

@ -1,5 +1,3 @@
@import url('https://fonts.googleapis.com/css2?family=Vazirmatn:wght@100..900&display=swap');
:root:where(:lang(fa)) {
--vp-font-family-base:
'Vazirmatn', 'Inter', ui-sans-serif, system-ui, sans-serif,

@ -1,11 +1,10 @@
import { createRequire } from 'module'
import { defineConfig, type DefaultTheme } from 'vitepress'
import { defineAdditionalConfig, type DefaultTheme } from 'vitepress'
const require = createRequire(import.meta.url)
const pkg = require('vitepress/package.json')
export const en = defineConfig({
lang: 'en-US',
export default defineAdditionalConfig({
description: 'Vite & Vue powered static site generator.',
themeConfig: {
@ -43,6 +42,10 @@ function nav(): DefaultTheme.NavItem[] {
{
text: pkg.version,
items: [
{
text: '1.6.4',
link: 'https://vuejs.github.io/vitepress/v1/'
},
{
text: 'Changelog',
link: 'https://github.com/vuejs/vitepress/blob/main/CHANGELOG.md'

@ -111,7 +111,7 @@ Set up a new project and change these settings using your dashboard:
- **Build Command:** `npm run docs:build`
- **Output Directory:** `docs/.vitepress/dist`
- **Node Version:** `18` (or above)
- **Node Version:** `20` (or above)
::: warning
Don't enable options like _Auto Minify_ for HTML code. It will remove comments from output which have meaning to Vue. You may see hydration mismatch errors if they get removed.
@ -163,7 +163,7 @@ Don't enable options like _Auto Minify_ for HTML code. It will remove comments f
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
node-version: 22
cache: npm # or pnpm / yarn
- name: Setup Pages
uses: actions/configure-pages@v4
@ -294,6 +294,10 @@ You can deploy your VitePress website on [Kinsta](https://kinsta.com/static-site
You can deploy your VitePress project to [Stormkit](https://www.stormkit.io) by following these [instructions](https://stormkit.io/blog/how-to-deploy-vitepress).
### CloudRay
You can deploy your VitePress project with [CloudRay](https://cloudray.io/) by following these [instructions](https://cloudray.io/articles/how-to-deploy-vitepress-site).
### Nginx
Here is a example of an Nginx server block configuration. This setup includes gzip compression for common text-based assets, rules for serving your VitePress site's static files with proper caching headers as well as handling `cleanUrls: true`.

@ -70,7 +70,7 @@ If your font is a local file referenced via `@font-face`, it will be processed a
export default {
transformHead({ assets }) {
// adjust the regex accordingly to match your font
const myFontFile = assets.find(file => /font-name\.\w+\.woff2/)
const myFontFile = assets.find(file => /font-name\.[\w-]+\.woff2/.test(file))
if (myFontFile) {
return [
[
@ -252,6 +252,7 @@ provide('toggle-appearance', async ({ clientX: x, clientY: y }: MouseEvent) => {
{
duration: 300,
easing: 'ease-in',
fill: 'forwards',
pseudoElement: `::view-transition-${isDark.value ? 'old' : 'new'}(root)`
}
)
@ -319,7 +320,7 @@ export default defineConfig({
{
find: /^.*\/VPNavBar\.vue$/,
replacement: fileURLToPath(
new URL('./components/CustomNavBar.vue', import.meta.url)
new URL('./theme/components/CustomNavBar.vue', import.meta.url)
)
}
]

@ -18,39 +18,19 @@ VitePress can be used on its own, or be installed into an existing project. In b
::: code-group
```sh [npm]
$ npm add -D vitepress
$ npm add -D vitepress@next
```
```sh [pnpm]
$ pnpm add -D vitepress
$ pnpm add -D vitepress@next
```
```sh [yarn]
$ yarn add -D vitepress
```
```sh [yarn (pnp)]
$ yarn add -D vitepress vue
$ yarn add -D vitepress@next vue
```
```sh [bun]
$ bun add -D vitepress
```
:::
::: details Getting missing peer deps warnings?
If using PNPM, you will notice a missing peer warning for `@docsearch/js`. This does not prevent VitePress from working. If you wish to suppress this warning, add the following to your `package.json`:
```json
"pnpm": {
"peerDependencyRules": {
"ignoreMissing": [
"@algolia/client-search",
"search-insights"
]
}
}
$ bun add -D vitepress@next
```
:::

@ -277,11 +277,11 @@ Wraps in a `<div class="vp-raw">`
}
```
It uses [`postcss-prefix-selector`](https://github.com/RadValentin/postcss-prefix-selector) under the hood. You can pass its options like this:
You can pass its options like this:
```js
postcssIsolateStyles({
includeFiles: [/vp-doc\.css/] // defaults to /base\.css/
includeFiles: [/custom\.css/] // defaults to [/vp-doc\.css/, /base\.css/]
})
```
@ -365,7 +365,7 @@ export default {
A [list of valid languages](https://shiki.style/languages) is available on Shiki's repository.
You may also customize syntax highlight theme in app config. Please see [`markdown` options](../reference/site-config#markdown) for more details.
You may also customize syntax highlight theme, configure language aliases, and set custom language labels in app config. Please see [`markdown` options](../reference/site-config#markdown) for more details.
## Line Highlighting in Code Blocks
@ -781,7 +781,7 @@ You can also [import snippets](#import-code-snippets) in code groups:
You can include a markdown file in another markdown file, even nested.
::: tip
You can also prefix the markdown path with `@`, it will act as the source root. By default, it's the VitePress project root, unless `srcDir` is configured.
You can also prefix the markdown path with `@`, and it will act as the source root. By default, the source root is the VitePress project root, unless `srcDir` is configured.
:::
For example, you can include a relative markdown file using this:

@ -336,6 +336,46 @@ export default {
}
```
### Watching Template and Data Files
When generating page content from templates or external data sources, you can use the watch option to automatically rebuild pages when those files change during development:
```js
// posts/[slug].paths.js
import fs from 'node:fs'
import { renderTemplate } from './templates/renderer.js'
export default {
// Watch for changes to template files and data sources
watch: [
'./templates/**/*.njk', // Template files
'../data/**/*.json' // Data files
],
paths(watchedFiles) {
// watchedFiles will be an array of absolute paths of the matched files
// Read data files to generate routes
const dataFiles = watchedFiles.filter(file => file.endsWith('.json'))
return dataFiles.map(file => {
const data = JSON.parse(fs.readFileSync(file, 'utf-8'))
return {
params: { slug: data.slug },
content: renderTemplate(data) // Use template to generate content
}
})
}
}
```
The `watch` option works the same way as in [data loaders](./data-loading#data-from-local-files):
- Accepts [glob patterns](https://github.com/mrmlnc/fast-glob#pattern-syntax) to match files
- Patterns are relative to the `.paths.js` file itself
- Changes to watched files trigger page regeneration and HMR during development
- In production builds, all pages are generated once regardless of watch configuration
### 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:

@ -12,7 +12,7 @@ Just want to try it out? Skip to the [Quickstart](./getting-started).
- **Documentation**
VitePress ships with a default theme designed for technical documentation. It powers this page you are reading right now, along with the documentation for [Vite](https://vitejs.dev/), [Rollup](https://rollupjs.org/), [Pinia](https://pinia.vuejs.org/), [VueUse](https://vueuse.org/), [Vitest](https://vitest.dev/), [D3](https://d3js.org/), [UnoCSS](https://unocss.dev/), [Iconify](https://iconify.design/) and [many more](https://www.vuetelescope.com/explore?framework.slug=vitepress).
VitePress ships with a default theme designed for technical documentation. It powers this page you are reading right now, along with the documentation for [Vite](https://vitejs.dev/), [Rollup](https://rollupjs.org/), [Pinia](https://pinia.vuejs.org/), [VueUse](https://vueuse.org/), [Vitest](https://vitest.dev/), [D3](https://d3js.org/), [UnoCSS](https://unocss.dev/), [Iconify](https://iconify.design/) and [many more](https://github.com/search?q=/"vitepress":+/+language:json&type=code).
The [official Vue.js documentation](https://vuejs.org/) is also based on VitePress, but uses a custom theme shared between multiple translations.
@ -50,8 +50,8 @@ Unlike many traditional SSGs where each navigation results in a full page reload
## What About VuePress?
VitePress is the spiritual successor of VuePress. The original VuePress was based on Vue 2 and webpack. With Vue 3 and Vite under the hood, VitePress provides significantly better DX, better production performance, a more polished default theme, and a more flexible customization API.
VitePress is the spiritual successor of VuePress 1. The original VuePress 1 was based on Vue 2 and webpack. With Vue 3 and Vite under the hood, VitePress provides significantly better DX, better production performance, a more polished default theme, and a more flexible customization API.
The API difference between VitePress and VuePress mostly lies in theming and customization. If you are using VuePress 1 with the default theme, it should be relatively straightforward to migrate to VitePress.
The API difference between VitePress and VuePress 1 mostly lies in theming and customization. If you are using VuePress 1 with the default theme, it should be relatively straightforward to migrate to VitePress.
There has also been effort invested into VuePress 2, which also supports Vue 3 and Vite with more compatibility with VuePress 1. However, maintaining two SSGs in parallel isn't sustainable, so the Vue team has decided to focus on VitePress as the main recommended SSG in the long run.
Maintaining two SSGs in parallel isn't sustainable, so the Vue team has decided to focus on VitePress as the main recommended SSG in the long run. Now VuePress 1 has been deprecated, and VuePress 2 has been handed over to the VuePress community team for further development and maintenance.

@ -1,9 +1,6 @@
---
layout: home
title: VitePress
titleTemplate: Vite & Vue Powered Static Site Generator
hero:
name: VitePress
text: Vite & Vue Powered Static Site Generator
@ -11,10 +8,10 @@ hero:
actions:
- theme: brand
text: What is VitePress?
link: /guide/what-is-vitepress
link: ./guide/what-is-vitepress
- theme: alt
text: Quickstart
link: /guide/getting-started
link: ./guide/getting-started
- theme: alt
text: GitHub
link: https://github.com/vuejs/vitepress

@ -43,7 +43,6 @@ vitepress build [root]
| `--base <path>` | Public base path (default: `/`) (`string`) |
| `--target <target>` | Transpile target (default: `"modules"`) (`string`) |
| `--outDir <dir>` | Output directory relative to **cwd** (default: `<root>/.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`

@ -89,7 +89,7 @@ type NavItem = NavItemWithLink | NavItemWithChildren
interface NavItemWithLink {
text: string
link: string
link: string | ((payload: PageData) => string)
activeMatch?: string
target?: string
rel?: string
@ -457,3 +457,38 @@ Can be used to customize the label of the skip to content link. This link is sho
- Default: `false`
Whether to show an external link icon next to external links in markdown.
## `useLayout` <Badge type="info" text="composable" />
Returns layout-related data. The returned object has the following type:
```ts
interface {
isHome: ComputedRef<boolean>
sidebar: Readonly<ShallowRef<DefaultTheme.SidebarItem[]>>
sidebarGroups: ComputedRef<DefaultTheme.SidebarItem[]>
hasSidebar: ComputedRef<boolean>
isSidebarEnabled: ComputedRef<boolean>
hasAside: ComputedRef<boolean>
leftAside: ComputedRef<boolean>
headers: Readonly<ShallowRef<DefaultTheme.OutlineItem[]>>
hasLocalNav: ComputedRef<boolean>
}
```
**Example:**
```vue
<script setup>
import { useLayout } from 'vitepress/theme'
const { hasSidebar } = useLayout()
</script>
<template>
<div v-if="hasSidebar">Only show when sidebar exists</div>
</template>
```

@ -2,8 +2,27 @@
The update time of the last content will be displayed in the lower right corner of the page. To enable it, add `lastUpdated` options to your config.
::: tip
You need to commit the markdown file to see the updated time.
::: info
VitePress displays the "last updated" time using the timestamp of the most recent Git commit for each file. To enable this, the Markdown file must be committed to Git.
Internally, VitePress runs `git log -1 --pretty="%ai"` on each file to retrieve its timestamp. If all pages show the same update time, it's likely due to shallow cloning (common in CI environments), which limits Git history.
To fix this in **GitHub Actions**, use the following in your workflow:
```yaml{4}
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
```
Other CI/CD platforms have similar settings.
If such options aren't available, you can prepend the `docs:build` command in your `package.json` with a manual fetch:
```json
"docs:build": "git fetch --unshallow && vitepress build docs"
```
:::
## Site-Level Config

@ -55,6 +55,8 @@ export default {
The `text` is the actual text displayed in nav, and the `link` is the link that will be navigated to when the text is clicked. For the link, set path to the actual file without `.md` prefix, and always start with `/`.
The `link` can also be a function that accepts [`PageData`](./runtime-api#usedata) as the argument and returns the path.
Nav links can also be dropdown menus. To do this, set `items` key on link option.
```js

@ -6,7 +6,7 @@ outline: deep
## Local Search
VitePress supports fuzzy full-text search using a in-browser index thanks to [minisearch](https://github.com/lucaong/minisearch/). To enable this feature, simply set the `themeConfig.search.provider` option to `'local'` in your `.vitepress/config.ts` file:
VitePress supports fuzzy full-text search using an in-browser index thanks to [minisearch](https://github.com/lucaong/minisearch/). To enable this feature, simply set the `themeConfig.search.provider` option to `'local'` in your `.vitepress/config.ts` file:
```ts
import { defineConfig } from 'vitepress'
@ -233,10 +233,16 @@ export default defineConfig({
},
modal: {
searchBox: {
resetButtonTitle: '清除查询条件',
resetButtonAriaLabel: '清除查询条件',
cancelButtonText: '取消',
cancelButtonAriaLabel: '取消'
clearButtonTitle: '清除查询条件',
clearButtonAriaLabel: '清除查询条件',
closeButtonText: '关闭',
closeButtonAriaLabel: '关闭',
placeholderText: '搜索文档',
placeholderTextAskAi: '向 AI 提问:',
placeholderTextAskAiStreaming: '回答中...',
searchInputLabel: '搜索',
backToKeywordSearchButtonText: '返回关键字搜索',
backToKeywordSearchButtonAriaLabel: '返回关键字搜索'
},
startScreen: {
recentSearchesTitle: '搜索历史',
@ -244,23 +250,48 @@ export default defineConfig({
saveRecentSearchButtonTitle: '保存至搜索历史',
removeRecentSearchButtonTitle: '从搜索历史中移除',
favoriteSearchesTitle: '收藏',
removeFavoriteSearchButtonTitle: '从收藏中移除'
removeFavoriteSearchButtonTitle: '从收藏中移除',
recentConversationsTitle: '最近的对话',
removeRecentConversationButtonTitle: '从历史记录中删除对话'
},
errorScreen: {
titleText: '无法获取结果',
helpText: '你可能需要检查你的网络连接'
},
footer: {
selectText: '选择',
navigateText: '切换',
closeText: '关闭',
searchByText: '搜索提供者'
},
noResultsScreen: {
noResultsText: '无法找到相关结果',
suggestedQueryText: '你可以尝试查询',
reportMissingResultsText: '你认为该查询应该有结果?',
reportMissingResultsLinkText: '点击反馈'
},
resultsScreen: {
askAiPlaceholder: '向 AI 提问: '
},
askAiScreen: {
disclaimerText: '答案由 AI 生成,可能不准确,请自行验证。',
relatedSourcesText: '相关来源',
thinkingText: '思考中...',
copyButtonText: '复制',
copyButtonCopiedText: '已复制!',
copyButtonTitle: '复制',
likeButtonTitle: '赞',
dislikeButtonTitle: '踩',
thanksForFeedbackText: '感谢你的反馈!',
preToolCallText: '搜索中...',
duringToolCallText: '搜索 ',
afterToolCallText: '已搜索'
},
footer: {
selectText: '选择',
submitQuestionText: '提交问题',
selectKeyAriaLabel: 'Enter 键',
navigateText: '切换',
navigateUpKeyAriaLabel: '向上箭头',
navigateDownKeyAriaLabel: '向下箭头',
closeText: '关闭',
backToSearchText: '返回搜索',
closeKeyAriaLabel: 'Esc 键',
poweredByText: '搜索提供者'
}
}
}
@ -274,6 +305,43 @@ export default defineConfig({
[These options](https://github.com/vuejs/vitepress/blob/main/types/docsearch.d.ts) can be overridden. Refer official Algolia docs to learn more about them.
### Algolia Ask AI Support {#ask-ai}
If you would like to include **Ask AI**, pass the `askAi` option (or any of the partial fields) inside `options`:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
themeConfig: {
search: {
provider: 'algolia',
options: {
appId: '...',
apiKey: '...',
indexName: '...',
// askAi: "YOUR-ASSISTANT-ID"
// OR
askAi: {
// at minimum you must provide the assistantId you received from Algolia
assistantId: 'XXXYYY',
// optional overrides if omitted, the top-level appId/apiKey/indexName values are reused
// apiKey: '...',
// appId: '...',
// indexName: '...'
}
}
}
}
})
```
::: warning Note
If want to default to keyword search and do not want to use Ask AI, just omit the `askAi` property
:::
The translations for the Ask AI UI live under `options.translations.modal.askAiScreen` and `options.translations.resultsScreen` — see the [type definitions](https://github.com/vuejs/vitepress/blob/main/types/docsearch.d.ts) for all keys.
### Crawler Config
Here is an example config based on what this site uses:

@ -180,36 +180,3 @@ export default {
}
}
```
## `useSidebar` <Badge type="info" text="composable" />
Returns sidebar-related data. The returned object has the following type:
```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
}
```
**Example:**
```vue
<script setup>
import { useSidebar } from 'vitepress/theme'
const { hasSidebar } = useSidebar()
</script>
<template>
<div v-if="hasSidebar">Only show when sidebar exists</div>
</template>
```

@ -53,12 +53,12 @@ const members = [
Say hello to our awesome team.
<VPTeamMembers size="small" :members="members" />
<VPTeamMembers size="small" :members />
```
The above will display a team member in card looking element. It should display something similar to below.
<VPTeamMembers size="small" :members="members" />
<VPTeamMembers size="small" :members />
`<VPTeamMembers>` component comes in 2 different sizes, `small` and `medium`. While it boils down to your preference, usually `small` size should fit better when used in doc page. Also, you may add more properties to each member such as adding "description" or "sponsor" button. Learn more about it in [`<VPTeamMembers>`](#vpteammembers).
@ -107,9 +107,7 @@ const members = [
team, some of whom have chosen to be featured below.
</template>
</VPTeamPageTitle>
<VPTeamMembers
:members="members"
/>
<VPTeamMembers :members />
</VPTeamPage>
```

@ -225,3 +225,16 @@ Then you can customize styles of this specific page in `.vitepress/theme/custom.
/* page-specific styles */
}
```
### isHome
- Type: `boolean`
The default theme relies on checks like `frontmatter.layout === 'home'` to determine if the current page is the home page.\
This is useful when you want to force show the home page elements in a custom layout.
```yaml
---
isHome: true
---
```

@ -24,7 +24,7 @@ export default {
}
```
:::details Dynamic (Async) Config
::: details Dynamic (Async) Config
If you need to dynamically generate the config, you can also default export a function. For example:
@ -458,7 +458,7 @@ export default {
### ignoreDeadLinks
- Type: `boolean | 'localhostLinks' | (string | RegExp | ((link: string) => boolean))[]`
- Type: `boolean | 'localhostLinks' | (string | RegExp | ((link: string, source: string) => boolean))[]`
- Default: `false`
When set to `true`, VitePress will not fail builds due to dead links.

@ -1,16 +1,17 @@
import { createRequire } from 'module'
import { defineConfig, type DefaultTheme } from 'vitepress'
import { defineAdditionalConfig, type DefaultTheme } from 'vitepress'
const require = createRequire(import.meta.url)
const pkg = require('vitepress/package.json')
export const es = defineConfig({
lang: 'es-CO',
description: 'Generador de Sitios Estaticos desarrollado con Vite y Vue.',
export default defineAdditionalConfig({
description: 'Generador de Sitios Estáticos desarrollado con Vite y Vue.',
themeConfig: {
nav: nav(),
search: { options: searchOptions() },
sidebar: {
'/es/guide/': { base: '/es/guide/', items: sidebarGuide() },
'/es/reference/': { base: '/es/reference/', items: sidebarReference() }
@ -23,7 +24,7 @@ export const es = defineConfig({
footer: {
message: 'Liberado bajo la licencia MIT',
copyright: `Derechos reservados © 2019-${new Date().getFullYear()} Evan You`
copyright: 'Todos los derechos reservados © 2019-PRESENTE Evan You'
},
docFooter: {
@ -36,11 +37,15 @@ export const es = defineConfig({
},
lastUpdated: {
text: 'Actualizado en',
formatOptions: {
dateStyle: 'short',
timeStyle: 'medium'
}
text: 'Actualizado el'
},
notFound: {
title: 'PÁGINA NO ENCONTRADA',
quote:
'Pero si no cambias de dirección y sigues buscando, podrías terminar donde te diriges.',
linkLabel: 'ir a inicio',
linkText: 'Llévame a inicio'
},
langMenuLabel: 'Cambiar Idioma',
@ -56,7 +61,7 @@ export const es = defineConfig({
function nav(): DefaultTheme.NavItem[] {
return [
{
text: 'Guia',
text: 'Guía',
link: '/es/guide/what-is-vitepress',
activeMatch: '/es/guide/'
},
@ -68,6 +73,10 @@ function nav(): DefaultTheme.NavItem[] {
{
text: pkg.version,
items: [
{
text: '1.6.4',
link: 'https://vuejs.github.io/vitepress/v1/es/'
},
{
text: 'Registro de cambios',
link: 'https://github.com/vuejs/vitepress/blob/main/CHANGELOG.md'
@ -87,7 +96,7 @@ function sidebarGuide(): DefaultTheme.SidebarItem[] {
text: 'Introducción',
collapsed: false,
items: [
{ text: 'Qué es VitePress', link: 'what-is-vitepress' },
{ text: '¿Qué es VitePress', link: 'what-is-vitepress' },
{ text: 'Iniciando', link: 'getting-started' },
{ text: 'Enrutamiento', link: 'routing' },
{ text: 'Despliegue', link: 'deploy' }
@ -130,7 +139,7 @@ function sidebarGuide(): DefaultTheme.SidebarItem[] {
]
},
{
text: 'Configuración y Referencia del API',
text: 'Configuración y Referencia de la API',
base: '/es/reference/',
link: 'site-config'
}
@ -161,7 +170,7 @@ function sidebarReference(): DefaultTheme.SidebarItem[] {
{ text: 'Links Anterior / Siguiente', link: 'prev-next-links' },
{ text: 'Editar Link', link: 'edit-link' },
{ text: 'Sello temporal de actualización', link: 'last-updated' },
{ text: 'Busqueda', link: 'search' },
{ text: 'Búsqueda', link: 'search' },
{ text: 'Carbon Ads', link: 'carbon-ads' }
]
}
@ -170,8 +179,8 @@ function sidebarReference(): DefaultTheme.SidebarItem[] {
]
}
export const search: DefaultTheme.AlgoliaSearchOptions['locales'] = {
es: {
function searchOptions(): Partial<DefaultTheme.AlgoliaSearchOptions> {
return {
placeholder: 'Buscar documentos',
translations: {
button: {
@ -180,10 +189,17 @@ export const search: DefaultTheme.AlgoliaSearchOptions['locales'] = {
},
modal: {
searchBox: {
resetButtonTitle: 'Limpiar búsqueda',
resetButtonAriaLabel: 'Limpiar búsqueda',
cancelButtonText: 'Cancelar',
cancelButtonAriaLabel: 'Cancelar'
clearButtonTitle: 'Limpiar búsqueda',
clearButtonAriaLabel: 'Limpiar búsqueda',
closeButtonText: 'Cerrar',
closeButtonAriaLabel: 'Cerrar',
placeholderText: undefined,
placeholderTextAskAi: undefined,
placeholderTextAskAiStreaming: 'Respondiendo...',
backToKeywordSearchButtonText:
'Volver a la búsqueda por palabras clave',
backToKeywordSearchButtonAriaLabel:
'Volver a la búsqueda por palabras clave'
},
startScreen: {
recentSearchesTitle: 'Historial de búsqueda',
@ -191,24 +207,52 @@ export const search: DefaultTheme.AlgoliaSearchOptions['locales'] = {
saveRecentSearchButtonTitle: 'Guardar en el historial de búsqueda',
removeRecentSearchButtonTitle: 'Borrar del historial de búsqueda',
favoriteSearchesTitle: 'Favoritos',
removeFavoriteSearchButtonTitle: 'Borrar de favoritos'
removeFavoriteSearchButtonTitle: 'Borrar de favoritos',
recentConversationsTitle: 'Conversaciones recientes',
removeRecentConversationButtonTitle:
'Eliminar esta conversación del historial'
},
errorScreen: {
titleText: 'No fue posible obtener resultados',
helpText: 'Verifique su conexión de red'
},
footer: {
selectText: 'Seleccionar',
navigateText: 'Navegar',
closeText: 'Cerrar',
searchByText: 'Busqueda por'
},
noResultsScreen: {
noResultsText: 'No fue posible encontrar resultados',
suggestedQueryText: 'Puede intentar una nueva búsqueda',
reportMissingResultsText:
'Deberian haber resultados para esa consulta?',
'¿Deberían haber resultados para esta consulta?',
reportMissingResultsLinkText: 'Click para enviar feedback'
},
resultsScreen: {
askAiPlaceholder: 'Preguntar a la IA: '
},
askAiScreen: {
disclaimerText:
'Las respuestas son generadas por IA y pueden contener errores. Verifica las respuestas.',
relatedSourcesText: 'Fuentes relacionadas',
thinkingText: 'Pensando...',
copyButtonText: 'Copiar',
copyButtonCopiedText: '¡Copiado!',
copyButtonTitle: 'Copiar',
likeButtonTitle: 'Me gusta',
dislikeButtonTitle: 'No me gusta',
thanksForFeedbackText: '¡Gracias por tu opinión!',
preToolCallText: 'Buscando...',
duringToolCallText: 'Buscando ',
afterToolCallText: 'Búsqueda de',
aggregatedToolCallText: 'Búsqueda de'
},
footer: {
selectText: 'Seleccionar',
submitQuestionText: 'Enviar pregunta',
selectKeyAriaLabel: 'Tecla Enter',
navigateText: 'Navegar',
navigateUpKeyAriaLabel: 'Flecha arriba',
navigateDownKeyAriaLabel: 'Flecha abajo',
closeText: 'Cerrar',
backToSearchText: 'Volver a la búsqueda',
closeKeyAriaLabel: 'Tecla Escape',
poweredByText: 'Búsqueda por'
}
}
}

@ -163,7 +163,7 @@ No active opciones como _Auto Minify_ para código HTML. Eso removera comentario
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
node-version: 22
cache: npm # o pnpm / yarn
- name: Setup Pages
uses: actions/configure-pages@v4

@ -70,7 +70,7 @@ Si su fuente es un archivo local referenciado via `@font-face`, ella será proce
export default {
transformHead({ assets }) {
// ajuste el regex para corresponder a su fuente
const myFontFile = assets.find(file => /font-name\.\w+\.woff2/)
const myFontFile = assets.find(file => /font-name\.[\w-]+\.woff2/.test(file))
if (myFontFile) {
return [
[
@ -251,6 +251,7 @@ provide('toggle-appearance', async ({ clientX: x, clientY: y }: MouseEvent) => {
{
duration: 300,
easing: 'ease-in',
fill: 'forwards',
pseudoElement: `::view-transition-${isDark.value ? 'old' : 'new'}(root)`
}
)

@ -18,35 +18,19 @@ VitePress puede ser usado solo, o ser instalado en un proyecto ya existente. En
::: code-group
```sh [npm]
$ npm add -D vitepress
$ npm add -D vitepress@next
```
```sh [pnpm]
$ pnpm add -D vitepress
$ pnpm add -D vitepress@next
```
```sh [yarn]
$ yarn add -D vitepress
$ yarn add -D vitepress@next
```
```sh [bun]
$ bun add -D vitepress
```
:::
::: details Recibiendo avisos sobre dependencias ausentes?
Si usa PNPM, percibirá un aviso de ausencia de `@docsearch/js`. Esto no evita que VitePress funcione. Si desea eliminar este aviso, adicione lo siguiente en su `package.json`:
```json
"pnpm": {
"peerDependencyRules": {
"ignoreMissing": [
"@algolia/client-search",
"search-insights"
]
}
}
$ bun add -D vitepress@next
```
:::

@ -256,11 +256,11 @@ La clase `vp-raw` también puede ser usada directamente en elementos. El aislami
}
```
El utiliza [`postcss-prefix-selector`](https://github.com/postcss/postcss-load-config) internamente. Puede pasar opciones así:
Puede pasar opciones así:
```js
postcssIsolateStyles({
includeFiles: [/vp-doc\.css/] // o padrão é /base\.css/
includeFiles: [/custom\.css/] // o padrão é [/vp-doc\.css/, /base\.css/]
})
```

@ -4,13 +4,13 @@ outline: deep
# Compatibilidad SSR {#ssr-compatibility}
VitePress pre-interpreta la aplicación en Node.js durante la compilación del producción, utilizando las capacidades de Interpretación del lado del servidor (SSR) de Vue. Esto significa que todo el código personalizado en los componentes del tema está sujeto a la compatibilidad SSR.
VitePress pre-renderiza la aplicación en Node.js durante la compilación de producción, utilizando las capacidades de Renderizado del Lado del Servidor (SSR) de Vue. Esto significa que todo el código personalizado en los componentes del tema está sujeto a la Compatibilidad con SSR.
La [sección SSR en la documentación Vue oficial](https://vuejs.org/guide/scaling-up/ssr.html) proporciona más contexto sobre lo que es SSR, la relación entre SSR / SSG y notas comunes sobre escribir código amigable con SSR. La regla general es acceder apenas APIs deln navegador / DOM en los hooks `beforeMount` o `mounted` de los componentes Vue.
La [sección SSR en la documentación Vue oficial](https://vuejs.org/guide/scaling-up/ssr.html) proporciona más contexto sobre lo que es SSR, la relación entre SSR / SSG y notas comunes sobre escribir código amigable para SSR. La regla general es acceder a las APIs del navegador / DOM solo en los hooks `beforeMount` o `mounted` de los componentes de Vue.
## `<ClientOnly>`
Se está usando o demostrando componentes que no son compatibles con SSR (por ejemplo, contienen directivas personalizadas), puede envolverlos en el componente embutido `<ClientOnly>`:
Si está usando o demostrando componentes que no son compatibles con SSR (por ejemplo, contienen directivas personalizadas), puede envolverlos en el componente incorporado `<ClientOnly>`:
```md
<ClientOnly>
@ -20,7 +20,7 @@ Se está usando o demostrando componentes que no son compatibles con SSR (por ej
## Bibliotecas que Acceden el API del Navegador en la Importación {#libraries-that-access-browser-api-on-import}
Algunos componentes o bibliotecas acceden APIs del navegador **en la Importación**. Para usar código que asume un ambiente de navegador en la importación, necesita importarlo dinámicamente.
Algunos componentes o librerías acceden a las APIs del navegador **al momento de ser importados**. Para usar código que asume un entorno de navegador en la importación, necesita importarlos dinámicamente.
### Importando en el Hook `mounted` {#importing-in-mounted-hook}
@ -29,7 +29,7 @@ Algunos componentes o bibliotecas acceden APIs del navegador **en la Importació
import { onMounted } from 'vue'
onMounted(() => {
import('./lib-que-accede-window-en-la-importacion').then((module) => {
import('./lib-que-accede-a-window-en-la-importacion').then((module) => {
// usar código
})
})
@ -38,17 +38,17 @@ onMounted(() => {
### Importación Condicional {#conditional-import}
Puede también importar condicionalmente usando el flag `import.meta.env.SSR` (parte de las [variables de entorno Vite](https://vitejs.dev/guide/env-and-mode.html#env-variables)):
También puede importar una dependencia condicionalmente utilizando la bandera `import.meta.env.SSR` (que forma parte de las [variables de entorno Vite](https://vitejs.dev/guide/env-and-mode.html#env-variables)):
```js
if (!import.meta.env.SSR) {
import('./lib-que-accede-window-en-la-importacion').then((module) => {
import('./lib-que-accede-a-window-en-la-importacion').then((module) => {
// usar código
})
}
```
Como [`Theme.enhanceApp`](./custom-theme#theme-interface) puede ser asíncrono, puede importar condicionalmente y registrar plugins Vue que acceden APIs del navegador en la importación:
Dado que [`Theme.enhanceApp`](./custom-theme#theme-interface) puede ser asíncrono, puede importar y registrar condicionalmente plugins de Vue que accedan a las APIs del navegador al ser importados:
```js [.vitepress/theme/index.js]
/** @type {import('vitepress').Theme} */
@ -56,7 +56,7 @@ export default {
// ...
async enhanceApp({ app }) {
if (!import.meta.env.SSR) {
const plugin = await import('plugin-que-accede-window-en-la-importacion')
const plugin = await import('plugin-que-accede-a-window-en-la-importacion')
app.use(plugin.default)
}
}
@ -71,7 +71,7 @@ export default {
// ...
async enhanceApp({ app }) {
if (!import.meta.env.SSR) {
const plugin = await import('plugin-que-accede-window-en-la-importacion')
const plugin = await import('plugin-que-accede-a-window-en-la-importacion')
app.use(plugin.default)
}
}
@ -80,14 +80,14 @@ export default {
### `defineClientComponent`
VitePress proporciona un auxiliar de conveniencia para importar componentes Vue que acceden APIs del navegador en la importación.
VitePress proporciona un auxiliar de conveniencia (helper) para importar componentes Vue que acceden a las APIs del navegador al ser importados.
```vue
<script setup>
import { defineClientComponent } from 'vitepress'
const ClientComp = defineClientComponent(() => {
return import('componente-que-accede-window-en-la-importacion')
return import('componente-que-accede-a-window-en-la-importacion')
})
</script>
@ -96,7 +96,7 @@ const ClientComp = defineClientComponent(() => {
</template>
```
Puede también pasar propiedades/hijos/_slots_ para el componente objetivo:
Puede pasar propiedades/hijos/_slots_ al componente objetivo:
```vue
<script setup>
@ -105,9 +105,9 @@ import { defineClientComponent } from 'vitepress'
const clientCompRef = ref(null)
const ClientComp = defineClientComponent(
() => import('componente-que-acessa-window-na-importacao'),
() => import('componente-que-accede-a-window-en-la-importacion'),
// los argumentos son pasados para h() - https://vuejs.org/api/render-function.html#h
// los argumentos se pasan a h() - https://vuejs.org/api/render-function.html#h
[
{
ref: clientCompRef

@ -128,7 +128,7 @@ Si un componente fuera usado en la mayoría de las páginas, ellos pueden ser re
Asegurese de que el nombre de un componente personalizado contenga un hífen o esté en PascalCase. Caso contrario, el será tratado como un elemento alineado y envuelto dentro de una tag `<p>`, lo que llevará a una incompatibilidad de hidratación pues `<p>` no permite que elementos de bloque sean colocados dentro de el.
:::
### Usando Componentes En Headers <ComponenteEnHeader /> {#using-components-in-headers}
### Usando Componentes En Headers <ComponentInHeader /> {#using-components-in-headers}
Puede usar componentes Vue en los headers, pero observe la diferencia entre las siguientes sintaxis:

@ -1,10 +1,10 @@
# Qué es VitePress? {#what-is-vitepress}
# ¿Qué es VitePress? {#what-is-vitepress}
VitePress es un [Generador de Sitios Estáticos](https://en.wikipedia.org/wiki/Static_site_generator) (SSG) proyectado para crear sitios rápidos y centrados en contenido. En suma, VitePress utiliza su contenido fuente escrito en [Markdown](https://en.wikipedia.org/wiki/Markdown), aplica un tema a el y genera páginas HTML estáticas que pueden ser facilmente implantadas en cualquier lugar.
VitePress es un [Generador de Sitios Estáticos](https://en.wikipedia.org/wiki/Static_site_generator) (SSG) diseñado para construir sitios web rápidos y enfocados en el contenido. En pocas palabras, VitePress toma tu contenido fuente escrito en [Markdown](https://en.wikipedia.org/wiki/Markdown), le aplica un tema y genera páginas HTML estáticas que se pueden desplegar fácilmente en cualquier lugar.
<div class="tip custom-block" style="padding-top: 8px">
Quiere apenas experimentar? Valla al [Início Rápido](./getting-started).
¿Quieres probarlo? Ve directo al [Inicio Rápido](./getting-started).
</div>
@ -12,46 +12,46 @@ Quiere apenas experimentar? Valla al [Início Rápido](./getting-started).
- **Documentación**
VitePress viene con un tema por defecto proyectado para documentación técnica. El alimenta esta página que está leyendo ahora, juntamente con la documentación [Vite](https://vitejs.dev/), [Rollup](https://rollupjs.org/), [Pinia](https://pinia.vuejs.org/), [VueUse](https://vueuse.org/), [Vitest](https://vitest.dev/), [D3](https://d3js.org/), [UnoCSS](https://unocss.dev/), [Iconify](https://iconify.design/) e [muchos otros](https://www.vuetelescope.com/explore?framework.slug=vitepress).
VitePress incluye un tema por defecto diseñado para documentación técnica. Este tema es el que se utiliza en la página que estás leyendo ahora, así como en la documentación de [Vite](https://vitejs.dev/), [Rollup](https://rollupjs.org/), [Pinia](https://pinia.vuejs.org/), [VueUse](https://vueuse.org/), [Vitest](https://vitest.dev/), [D3](https://d3js.org/), [UnoCSS](https://unocss.dev/), [Iconify](https://iconify.design/) y [muchos otros](https://github.com/search?q=/"vitepress":+/+language:json&type=code).
La [documentación oficial Vue.js](https://vuejs.org/) también está basada en VitePress, pero usa un tema personalizado compartido entre varias traducciones.
La [documentación oficial Vue.js](https://vuejs.org/) también está basada en VitePress, pero utiliza un tema personalizado compartido entre varias traducciones.
- **Blogs, Portfólios y sitios de Marketing**
- **Blogs, Portfolios y sitios de Marketing**
VitePress soporta [temas totalmente personalizables](./custom-theme), con la experiencia de desarrollador por defecto de una aplicaciónn Vite + Vue. La construcción con Vite significa que puede aprovechar directamente plugins Vite de su rico ecosistema. Adicionalmente, VitePress proporciona APIs flexibles para[cargar datos](./data-loading) (locales o remotos) y [generar rutas dinámicamente](./routing#dynamic-routes). Puede usarlo para construir practicamente cualquier cosa desde que los datos puedan ser determinados en el momento del build.
VitePress soporta [temas completamente personalizables](./custom-theme), con la experiencia de desarrollo de una aplicación estándar de Vite + Vue. Al estar construido sobre Vite, también puedes aprovechar directamente los plugins de su rico ecosistema. Adicionalmente, VitePress proporciona APIs flexibles para [cargar datos](./data-loading) (locales o remotos) y [generar rutas dinámicamente](./routing#dynamic-routes). Puedes usarlo para construir prácticamente cualquier cosa, siempre y cuando los datos puedan ser determinados en el momento de la construcción.
El [blog oficial Vue.js](https://blog.vuejs.org/) es un blog simple que genera su página inicial basada en contenido local.
El [blog oficial Vue.js](https://blog.vuejs.org/) es un blog simple que genera su página de inicio basándose en contenido local.
## Experiencia de Desarrollador {#developer-experience}
VitePress visa proporcionar excelente Experiencia de Desarrollador (DX) al trabajar con contenido en Markdown.
VitePress busca ofrecer una excelente Experiencia de Desarrollador (DX) al trabajar con contenido Markdown.
- **[Alimentado por Vite:](https://vitejs.dev/)** inicialización instantánea del servidor, con ediciones siempre reflejadas instantáneamente (<100ms) sin recarga de página.
- **[Con tecnología Vite:](https://vitejs.dev/)** inicio instantáneo del servidor, con los cambios reflejados al instante (<100ms) sin recargar la página.
- **[Extensiones Markdown Integradas:](./markdown)** Frontmatter, tablas, destaque de sintaxis... usted escoje. Especificamente, VitePress proporciona muchos recursos para trabajar con bloques de código, tornandolo ideal para documentación altamente técnica.
- **[Extensiones Markdown Integradas:](./markdown)** Frontmatter, tablas, destaque de sintaxis... tú decides. Específicamente, VitePress proporciona muchos recursos para trabajar con bloques de código, tornándolo ideal para documentación altamente técnica.
- **[Markdown Mejorado por Vue:](./using-vue)** cada página Markdown es también un [Componente de Archivo único](https://pt.vuejs.org/guide/scaling-up/sfc.html), gracias a la compatibilidad de sintaxis de 100% del template Vue con HTML. Puede también incorporar iteractividad con su contenido estático usando recursos de template Vue o componentes Vue importados.
- **[Markdown Mejorado con Vue:](./using-vue)** cada página Markdown es también un [Componente de Archivo único](https://vuejs.org/guide/scaling-up/sfc.html) de Vue, gracias a la compatibilidad del 100% de la sintaxis de las plantillas de Vue con HTML. Puedes incrustar interactividad en tu contenido estático usando las funciones de plantillas de Vue o componentes de Vue importados.
## Desempeño {#performance}
Al contrario de muchos SSGs tradicionales, un sitio generado por VitePress es la verdad una [Single Page Application](https://en.wikipedia.org/wiki/Single-page_application) (SPA).
A diferencia de muchos SSG tradicionales donde cada navegación resulta en una recarga completa de la página, un sitio web generado por VitePress sirve HTML estático en la visita inicial, pero se convierte en una [Single Page Application](https://en.wikipedia.org/wiki/Single-page_application) (SPA) para las navegaciones posteriores dentro del sitio. Este modelo, en nuestra opinión, ofrece un equilibrio óptimo para el rendimiento:
- **Carga Inicial Rápida**
La visita inicial a cualquier página será servida con el HTML estático pré-renderizado para velocidad de carga rápida y SEO optimizado. La página entonces carga un paquete JavaScript que transforma la página en una SPA Vue ("hidratación"). El proceso de hidratación es extremadamente rápido: en [PageSpeed Insights](https://pagespeed.web.dev/report?url=https%3A%2F%2Fvitepress.dev%2F), sitios típicos VitePress alcanzan puntuaciones de desempeño casi perfectas, incluso en dispositivos móbiles de bajo desempeño con una red lenta.
La visita inicial a cualquier página será servida con el HTML estático pre-renderizado para una velocidad de carga rápida y SEO óptimo. La página entonces carga un paquete JavaScript que transforma la página en una SPA de Vue (a este proceso se le llama "hidratación"). A diferencia de la creencia popular de que la hidratación de una SPA es lenta, este proceso es de hecho extremadamente rápido gracias al rendimiento nativo y a las optimizaciones del compilador de Vue 3. En [PageSpeed Insights](https://pagespeed.web.dev/report?url=https%3A%2F%2Fvitepress.dev%2F), los sitios típicos VitePress alcanzan puntuaciones de desempeño casi perfectas, incluso en dispositivos móbiles de gama baja con una red lenta.
- **Navegación Rápida pos-carga**
Más importante todavía, el modelo SPA lleva a una mejor experiencia del usuario **después** de la carga inicial. La navegación subsequente dentro del sitio no causará una recarga adicional completa de la página. En vez de eso, el contenido de la página de entrada será buscado y actualizado dinámicamente. VitePress también pre-carga automáticamente pedazos de página para links que están dentro del viewport. En la mayoría de los casos, la navegación pos-carga parecerá instantánea.
Más importante aún, el modelo SPA conduce a una mejor experiencia de usuario **después** de la carga inicial. Las navegaciones posteriores dentro del sitio ya no causarán una recarga completa de la página. En vez de eso, el contenido de la página a la que se accede se buscará y actualizará dinámicamente. VitePress también pre-carga automáticamente fragmentos de las páginas para los enlaces que están dentro del viewport. En la mayoría de los casos, la navegación pos-carga se sentirá instantánea.
- **Interactividad Sin Penalidades**
- **Interactividad Sin Penalización**
Para ser capaz de hidratar las partes dinámicas Vue incorporadas dentro del Markdown estático, cada página Markdown es procesada como un componente Vue y compilada en JavaScript. Esto puede parecer ineficiente, pero el compilador Vue es suficientemente inteligente para separar las partes estáticas y dinámicas, minimizando tanto el costo de hidratación así como el tamaño de carga. Para la carga inicial de la página, las partes estáticas son automáticamente eliminadas de la carga JavaScript y omitidas durante la hidratación.
Para ser capaz de hidratar las partes dinámicas de Vue incrustadas dentro del Markdown estático, cada página Markdown es procesada como un componente Vue y compilada en JavaScript. Esto puede parecer ineficiente, pero el compilador de Vue es lo suficientemente inteligente como para separar las partes estáticas y dinámicas, minimizando tanto el costo de hidratación así como el tamaño de carga útil (payload). Para la carga inicial de la página, las partes estáticas son automáticamente eliminadas del payload de JavaScript y se omiten durante la hidratación.
## Y VuePress? {#what-about-vuepress}
## ¿Y VuePress? {#what-about-vuepress}
VitePress es el sucesor espiritual de VuePress. VuePress era orginalmente basado en Vue 2 y webpack. Con Vue 3 y Vite, VitePress ofrece una experiencia de desarrollador significamente mejor, mejor desempeño en producción, un tema por defecto más pulido y un API de personalización más flexible.
VitePress es el sucesor espiritual de VuePress. El VuePress original se basó en Vue 2 y webpack. Con Vue 3 y Vite como base, VitePress ofrece una Experiencia de Desarrollador (DX) significativamente mejor, un mejor rendimiento en producción, un tema por defecto más pulido y una API de personalización más flexible.
A diferencia del API entre VitePress y VuePress reside principalmente en temas y personalización. Si estuviera usando VuePress 1 con el tema por defecto, la migración para VitePress debe ser relativamente simple.
La diferencia entre la API de VitePress y VuePress radica principalmente en los temas y la personalización. Si estás usando VuePress 1 con el tema por defecto, debería ser relativamente sencillo migrar a VitePress.
También hubo esfuerzo invertido en VuePress 2, que también soporta Vue 3 y Vite con mejor compatibilidad que con VuePress 1. Sin embargo, mantener dos SSGs en paralelo no es sustentable, entonces el equipo Vue decidió enfocarse en VitePress como el principal SSG recomendado a largo plazo.
También se ha invertido esfuerzo en VuePress 2, que también es compatible con Vue 3 y Vite, y tiene mayor compatibilidad con VuePress 1. Sin embargo, mantener dos SSG en paralelo no es sostenible, por lo que el equipo de Vue ha decidido centrarse en VitePress como el principal SSG recomendado a largo plazo.

@ -1,9 +1,6 @@
---
layout: home
title: VitePress
titleTemplate: Generador de Sitios Estáticos desarrollado con Vite y Vue
hero:
name: VitePress
text: Generador de Sitios Estáticos Vite y Vue
@ -11,10 +8,10 @@ hero:
actions:
- theme: brand
text: Qué es VitePress?
link: /es/guide/what-is-vitepress
link: ./guide/what-is-vitepress
- theme: alt
text: Iniciar
link: /es/guide/getting-started
link: ./guide/getting-started
- theme: alt
text: GitHub
link: https://github.com/vuejs/vitepress

@ -43,7 +43,6 @@ vitepress build [root]
| `--base <path>` | Ruta de base pública (por defecto: `/`) (`string`) |
| `--target <target>` | Transpilar objetivo (por defecto: `"modules"`) (`string`) |
| `--outDir <dir>` | Directorio de salida relativo a **cwd** (por defecto: `<root>/.vitepress/dist`) (`string`) |
| `--minify [minifier]` | Habilitar/desabilitar la minificación, o especifica un minero para usar (por defecto: `"esbuild"`) (`boolean \| "terser" \| "esbuild"`) |
| `--assetsInlineLimit <number>` | Limitar los bytes para alinear los activos en base 64 (por defecto: `4096`) (`number`) |
## `vitepress preview`

@ -89,7 +89,7 @@ type NavItem = NavItemWithLink | NavItemWithChildren
interface NavItemWithLink {
text: string
link: string
link: string | ((payload: PageData) => string)
activeMatch?: string
target?: string
rel?: string

@ -55,6 +55,8 @@ export default {
`text` es el texto que se muestra en la navegación, y el `link` es el link al que será navegando cuando se hace click en el texto. Para el enlace, establezca la ruta al archivo sin el prefijo `.md` y siempre comenzar por `/`.
El `link` también puede ser una función que acepte [`PageData`](./runtime-api#usedata) como argumento y devuelva la ruta.
Links de navegación también pueden ser menus _dropdown_. Para hacer eso, establezca la clave de `items` en la opción del link.
```js

@ -216,16 +216,19 @@ export default defineConfig({
zh: {
placeholder: '搜索文档',
translations: {
button: {
buttonText: '搜索文档',
buttonAriaLabel: '搜索文档'
},
button: { buttonText: '搜索文档', buttonAriaLabel: '搜索文档' },
modal: {
searchBox: {
resetButtonTitle: '清除查询条件',
resetButtonAriaLabel: '清除查询条件',
cancelButtonText: '取消',
cancelButtonAriaLabel: '取消'
clearButtonTitle: '清除查询条件',
clearButtonAriaLabel: '清除查询条件',
closeButtonText: '关闭',
closeButtonAriaLabel: '关闭',
placeholderText: '搜索文档',
placeholderTextAskAi: '向 AI 提问:',
placeholderTextAskAiStreaming: '回答中...',
searchInputLabel: '搜索',
backToKeywordSearchButtonText: '返回关键字搜索',
backToKeywordSearchButtonAriaLabel: '返回关键字搜索'
},
startScreen: {
recentSearchesTitle: '搜索历史',
@ -233,23 +236,46 @@ export default defineConfig({
saveRecentSearchButtonTitle: '保存至搜索历史',
removeRecentSearchButtonTitle: '从搜索历史中移除',
favoriteSearchesTitle: '收藏',
removeFavoriteSearchButtonTitle: '从收藏中移除'
removeFavoriteSearchButtonTitle: '从收藏中移除',
recentConversationsTitle: '最近的对话',
removeRecentConversationButtonTitle: '从历史记录中删除对话'
},
errorScreen: {
titleText: '无法获取结果',
helpText: '你可能需要检查你的网络连接'
},
footer: {
selectText: '选择',
navigateText: '切换',
closeText: '关闭',
searchByText: '搜索提供者'
},
noResultsScreen: {
noResultsText: '无法找到相关结果',
suggestedQueryText: '你可以尝试查询',
reportMissingResultsText: '你认为该查询应该有结果?',
reportMissingResultsLinkText: '点击反馈'
},
resultsScreen: { askAiPlaceholder: '向 AI 提问: ' },
askAiScreen: {
disclaimerText: '答案由 AI 生成,可能不准确,请自行验证。',
relatedSourcesText: '相关来源',
thinkingText: '思考中...',
copyButtonText: '复制',
copyButtonCopiedText: '已复制!',
copyButtonTitle: '复制',
likeButtonTitle: '赞',
dislikeButtonTitle: '踩',
thanksForFeedbackText: '感谢你的反馈!',
preToolCallText: '搜索中...',
duringToolCallText: '搜索 ',
afterToolCallText: '已搜索'
},
footer: {
selectText: '选择',
submitQuestionText: '提交问题',
selectKeyAriaLabel: 'Enter 键',
navigateText: '切换',
navigateUpKeyAriaLabel: '向上箭头',
navigateDownKeyAriaLabel: '向下箭头',
closeText: '关闭',
backToSearchText: '返回搜索',
closeKeyAriaLabel: 'Esc 键',
poweredByText: '搜索提供者'
}
}
}
@ -261,6 +287,26 @@ export default defineConfig({
})
```
### Algolia Ask AI Support {#ask-ai}
Si deseas incluir **Ask AI**, pasa la opción `askAi` (o alguno de sus campos parciales) dentro de `options`:
```ts
options: {
appId: '...',
apiKey: '...',
indexName: '...',
// askAi: 'TU-ASSISTANT-ID'
askAi: {
assistantId: 'XXXYYY'
}
}
```
::: warning Nota
Si prefieres solo la búsqueda por palabra clave y no la Ask AI, simplemente omite `askAi`.
:::
[Estas opciones](https://github.com/vuejs/vitepress/blob/main/types/docsearch.d.ts) se pueden superponer. Consulte la documentación oficial de Algolia para obtener más información sobre ellos.
### Configuración _Crawler_ {#crawler-config}

@ -181,36 +181,3 @@ export default {
}
}
```
## `useSidebar` <Badge type="info" text="composable" />
Devuelve datos relacionados con la barra lateral. El objeto devuelto tiene el siguiente tipo:
```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
}
```
**Exemplo:**
```vue
<script setup>
import { useSidebar } from 'vitepress/theme'
const { hasSidebar } = useSidebar()
</script>
<template>
<div v-if="hasSidebar">Sólo visible cuando existe la barra lateral</div>
</template>
```

@ -53,12 +53,12 @@ const members = [
Saluda a nuestro increible equipo.
<VPTeamMembers size="small" :members="members" />
<VPTeamMembers size="small" :members />
```
El código anterior mostrará a un miembro del equipo en un elemento similar a una tarjeta. Debería mostrar algo similar a lo siguiente.
<VPTeamMembers size="small" :members="members" />
<VPTeamMembers size="small" :members />
El componente `<VPTeamMembers>` viene en dos tamaños diferentes, pequeño `small` y médio `medium`. Si bien es una cuestión de preferencia, generalmente el tamaño `small` debería encajar mejor cuando se use en la página del documento. Además, puede agregar más propiedades a cada miembro, como agregar el botón "descripción" o "patrocinador". Obtenga más información sobre en [`<VPTeamMembers>`](#vpteammembers).
@ -107,9 +107,7 @@ const members = [
Algunos de los miembros han elegido aparecer a continuación.
</template>
</VPTeamPageTitle>
<VPTeamMembers
:members="members"
/>
<VPTeamMembers :members />
</VPTeamPage>
```

@ -24,7 +24,7 @@ export default {
}
```
:::details Configuración dinámica (Assíncrona)
::: details Configuración dinámica (Assíncrona)
Si necesitas generar dinamicamente la configuración, también puedes exportar por defecto una función. Por ejemplo:
@ -458,7 +458,7 @@ export default {
### ignoreDeadLinks
- Tipo: `boolean | 'localhostLinks' | (string | RegExp | ((link: string) => boolean))[]`
- Tipo: `boolean | 'localhostLinks' | (string | RegExp | ((link: string, source: string) => boolean))[]`
- Predeterminado: `false`
Cuando se establece en `true`, VitePress no dejará de compilarse debido a links rotos.
@ -613,7 +613,7 @@ export default {
`transformHead` es un enlace de compilación para transformar el encabezado antes de generar cada página. Esto le permite agregar entradas de encabezado que no se pueden agregar estáticamente a la configuración de VitePress. Sólo necesita devolver entradas adicionales, que se fusionarán automáticamente con las existentes.
:::warning
::: warning
No mutes ningún elemento dentro `context`.
:::
@ -681,7 +681,7 @@ export default {
- Tipo: `(code: string, id: string, context: TransformContext) => Awaitable<string | void>`
`transformHtml` es un gancho de compilación para transformar el contenido de cada página antes de guardarla en el disco.
:::warning
::: warning
No mute ningún elemento dentro del `context`. Además, modificar el contenido HTML puede provocar problemas de hidratación en tiempo de ejecución.
:::
@ -698,7 +698,7 @@ export default {
`transformPageData` es un gancho para transformar los datos de cada página. Puedes hacer mutaciones directamente en `pageData` o devolver valores modificados que se fusionarán con los datos de la página.
:::warning
::: warning
No mute ningún elemento dentro del `context` y tenga cuidado ya que esto puede afectar el rendimiento del servidor de desarrollo, especialmente si tiene algunas solicitudes de red o cálculos pesados (como generar imágenes) en el gancho. Puede consultar `process.env.NODE_ENV === 'production'` para ver la lógica condicional.
:::

@ -1,25 +1,24 @@
import { createRequire } from 'module'
import { defineConfig, type DefaultTheme } from 'vitepress'
import { defineAdditionalConfig, type DefaultTheme } from 'vitepress'
const require = createRequire(import.meta.url)
const pkg = require('vitepress/package.json')
export const fa = defineConfig({
title: 'ویت‌پرس',
lang: 'fa-IR',
description: 'Vite & Vue powered static site generator.',
dir: 'rtl',
markdown: {
container: {
tipLabel: 'نکته',
warningLabel: 'هشدار',
dangerLabel: 'خطر',
infoLabel: 'اطلاعات',
detailsLabel: 'جزئیات'
}
},
export default defineAdditionalConfig({
description: 'ژنراتور استاتیک وب‌سایت با Vite و Vue',
// prettier-ignore
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=Vazirmatn:wght@100..900&display=swap', rel: 'stylesheet' }],
],
themeConfig: {
nav: nav(),
search: { options: searchOptions() },
sidebar: {
'/fa/guide/': { base: '/fa/guide/', items: sidebarGuide() },
'/fa/reference/': { base: '/fa/reference/', items: sidebarReference() }
@ -45,11 +44,15 @@ export const fa = defineConfig({
},
lastUpdated: {
text: 'آخرین به‌روزرسانی‌',
formatOptions: {
dateStyle: 'short',
timeStyle: 'medium'
}
text: 'آخرین به‌روزرسانی‌'
},
notFound: {
title: 'صفحه پیدا نشد',
quote:
'اما اگر جهت خود را تغییر ندهید و همچنان به جستجو ادامه دهید، ممکن است در نهایت به جایی برسید که در حال رفتن به آن هستید.',
linkLabel: 'برو به خانه',
linkText: 'من را به خانه ببر'
},
langMenuLabel: 'تغییر زبان',
@ -58,14 +61,6 @@ export const fa = defineConfig({
darkModeSwitchLabel: 'تم تاریک',
lightModeSwitchTitle: 'رفتن به حالت روشن',
darkModeSwitchTitle: 'رفتن به حالت تاریک',
notFound: {
linkLabel: 'بازگشت به خانه',
linkText: 'بازگشت به خانه',
title: 'صفحه مورد نظر یافت نشد',
code: '۴۰۴',
quote:
'اما اگر جهت خود را تغییر ندهید و اگر ادامه دهید به دنبال چیزی که دنبال می‌کنید، ممکن است در نهایت به جایی که در حال رفتن به سمتش هستید، برسید.'
},
siteTitle: 'ویت‌پرس'
}
})
@ -85,6 +80,10 @@ function nav(): DefaultTheme.NavItem[] {
{
text: pkg.version,
items: [
{
text: '1.6.4',
link: 'https://vuejs.github.io/vitepress/v1/fa/'
},
{
text: 'Changelog',
link: 'https://github.com/vuejs/vitepress/blob/main/CHANGELOG.md'
@ -181,8 +180,8 @@ function sidebarReference(): DefaultTheme.SidebarItem[] {
]
}
export const search: DefaultTheme.AlgoliaSearchOptions['locales'] = {
fa: {
function searchOptions(): Partial<DefaultTheme.AlgoliaSearchOptions> {
return {
placeholder: 'جستجوی مستندات',
translations: {
button: {
@ -191,31 +190,67 @@ export const search: DefaultTheme.AlgoliaSearchOptions['locales'] = {
},
modal: {
searchBox: {
resetButtonTitle: 'آغاز مجدد جستجو',
resetButtonAriaLabel: 'آغاز مجدد جستجو',
cancelButtonText: 'لغو',
cancelButtonAriaLabel: 'لغو'
clearButtonTitle: 'پاک کردن جستجو',
clearButtonAriaLabel: 'پاک کردن جستجو',
closeButtonText: 'بستن',
closeButtonAriaLabel: 'بستن',
placeholderText: 'جستجوی مستندات',
placeholderTextAskAi: 'از هوش مصنوعی بپرسید: ',
placeholderTextAskAiStreaming: 'در حال پاسخ...',
searchInputLabel: 'جستجو',
backToKeywordSearchButtonText: 'بازگشت به جستجوی کلیدواژه',
backToKeywordSearchButtonAriaLabel: 'بازگشت به جستجوی کلیدواژه'
},
startScreen: {
recentSearchesTitle: 'جستجو‌های اخیر',
noRecentSearchesText: 'تاریخچه جستجویی یافت نشد.',
saveRecentSearchButtonTitle: 'ذخیره تاریخچه جستجو',
removeRecentSearchButtonTitle: 'حذف تاریخچه جستجو',
favoriteSearchesTitle: 'موارد دلخواه',
removeFavoriteSearchButtonTitle: 'حذف مورد دلخواه'
recentSearchesTitle: 'جستجوهای اخیر',
noRecentSearchesText: 'هیچ جستجوی اخیر',
saveRecentSearchButtonTitle: 'ذخیره در تاریخچه جستجو',
removeRecentSearchButtonTitle: 'حذف از تاریخچه جستجو',
favoriteSearchesTitle: 'علاقه‌مندی‌ها',
removeFavoriteSearchButtonTitle: 'حذف از علاقه‌مندی‌ها',
recentConversationsTitle: 'گفتگوهای اخیر',
removeRecentConversationButtonTitle: 'حذف این گفتگو از تاریخچه'
},
errorScreen: {
titleText: 'نتیجه‌ای یافت نشد برای',
titleText: 'عدم امکان دریافت نتایج',
helpText: 'اتصال شبکه خود را بررسی کنید'
},
noResultsScreen: {
noResultsText: 'هیچ نتیجه‌ای یافت نشد',
suggestedQueryText: 'می‌توانید جستجوی دیگری امتحان کنید',
reportMissingResultsText: 'فکر می‌کنید باید نتیجه‌ای نمایش داده شود؟',
reportMissingResultsLinkText: 'برای ارسال بازخورد کلیک کنید'
},
resultsScreen: {
askAiPlaceholder: 'از هوش مصنوعی بپرسید: '
},
askAiScreen: {
disclaimerText:
'پاسخ‌ها توسط هوش مصنوعی تولید می‌شوند و ممکن است خطا داشته باشند. لطفاً بررسی کنید.',
relatedSourcesText: 'منابع مرتبط',
thinkingText: 'در حال پردازش...',
copyButtonText: 'کپی',
copyButtonCopiedText: 'کپی شد!',
copyButtonTitle: 'کپی',
likeButtonTitle: 'پسندیدم',
dislikeButtonTitle: 'نپسندیدم',
thanksForFeedbackText: 'از بازخورد شما سپاسگزاریم!',
preToolCallText: 'در حال جستجو...',
duringToolCallText: 'در حال جستجو برای ',
afterToolCallText: 'جستجو انجام شد',
aggregatedToolCallText: 'جستجو انجام شد'
},
footer: {
selectText: 'انتخاب',
navigateText: 'رفتن',
submitQuestionText: 'ارسال پرسش',
selectKeyAriaLabel: 'کلید Enter',
navigateText: 'حرکت',
navigateUpKeyAriaLabel: 'کلید جهت بالا',
navigateDownKeyAriaLabel: 'کلید جهت پایین',
closeText: 'بستن',
searchByText: ' جستجو با '
},
noResultsScreen: {
noResultsText: 'نتیجه‌ای یافت نشد برای'
backToSearchText: 'بازگشت به جستجو',
closeKeyAriaLabel: 'کلید Escape',
poweredByText: 'جستجو توسط'
}
}
}

@ -161,7 +161,7 @@ Cache-Control: max-age=31536000,immutable
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
node-version: 22
cache: npm # or pnpm / yarn
- name: Setup Pages
uses: actions/configure-pages@v4

@ -70,7 +70,7 @@ export default DefaultTheme
export default {
transformHead({ assets }) {
// منظور شده برای همسان سازی font خود، regex مورد نیاز را تنظیم کنید
const myFontFile = assets.find(file => /font-name\.\w+\.woff2/)
const myFontFile = assets.find(file => /font-name\.[\w-]+\.woff2/.test(file))
if (myFontFile) {
return [
[
@ -254,6 +254,7 @@ provide('toggle-appearance', async ({ clientX: x, clientY: y }: MouseEvent) => {
{
duration: 300,
easing: 'ease-in',
fill: 'forwards',
pseudoElement: `::view-transition-${isDark.value ? 'old' : 'new'}(root)`
}
)

@ -18,40 +18,19 @@
::: code-group
```sh [npm]
$ npm add -D vitepress
$ npm add -D vitepress@next
```
```sh [pnpm]
$ pnpm add -D vitepress
$ pnpm add -D vitepress@next
```
```sh [yarn]
$ yarn add -D vitepress
```
```sh [yarn (pnp)]
$ yarn add -D vitepress vue
$ yarn add -D vitepress@next vue
```
```sh [bun]
$ bun add -D vitepress
```
:::
::: details درباره peer dependency های ناموجود هشدار دریافت می‌کنید؟
اگر از PNPM استفاده می‌کنید، متوجه هشدار peer dependency برای `@docsearch/js` خواهید شد. این مسئله جلوی عملکرد ویت‌پرس را نمی‌گیرد. اگر می‌خواهید این هشدار را نادیده بگیرید، موارد زیر را به `package.json` خود اضافه کنید:
```json
"pnpm": {
"peerDependencyRules": {
"ignoreMissing": [
"@algolia/client-search",
"search-insights"
]
}
}
$ bun add -D vitepress@next
```
:::

@ -255,11 +255,11 @@ export default defineConfig({
}
```
این از [`postcss-prefix-selector`](https://github.com/postcss/postcss-load-config) استفاده می‌کند. می‌توانید گزینه‌های آن را به این صورت پاس بدهید:
می‌توانید گزینه‌های آن را به این صورت پاس بدهید:
```js
postcssIsolateStyles({
includeFiles: [/vp-doc\.css/] // به طور پیش‌فرض /base\.css/
includeFiles: [/custom\.css/] // به طور پیش‌فرض [/vp-doc\.css/, /base\.css/]
})
```

@ -12,7 +12,7 @@
- **مستندسازی**
ویت‌پرس با یک تم پیش‌فرض طراحی شده برای مستندات فنی ارائه می‌شود. این صفحه‌ای که اکنون در حال خواندن آن هستید و همچنین مستندات [Vite](https://vitejs.dev/)، [Rollup](https://rollupjs.org/)، [Pinia](https://pinia.vuejs.org/)، [VueUse](https://vueuse.org/)، [Vitest](https://vitest.dev/)، [D3](https://d3js.org/)، [UnoCSS](https://unocss.dev/)، [Iconify](https://iconify.design/) و [بسیاری دیگر](https://www.vuetelescope.com/explore?framework.slug=vitepress) با استفاده از ویت‌پرس ساخته شده‌اند.
ویت‌پرس با یک تم پیش‌فرض طراحی شده برای مستندات فنی ارائه می‌شود. این صفحه‌ای که اکنون در حال خواندن آن هستید و همچنین مستندات [Vite](https://vitejs.dev/)، [Rollup](https://rollupjs.org/)، [Pinia](https://pinia.vuejs.org/)، [VueUse](https://vueuse.org/)، [Vitest](https://vitest.dev/)، [D3](https://d3js.org/)، [UnoCSS](https://unocss.dev/)، [Iconify](https://iconify.design/) و [بسیاری دیگر](https://github.com/search?q=/"vitepress":+/+language:json&type=code) با استفاده از ویت‌پرس ساخته شده‌اند.
[مستندات رسمی Vue.js](https://vuejs.org/) نیز بر پایه ویت‌پرس ساخته شده است، اما از یک تم سفارشی که بین چندین ترجمه مشترک است استفاده می‌کند.

@ -1,9 +1,6 @@
---
layout: home
title: ویت‌پرس
titleTemplate: Vite & Vue Powered Static Site Generator
hero:
name: ویت‌پرس
text: سازنده سایت‌های ایستا به کمک Vite و Vue

@ -43,7 +43,6 @@ vitepress build [root]
| `--base <path>` | مسیر پایه عمومی (پیش‌فرض: `/`) (`string`) |
| `--target <target>` | هدف ترنسپایل (پیش‌فرض: `"modules"`) (`string`) |
| `--outDir <dir>` | دایرکتوری خروجی نسبت به **cwd** (پیش‌فرض: `<root>/.vitepress/dist`) (`string`) |
| `--minify [minifier]` | فعال یا غیرفعال کردن فشرده‌سازی، یا تعیین فشرده‌سازی برای استفاده (پیش‌فرض: `"esbuild"`) (`boolean \| "terser" \| "esbuild"`) |
| `--assetsInlineLimit <number>` | آستانه تبدیل پایه ۶۴ استاتیک به بایت (پیش‌فرض: `4096`) (`number`) |
## `vitepress preview` {#vitepress-preview}

@ -89,7 +89,7 @@ type NavItem = NavItemWithLink | NavItemWithChildren
interface NavItemWithLink {
text: string
link: string
link: string | ((payload: PageData) => string)
activeMatch?: string
target?: string
rel?: string

@ -55,6 +55,8 @@ export default {
`text` متن واقعی است که در ناوبری نمایش داده می‌شود و `link` لینکی است که هنگام کلیک بر روی متن به آن ناوبری می‌شود. برای لینک، مسیر را به صورت واقعی بدون پیشوند `.md` تنظیم کنید و همیشه با `/` شروع کنید.
`link` همچنین می‌تواند تابعی باشد که [`PageData`](./runtime-api#usedata) را به عنوان آرگومان بپذیرد و مسیر را برگرداند.
لینک‌های ناوبری همچنین می‌توانند منوهای کشویی باشند. برای این کار، کلید `items` را در گزینه لینک تنظیم کنید.
```js

@ -212,9 +212,7 @@ export default defineConfig({
import { defineConfig } from 'vitepress'
export default defineConfig({
themeConfig:
{
themeConfig: {
search: {
provider: 'algolia',
options: {
@ -223,40 +221,40 @@ export default defineConfig({
indexName: '...',
locales: {
zh: {
placeholder: 'جستجو در مستندات',
placeholder: '搜索文档',
translations: {
button: {
buttonText: 'جستجو در مستندات',
buttonAriaLabel: 'جستجو در مستندات'
buttonText: '搜索文档',
buttonAriaLabel: '搜索文档'
},
modal: {
searchBox: {
resetButtonTitle: 'پاک کردن شرایط جستجو',
resetButtonAriaLabel: 'پاک کردن شرایط جستجو',
cancelButtonText: 'لغو',
cancelButtonAriaLabel: 'لغو'
resetButtonTitle: '清除搜索条件',
resetButtonAriaLabel: '清除搜索条件',
cancelButtonText: '取消',
cancelButtonAriaLabel: '取消'
},
startScreen: {
recentSearchesTitle: 'تاریخچه جستجو',
noRecentSearchesText: 'هیچ تاریخچه جستجویی وجود ندارد',
saveRecentSearchButtonTitle: 'ذخیره در تاریخچه جستجو',
removeRecentSearchButtonTitle: 'حذف از تاریخچه جستجو'
recentSearchesTitle: '最近搜索',
noRecentSearchesText: '没有最近搜索',
saveRecentSearchButtonTitle: '保存到最近搜索',
removeRecentSearchButtonTitle: '从最近搜索中删除'
},
errorScreen: {
titleText: 'نمایش نتایج امکان‌پذیر نیست',
helpText: 'شما ممکن است نیاز به بررسی اتصال اینترنت خود داشته باشید'
titleText: '无法显示结果',
helpText: '您可能需要检查您的互联网连接'
},
footer: {
selectText: 'انتخاب',
navigateText: 'جابجایی',
closeText: 'بستن',
searchByText: 'جستجو توسط'
selectText: '选择',
navigateText: '导航',
closeText: '关闭',
searchByText: '搜索由'
},
noResultsScreen: {
noResultsText: 'نتیجه‌ای پیدا نشد',
suggestedQueryText: 'می‌توانید امتحان کنید',
reportMissingResultsText: 'فکر می‌کنید باید نتایجی وجود داشته باشد؟',
reportMissingResultsLinkText: 'برای بازخورد کلیک کنید'
noResultsText: '没有找到结果',
suggestedQueryText: '您可以尝试',
reportMissingResultsText: '您认为应该有结果吗?',
reportMissingResultsLinkText: '点击这里报告'
}
}
}
@ -377,3 +375,22 @@ new Crawler({
}
})
```
### پشتیبانی Algolia Ask AI {#ask-ai}
برای فعال‌سازی **Ask AI** کافی است گزینه `askAi` را اضافه کنید:
```ts
options: {
appId: '...',
apiKey: '...',
indexName: '...',
askAi: {
assistantId: 'XXXYYY'
}
}
```
::: warning نکته
اگر فقط به جستجوی کلمات کلیدی نیاز دارید، `askAi` را اضافه نکنید.
:::

@ -178,38 +178,3 @@ export default {
}
}
```
## `useSidebar` <Badge type="info" text="composable" /> {#usesidebar}
داده‌های مربوط به نوار کناری را برمی‌گرداند. شیء برگردانده شده دارای نوع‌های زیر است:
```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">فقط ن
مایش داده شود زمانی که نوار کناری وجود دارد</div>
</template>
```

@ -53,12 +53,12 @@ const members = [
با سلام به تیم فوق‌العاده‌ی ما خوش آمدید.
<VPTeamMembers size="small" :members="members" />
<VPTeamMembers size="small" :members />
```
بالا به صورت عنصری با شکل کارتی اعضای تیم را نمایش می‌دهد. باید به شکل زیر نمایش داده شود.
<VPTeamMembers size="small" :members="members" />
<VPTeamMembers size="small" :members />
کامپوننت `<VPTeamMembers>` دارای دو اندازه مختلف، `small` و `medium` است. معمولاً اندازه `small` برای استفاده در صفحات مستندات مناسب‌تر است. همچنین می‌توانید ویژگی‌های بیشتری برای هر عضو اضافه کنید مانند "توضیحات" یا "دکمه حامی". جهت کسب اطلاعات بیشتر به [`<VPTeamMembers>`](#vpteammembers) مراجعه کنید.
@ -106,9 +106,7 @@ const members = [
توسعه ویت‌پرس توسط تیمی بین‌المللی راهنمایی می‌شود، برخی از اعضا که انتخاب کرده‌اند تا در زیر نمایش داده شوند.
</template>
</VPTeamPageTitle>
<VPTeamMembers
:members="members"
/>
<VPTeamMembers :members />
</VPTeamPage>
```

@ -24,7 +24,7 @@ export default {
}
```
:::details تنظیمات پویا (غیرهمزمان)
::: details تنظیمات پویا (غیرهمزمان)
اگر نیاز دارید به طور پویا تنظیمات را تولید کنید، می‌توانید یک تابع صادر کنید. به عنوان مثال:
@ -354,7 +354,7 @@ export default {
وقتی تنظیم شود به `true`، ویت‌پرس `.html` انتهایی را از URL ها حذف می‌کند. همچنین ببینید [تولید URL تمیز](../guide/routing#generating-clean-url).
::: هشدار نیاز به پشتیبانی سرور
::: warning هشدار نیاز به پشتیبانی سرور
فعال کردن این ممکن است نیاز به پیکربندی اضافی در پلتفرم میزبان شما داشته باشد. برای اینکه کار کند، سرور شما باید بتواند `/foo.html` را زمانی که `/foo` بازدید می‌شود **بدون ریدایرکت** سرو کند.
:::
@ -441,7 +441,7 @@ export default {
### ignoreDeadLinks
- نوع: `boolean | 'localhostLinks' | (string | RegExp | ((link: string) => boolean))[]`
- نوع: `boolean | 'localhostLinks' | (string | RegExp | ((link: string, source: string) => boolean))[]`
- پیش‌فرض: `false`
زمانی که به `true` تنظیم شود، ویت‌پرس به دلیل لینک‌های مرده ساخت‌ها را شکست نخواهد داد.

@ -0,0 +1,225 @@
import { createRequire } from 'module'
import { defineAdditionalConfig, type DefaultTheme } from 'vitepress'
const require = createRequire(import.meta.url)
const pkg = require('vitepress/package.json')
export default defineAdditionalConfig({
description: 'Vite と Vue による静的サイトジェネレーター',
themeConfig: {
nav: nav(),
search: { options: searchOptions() },
sidebar: {
'/ja/guide/': { base: '/ja/guide/', items: sidebarGuide() },
'/ja/reference/': { base: '/ja/reference/', items: sidebarReference() }
},
editLink: {
pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',
text: 'GitHub でこのページを編集'
},
footer: {
message: 'MIT ライセンスの下で公開されています。',
copyright: 'Copyright © 2019-present Evan You'
}
}
})
function nav(): DefaultTheme.NavItem[] {
return [
{
text: 'ガイド',
link: '/ja/guide/what-is-vitepress',
activeMatch: '/guide/'
},
{
text: 'リファレンス',
link: '/ja/reference/site-config',
activeMatch: '/reference/'
},
{
text: pkg.version,
items: [
{
text: '1.6.4',
link: 'https://vuejs.github.io/vitepress/v1/'
},
{
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: 'フロントマター', 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: 'サイトマップ生成', link: 'sitemap-generation' }
]
},
{
text: '設定 & API リファレンス',
base: '/ja/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: '/ja/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 広告', link: 'carbon-ads' }
]
}
]
}
]
}
function searchOptions(): Partial<DefaultTheme.AlgoliaSearchOptions> {
return {
placeholder: 'ドキュメントを検索',
translations: {
button: {
buttonText: '検索',
buttonAriaLabel: '検索'
},
modal: {
searchBox: {
clearButtonTitle: '検索をクリア',
clearButtonAriaLabel: '検索をクリア',
closeButtonText: '閉じる',
closeButtonAriaLabel: '閉じる',
placeholderText: 'ドキュメントを検索',
placeholderTextAskAi: 'AI に質問: ',
placeholderTextAskAiStreaming: '回答を作成中...',
searchInputLabel: '検索',
backToKeywordSearchButtonText: 'キーワード検索に戻る',
backToKeywordSearchButtonAriaLabel: 'キーワード検索に戻る'
},
startScreen: {
recentSearchesTitle: '検索履歴',
noRecentSearchesText: '最近の検索はありません',
saveRecentSearchButtonTitle: '検索履歴に保存',
removeRecentSearchButtonTitle: '検索履歴から削除',
favoriteSearchesTitle: 'お気に入り',
removeFavoriteSearchButtonTitle: 'お気に入りから削除',
recentConversationsTitle: '最近の会話',
removeRecentConversationButtonTitle: '会話履歴から削除'
},
errorScreen: {
titleText: '結果を取得できません',
helpText: 'ネットワーク接続を確認してください'
},
noResultsScreen: {
noResultsText: '結果が見つかりません',
suggestedQueryText: '別の検索語を試してください',
reportMissingResultsText: '結果があるはずだと思いますか?',
reportMissingResultsLinkText: 'フィードバックを送る'
},
resultsScreen: {
askAiPlaceholder: 'AI に質問: '
},
askAiScreen: {
disclaimerText:
'AI が生成した回答には誤りが含まれる可能性があります。必ずご確認ください。',
relatedSourcesText: '関連ソース',
thinkingText: '考え中...',
copyButtonText: 'コピー',
copyButtonCopiedText: 'コピーしました!',
copyButtonTitle: 'コピー',
likeButtonTitle: 'いいね',
dislikeButtonTitle: 'よくない',
thanksForFeedbackText: 'フィードバックありがとうございます!',
preToolCallText: '検索中...',
duringToolCallText: '検索中 ',
afterToolCallText: '検索完了',
aggregatedToolCallText: '検索完了'
},
footer: {
selectText: '選択',
submitQuestionText: '質問を送信',
selectKeyAriaLabel: 'Enter キー',
navigateText: '移動',
navigateUpKeyAriaLabel: '上矢印キー',
navigateDownKeyAriaLabel: '下矢印キー',
closeText: '閉じる',
backToSearchText: '検索に戻る',
closeKeyAriaLabel: 'Esc キー',
poweredByText: '提供: '
}
}
}
}
}

@ -0,0 +1,66 @@
# アセットの取り扱い {#asset-handling}
## 静的アセットの参照 {#referencing-static-assets}
すべての Markdown ファイルは Vue コンポーネントにコンパイルされ、[Vite](https://vitejs.dev/guide/assets.html) によって処理されます。Markdown 内では、相対 URL を使ってアセットを参照することが **推奨されます**。
```md
![画像](./image.png)
```
Markdown ファイル内、テーマの `*.vue` コンポーネント内、スタイルや通常の `.css` ファイル内でも、アセットはプロジェクトルートを基準とした絶対パス、またはファイルシステムを基準とした相対パスで参照できます。後者は Vite、Vue CLI、あるいは webpack の `file-loader` を使ったことがある場合に慣れ親しんだ挙動です。
一般的な画像、メディア、フォントファイルタイプは自動的にアセットとして検出され、含まれます。
::: tip リンクされたファイルはアセットとして扱われません
Markdown ファイル内のリンクで参照された PDF やその他のドキュメントは、自動的にアセットとして扱われません。これらのリンクファイルにアクセスできるようにするには、手動でプロジェクトの [`public`](#the-public-directory) ディレクトリに配置する必要があります。
:::
絶対パスを含むすべての参照されたアセットは、プロダクションビルド時にハッシュ化されたファイル名で出力ディレクトリにコピーされます。参照されないアセットはコピーされません。4kb 未満の画像アセットは base64 としてインライン化されます(これは [`vite`](../reference/site-config#vite) 設定オプションで変更可能です)。
すべての **静的な** パス参照(絶対パスを含む)は、作業ディレクトリの構造を基準にする必要があります。
## Public ディレクトリ {#the-public-directory}
Markdown やテーマコンポーネントで直接参照されない静的アセットを提供する必要がある場合や、特定のファイルをオリジナルのファイル名のまま提供したい場合があります。
例えば `robots.txt`、favicon、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
![画像](/image-inside-public.png)
```
この場合は `base` の設定値を変更しても、参照を修正する必要はありません。
ただし、テーマコンポーネントで動的にアセットをリンクする場合(例:テーマ設定値に基づいた画像の `src`)は注意が必要です。
```vue
<img :src="theme.logoPath" />
```
この場合は、VitePress が提供する [`withBase` ヘルパー](../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 が認証を必要とする場合は、API トークンを格納するための `.env` を作成し、次のように読み込みます。
```js
// posts/[id].paths.js
import { loadEnv } from 'vitepress'
const env = loadEnv('', process.cwd())
```
2. CMS から必要なデータを取得し、適切なパスデータの形式に整形します。
```js
export default {
async paths() {
// 必要に応じて各 CMS のクライアントライブラリを使用
const data = await (await fetch('https://my-cms-api', {
headers: {
// 必要ならトークン
}
})).json()
return data.map(entry => {
return {
params: { id: entry.id, /* title, authors, date など */ },
content: entry.content
}
})
}
}
```
3. ページ内でコンテンツをレンダリングします。
```md
# {{ $params.title }}
- {{ $params.date }} に {{ $params.author }} が作成
<!-- @content -->
```
## 連携ガイドの募集 {#integration-guides}
特定の CMS と VitePress の連携ガイドを書かれた方は、下部の「Edit this page」リンクからぜひ投稿してください

@ -0,0 +1,213 @@
# カスタムテーマを使う {#using-a-custom-theme}
## テーマの解決 {#theme-resolving}
カスタムテーマを有効にするには、`.vitepress/theme/index.js` または `.vitepress/theme/index.ts` ファイル(「テーマエントリファイル」)を作成します。
```
.
├─ docs # プロジェクトルート
│ ├─ .vitepress
│ │ ├─ theme
│ │ │ └─ index.js # テーマエントリ
│ │ └─ config.js # 設定ファイル
│ └─ index.md
└─ package.json
```
VitePress はテーマエントリファイルを検出すると、常にデフォルトテーマではなくカスタムテーマを使用します。ただし、[デフォルトテーマを拡張](./extending-default-theme) してその上で高度なカスタマイズを行うことも可能です。
## テーマインターフェース {#theme-interface}
VitePress のカスタムテーマは次のインターフェースを持つオブジェクトとして定義されます。
```ts
interface Theme {
/**
* すべてのページに適用されるルートレイアウトコンポーネント
* @required
*/
Layout: Component
/**
* Vue アプリインスタンスを拡張
* @optional
*/
enhanceApp?: (ctx: EnhanceAppContext) => Awaitable<void>
/**
* 別のテーマを拡張し、そのテーマの `enhanceApp` を先に実行
* @optional
*/
extends?: Theme
}
interface EnhanceAppContext {
app: App // Vue アプリインスタンス
router: Router // VitePress のルーターインスタンス
siteData: Ref<SiteData> // サイト全体のメタデータ
}
```
テーマエントリファイルでは、このテーマをデフォルトエクスポートとして公開します。
```js [.vitepress/theme/index.js]
// テーマエントリでは Vue ファイルを直接インポートできます
// VitePress は @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>
<!-- この部分に markdown コンテンツが描画されます -->
<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) ヘルパーを使うと、条件によってレイアウトを切り替えるために必要なすべてのランタイムデータを取得できます。アクセスできるデータのひとつにフロントマターがあります。これを利用すると、ページごとにレイアウトを制御できます。例えば、ユーザーが特別なホームページレイアウトを使いたい場合は以下のように記述します。
```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 /> が <Content /> を描画 -->
</template>
```
利用可能なすべての機能は [Runtime 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. 設定ファイルやフロントマターを通じて、テーマ設定オプションを文書化する。
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/config.ts]
import baseConfig from 'awesome-vitepress-theme/config'
export default {
// 必要に応じてテーマの基本設定を拡張
extends: baseConfig
}
```
テーマがテーマ設定用の型を提供している場合:
```ts [.vitepress/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: {
// 型は `ThemeConfig`
}
})
```

@ -0,0 +1,212 @@
# ビルド時のデータの読み込み {#build-time-data-loading}
VitePress には **データローダー (data loaders)** という機能があり、任意のデータを読み込み、ページやコンポーネントからインポートすることができます。データの読み込みは **ビルド時のみ** 実行され、最終的な 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() {
// リモートデータを取得
return (await fetch('...')).json()
}
}
```
## ローカルファイルからのデータ {#data-from-local-files}
ローカルファイルに基づいたデータを生成する必要がある場合は、データローダー内で `watch` オプションを使用し、ファイルの変更をホットリロードに反映させることが推奨されます。
`watch` では [glob パターン](https://github.com/mrmlnc/fast-glob#pattern-syntax) を利用して複数ファイルをマッチさせることができ、パターンはローダーファイルからの相対パスで指定できます。`load()` 関数にはマッチしたファイルの絶対パスが渡されます。
以下は CSV ファイルを読み込み [csv-parse](https://github.com/adaltas/node-csv/tree/master/packages/csv-parse/) を使って JSON に変換する例です。このコードはビルド時にのみ実行されるため、CSV パーサーがクライアントに送られることはありません。
```js
import fs from 'node:fs'
import { parse } from 'csv-parse/sync'
export default {
watch: ['./data/*.csv'],
load(watchedFiles) {
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#source-directory) からの相対 glob パターンを受け取り、`{ watch, load }` を返すデータローダーオブジェクトを生成します。これをデータローダーファイルのデフォルトエクスポートにできます。開発時のパフォーマンスを向上させるために、ファイルの更新時刻に基づくキャッシュも行われます。
このローダーは Markdown ファイルにのみ対応し、それ以外のファイルは無視されます。
読み込まれるデータは `ContentData[]` 型の配列です。
```ts
interface ContentData {
url: string // ページのマッピング URL例: /posts/hello.html
frontmatter: Record<string, any> // ページのフロントマター
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, // 生の markdown ソースを含める?
render: true, // レンダリングされた HTML を含める?
excerpt: true, // 抜粋を含める?
transform(rawData) {
return rawData
.sort((a, b) => {
return +new Date(b.frontmatter.date) - +new Date(a.frontmatter.date)
})
.map((page) => {
page.src // 生の markdown ソース
page.html // レンダリングされた HTML
page.excerpt // 抜粋 HTML最初の `---` までの内容)
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()
// メタデータを基にファイルを生成(例: RSS フィード)
}
}
```
**型定義**
```ts
interface ContentOptions<T = ContentData[]> {
includeSrc?: boolean
render?: boolean
excerpt?:
| boolean
| ((file: { data: { [key: string]: any }; content: string; excerpt?: string }, options?: any) => void)
| string
transform?: (data: ContentData[]) => T | Promise<T>
}
```
## 型付きデータローダー {#typed-data-loaders}
TypeScript を使用する場合は、ローダーと `data` エクスポートを型付けできます。
```ts
import { defineLoader } from 'vitepress'
export interface Data {
// データ型
}
declare const data: Data
export { data }
export default defineLoader({
watch: ['...'],
async load(): Promise<Data> {
// ...
}
})
```
## 設定情報の取得 {#configuration}
ローダー内で設定情報を取得するには次のようにします。
```ts
import type { SiteConfig } from 'vitepress'
const config: SiteConfig = (globalThis as any).VITEPRESS_CONFIG
```

@ -0,0 +1,348 @@
---
outline: deep
---
# VitePress サイトをデプロイする {#deploy-your-vitepress-site}
以下のガイドは、次の前提に基づいています。
- VitePress のサイトはプロジェクトの `docs` ディレクトリ内にある。
- デフォルトのビルド出力ディレクトリ(`.vitepress/dist`)を使用している。
- VitePress はプロジェクトのローカル依存としてインストールされており、`package.json` に次のスクリプトが設定されている。
```json [package.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 サーバーを起動し、出力ディレクトリ `.vitepress/dist``http://localhost:4173` で配信します。プロダクションへプッシュする前に見た目を確認できます。
3. `--port` 引数でサーバーのポートを設定できます。
```json
{
"scripts": {
"docs:preview": "vitepress preview docs --port 8080"
}
}
```
これで `docs:preview``http://localhost:8080` でサーバーを起動します。
## 公開ベースパスの設定 {#setting-a-public-base-path}
デフォルトでは、サイトはドメインのルートパス(`/`)にデプロイされることを想定しています。サイトをサブパス、例:`https://mywebsite.com/blog/` で配信する場合は、VitePress の設定で [`base`](../reference/site-config#base) オプションを `'/blog/'` に設定してください。
**例:** GitHubまたは GitLabPages に `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 ディレクトリ](./asset-handling#the-public-directory) に配置します(この例では `docs/public/_headers`)。そうすると、ビルド出力にそのままコピーされます。
[Netlify のカスタムヘッダードキュメント](https://docs.netlify.com/routing/headers/)
:::
::: details `vercel.json` による Vercel 設定例
```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 {#netlify-vercel-cloudflare-pages-aws-amplify-render}
新しいプロジェクトを作成し、ダッシュボードで次の設定に変更します。
- **Build Command:** `npm run docs:build`
- **Output Directory:** `docs/.vitepress/dist`
- **Node Version:** `20`(以上)
::: warning
HTML の _Auto Minify_ のようなオプションを有効にしないでください。Vue にとって意味のあるコメントが出力から削除され、削除されるとハイドレーションの不整合エラーが発生する可能性があります。
:::
### GitHub Pages {#github-pages}
1. プロジェクトの `.github/workflows` ディレクトリに `deploy.yml` を作成し、以下の内容を記述します。
```yaml [.github/workflows/deploy.yml]
# 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@v4
with:
fetch-depth: 0 # Not needed if lastUpdated is not enabled
# - uses: pnpm/action-setup@v3 # Uncomment this block if you're using pnpm
# with:
# version: 9 # Not needed if you've set "packageManager" in package.json
# - uses: oven-sh/setup-bun@v1 # Uncomment this if you're using Bun
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm # or pnpm / yarn
- name: Setup Pages
uses: actions/configure-pages@v4
- 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
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
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@v4
```
::: warning
VitePress の `base` オプションが正しく設定されていることを確認してください。詳細は [公開ベースパスの設定](#公開ベースパスの設定) を参照してください。
:::
2. リポジトリ設定の「Pages」メニューで、「Build and deployment > Source」を「GitHub Actions」に設定します。
3. 変更を `main` ブランチにプッシュし、GitHub Actions の完了を待ちます。設定に応じて、サイトは `https://<username>.github.io/[repository]/` または `https://<custom-domain>/` にデプロイされます。以後、`main` へのプッシュごとに自動デプロイされます。
### GitLab Pages {#gitlab-pages}
1. VitePress の設定で `outDir``../public` に設定します。`https://<username>.gitlab.io/<repository>/` にデプロイする場合は `base``'/<repository>/'` に設定します。カスタムドメイン、ユーザー/グループページ、または GitLab の「Use unique domain」を有効にしている場合は `base` は不要です。
2. プロジェクトのルートに `.gitlab-ci.yml` を作成して、以下を追加します。これにより、コンテンツを更新するたびにサイトがビルド・デプロイされます。
```yaml [.gitlab-ci.yml]
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 Static Web Apps {#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 [firebase.json]
{
"hosting": {
"public": "docs/.vitepress/dist",
"ignore": []
}
}
```
`.firebaserc`:
```json [.firebaserc]
{
"projects": {
"default": "<YOUR_FIREBASE_ID>"
}
}
```
2. `npm run docs:build` の後、次のコマンドでデプロイします。
```sh
firebase deploy
```
### Surge {#surge}
1. `npm run docs:build` の後、次のコマンドでデプロイします。
```sh
npx surge docs/.vitepress/dist
```
### Heroku {#heroku}
1. [`heroku-buildpack-static`](https://elements.heroku.com/buildpacks/heroku/heroku-buildpack-static) のドキュメントとガイドに従います。
2. プロジェクトのルートに `static.json` を作成し、以下を記述します。
```json [static.json]
{
"root": "docs/.vitepress/dist"
}
```
### Edgio {#edgio}
[Creating and Deploying a VitePress App To Edgio](https://docs.edg.io/guides/vitepress) を参照してください。
### Kinsta Static Site Hosting {#kinsta-static-site-hosting}
[VitePress](https://kinsta.com/static-site-hosting/) を [こちらの手順](https://kinsta.com/docs/vitepress-static-site-example/) に従ってデプロイできます。
### Stormkit {#stormkit}
[VitePress プロジェクトを Stormkit にデプロイ](https://stormkit.io/blog/how-to-deploy-vitepress) する手順を参照してください。
### CloudRay {#cloudray}
[CloudRay](https://cloudray.io/) でのデプロイ方法は [こちらの手順](https://cloudray.io/articles/how-to-deploy-vitepress-site) を参照してください。
### Nginx {#nginx}
以下は Nginx サーバーブロックの設定例です。一般的なテキスト系アセットの gzip 圧縮、VitePress サイトの静的ファイル配信における適切なキャッシュヘッダー、そして `cleanUrls: true` のハンドリングを含みます。
```nginx
server {
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
listen 80;
server_name _;
index index.html;
location / {
# content location
root /app;
# exact matches -> reverse clean urls -> folders -> not found
try_files $uri $uri.html $uri/ =404;
# non existent pages
error_page 404 /404.html;
# a folder without index.html raises 403 in this setup
error_page 403 /404.html;
# adjust caching headers
# files in the assets folder have hashes filenames
location ~* ^/assets/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
}
```
この設定は、ビルド済みの VitePress サイトがサーバー上の `/app` ディレクトリに配置されていることを想定しています。サイトのファイルが別の場所にある場合は、`root` ディレクティブを適宜変更してください。
::: warning index.html をデフォルトにしない
`try_files` の解決先を、他の Vue アプリのように index.html にフォールバックさせないでください。不正なページ状態になります。
:::
詳細は [公式 nginx ドキュメント](https://nginx.org/en/docs/)、Issue [#2837](https://github.com/vuejs/vitepress/discussions/2837)、[#3235](https://github.com/vuejs/vitepress/issues/3235)、および Mehdi Merah 氏の [ブログ記事](https://blog.mehdi.cc/articles/vitepress-cleanurls-on-nginx-environment#readings) を参照してください。

@ -0,0 +1,332 @@
---
outline: deep
---
# デフォルトテーマの拡張 {#extending-the-default-theme}
VitePress のデフォルトテーマはドキュメント向けに最適化されており、カスタマイズ可能です。利用できるオプションの一覧は [デフォルトテーマの概要](../reference/default-theme-config) を参照してください。
しかし、設定だけでは不十分なケースもあります。例えば:
1. CSS のスタイルを微調整したい
2. グローバルコンポーネントの登録など、Vue アプリインスタンスを変更したい
3. レイアウトのスロット経由でテーマに独自コンテンツを挿入したい
これらの高度なカスタマイズには、デフォルトテーマを「拡張」するカスタムテーマを使用する必要があります。
::: 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/my-fonts.css */
:root {
--vp-font-family-base: /* 通常テキスト用フォント */
--vp-font-family-mono: /* コード用フォント */
}
```
::: warning
[Team Page](../reference/default-theme-team-page) などのオプションコンポーネントを使う場合も、必ず `vitepress/theme-without-fonts` からインポートしてください。
:::
フォントが `@font-face` で参照されるローカルファイルの場合、アセットとして処理され、ハッシュ付きファイル名で `.vitepress/dist/assets` に出力されます。このファイルをプリロードするには、[transformHead](../reference/site-config#transformhead) ビルドフックを使います。
```js [.vitepress/config.js]
export default {
transformHead({ assets }) {
// 使うフォントに合わせて正規表現を調整
const myFontFile = assets.find(file => /font-name\.[\w-]+\.woff2/.test(file))
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 }) {
// 独自のグローバルコンポーネントを登録
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 }) {
// 独自のグローバルコンポーネントを登録
app.component('MyGlobalComponent' /* ... */)
}
} satisfies Theme
```
Vite を使っているため、Vite の [glob import 機能](https://vitejs.dev/guide/features.html#glob-import) を利用してディレクトリ内のコンポーネントを自動登録することもできます。
## レイアウトスロット {#layout-slots}
デフォルトテーマの `<Layout/>` コンポーネントには、ページ内の特定の位置にコンテンツを挿入するためのスロットがいくつか用意されています。以下は、アウトラインの前にコンポーネントを挿入する例です。
```js [.vitepress/theme/index.js]
import DefaultTheme from 'vitepress/theme'
import MyLayout from './MyLayout.vue'
export default {
extends: DefaultTheme,
// スロットを注入するラッパーコンポーネントで Layout を上書き
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'`(デフォルト)を有効にしているとき:
- `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'` を有効にしているとき:
- `home-hero-before`
- `home-hero-info-before`
- `home-hero-info`
- `home-hero-info-after`
- `home-hero-actions-after`
- `home-hero-image`
- `home-hero-after`
- `home-features-before`
- `home-features-after`
- フロントマターで `layout: 'page'` を有効にしているとき:
- `page-top`
- `page-bottom`
- 404Not Foundページ:
- `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`
## 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',
fill: 'forwards',
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>
```
結果(**注意!**:点滅や急な動き、明るい光を含みます):
<details>
<summary>デモ</summary>
![Appearance Toggle Transition Demo](/appearance-toggle-transition.webp)
</details>
詳細は [Chrome Docs](https://developer.chrome.com/docs/web-platform/view-transitions/) を参照してください。
### ルート遷移時 {#on-route-change}
近日公開。
## 内部コンポーネントの置き換え {#overriding-internal-components}
Vite の [エイリアス](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('./theme/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 フロントマターをサポートしており、[gray-matter](https://github.com/jonschlinkert/gray-matter) で解析します。フロントマターは Markdown ファイルの先頭(`<script>` タグを含むあらゆる要素より前)に配置し、三本のハイフンで囲まれた **有効な YAML** 形式で記述します。例:
```md
---
title: Docs with VitePress
editLink: true
---
```
サイトやデフォルトテーマの多くの設定オプションには、フロントマター上で対応するオプションがあります。フロントマターを使うことで、**そのページに限って** 特定の振る舞いを上書きできます。詳細は [Frontmatter Config Reference](../reference/frontmatter-config) を参照してください。
また、独自のカスタムフロントマターデータを定義し、ページ上の動的な Vue 式で利用することもできます。
## フロントマターデータへのアクセス {#accessing-frontmatter-data}
フロントマターデータは特別なグローバル変数 `$frontmatter` で参照できます。
Markdown ファイル内での使用例:
```md
---
title: Docs with VitePress
editLink: true
---
# {{ $frontmatter.title }}
Guide content
```
[`useData()`](../reference/runtime-api#usedata) ヘルパーを使えば、`<script setup>` 内からも現在のページのフロントマターデータにアクセスできます。
## 代替フロントマター形式 {#alternative-frontmatter-formats}
VitePress は JSON フロントマター構文もサポートしています。中括弧で開始・終了する形式です。
```json
---
{
"title": "Blogging Like a Hacker",
"editLink": true
}
---
```

@ -0,0 +1,197 @@
# はじめに {#getting-started}
## オンラインで試す {#try-it-online}
[VitePress](https://vitepress.new) をブラウザ上で直接試すことができます。
## インストール {#installation}
### 前提条件 {#prerequisites}
- [Node.js](https://nodejs.org/) バージョン 18 以上
- VitePress をコマンドラインインターフェース (CLI) で操作するためのターミナル
- [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@next
```
```sh [pnpm]
$ pnpm add -D vitepress@next
```
```sh [yarn]
$ yarn add -D vitepress@next vue
```
```sh [bun]
$ bun add -D vitepress@next
```
:::
::: 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 [yarn]
$ yarn vitepress init
```
```sh [bun]
$ bun vitepress init
```
:::
いくつかの簡単な質問が表示されます。
<<< @/snippets/init.ansi
::: tip Vue をピア依存関係に
Vue コンポーネントや API を使ったカスタマイズを行う場合は、明示的に `vue` を依存関係としてインストールしてください。
:::
## ファイル構成 {#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/cache` に、本番ビルド出力は `.vitepress/dist` に保存されます。Git を使用している場合は `.gitignore` に追加してください。これらの場所は [設定](../reference/site-config#outdir) で変更可能です。
:::
### 設定ファイル {#the-config-file}
設定ファイル (`.vitepress/config.js`) では、VitePress サイトのさまざまな動作をカスタマイズできます。最も基本的なオプションはサイトのタイトルと説明です。
```js [.vitepress/config.js]
export default {
// サイトレベルのオプション
title: 'VitePress',
description: 'Just playing around.',
themeConfig: {
// テーマレベルのオプション
}
}
```
テーマの動作は `themeConfig` オプションで設定できます。利用可能なすべての設定オプションは [Config Reference](../reference/site-config) を参照してください。
### ソースファイル {#source-files}
`.vitepress` ディレクトリ外の Markdown ファイルは **ソースファイル** とみなされます。
VitePress は **ファイルベースのルーティング** を採用しています。各 `.md` ファイルは同じパスを持つ `.html` ファイルにコンパイルされます。例えば `index.md``index.html` にコンパイルされ、サイトのルート `/` で表示されます。
VitePress にはクリーン URL の生成、パスの書き換え、動的なページ生成といった機能もあります。これらは [ルーティングガイド](./routing) で解説します。
## 実行してみる {#up-and-running}
セットアッププロセスで許可した場合、以下の npm スクリプトが `package.json` に追加されています。
```json [package.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 vitepress dev docs
```
```sh [yarn]
$ yarn vitepress dev docs
```
```sh [bun]
$ bun vitepress dev docs
```
:::
その他のコマンドラインの使い方は [CLI リファレンス](../reference/cli) に記載されています。
開発サーバーは `http://localhost:5173` で動作します。ブラウザでこの URL にアクセスすると、新しいサイトが確認できます。
## 次のステップ {#what-s-next}
- Markdown ファイルがどのように HTML にマッピングされるかを理解するには、[ルーティングガイド](./routing) を読みましょう。
- ページ内でできることMarkdown コンテンツの記述や Vue コンポーネントの利用などを知るには、ガイドの「Writing」セクションを参照してください。まずは [Markdown 拡張](./markdown) を学ぶのがおすすめです。
- デフォルトドキュメントテーマの機能を知りたい場合は、[Default Theme Config Reference](../reference/default-theme-config) を確認してください。
- サイトの見た目をさらにカスタマイズしたい場合は、[デフォルトテーマの拡張](./extending-default-theme) や [カスタムテーマの構築](./custom-theme) を検討してください。
- ドキュメントサイトが形になったら、必ず [デプロイガイド](./deploy) を読んでください。

@ -0,0 +1,111 @@
# 多言語対応 {#internationalization}
組み込みの i18n 機能を使うには、次のようなディレクトリ構成を作成します。
```
docs/
├─ es/
│ ├─ foo.md
├─ fr/
│ ├─ foo.md
├─ foo.md
```
次に `docs/.vitepress/config.ts` で設定します。
```ts [docs/.vitepress/config.ts]
import { defineConfig } from 'vitepress'
export default defineConfig({
// 共有のプロパティやトップレベル設定...
locales: {
root: {
label: 'English',
lang: 'en'
},
fr: {
label: 'French',
lang: 'fr', // 省略可。最終的に html タグの `lang` 属性として付与されます
link: '/fr/guide' // デフォルトは /fr/。ナビバーの言語メニューに表示。外部 URL でも可
// ロケール固有のその他のプロパティ...
}
}
})
```
各ロケールroot を含む)ごとに、次のプロパティを上書きできます。
```ts
interface LocaleSpecificConfig<ThemeConfig = any> {
lang?: string
dir?: string
title?: string
titleTemplate?: string | boolean
description?: string
head?: HeadConfig[] // 既存の head とマージ。重複する meta タグは自動的に除去
themeConfig?: ThemeConfig // シャローにマージ。共通項目はトップレベルの themeConfig に置けます
}
```
デフォルトテーマのプレースホルダ文言のカスタマイズについては [`DefaultTheme.Config`](https://github.com/vuejs/vitepress/blob/main/types/default-theme.d.ts) を参照してください。`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` クッキーでユーザーの言語選択を保持できます。
```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, inBrowser } 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'` を指定し、<https://github.com/MohammadYounes/rtlcss><https://github.com/vkalinichev/postcss-rtl>、または <https://github.com/elchininet/postcss-rtlcss> のような RTLCSS 系の PostCSS プラグインを使用してください。CSS の詳細度の問題を避けるため、PostCSS プラグインでは `:where([dir="ltr"])``:where([dir="rtl"])` を接頭辞として使うよう設定してください。

File diff suppressed because it is too large Load Diff

@ -0,0 +1,23 @@
# MPA モード <Badge type="warning" text="experimental" /> {#mpa-mode}
MPAMulti-Page Applicationモードは、コマンドラインの `vitepress build --mpa`、または設定で `mpa: true` を指定することで有効化できます。
MPA モードでは、既定で **あらゆるページが JavaScript を含まずに** レンダリングされます。結果として、本番サイトは監査ツールにおける初回訪問のパフォーマンススコアが向上しやすくなります。
一方、SPA のナビゲーションがないため、ページ間リンクはフルリロードになります。読み込み後のページ遷移は、SPA モードのような即時性はありません。
また、「既定で JS なし」ということは、実質的に 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,385 @@
---
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-directories}
VitePress プロジェクトのファイル構成には重要な概念が 2 つあります:**プロジェクトルート** と **ソースディレクトリ** です。
### プロジェクトルート {#project-root}
プロジェクトルートは、VitePress が特別なディレクトリである `.vitepress` を探しにいく場所です。`.vitepress` ディレクトリは、VitePress の設定ファイル、開発サーバーのキャッシュ、ビルド出力、任意のテーマカスタマイズコードのための予約場所です。
コマンドラインから `vitepress dev``vitepress build` を実行すると、VitePress は現在の作業ディレクトリをプロジェクトルートとして使用します。サブディレクトリをルートとして指定したい場合は、コマンドに相対パスを渡します。例えば、VitePress プロジェクトが `./docs` にある場合、`vitepress dev docs` を実行します:
```
.
├─ docs # プロジェクトルート
│ ├─ .vitepress # 設定ディレクトリ
│ ├─ 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'` の場合、ファイル構成は次のようになります:
```
. # プロジェクトルート
├─ .vitepress # 設定ディレクトリ
└─ src # ソースディレクトリ
├─ getting-started.md
└─ index.md
```
ソースから HTML へのマッピングは次のとおりです:
```
src/index.md --> /index.html / でアクセス可能)
src/getting-started.md --> /getting-started.html
```
## ページ間リンク {#linking-between-pages}
ページ間のリンクには、絶対パスと相対パスのどちらも使用できます。`.md` と `.html` の拡張子はどちらも機能しますが、最終的な URL を設定に応じて VitePress が生成できるよう、**拡張子は省略する** のがベストプラクティスです。
```md
<!-- 良い例 -->
[はじめに](./getting-started)
[はじめに](../guide/getting-started)
<!-- 悪い例 -->
[はじめに](./getting-started.md)
[はじめに](./getting-started.html)
```
画像などのアセットへのリンクについては、[アセットの取り扱い](./asset-handling) を参照してください。
### VitePress 管理外のページへのリンク {#linking-to-non-vitepress-pages}
サイト内で VitePress が生成していないページへリンクしたい場合は、フル URL新しいタブで開くを使うか、明示的にターゲットを指定します。
**入力**
```md
[pure.html へのリンク](/pure.html){target="_self"}
```
**出力**
[pure.html へのリンク](/pure.html){target="_self"}
::: tip 注意
Markdown のリンクでは、`base` が自動的に URL の先頭に付与されます。つまり、`base` の外にあるページへリンクしたい場合は、ブラウザの相対解決に従って `../../pure.html` のように書く必要があります。
あるいは、アンカータグの構文を直接使うこともできます:
```md
<a href="/pure.html" target="_self">pure.html へのリンク</a>
```
:::
## クリーン URL の生成 {#generating-clean-urls}
::: warning サーバー側の対応が必要
VitePress でクリーン URL を提供するには、サーバー側のサポートが必要です。
:::
既定では、VitePress は内部リンクを `.html` で終わる URL に解決します。しかし、`.html` を含まない「クリーン URL」`example.com/path`)を好む場合もあります。
一部のサーバーやホスティングNetlify、Vercel、GitHub Pagesは、リダイレクトなしに `/foo``/foo.html` にマッピングできます。
- Netlify と GitHub Pages はデフォルトで対応しています。
- Vercel は [`vercel.json` の `cleanUrls` オプション](https://vercel.com/docs/concepts/projects/project-configuration#cleanurls) を有効にする必要があります。
この機能が利用可能であれば、VitePress 側の [`cleanUrls`](../reference/site-config#cleanurls) 設定も有効化してください。これにより:
- ページ間の内部リンクが `.html` 拡張子なしで生成されます。
- 現在のパスが `.html` で終わっている場合、拡張子なしのパスへクライアントサイドのリダイレクトを行います。
もしサーバーをそのように設定できない場合は、次のようなディレクトリ構造に手動でする必要があります:
```
.
├─ getting-started
│ └─ index.md
├─ installation
│ └─ index.md
└─ index.md
```
## ルートのリライト {#route-rewrites}
ソースディレクトリ構造と生成ページのマッピングをカスタマイズできます。これは複雑なプロジェクト構成で有用です。例えば、複数パッケージを持つモノレポで、ソースファイルと並べてドキュメントを配置したい場合:
```
.
└─ packages
├─ pkg-a
│ └─ src
│ ├─ foo.md
│ └─ index.md
└─ pkg-b
└─ src
├─ bar.md
└─ index.md
```
生成したいページが次のような場合:
```
packages/pkg-a/src/index.md --> /pkg-a/index.html
packages/pkg-a/src/foo.md --> /pkg-a/foo.html
packages/pkg-b/src/index.md --> /pkg-b/index.html
packages/pkg-b/src/bar.md --> /pkg-b/bar.html
```
[`rewrites`](../reference/site-config#rewrites) オプションを次のように設定します:
```ts [.vitepress/config.js]
export default {
rewrites: {
'packages/pkg-a/src/index.md': 'pkg-a/index.md',
'packages/pkg-a/src/foo.md': 'pkg-a/foo.md',
'packages/pkg-b/src/index.md': 'pkg-b/index.md',
'packages/pkg-b/src/bar.md': 'pkg-b/bar.md'
}
}
```
`rewrites` は動的なルートパラメータにも対応しています。上記の例で多くのパッケージがある場合、同じ構造なら次のように簡略化できます:
```ts
export default {
rewrites: {
'packages/:pkg/src/:slug*': ':pkg/:slug*'
}
}
```
リライトのパスは `path-to-regexp` パッケージでコンパイルされます。高度な構文は[ドキュメント](https://github.com/pillarjs/path-to-regexp/tree/6.x#parameters)を参照してください。
`rewrites` は、元のパスを受け取って新しいパスを返す **関数** として定義することもできます:
```ts
export default {
rewrites(id) {
return id.replace(/^packages\/([^/]+)\/src\//, '$1/')
}
}
```
::: warning リライト時の相対リンク
リライトを有効にした場合、**相対リンクはリライト後のパスに基づいて** 記述してください。例えば、`packages/pkg-a/src/pkg-a-code.md` から `packages/pkg-b/src/pkg-b-code.md` への相対リンクを作るには、次のように書きます:
```md
[PKG B へのリンク](../pkg-b/pkg-b-code)
```
:::
## 動的ルート {#dynamic-routes}
ひとつの Markdown ファイルと動的データから多数のページを生成できます。例えば、`packages/[pkg].md` を作成して、プロジェクト内の各パッケージに対応するページを生成できます。ここで `[pkg]` セグメントは、それぞれのページを区別する **ルートパラメータ** です。
### パスローダーファイル {#path-loader-files}
VitePress は静的サイトジェネレーターなので、生成可能なページパスはビルド時に確定している必要があります。したがって、動的ルートページには **パスローダーファイル** が **必須** です。`packages/[pkg].md` に対しては `packages/[pkg].paths.js``.ts` も可)が必要です:
```
.
└─ packages
├─ [pkg].md # ルートテンプレート
└─ [pkg].paths.js # ルートのパスローダー
```
パスローダーは、`paths` メソッドを持つオブジェクトをデフォルトエクスポートします。`paths` は `params` プロパティを持つオブジェクトの配列を返します。各オブジェクトが 1 ページに対応します。
例えば次の `paths` 配列を返すと:
```js
// packages/[pkg].paths.js
export default {
paths() {
return [
{ params: { pkg: 'foo' }},
{ params: { pkg: 'bar' }}
]
}
}
```
生成される HTML は次のようになります:
```
.
└─ packages
├─ foo.html
└─ bar.html
```
### 複数パラメータ {#multiple-params}
動的ルートに複数のパラメータを含めることもできます。
**ファイル構成**
```
.
└─ 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 のルートファイルでは、Vue 式内で `$params` グローバルプロパティから現在ページのパラメータにアクセスできます:
```md
- パッケージ名: {{ $params.pkg }}
- バージョン: {{ $params.version }}
```
[`useData`](../reference/runtime-api#usedata) ランタイム API からも、現在ページのパラメータにアクセスできますMarkdown と Vue コンポーネントの両方で利用可能):
```vue
<script setup>
import { useData } from 'vitepress'
// params は Vue の ref
const { params } = useData()
console.log(params.value)
</script>
```
### 生コンテンツのレンダリング {#rendering-raw-content}
ページに渡したパラメータはクライアント JavaScript のペイロードにシリアライズされます。そのため、リモート 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 // 生の Markdown または HTML
}
})
}
}
```
そのうえで、Markdown ファイル内で次の特別な構文を使って、そのコンテンツを埋め込みます:
```md
<!-- @content -->
```

@ -0,0 +1,58 @@
# サイトマップ生成 {#sitemap-generation}
VitePress には、サイト用の `sitemap.xml` を生成する機能が標準で用意されています。有効化するには、`.vitepress/config.js` に次を追加します。
```ts
export default {
sitemap: {
hostname: 'https://example.com'
}
}
```
`siteamp.xml``<lastmod>` タグを含めるには、[`lastUpdated`](../reference/default-theme-last-updated) オプションを有効にします。
## オプション {#options}
サイトマップ生成は [`sitemap`](https://www.npmjs.com/package/sitemap) モジュールで行われます。設定ファイルの `sitemap` に、このモジュールがサポートする任意のオプションを渡せます。指定した値はそのまま `SitemapStream` コンストラクタに渡されます。詳しくは [`sitemap` のドキュメント](https://www.npmjs.com/package/sitemap#options-you-can-pass) を参照してください。例:
```ts
export default {
sitemap: {
hostname: 'https://example.com',
lastmodDateOnly: false
}
}
```
設定で `base` を使っている場合は、`hostname` にもそれを付与してください:
```ts
export default {
base: '/my-site/',
sitemap: {
hostname: 'https://example.com/my-site/'
}
}
```
## `transformItems` フック {#transformitems-hook}
`siteamp.xml` に書き出す直前にサイトマップ項目を加工するには、`sitemap.transformItems` フックを使います。このフックはサイトマップ項目の配列を受け取り、配列を返す必要があります。例:
```ts
export default {
sitemap: {
hostname: 'https://example.com',
transformItems: (items) => {
// 既存項目の追加・変更・フィルタリングが可能
items.push({
url: '/extra-page',
changefreq: 'monthly',
priority: 0.8
})
return items
}
}
}
```

@ -0,0 +1,135 @@
---
outline: deep
---
# SSR 互換性 {#ssr-compatibility}
VitePress は本番ビルド時に、Node.js 上で Vue のサーバーサイドレンダリングSSR機能を使ってアプリを事前レンダリングします。つまり、テーマコンポーネント内のすべてのカスタムコードは SSR 互換性の対象になります。
[公式 Vue ドキュメントの SSR セクション](https://vuejs.org/guide/scaling-up/ssr.html)では、SSR とは何か、SSR と SSG の関係、そして SSR に優しいコードを書く際の一般的な注意点が解説されています。経験則としては、**ブラウザ / DOM API へのアクセスは Vue コンポーネントの `beforeMount` または `mounted` フック内に限定** するのが安全です。
## `<ClientOnly>` {#clientonly}
SSR に適さないコンポーネント(例:カスタムディレクティブを含むなど)を使用・デモする場合は、組み込みの `<ClientOnly>` コンポーネントでラップできます。
```md
<ClientOnly>
<NonSSRFriendlyComponent />
</ClientOnly>
```
## インポート時に Browser 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) => {
// ここでコードを利用
})
})
</script>
```
### 条件付きインポート {#conditional-import}
[`import.meta.env.SSR`](https://vitejs.dev/guide/env-and-mode.html#env-variables) フラグVite の環境変数の一部)を使って、依存関係を条件付きでインポートすることもできます。
```js
if (!import.meta.env.SSR) {
import('./lib-that-access-window-on-import').then((module) => {
// ここでコードを利用
})
}
```
[`Theme.enhanceApp`](./custom-theme#theme-interface) は非同期にできるため、**インポート時に Browser 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 は、**インポート時に Browser API にアクセスする Vue コンポーネント** を読み込むためのユーティリティを提供します。
```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'),
// 引数は 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')]
}
],
// コンポーネント読み込み後のコールバック(非同期可)
() => {
console.log(clientCompRef.value)
}
)
</script>
<template>
<ClientComp />
</template>
```
ターゲットコンポーネントは、ラッパーコンポーネントの mounted フックで初めてインポートされます。

@ -0,0 +1,288 @@
# MarkdownでVueを使う {#using-vue-in-markdown}
VitePress では、各 Markdown ファイルはまず HTML にコンパイルされ、その後 [Vue の単一ファイルコンポーネントSFC](https://vuejs.org/guide/scaling-up/sfc.html) として処理されます。つまり、Markdown 内で Vue のあらゆる機能が使えます。動的テンプレート、Vue コンポーネントの利用、`<script>` タグを追加してページ内ロジックを書くことも可能です。
なお、VitePress は Vue のコンパイラを利用して、Markdown コンテンツの**純粋に静的な部分**を自動検出・最適化します。静的コンテンツは単一のプレースホルダノードに最適化され、初回訪問時の JavaScript ペイロードから除外されます。クライアント側のハイドレーションでもスキップされます。要するに、そのページで**動的な部分に対してだけ**コストを支払うことになります。
::: tip SSR 互換性
Vue の使用は SSR 互換である必要があります。詳細と一般的な回避策は [SSR 互換性](./ssr-compat) を参照してください。
:::
## テンプレート記法 {#templating}
### 補間 {#interpolation}
各 Markdown は最初に HTML にコンパイルされ、その後 Vite の処理パイプラインで Vue コンポーネントとして扱われます。つまり、テキスト内で 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 になることです。すべてのタグはフロントマターの**後**に配置してください。
```html
---
hello: world
---
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
## Markdown コンテンツ
現在の値: {{ 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>
# ドキュメント
これはカスタムコンポーネントを使う .md です
<CustomComponent />
## 続き
...
```
### グローバル登録 {#registering-components-globally}
ほとんどのページで使うコンポーネントは、Vue アプリインスタンスをカスタマイズしてグローバル登録できます。例は [デフォルトテーマの拡張](./extending-default-theme#registering-global-components) を参照してください。
::: warning 重要
カスタムコンポーネント名にはハイフンを含めるか、PascalCase を使用してください。そうでない場合、インライン要素として解釈されて `<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 は CSS プリプロセッサ(`.scss`、`.sass`、`.less`、`.styl`、`.stylus`)を[標準サポート](https://vitejs.dev/guide/features.html#css-pre-processors)しています。Vite 固有のプラグインは不要ですが、各プリプロセッサ本体のインストールは必要です。
```
# .scss / .sass
npm install -D sass
# .less
npm install -D less
# .styl / .stylus
npm install -D stylus
```
その後、Markdown やテーマコンポーネントで次のように使えます。
```vue
<style lang="sass">
.title
font-size: 20px
</style>
```
## Teleport の利用 {#using-teleports}
現時点で VitePress は、SSG における Teleport を **body** へのみサポートしています。その他のターゲットへ Teleport したい場合は、組み込みの `<ClientOnly>` でラップするか、[`postRender` フック](../reference/site-config#postrender)で最終ページ HTML の適切な位置に Teleport のマークアップを注入してください。
<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>
## VS Code の IntelliSense サポート {#vs-code-intellisense-support}
<!-- Based on https://github.com/vuejs/language-tools/pull/4321 -->
Vue は [Vue - Official VS Code plugin](https://marketplace.visualstudio.com/items?itemName=Vue.volar) により、標準で IntelliSense を提供します。ただし `.md` ファイルでも有効にするには、設定ファイルをいくつか調整する必要があります。
1. tsconfig/jsconfig の `include``vueCompilerOptions.vitePressExtensions``.md` パターンを追加します。
::: code-group
```json [tsconfig.json]
{
"include": [
"docs/**/*.ts",
"docs/**/*.vue",
"docs/**/*.md",
],
"vueCompilerOptions": {
"vitePressExtensions": [".md"],
},
}
```
:::
2. VS Code の設定で、`vue.server.includeLanguages` に `markdown` を追加します。
::: code-group
```json [.vscode/settings.json]
{
"vue.server.includeLanguages": ["vue", "markdown"]
}
```
:::

@ -0,0 +1,57 @@
# VitePress とは? {#what-is-vitepress}
VitePress は、高速でコンテンツ中心の Web サイトを構築するための [静的サイトジェネレーターSSG](https://en.wikipedia.org/wiki/Static_site_generator) です。要するに、VitePress は [Markdown](https://en.wikipedia.org/wiki/Markdown) で書かれたソースコンテンツにテーマを適用し、どこにでも簡単にデプロイできる静的 HTML ページを生成します。
<div class="tip custom-block" style="padding-top: 8px">
まずは試してみたい? [クイックスタート](./getting-started) へどうぞ。
</div>
## ユースケース {#use-cases}
- **ドキュメント**
VitePress には技術ドキュメント向けに設計されたデフォルトテーマが同梱されています。今あなたが読んでいるこのページのほか、[Vite](https://vitejs.dev/)、[Rollup](https://rollupjs.org/)、[Pinia](https://pinia.vuejs.org/)、[VueUse](https://vueuse.org/)、[Vitest](https://vitest.dev/)、[D3](https://d3js.org/)、[UnoCSS](https://unocss.dev/)、[Iconify](https://iconify.design/) など、[まだまだたくさん](https://github.com/search?q=/"vitepress":+/+language:json&type=code)のドキュメントサイトで使われています。
[公式の Vue.js ドキュメント](https://vuejs.org/) も VitePress をベースにしています(複数言語で共有されるカスタムテーマを使用)。
- **ブログ/ポートフォリオ/マーケティングサイト**
VitePress は [フルカスタムテーマ](./custom-theme) をサポートし、標準的な Vite + Vue アプリ同様の開発体験を提供します。Vite 上に構築されているため、豊富なエコシステムから Vite プラグインを直接活用できます。さらに、[データの読み込み](./data-loading)(ローカル/リモート)や [ルートの動的生成](./routing#dynamic-routes) のための柔軟な API も提供します。ビルド時にデータが確定できる限り、ほとんど何でも構築できます。
公式の [Vue.js ブログ](https://blog.vuejs.org/) は、ローカルコンテンツに基づいてインデックスページを生成するシンプルなブログです。
## 開発体験 {#developer-experience}
VitePress は、Markdown コンテンツを扱う際の優れた開発体験DXを目指しています。
- **[Vite 駆動](https://vitejs.dev/)**:即時サーバー起動、編集はページリロードなしで常に瞬時(<100ms)に反映。
- **[ビルトインの Markdown 拡張](./markdown)**Frontmatter、表、シンタックスハイライト…必要なものはひと通り。特にコードブロック周りの機能が充実しており、高度な技術ドキュメントに最適です。
- **[Vue 拡張 Markdown](./using-vue)**:各 Markdown ページは Vue の [単一ファイルコンポーネントSFC](https://vuejs.org/guide/scaling-up/sfc.html) としても機能します。HTML と 100% 互換な Vue テンプレートを活かし、Vue のテンプレート機能やインポートしたコンポーネントで静的コンテンツにインタラクションを埋め込めます。
## パフォーマンス {#performance}
多くの従来型 SSG と異なり、VitePress で生成されたサイトは **初回訪問では静的 HTML** を返し、その後のサイト内ナビゲーションは [シングルページアプリケーションSPA](https://en.wikipedia.org/wiki/Single-page_application) として動作します。これはパフォーマンス面で最適なバランスだと考えています。
- **初期ロードが速い**
どのページへの初回訪問でも、静的な事前レンダリング HTML が配信され、高速な読み込みと最適な SEO を実現します。続いて JavaScript バンドルが読み込まれ、ページが Vue の SPA に「ハイドレート」されます。SPA のハイドレーションは遅いという通説に反し、Vue 3 の素のパフォーマンスとコンパイラ最適化により非常に高速です。[PageSpeed Insights](https://pagespeed.web.dev/report?url=https%3A%2F%2Fvitepress.dev%2F) でも、VitePress サイトは低速回線のローエンド端末でもほぼ満点のスコアを達成できます。
- **読み込み後のナビゲーションが速い**
さらに重要なのは、初回ロード**後**の体験が向上することです。サイト内の以降の移動ではフルリロードは発生せず、遷移先のコンテンツを取得して動的に更新します。VitePress はビューポート内のリンクに対してページチャンクを自動プリフェッチするため、ほとんどの場合で遷移は「即時」に感じられます。
- **インタラクションのペナルティなし**
静的 Markdown に埋め込まれた動的な Vue 部分をハイドレートできるよう、各 Markdown ページは Vue コンポーネントとして処理され JavaScript にコンパイルされます。一見非効率に思えますが、Vue コンパイラは静的部分と動的部分を賢く分離し、ハイドレーションのコストとペイロードを最小化します。初回ロードでは静的部分は自動的に JS ペイロードから除外され、ハイドレーションでもスキップされます。
## VuePress はどうなるの? {#what-about-vuepress}
VitePress は VuePress 1 の精神的後継です。元の VuePress 1 は Vue 2 と webpack をベースとしていました。VitePress は内部に Vue 3 と Vite を採用し、開発体験・本番性能・完成度の高いデフォルトテーマ・より柔軟なカスタマイズ API を提供します。
VitePress と VuePress 1 の API の違いは主にテーマやカスタマイズ周りにあります。VuePress 1 でデフォルトテーマを使っている場合は、比較的容易に移行できます。
2 つの SSG を並行して維持するのは現実的ではないため、Vue チームは長期的に VitePress を推奨 SSG とする方針に集中しています。現在、VuePress 1 は非推奨となり、VuePress 2 は今後の開発・保守を VuePress コミュニティチームに委ねています。

@ -0,0 +1,35 @@
---
layout: home
hero:
name: VitePress
text: Vite & Vue をベースにした静的サイトジェネレーター
tagline: Markdown から美しいドキュメントを数分で
actions:
- theme: brand
text: VitePress とは?
link: ./guide/what-is-vitepress
- theme: alt
text: クイックスタート
link: ./guide/getting-started
- theme: alt
text: GitHub
link: https://github.com/vuejs/vitepress
image:
src: /vitepress-logo-large.svg
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 による高速初期ロードと、クライアントサイドルーティングによる快適なページ遷移。
---

@ -0,0 +1,73 @@
# コマンドラインインターフェイス {#command-line-interface}
## `vitepress dev`
指定したディレクトリをルートとして VitePress の開発サーバーを起動します。既定はカレントディレクトリです。カレントディレクトリで実行する場合、`dev` コマンドは省略できます。
### 使い方 {#usage}
```sh
# カレントディレクトリで起動(`dev` を省略)
vitepress
# サブディレクトリで起動
vitepress dev [root]
```
### オプション {#options}
| オプション | 説明 |
| ------------------ | -------------------------------------------------------------------- |
| `--open [path]` | 起動時にブラウザを開く(`boolean \| string` |
| `--port <port>` | ポート番号を指定(`number` |
| `--base <path>` | 公開時のベースパス(既定: `/``string` |
| `--cors` | CORS を有効化 |
| `--strictPort` | 指定ポートが使用中なら終了(`boolean` |
| `--force` | 最適化時にキャッシュを無視して再バンドル(`boolean` |
## `vitepress build`
本番用に VitePress サイトをビルドします。
### 使い方 {#usage-1}
```sh
vitepress build [root]
```
### オプション {#options-1}
| オプション | 説明 |
| ----------------------------- | -------------------------------------------------------------------------------------------------- |
| `--mpa`(実験的) | クライアント側ハイドレーションなしの [MPA モード](../guide/mpa-mode) でビルド(`boolean` |
| `--base <path>` | 公開時のベースパス(既定: `/``string` |
| `--target <target>` | トランスパイルターゲット(既定: `"modules"``string` |
| `--outDir <dir>` | 出力先ディレクトリ(**cwd** からの相対)(既定: `<root>/.vitepress/dist``string` |
| `--assetsInlineLimit <number>`| 静的アセットを base64 インライン化する閾値(バイト)(既定: `4096``number` |
## `vitepress preview`
本番ビルドをローカルでプレビューします。
### 使い方 {#usage-2}
```sh
vitepress preview [root]
```
### オプション {#options-2}
| オプション | 説明 |
| ------------------ | ----------------------------------------- |
| `--base <path>` | 公開時のベースパス(既定: `/``string` |
| `--port <port>` | ポート番号を指定(`number` |
## `vitepress init`
カレントディレクトリで [セットアップウィザード](../guide/getting-started#setup-wizard) を起動します。
### 使い方 {#usage-3}
```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 変数を上書きすることで、バッジのスタイルをカスタマイズできます。以下はデフォルト値です:
```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>` コンポーネントは次の props を受け取ります。
```ts
interface Props {
// `<slot>` が渡された場合、この値は無視されます。
text?: string
// 既定値は `tip`
type?: 'info' | 'tip' | 'warning' | 'danger'
}
```

@ -0,0 +1,22 @@
# Carbon 広告 {#carbon-ads}
VitePress は [Carbon Ads](https://www.carbonads.net/) をネイティブにサポートしています。設定で Carbon Ads の認証情報を定義すると、ページ上に広告が表示されます。
```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,494 @@
# デフォルトテーマの設定 {#default-theme-config}
テーマ設定では、テーマのカスタマイズができます。設定ファイルの `themeConfig` オプションで定義します。
```ts
export default {
lang: 'en-US',
title: 'VitePress',
description: 'Vite & Vue powered static site generator.',
// テーマ関連の設定
themeConfig: {
logo: '/logo.svg',
nav: [...],
sidebar: { ... }
}
}
```
**このページで説明するオプションは、デフォルトテーマにのみ適用されます。** テーマによって期待する設定は異なります。カスタムテーマを使用する場合、ここで定義したテーマ設定オブジェクトはテーマへ渡され、テーマ側がそれに基づいて条件付きの挙動を定義できます。
## i18nRouting
- 型: `boolean`
ロケールを `zh` のように切り替えると、URL は `/foo`(または `/en/foo/`)から `/zh/foo` に変わります。`themeConfig.i18nRouting` を `false` に設定すると、この挙動を無効化できます。
## logo
- 型: `ThemeableImage`
サイトタイトルの直前に、ナビゲーションバーに表示されるロゴ。パス文字列、またはライト/ダークモードで異なるロゴを設定するオブジェクトを受け取ります。
```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` の場合、ナビのタイトルを非表示にします。ロゴ自体にサイト名が含まれている場合に便利です。
```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 | ((payload: PageData) => string)
activeMatch?: string
target?: string
rel?: string
noIcon?: boolean
}
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[] | { items: SidebarItem[]; base: string }
}
export type SidebarItem = {
/**
* 項目のテキストラベル
*/
text?: string
/**
* 項目のリンク
*/
link?: string
/**
* 子項目
*/
items?: SidebarItem[]
/**
* 指定しない場合、グループは折りたたみ不可。
*
* `true` なら折りたたみ可能でデフォルト折りたたみ
*
* `false` なら折りたたみ可能だがデフォルト展開
*/
collapsed?: boolean
/**
* 子項目のベースパス
*/
base?: string
/**
* 前/次リンクのフッターに表示するテキストをカスタマイズ
*/
docFooterText?: string
rel?: string
target?: string
}
```
## aside
- 型: `boolean | 'left'`
- 既定値: `true`
- ページごとに [frontmatter](./frontmatter-config#aside) で上書き可能
`false` でサイドコンテナの描画を無効化。\
`true` で右側に表示。\
`left` で左側に表示。
すべてのビューポートで無効にしたい場合は、代わりに `outline: false` を使用してください。
## outline
- 型: `Outline | Outline['level'] | false`
- レベルはページごとに [frontmatter](./frontmatter-config#outline) で上書き可能
`false` でアウトラインコンテナの描画を無効化。詳細は以下を参照:
```ts
interface Outline {
/**
* アウトラインに表示する見出しレベル
* 単一の数値なら、そのレベルのみ表示
* タプルなら最小レベルと最大レベル
* `'deep'``[2, 6]` と同じ(`<h2>` 〜 `<h6>` を表示)
*
* @default 2
*/
level?: number | [number, number] | 'deep'
/**
* アウトラインに表示するタイトル
*
* @default 'On this page'
*/
label?: string
}
```
## socialLinks
- 型: `SocialLink[]`
ナビゲーションにアイコン付きのソーシャルリンクを表示します。
```ts
export default {
themeConfig: {
socialLinks: [
// simple-icons (https://simpleicons.org/) の任意のアイコンを指定可能
{ icon: 'github', link: 'https://github.com/vuejs/vitepress' },
{ icon: 'twitter', link: '...' },
// SVG 文字列を渡してカスタムアイコンも可
{
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: '...',
// アクセシビリティ向けにカスタムラベルも指定可(推奨)
ariaLabel: 'cool link'
}
]
}
}
```
```ts
interface SocialLink {
icon: string | { svg: string }
link: string
ariaLabel?: string
}
```
## footer
- 型: `Footer`
- ページごとに [frontmatter](./frontmatter-config#footer) で上書き可能
フッター設定。メッセージや著作権表示を追加できますが、ページにサイドバーがある場合はデザイン上表示されません。
```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) で上書き可能
「このページを編集」リンクを表示します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
}
```
詳細は [デフォルトテーマ: 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`
ダークモード切替スイッチのラベル(モバイル表示のみ)をカスタマイズします。
## lightModeSwitchTitle
- 型: `string`
- 既定値: `Switch to light theme`
ホバー時に表示されるライトモード切替のタイトルをカスタマイズします。
## darkModeSwitchTitle
- 型: `string`
- 既定値: `Switch to dark theme`
ホバー時に表示されるダークモード切替のタイトルをカスタマイズします。
## sidebarMenuLabel
- 型: `string`
- 既定値: `Menu`
サイドバーメニューのラベル(モバイル表示のみ)をカスタマイズします。
## returnToTopLabel
- 型: `string`
- 既定値: `Return to top`
トップに戻るボタンのラベル(モバイル表示のみ)をカスタマイズします。
## langMenuLabel
- 型: `string`
- 既定値: `Change language`
ナビバーの言語切替ボタンの aria-label をカスタマイズします。[i18n](../guide/i18n) を使う場合に有効です。
## skipToContentLabel
- 型: `string`
- 既定値: `Skip to content`
コンテンツへスキップリンクのラベルをカスタマイズします。キーボード操作時に表示されます。
## externalLinkIcon
- 型: `boolean`
- 既定値: `false`
Markdown 内の外部リンクの横に外部リンクアイコンを表示するかどうか。
## `useLayout` <Badge type="info" text="composable" />
レイアウト関連のデータを返します。返り値の型は次のとおりです。
```ts
interface {
isHome: ComputedRef<boolean>
sidebar: Readonly<ShallowRef<DefaultTheme.SidebarItem[]>>
sidebarGroups: ComputedRef<DefaultTheme.SidebarItem[]>
hasSidebar: ComputedRef<boolean>
isSidebarEnabled: ComputedRef<boolean>
hasAside: ComputedRef<boolean>
leftAside: ComputedRef<boolean>
headers: Readonly<ShallowRef<DefaultTheme.OutlineItem[]>>
hasLocalNav: ComputedRef<boolean>
}
```
**例:**
```vue
<script setup>
import { useLayout } from 'vitepress/theme'
const { hasSidebar } = useLayout()
</script>
<template>
<div v-if="hasSidebar">サイドバーがあるときだけ表示</div>
</template>
```

@ -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: 'GitHub でこのページを編集'
}
}
}
```
## フロントマターでの設定 {#frontmatter-config}
ページごとに無効化するには、フロントマターで `editLink` オプションを使用します。
```yaml
---
editLink: false
---
```

@ -0,0 +1,55 @@
# フッター {#footer}
`themeConfig.footer` を設定すると、ページ下部にグローバルフッターが表示されます。
```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
}
```
上記の設定は 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) スロットの利用を検討してください。
:::
なお、[SideBar](./default-theme-sidebar) が表示されている場合はフッターは表示されません。
## フロントマターでの設定 {#frontmatter-config}
ページ単位で無効化するには、フロントマターの `footer` オプションを使用します。
```yaml
---
footer: false
---
```

@ -0,0 +1,188 @@
# ホームページ {#home-page}
VitePress のデフォルトテーマにはホームページ用レイアウトが用意されています([このサイトのトップページ](../) でも使われています)。[フロントマター](./frontmatter-config) に `layout: home` を指定すれば、任意のページで利用できます。
```yaml
---
layout: home
---
```
ただし、この指定だけでは多くのことは起きません。`hero` や `features` などの追加オプションを設定して、ホームページにあらかじめ用意された複数の「セクション」を配置できます。
## ヒーローセクション {#hero-section}
ヒーローセクションはホームページの最上部に表示されます。設定例は次のとおりです。
```yaml
---
layout: home
hero:
name: VitePress
text: Vite & Vue powered static site generator.
tagline: 概要テキスト...
image:
src: /logo.png
alt: VitePress
actions:
- theme: brand
text: はじめる
link: /guide/what-is-vitepress
- theme: alt
text: GitHub で見る
link: https://github.com/vuejs/vitepress
---
```
```ts
interface Hero {
// `text` の上に表示される短い文字列。ブランドカラーで表示。
// 製品名のような短い文言を想定。
name?: string
// ヒーローセクションのメインテキスト。`h1` として出力。
text: string
// `text` の下に表示されるタグライン。
tagline?: string
// テキストとタグラインの横に表示する画像。
image?: ThemeableImage
// ヒーローに表示するアクションボタン。
actions?: HeroAction[]
}
type ThemeableImage =
| string
| { src: string; alt?: string }
| { light: string; dark: string; alt?: string }
interface HeroAction {
// ボタンのカラーテーマ。既定は `brand`
theme?: 'brand' | 'alt'
// ボタンのラベル。
text: string
// ボタンのリンク先。
link: string
// a 要素の target 属性。
target?: string
// a 要素の rel 属性。
rel?: string
}
```
### name の色をカスタマイズする {#customizing-the-name-color}
`name` にはブランドカラー(`--vp-c-brand-1`)が使われますが、`--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-section}
フィーチャーセクションでは、ヒーロー直下に任意の数の機能説明を並べられます。フロントマターに `features` オプションを指定して設定します。
各フィーチャーにはアイコン絵文字または画像を指定できます。アイコンが画像svg, png, jpeg など)の場合は、**適切な幅・高さ** を指定してください。必要に応じて説明テキストや実サイズ、ライト/ダーク用の差し替えも指定できます。
```yaml
---
layout: home
features:
- icon: 🛠️
title: いつでもシンプル&ミニマル
details: 概要テキスト...
- icon:
src: /cool-feature-icon.svg
title: もうひとつの便利機能
details: 概要テキスト...
- icon:
dark: /dark-feature-icon.svg
light: /light-feature-icon.svg
title: さらに別の機能
details: 概要テキスト...
---
```
```ts
interface Feature {
// 各フィーチャーボックスに表示するアイコン。
icon?: FeatureIcon
// フィーチャーのタイトル。
title: string
// フィーチャーの詳細説明。
details: string
// フィーチャーをクリックしたときのリンク(内部・外部どちらも可)。
//
// 例: `guide/reference/default-theme-home-page``https://example.com`
link?: string
// フィーチャー内に表示するリンクテキスト。
// `link` と併用するのが最適。
//
// 例: `Learn more`, `Visit page` など
linkText?: string
// `link` 用の rel 属性。
//
// 例: `external`
rel?: string
// `link` 用の target 属性。
target?: string
}
type FeatureIcon =
| string
| { src: string; alt?: string; width?: string; height: string }
| {
light: string
dark: string
alt?: string
width?: string
height: string
}
```
## Markdown コンテンツ {#markdown-content}
`---` で区切るフロントマターの下に Markdown を書くだけで、ホームページに追加コンテンツを表示できます。
````md
---
layout: home
hero:
name: VitePress
text: Vite & Vue powered static site generator.
---
## はじめに
`npx` を使えば、すぐに VitePress を始められます!
```sh
npm init
npx vitepress init
```

@ -0,0 +1,46 @@
# 最終更新日時 {#last-updated}
ページ右下に、コンテンツの最終更新時刻を表示できます。有効化するには、設定に `lastUpdated` オプションを追加します。
::: info
VitePress は各ファイルの **直近の Git コミットのタイムスタンプ** を用いて「最終更新」を表示します。これを有効にするには、対象の Markdown ファイルが Git にコミットされている必要があります。
内部的には、各ファイルに対して `git log -1 --pretty="%ai"` を実行してタイムスタンプを取得します。すべてのページで同じ更新時刻が表示される場合、CI 環境でよくある)**浅いクローンshallow clone** により Git の履歴が取得できていない可能性があります。
**GitHub Actions** での修正例は次のとおりです。
```yaml{4}
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
```
他の CI/CD プラットフォームでも同様の設定が用意されています。
もしそのようなオプションが使えない場合は、`package.json` のビルドスクリプトで手動フェッチを前置してください。
```json
"docs:build": "git fetch --unshallow && vitepress build docs"
```
:::
## サイトレベルの設定 {#site-level-config}
```js
export default {
lastUpdated: true
}
```
## フロントマターでの設定 {#frontmatter-config}
ページ単位で無効化するには、フロントマターで `lastUpdated` を指定します。
```yaml
---
lastUpdated: false
---
```
より詳しくは [デフォルトテーマ: 最終更新](./default-theme-config#lastupdated) を参照してください。テーマレベルで truthy な値を設定すると、サイトまたはページで明示的に無効化しない限り、この機能は有効になります。

@ -0,0 +1,62 @@
# レイアウト {#layout}
ページの [フロントマター](./frontmatter-config) の `layout` オプションでページのレイアウトを選択できます。利用可能なレイアウトは `doc`、`page`、`home` の 3 種類です。何も指定しない場合は `doc` として扱われます。
```yaml
---
layout: doc
---
```
## Doc レイアウト {#doc-layout}
`doc` は既定のレイアウトで、Markdown 全体を「ドキュメント」風にスタイリングします。コンテンツ全体を `vp-doc` という CSS クラスでラップし、その配下の要素にスタイルを適用します。
`p``h2` などほぼすべての汎用要素に特別なスタイルが当たります。そのため、Markdown 内にカスタム HTML を追加した場合も、これらのスタイルの影響を受ける点に注意してください。
また、以下のようなドキュメント特有の機能も提供します。これらはこのレイアウトでのみ有効になります。
- 編集リンクEdit Link
- 前後リンクPrev / Next Link
- アウトラインOutline
- [Carbon 広告](./default-theme-carbon-ads)
## Page レイアウト {#page-layout}
`page` は「ブランクページ」として扱われます。Markdown はパースされ、[Markdown 拡張](../guide/markdown) も `doc` と同様に機能しますが、既定のスタイルは適用されません。
このレイアウトでは、VitePress テーマにマークアップを干渉させず、すべてを自分でスタイルできます。独自のカスタムページを作成したい場合に便利です。
なお、このレイアウトでも、ページがサイドバー設定に一致する場合はサイドバーが表示されます。
## Home レイアウト {#home-layout}
`home` はテンプレート化された「ホームページ」を生成します。このレイアウトでは、`hero` や `features` などの追加オプションでコンテンツをさらにカスタマイズできます。詳しくは [デフォルトテーマ: ホームページ](./default-theme-home-page) を参照してください。
## レイアウトなし {#no-layout}
レイアウトを一切適用したくない場合は、フロントマターで `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,215 @@
# ナビゲーション {#nav}
ナビはページ上部に表示されるナビゲーションバーです。サイトタイトル、グローバルメニューリンクなどを含みます。
## サイトタイトルとロゴ {#site-title-and-logo}
既定では、ナビには [`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` はナビに表示される文字列、`link` はクリック時に遷移するリンクです。内部リンクは `.md` 拡張子を付けず、必ず `/` で始めるようにしてください。
`link` には、[`PageData`](./runtime-api#usedata) を受け取ってパスを返す関数を指定することもできます。
ナビリンクはドロップダウンメニューにもできます。リンクオプションに `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' }
]
}
]
}
}
```
なお、ドロップダウンのタイトル(上の例の `Dropdown Menu`)には `link` は設定できません。ドロップダウンを開くボタンになるためです。
さらに、ドロップダウン内を「セクション」に分けることもできます(入れ子の `items` を使います)。
```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: [
// ユーザーが `/config/` 配下にいるときにアクティブになる
{
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'
}
]
}
}
```
## ソーシャルリン<E383AA> {#social-links}
[`socialLinks`](./default-theme-config#sociallinks) を参照してください。
## カスタムコンポーネント {#custom-components}
`component` オプションを使って、ナビゲーションバーにカスタムコンポーネントを配置できます。`component` には Vue コンポーネント名を指定し、[Theme.enhanceApp](../guide/custom-theme#theme-interface) で **グローバル登録** しておく必要があります。
```js [.vitepress/config.js]
export default {
themeConfig: {
nav: [
{
text: 'My Menu',
items: [
{
component: 'MyCustomComponent',
// コンポーネントに渡す任意の props
props: {
title: 'My Custom Component'
}
}
]
},
{
component: 'AnotherCustomComponent'
}
]
}
}
```
次に、コンポーネントをグローバル登録します。
```js [.vitepress/theme/index.js]
import DefaultTheme from 'vitepress/theme'
import MyCustomComponent from './components/MyCustomComponent.vue'
import AnotherCustomComponent from './components/AnotherCustomComponent.vue'
/** @type {import('vitepress').Theme} */
export default {
extends: DefaultTheme,
enhanceApp({ app }) {
app.component('MyCustomComponent', MyCustomComponent)
app.component('AnotherCustomComponent', AnotherCustomComponent)
}
}
```
コンポーネントはナビゲーションバー内にレンダリングされます。VitePress は次の追加 props をコンポーネントに提供します。
- `screenMenu`: モバイルのナビメニュー内にあるかどうかを示す任意の boolean
e2e テスト内の例は[こちら](https://github.com/vuejs/vitepress/tree/main/__tests__/e2e/.vitepress)を参照してください。

@ -0,0 +1,43 @@
# 前/次リンク {#prev-next-links}
ドキュメントのフッターに表示される「前のページ」「次のページ」のテキストとリンクをカスタマイズできます。サイドバーに表示しているタイトルとは別の文言を使いたい場合や、フッターを無効化したり、サイドバーに含まれていないページへリンクしたい場合に便利です。
## prev
- 型: `string | false | { text?: string; link?: string }`
- 詳細:
前のページへのリンクに表示するテキスト/リンクを指定します。フロントマターで設定しない場合は、サイドバー設定から自動推測されます。
- 例:
- テキストだけをカスタマイズ:
```yaml
---
prev: 'Get Started | Markdown'
---
```
- テキストとリンクの両方をカスタマイズ:
```yaml
---
prev:
text: 'Markdown'
link: '/guide/markdown'
---
```
- 前のページを非表示にする:
```yaml
---
prev: false
---
```
## next
`prev` と同様ですが、次のページ用の設定です。

@ -0,0 +1,451 @@
---
outline: deep
---
# 検索 {#search}
## ローカル検索 {#local-search}
VitePress は、[minisearch](https://github.com/lucaong/minisearch/) によるブラウザ内インデックスを使った曖昧一致の全文検索をサポートします。有効化するには、`.vitepress/config.ts` で `themeConfig.search.provider``'local'` に設定します。
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
themeConfig: {
search: {
provider: 'local'
}
}
})
```
表示例:
![screenshot of the search modal](/search.png)
代わりに [Algolia DocSearch](#algolia-search) や、次のコミュニティ製プラグインを使うこともできます。
- <https://www.npmjs.com/package/vitepress-plugin-search>
- <https://www.npmjs.com/package/vitepress-plugin-pagefind>
- <https://www.npmjs.com/package/@orama/plugin-vitepress>
### i18n {#local-search-i18n}
多言語検索を行う設定例です。
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
themeConfig: {
search: {
provider: 'local',
options: {
locales: {
zh: { // 既定ロケールの文言も翻訳したい場合はこれを `root`
translations: {
button: {
buttonText: '搜索',
buttonAriaLabel: '搜索'
},
modal: {
displayDetails: '显示详细列表',
resetButtonTitle: '重置搜索',
backButtonTitle: '关闭搜索',
noResultsText: '没有结果',
footer: {
selectText: '选择',
selectKeyAriaLabel: '输入',
navigateText: '导航',
navigateUpKeyAriaLabel: '上箭头',
navigateDownKeyAriaLabel: '下箭头',
closeText: '关闭',
closeKeyAriaLabel: 'esc'
}
}
}
}
}
}
}
}
})
```
### 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-async')} md
*/
async _render(src, env, md) {
// HTML 文字列を返す
}
}
}
}
})
```
この関数はクライアント側のサイトデータからは除外されるため、Node.js の API を使用できます。
#### 例: 検索対象からページを除外する {#example-excluding-pages-from-search}
フロントマターに `search: false` を追加すると、そのページを検索対象から除外できます。あるいは次のようにもできます。
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
themeConfig: {
search: {
provider: 'local',
options: {
async _render(src, env, md) {
const html = await md.renderAsync(src, env)
if (env.frontmatter?.search === false) return ''
if (env.relativePath.startsWith('some/path')) return ''
return html
}
}
}
}
})
```
::: warning 注意
カスタムの `_render` 関数を提供する場合、`search: false` の処理は自分で行う必要があります。また、`env` は `md.renderAsync` の呼び出し前には完全ではないため、`frontmatter` などの任意プロパティのチェックはその後に行ってください。
:::
#### 例: コンテンツの変換 — 見出しアンカーを追加 {#example-transforming-content-adding-anchors}
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
themeConfig: {
search: {
provider: 'local',
options: {
async _render(src, env, md) {
const html = await md.renderAsync(src, env)
if (env.frontmatter?.title)
return await md.renderAsync(`# ${env.frontmatter.title}`) + html
return html
}
}
}
}
})
```
## Algolia 検索 {#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: {
clearButtonTitle: '清除查询条件',
clearButtonAriaLabel: '清除查询条件',
closeButtonText: '关闭',
closeButtonAriaLabel: '关闭',
placeholderText: '搜索文档',
placeholderTextAskAi: '向 AI 提问:',
placeholderTextAskAiStreaming: '回答中...',
searchInputLabel: '搜索',
backToKeywordSearchButtonText: '返回关键字搜索',
backToKeywordSearchButtonAriaLabel: '返回关键字搜索'
},
startScreen: {
recentSearchesTitle: '搜索历史',
noRecentSearchesText: '没有搜索历史',
saveRecentSearchButtonTitle: '保存至搜索历史',
removeRecentSearchButtonTitle: '从搜索历史中移除',
favoriteSearchesTitle: '收藏',
removeFavoriteSearchButtonTitle: '从收藏中移除',
recentConversationsTitle: '最近的对话',
removeRecentConversationButtonTitle: '从历史记录中删除对话'
},
errorScreen: {
titleText: '无法获取结果',
helpText: '你可能需要检查你的网络连接'
},
noResultsScreen: {
noResultsText: '无法找到相关结果',
suggestedQueryText: '你可以尝试查询',
reportMissingResultsText: '你认为该查询应该有结果?',
reportMissingResultsLinkText: '点击反馈'
},
resultsScreen: {
askAiPlaceholder: '向 AI 提问: '
},
askAiScreen: {
disclaimerText: '答案由 AI 生成,可能不准确,请自行验证。',
relatedSourcesText: '相关来源',
thinkingText: '思考中...',
copyButtonText: '复制',
copyButtonCopiedText: '已复制!',
copyButtonTitle: '复制',
likeButtonTitle: '赞',
dislikeButtonTitle: '踩',
thanksForFeedbackText: '感谢你的反馈!',
preToolCallText: '搜索中...',
duringToolCallText: '搜索 ',
afterToolCallText: '已搜索'
},
footer: {
selectText: '选择',
submitQuestionText: '提交问题',
selectKeyAriaLabel: 'Enter 键',
navigateText: '切换',
navigateUpKeyAriaLabel: '向上箭头',
navigateDownKeyAriaLabel: '向下箭头',
closeText: '关闭',
backToSearchText: '返回搜索',
closeKeyAriaLabel: 'Esc 键',
poweredByText: '搜索提供者'
}
}
}
}
}
}
}
}
})
```
[これらのオプション](https://github.com/vuejs/vitepress/blob/main/types/docsearch.d.ts) は上書きできます。詳細は Algolia の公式ドキュメントを参照してください。
### Algolia Ask AI のサポート {#ask-ai}
**Ask AI** を有効にするには、`options` 内に `askAi` オプション(またはその一部)を指定します。
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
themeConfig: {
search: {
provider: 'algolia',
options: {
appId: '...',
apiKey: '...',
indexName: '...',
// askAi: "YOUR-ASSISTANT-ID"
// または
askAi: {
// 少なくとも Algolia から受け取った assistantId を指定
assistantId: 'XXXYYY',
// 任意の上書き — 省略時は上位の appId/apiKey/indexName を再利用
// apiKey: '...',
// appId: '...',
// indexName: '...'
}
}
}
}
})
```
::: warning 注意
キーワード検索を既定にして Ask AI を使わない場合は、`askAi` を指定しないでください。
:::
Ask AI UI の翻訳は `options.translations.modal.askAiScreen``options.translations.resultsScreen` にあります。すべてのキーは[型定義](https://github.com/vuejs/vitepress/blob/main/types/docsearch.d.ts)を参照してください。
### クローラー設定 {#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: 'section.has-active div h2',
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'
}
}
})
```

@ -0,0 +1,180 @@
# サイドバー {#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}
最もシンプルな構成は、リンクの配列を 1 つ渡す方法です。第 1 階層のアイテムがサイドバーの「セクション」を表します。各セクションは `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: [
// `/guide/index.md` を表示
{ text: 'Introduction', link: '/guide/' }
]
}
]
}
}
```
サイドバーのアイテムは、ルートから数えて最大 6 階層まで入れ子にできます。7 階層以上は無視され、表示されません。
```js
export default {
themeConfig: {
sidebar: [
{
text: 'Level 1',
items: [
{
text: 'Level 2',
items: [
{
text: 'Level 3',
items: [
...
]
}
]
}
]
}
]
}
}
```
## 複数のサイドバー {#multiple-sidebars}
ページのパスに応じて異なるサイドバーを表示できます。たとえば、このサイトのように「Guide」セクションと「Config」セクションでナビゲーションを分けたい場合に便利です。
まず、対象のセクションごとにディレクトリを分けてページを配置します。
```
.
├─ guide/
│ ├─ index.md
│ ├─ one.md
│ └─ two.md
└─ config/
├─ index.md
├─ three.md
└─ four.md
```
次に、各セクション用のサイドバーを設定します。この場合、配列ではなくオブジェクトを渡します。
```js
export default {
themeConfig: {
sidebar: {
// ユーザーが `guide` ディレクトリ配下にいるときに表示
'/guide/': [
{
text: 'Guide',
items: [
{ text: 'Index', link: '/guide/' },
{ text: 'One', link: '/guide/one' },
{ text: 'Two', link: '/guide/two' }
]
}
],
// ユーザーが `config` ディレクトリ配下にいるときに表示
'/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: [...]
}
]
}
}
```

@ -0,0 +1,255 @@
<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 コンポーネント群を使ってチームページを構成できます。使い方は 2 通りあり、ドキュメントページに埋め込む方法と、専用のチームページを作成する方法があります。
## ページ内にメンバー一覧を表示する {#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>
# 私たちのチーム
私たちの素晴らしいチームを紹介します。
<VPTeamMembers size="small" :members />
```
上記のように、カード風の要素でメンバーが表示されます。下図のような見た目になります。
<VPTeamMembers size="small" :members />
`<VPTeamMembers>` コンポーネントには `small``medium` の 2 種類のサイズがあります。好みによりますが、ドキュメントページ内で使う場合は `small` が馴染みやすいことが多いでしょう。各メンバーに「説明文」や「スポンサー」ボタンなど、追加のプロパティを付けることもできます。詳細は [`<VPTeamMembers>`](#vpteammembers) を参照してください。
小規模なチームで専用ページまでは不要な場合や、文脈上の参考として一部のメンバーのみを紹介したい場合は、ドキュメントページへ埋め込む方法が適しています。
メンバーが多い場合や、より広いスペースで紹介したい場合は、[専用のチームページを作成する](#専用のチームページを作成する) ことを検討してください。
## 専用のチームページを作成する {#create-a-full-team-page}
ドキュメントページにメンバーを追加する代わりに、カスタムの [ホームページ](./default-theme-home-page) と同様、専用のチームページを作成することもできます。
まず新しい md ファイルを作成します。ファイル名は任意ですが、ここでは `team.md` とします。このファイルでフロントマターに `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>
私たちのチーム
</template>
<template #lead>
VitePress の開発は国際的なチームによって主導されています。
その一部を以下に紹介します。
</template>
</VPTeamPageTitle>
<VPTeamMembers :members />
</VPTeamPage>
```
専用のチームページを作る際は、必ずすべてのチーム関連コンポーネントを `<VPTeamPage>` でラップしてください。レイアウトや余白などが適切に適用されます。
`<VPPageTitle>` はページタイトルのセクションを追加します。タイトルは `<h1>` 見出しになります。`#title` と `#lead` スロットでチームについて説明を書きましょう。
`<VPMembers>` はドキュメントページで使う場合と同様に、メンバー一覧を表示します。
### セクションを追加してメンバーを分ける {#add-sections-to-divide-team-members}
チームページに「セクション」を追加できます。たとえば、コアメンバーとコミュニティパートナーなど、役割ごとにメンバーを分けて説明しやすくできます。
そのためには、先ほど作成した `team.md``<VPTeamPageSection>` コンポーネントを追加します。
```html
---
layout: page
---
<script setup>
import {
VPTeamPage,
VPTeamPageTitle,
VPTeamMembers,
VPTeamPageSection
} from 'vitepress/theme'
const coreMembers = [...]
const partners = [...]
</script>
<VPTeamPage>
<VPTeamPageTitle>
<template #title>私たちのチーム</template>
<template #lead>...</template>
</VPTeamPageTitle>
<VPTeamMembers size="medium" :members="coreMembers" />
<VPTeamPageSection>
<template #title>パートナー</template>
<template #lead>...</template>
<template #members>
<VPTeamMembers size="small" :members="partners" />
</template>
</VPTeamPageSection>
</VPTeamPage>
```
`<VPTeamPageSection>``VPTeamPageTitle` と同様に `#title``#lead` のスロットを持ち、さらにメンバー表示用の `#members` スロットを備えます。
`#members` スロット内に `<VPTeamMembers>` を配置するのを忘れないでください。
## `<VPTeamMembers>`
`<VPTeamMembers>` コンポーネントは、与えられたメンバー配列を表示します。
```html
<VPTeamMembers
size="medium"
:members="[
{ avatar: '...', name: '...' },
{ avatar: '...', name: '...' },
...
]"
/>
```
```ts
interface Props {
// 各メンバーカードのサイズ。既定は `medium`
size?: 'small' | 'medium'
// 表示するメンバー一覧。
members: TeamMember[]
}
interface TeamMember {
// メンバーのアバター画像
avatar: string
// メンバー名
name: string
// 名前の下に表示する肩書き(例: Developer, Software Engineer など)
title?: string
// 所属組織名
org?: string
// 所属組織への URL
orgLink?: string
// メンバーの説明
desc?: string
// ソーシャルリンク(例: GitHub, Twitter など)
// Social Links オブジェクトを渡せます。
// 参照: https://vitepress.dev/reference/default-theme-config.html#sociallinks
links?: SocialLink[]
// メンバーのスポンサー用 URL
sponsor?: string
// スポンサーボタンのテキスト。既定は 'Sponsor'
actionText?: string
}
```
## `<VPTeamPage>`
専用のチームページを作成する際のルートコンポーネントです。単一のスロットのみを受け取り、渡されたチーム関連コンポーネント全体に適切なスタイルを適用します。
## `<VPTeamPageTitle>`
ページの「タイトル」セクションを追加します。`<VPTeamPage>` の直下に置くのが最適です。`#title` と `#lead` のスロットを受け取ります。
```html
<VPTeamPage>
<VPTeamPageTitle>
<template #title>
私たちのチーム
</template>
<template #lead>
VitePress の開発は国際的なチームによって主導されています。
その一部を以下に紹介します。
</template>
</VPTeamPageTitle>
</VPTeamPage>
```
## `<VPTeamPageSection>`
チームページ内に「セクション」を作成します。`#title`、`#lead`、`#members` の各スロットを受け取ります。`<VPTeamPage>` の中に必要な数だけ追加できます。
```html
<VPTeamPage>
...
<VPTeamPageSection>
<template #title>パートナー</template>
<template #lead>Lorem ipsum...</template>
<template #members>
<VPTeamMembers :members="data" />
</template>
</VPTeamPageSection>
</VPTeamPage>
```

@ -0,0 +1,240 @@
---
outline: deep
---
# フロントマター設定 {#frontmatter-config}
フロントマターはページ単位の設定を可能にします。各 Markdown ファイルで、サイト全体やテーマレベルの設定を上書きできます。フロントマターでしか定義できない項目もあります。
使用例:
```md
---
title: Docs with VitePress
editLink: true
---
```
Vue の式内では、グローバル `$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}
以下のフロントマター項目は、デフォルトテーマ使用時にのみ適用されます。
### layout
- 型: `doc | home | page`
- 既定値: `doc`
ページのレイアウトを決めます。
- `doc` — Markdown コンテンツにドキュメント向けの既定スタイルを適用します。
- `home` — 「ホームページ」用の特別なレイアウト。`hero` や `features` を追加指定して、ランディングページを素早く構築できます。
- `page``doc` と似ていますが、コンテンツにスタイルを適用しません。完全にカスタムなページを作りたい場合に便利です。
```yaml
---
layout: doc
---
```
### hero <Badge type="info" text="home ページ専用" />
`layout: home` のときのヒーローセクションの内容を定義します。詳しくは [デフォルトテーマ: ホームページ](./default-theme-home-page) を参照。
### features <Badge type="info" text="home ページ専用" />
`layout: home` のときのフィーチャーセクションに表示する項目を定義します。詳しくは [デフォルトテーマ: ホームページ](./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` レイアウトでの aside コンポーネントの位置を定義します。
この値を `false` にすると aside コンテナを表示しません。\
`true` にすると右側に表示します。\
`'left'` にすると左側に表示します。
```yaml
---
aside: false
---
```
### outline
- 型: `number | [number, number] | 'deep' | false`
- 既定値: `2`
ページのアウトラインに表示する見出しレベルです。[config.themeConfig.outline.level](./default-theme-config#outline) と同じ意味で、サイトレベルの設定を上書きします。
```yaml
---
outline: [2, 4]
---
```
### 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 {
/* ページ固有のスタイル */
}
```
### isHome
- 型: `boolean`
デフォルトテーマは通常、`frontmatter.layout === 'home'` のチェックに基づいてホームページかどうかを判断します。\
カスタムレイアウトでホームページ用の要素を強制的に表示したい場合に便利です。
```yaml
---
isHome: true
---
```

@ -0,0 +1,173 @@
# ランタイム API {#runtime-api}
VitePress には、アプリのデータへアクセスするための組み込み API がいくつか用意されています。さらに、グローバルに使用できる組み込みコンポーネントも提供されています。
ヘルパーメソッドは `vitepress` からグローバルインポートでき、主にカスタムテーマの Vue コンポーネントで使われます。Markdown ファイルは Vue の [Single File Component](https://vuejs.org/guide/scaling-up/sfc.html) にコンパイルされるため、`.md` ファイル内でも使用できます。
`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: Ref<SiteData<T>>
/**
* .vitepress/config.js の themeConfig
*/
theme: Ref<T>
/**
* ページ単位のメタデータ
*/
page: Ref<PageData>
/**
* ページのフロントマター
*/
frontmatter: Ref<PageData['frontmatter']>
/**
* 動的ルートのパラメータ
*/
params: Ref<PageData['params']>
title: Ref<string>
description: Ref<string>
lang: Ref<string>
isDark: Ref<boolean>
dir: Ref<string>
localeIndex: Ref<string>
/**
* 現在の location hash
*/
hash: 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 {
/**
* 現在のルート
*/
route: Route
/**
* 新しい URL へ遷移
*/
go: (to?: string) => Promise<void>
/**
* ルートが変わる前に呼ばれる。`false` を返すと遷移をキャンセル
*/
onBeforeRouteChange?: (to: string) => Awaitable<void | boolean>
/**
* ページコンポーネントが読み込まれる前(履歴が更新された後)に呼ばれる。
* `false` を返すと遷移をキャンセル
*/
onBeforePageLoad?: (to: string) => Awaitable<void | boolean>
/**
* ページコンポーネントが読み込まれた後(更新前)に呼ばれる
*/
onAfterPageLoad?: (to: string) => Awaitable<void>
/**
* ルートが変わった後に呼ばれる
*/
onAfterRouteChange?: (to: string) => Awaitable<void>
}
```
## `withBase` <Badge type="info" text="helper" />
- **型**: `(path: string) => string`
設定された [`base`](./site-config#base) を指定の URL パスに付与します。[Base URL](../guide/asset-handling#base-url) も参照。
## `<Content />` <Badge type="info" text="component" />
レンダリング済みの Markdown コンテンツを表示します。[独自テーマの作成時](../guide/custom-theme) に便利です。
```vue
<template>
<h1>Custom Layout!</h1>
<Content />
</template>
```
## `<ClientOnly />` <Badge type="info" text="component" />
スロット内容をクライアント側でのみレンダリングします。
VitePress アプリは静的ビルド時に Node.js 上でサーバーレンダリングされるため、Vue の使用はユニバーサルコードの要件に従う必要があります。要するに、ブラウザDOM API へのアクセスは beforeMount / mounted フック内に限定してください。
SSR 非対応(例: カスタムディレクティブを含む)なコンポーネントを使用・デモする場合は、`ClientOnly` でラップできます。
```vue-html
<ClientOnly>
<NonSSRFriendlyComponent />
</ClientOnly>
```
- 関連: [SSR 互換性](../guide/ssr-compat)
## `$frontmatter` <Badge type="info" text="template global" />
Vue の式内で現在ページの [フロントマター](../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,722 @@
---
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 Modules 構文の使用を推奨します。設定オブジェクトをデフォルトエクスポートしてください。
```ts
export default {
// アプリレベルの設定
lang: 'en-US',
title: 'VitePress',
description: 'Vite & Vue powered static site generator.',
...
}
```
::: details 動的(非同期)設定
設定を動的に生成する必要がある場合は、関数をデフォルトエクスポートすることもできます。例:
```ts
import { defineConfig } from 'vitepress'
export default async () => {
const posts = await (await fetch('https://my-cms.com/blog-posts')).json()
return defineConfig({
// アプリレベル設定
lang: 'en-US',
title: 'VitePress',
description: 'Vite & Vue powered static site generator.',
// テーマレベル設定
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({
// アプリレベル設定
lang: 'en-US',
title: 'VitePress',
description: 'Vite & Vue powered static site generator.',
// テーマレベル設定
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: {
// 型は `DefaultTheme.Config`
}
})
```
カスタムテーマを使用しており、そのテーマ設定に型チェックを効かせたい場合は、代わりに `defineConfigWithTheme` を使い、ジェネリクスでカスタムテーマの設定型を渡してください。
```ts
import { defineConfigWithTheme } from 'vitepress'
import type { ThemeConfig } from 'your-theme'
export default defineConfigWithTheme<ThemeConfig>({
themeConfig: {
// 型は `ThemeConfig`
}
})
```
### Vite・Vue・Markdown の設定 {#vite-vue-markdown-config}
- **Vite**
Vite の設定は VitePress 設定の [vite](#vite) オプションで行えます。別途 Vite の設定ファイルを作る必要はありません。
- **Vue**
VitePress には公式の Vue プラグイン([@vitejs/plugin-vue](https://github.com/vitejs/vite-plugin-vue))が同梱されています。オプションは VitePress 設定の [vue](#vue) から指定できます。
- **Markdown**
既定の [Markdown-It](https://github.com/markdown-it/markdown-it) インスタンスは、VitePress 設定の [markdown](#markdown) オプションでカスタマイズできます。
## サイトメタデータ {#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>` に追加で出力する要素。ユーザーが追加したタグは、VitePress のタグの後、`</head>` の直前にレンダリングされます。
```ts
type HeadConfig =
| [string, Record<string, string>]
| [string, Record<string, string>, string]
```
#### 例: favicon を追加 {#example-adding-a-favicon}
```ts
export default {
head: [['link', { rel: 'icon', href: '/favicon.ico' }]]
} // favicon.ico は public に配置。base を設定している場合は /base/favicon.ico を利用
/* 出力結果:
<link rel="icon" href="/favicon.ico">
*/
```
#### 例: Google Fonts を追加 {#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' }
]
]
}
/* 出力結果:
<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">
*/
```
#### 例: Service Worker を登録 {#example-registering-a-service-worker}
```ts
export default {
head: [
[
'script',
{ id: 'register-sw' },
`;(() => {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
}
})()`
]
]
}
/* 出力結果:
<script id="register-sw">
;(() => {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
}
})()
</script>
*/
```
#### 例: Google Analytics を使用 {#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');`
]
]
}
/* 出力結果:
<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`
サイトの言語属性。ページ HTML の `<html lang="en-US">` として出力されます。
```ts
export default {
lang: 'en-US'
}
```
### base
- 型: `string`
- 既定値: `/`
サイトをデプロイするベース URL。GitHub Pages などサブパス配下にデプロイする場合に設定が必要です。たとえば `https://foo.github.io/bar/` にデプロイする場合、`base` は `'/bar/'` にします。先頭と末尾は必ずスラッシュにしてください。
`/` で始まる他のオプション内の URL には、この `base` が自動的に付与されます。1 回設定すれば十分です。
```ts
export default {
base: '/base/'
}
```
## ルーティング {#routing}
### cleanUrls
- 型: `boolean`
- 既定値: `false`
`true` にすると、URL の末尾の `.html` を削除します。あわせて [クリーン URL の生成](../guide/routing#generating-clean-url) も参照してください。
::: warning サーバ設定が必要
ホスティング環境によっては追加の設定が必要です。`/foo` へのアクセス時に **リダイレクトなしで** `/foo.html` を返せるサーバ設定が必要です。
:::
### rewrites
- 型: `Record<string, string>`
ディレクトリと 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 ファイルにマッチする [glob パターン](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, source: string) => boolean))[]`
- 既定値: `false`
`true` にすると、デッドリンクがあってもビルド失敗にしません。
`'localhostLinks'` にすると、`localhost` へのリンクはチェック対象外にしつつ、その他のデッドリンクではビルドを失敗させます。
```ts
export default {
ignoreDeadLinks: true
}
```
正確な URL 文字列、正規表現、カスタムフィルタ関数の配列として指定することもできます。
```ts
export default {
ignoreDeadLinks: [
// 正確に "/playground" を無視
'/playground',
// すべての localhost リンクを無視
/^https?:\/\/localhost/,
// パスに "/repl/" を含むリンクを無視
/\/repl\//,
// カスタム関数: "ignore" を含むリンクを無視
(url) => {
return url.toLowerCase().includes('ignore')
}
]
}
```
### metaChunk <Badge type="warning" text="experimental" />
- 型: `boolean`
- 既定値: `false`
`true` にすると、各ページのメタデータを初期 HTML にインラインせず、別の JavaScript チャンクに抽出します。これにより各ページの HTML ペイロードが小さくなり、メタデータをキャッシュ可能にすることで、多数のページがあるサイトでサーバ帯域を削減できます。
### mpa <Badge type="warning" text="experimental" />
- 型: `boolean`
- 既定値: `false`
`true` にすると、本番アプリは [MPA モード](../guide/mpa-mode) でビルドされます。MPA モードは既定でクライアント JavaScript を 0kb で配信する代わりに、クライアントサイドのナビゲーションを無効にし、相互作用には明示的な opt-in が必要です。
## テーマ関連 {#theming}
### appearance
- 型: `boolean | 'dark' | 'force-dark' | 'force-auto' | import('@vueuse/core').UseDarkOptions`
- 既定値: `true`
ダークモードを有効にするか(`<html>` に `.dark` クラスを付与)。
- `true` の場合、ユーザーの環境設定に従います。
- `dark` の場合、ユーザーが切り替えない限りダークを既定にします。
- `false` の場合、ユーザーはテーマを切り替えできません。
- `'force-dark'` の場合、常にダークで固定(切替不可)。
- `'force-auto'` の場合、常にユーザーの環境設定に従い(切替不可)。
このオプションは、ローカルストレージの `vitepress-theme-appearance` から設定を復元するインラインスクリプトを挿入します。これにより、ページ描画前に `.dark` クラスを適用してフリッカを防ぎます。
`appearance.initialValue``'dark' | undefined` のみサポート。Ref や getter は使えません。
### 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)、構文ハイライトに [Shiki](https://github.com/shikijs/shiki) を使用しています。必要に応じて Markdown 関連の各種オプションを指定できます。
```js
export default {
markdown: {...}
}
```
利用可能なオプションは [型定義と JSDoc](https://github.com/vuejs/vitepress/blob/main/src/node/markdown/markdown.ts) を参照してください。
### vite
- 型: `import('vite').UserConfig`
内部の Vite 開発サーバ/バンドラへ生の [Vite Config](https://vitejs.dev/config/) を渡します。
```js
export default {
vite: {
// Vite の設定
}
}
```
### vue
- 型: `import('@vitejs/plugin-vue').Options`
内部の `@vitejs/plugin-vue` インスタンスへオプションをそのまま渡します。
```js
export default {
vue: {
// @vitejs/plugin-vue のオプション
}
}
```
## ビルドフック {#build-hooks}
VitePress のビルドフックを使うと、サイトに機能や振る舞いを追加できます。
- サイトマップ
- 検索インデックス
- 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 中の teleport コンテンツの処理に利用できます。
```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 を変換するためのビルドフックです。設定ファイルでは静的に追加できない head 要素を追加できます。追加分のみ返せば、既存のものと自動でマージされます。
::: warning
`context` 内の値は変更しないでください。
:::
```ts
export default {
async transformHead(context) {
// ...
}
}
```
```ts
interface TransformContext {
page: string // 例: index.mdsrcDir からの相対)
assets: string[] // 解決済みの公開 URL非 js/css アセット)
siteConfig: SiteConfig
siteData: SiteData
pageData: PageData
title: string
description: string
head: HeadConfig[]
content: string
}
```
このフックは静的サイト生成時のみ呼ばれ、開発中には呼ばれません。開発中に動的な head 要素を追加したい場合は、代わりに [`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`
}
])
}
}
```
#### 例: 正規 URL の `<link>` を追加 {#example-adding-a-canonical-url-link}
```ts
export default {
transformPageData(pageData) {
const canonicalUrl = `https://example.com/${pageData.relativePath}`
.replace(/index\.md$/, '')
.replace(/\.md$/, '.html')
pageData.frontmatter.head ??= []
pageData.frontmatter.head.push([
'link',
{ rel: 'canonical', href: canonicalUrl }
])
}
}
```
### 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` を直接変更するか、変更値を返してマージさせることができます。
::: warning
`context` 内の値は変更しないでください。ネットワークリクエストや重い計算(画像生成など)を行うと開発サーバのパフォーマンスに影響します。`process.env.NODE_ENV === 'production'` を用いた条件分岐を検討してください。
:::
```ts
export default {
async transformPageData(pageData, { siteConfig }) {
pageData.contributors = await getPageContributors(pageData.relativePath)
}
// あるいはマージ用の値を返す
async transformPageData(pageData, { siteConfig }) {
return {
contributors: await getPageContributors(pageData.relativePath)
}
}
}
```
```ts
interface TransformPageContext {
siteConfig: SiteConfig
}
```

@ -1,16 +1,17 @@
import { createRequire } from 'module'
import { defineConfig, type DefaultTheme } from 'vitepress'
import { defineAdditionalConfig, type DefaultTheme } from 'vitepress'
const require = createRequire(import.meta.url)
const pkg = require('vitepress/package.json')
export const ko = defineConfig({
lang: 'ko-KR',
export default defineAdditionalConfig({
description: 'Vite 및 Vue 기반 정적 사이트 생성기.',
themeConfig: {
nav: nav(),
search: { options: searchOptions() },
sidebar: {
'/ko/guide/': { base: '/ko/guide/', items: sidebarGuide() },
'/ko/reference/': { base: '/ko/reference/', items: sidebarReference() }
@ -39,6 +40,14 @@ export const ko = defineConfig({
text: '업데이트 날짜'
},
notFound: {
title: '페이지를 찾을 수 없습니다',
quote:
'방향을 바꾸지 않고 계속 찾다 보면 결국 당신이 가고 있는 곳에 도달할 수도 있습니다.',
linkLabel: '홈으로 가기',
linkText: '집으로 데려가줘'
},
langMenuLabel: '언어 변경',
returnToTopLabel: '맨 위로 돌아가기',
sidebarMenuLabel: '사이드바 메뉴',
@ -64,6 +73,10 @@ function nav(): DefaultTheme.NavItem[] {
{
text: pkg.version,
items: [
{
text: '1.6.4',
link: 'https://vuejs.github.io/vitepress/v1/ko/'
},
{
text: '변경 로그',
link: 'https://github.com/vuejs/vitepress/blob/main/CHANGELOG.md'
@ -208,8 +221,8 @@ function sidebarReference(): DefaultTheme.SidebarItem[] {
]
}
export const search: DefaultTheme.AlgoliaSearchOptions['locales'] = {
ko: {
function searchOptions(): Partial<DefaultTheme.AlgoliaSearchOptions> {
return {
placeholder: '문서 검색',
translations: {
button: {
@ -218,10 +231,16 @@ export const search: DefaultTheme.AlgoliaSearchOptions['locales'] = {
},
modal: {
searchBox: {
resetButtonTitle: '검색 지우기',
resetButtonAriaLabel: '검색 지우기',
cancelButtonText: '취소',
cancelButtonAriaLabel: '취소'
clearButtonTitle: '검색 지우기',
clearButtonAriaLabel: '검색 지우기',
closeButtonText: '닫기',
closeButtonAriaLabel: '닫기',
placeholderText: '문서 검색',
placeholderTextAskAi: 'AI에게 물어보기: ',
placeholderTextAskAiStreaming: '답변 작성 중...',
searchInputLabel: '검색',
backToKeywordSearchButtonText: '키워드 검색으로 돌아가기',
backToKeywordSearchButtonAriaLabel: '키워드 검색으로 돌아가기'
},
startScreen: {
recentSearchesTitle: '검색 기록',
@ -229,23 +248,50 @@ export const search: DefaultTheme.AlgoliaSearchOptions['locales'] = {
saveRecentSearchButtonTitle: '검색 기록에 저장',
removeRecentSearchButtonTitle: '검색 기록에서 삭제',
favoriteSearchesTitle: '즐겨찾기',
removeFavoriteSearchButtonTitle: '즐겨찾기에서 삭제'
removeFavoriteSearchButtonTitle: '즐겨찾기에서 삭제',
recentConversationsTitle: '최근 대화',
removeRecentConversationButtonTitle: '대화를 기록에서 삭제'
},
errorScreen: {
titleText: '결과를 가져올 수 없습니다',
helpText: '네트워크 연결을 확인하세요'
},
noResultsScreen: {
noResultsText: '결과를 찾을 수 없습니다',
suggestedQueryText: '다른 검색어를 시도해 보세요',
reportMissingResultsText: '결과가 있어야 한다고 생각하나요?',
reportMissingResultsLinkText: '피드백 보내기'
},
resultsScreen: {
askAiPlaceholder: 'AI에게 물어보기: '
},
askAiScreen: {
disclaimerText:
'AI가 생성한 답변으로 오류가 있을 수 있습니다. 반드시 확인하세요.',
relatedSourcesText: '관련 소스',
thinkingText: '생각 중...',
copyButtonText: '복사',
copyButtonCopiedText: '복사됨!',
copyButtonTitle: '복사',
likeButtonTitle: '좋아요',
dislikeButtonTitle: '싫어요',
thanksForFeedbackText: '피드백 감사합니다!',
preToolCallText: '검색 중...',
duringToolCallText: '검색 중 ',
afterToolCallText: '검색 완료',
aggregatedToolCallText: '검색 완료'
},
footer: {
selectText: '선택',
submitQuestionText: '질문 보내기',
selectKeyAriaLabel: 'Enter 키',
navigateText: '탐색',
navigateUpKeyAriaLabel: '위쪽 화살표',
navigateDownKeyAriaLabel: '아래쪽 화살표',
closeText: '닫기',
searchByText: '검색 기준'
},
noResultsScreen: {
noResultsText: '결과를 찾을 수 없습니다',
suggestedQueryText: '새로운 검색을 시도할 수 있습니다',
reportMissingResultsText: '해당 검색어에 대한 결과가 있어야 합니까?',
reportMissingResultsLinkText: '피드백 보내기 클릭'
backToSearchText: '검색으로 돌아가기',
closeKeyAriaLabel: 'Esc 키',
poweredByText: '제공: '
}
}
}

@ -162,7 +162,7 @@ HTML 코드에 대해 _Auto Minify_ 옵션을 활성화하지 마세요. 이는
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
node-version: 22
cache: npm # 또는 pnpm / yarn
- name: Setup Pages
uses: actions/configure-pages@v4

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save