Merge branch 'main' into chore/markdown-it-as-dependencies

pull/5038/head
Barbapapazes 2 weeks ago
commit 98135f7ce4
No known key found for this signature in database
GPG Key ID: 4746D5AF03FBAEA3

@ -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,10 +9,22 @@ on:
types: [opened, synchronize, labeled, ready_for_review]
paths-ignore:
- '.github/**'
- '!.github/workflows/cr.yml'
- '__tests__/**'
- 'art/**'
- 'docs/**'
- '*.md'
push:
branches: [main]
paths-ignore:
- '.github/**'
- '!.github/workflows/cr.yml'
- '__tests__/**'
- 'art/**'
- 'docs/**'
- '*.md'
tags-ignore:
- '*'
permissions: {}
@ -22,15 +34,15 @@ concurrency:
jobs:
release:
if: ${{ !github.event.pull_request.draft && contains(github.event.pull_request.labels.*.name, 'cr-tracked') && !contains(github.event.pull_request.labels.*.name, 'spam') && !contains(github.event.pull_request.labels.*.name, 'invalid') }}
if: ${{ ((github.event_name == 'pull_request' && !github.event.pull_request.draft && contains(github.event.pull_request.labels.*.name, 'cr-tracked') && !contains(github.event.pull_request.labels.*.name, 'spam') && !contains(github.event.pull_request.labels.*.name, 'invalid')) || (github.event_name == 'push' && !startsWith(github.event.head_commit.message, 'release:'))) && github.repository == 'vuejs/vitepress' }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v3
- uses: actions/setup-node@v4
- uses: actions/checkout@v5
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v6
with:
node-version: 22
node-version: 24
cache: pnpm
- run: pnpm install
- run: pnpm build

@ -12,7 +12,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Create Release for Tag
id: release_tag

@ -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

@ -1,10 +1,5 @@
name: Test
env:
NODE_OPTIONS: --max-old-space-size=6144
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: '1'
VITEST_SEGFAULT_RETRY: 3
on:
push:
branches: [main]
@ -20,27 +15,33 @@ concurrency:
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node_version: [18, 20, 22]
os: [ubuntu-latest]
node_version: [20, 22, 24, latest]
include:
- os: windows-latest
node_version: 24
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Install pnpm
uses: pnpm/action-setup@v3
uses: pnpm/action-setup@v4
- name: Set node version to ${{ matrix.node_version }}
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node_version }}
cache: pnpm
- name: Install deps
run: pnpm install
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
- name: Install Playwright
run: pnpm playwright install chromium

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

@ -1,3 +1,340 @@
## [2.0.0-alpha.14](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.13...v2.0.0-alpha.14) (2025-11-21)
### Bug Fixes
- log dead links in dev mode too ([179ee62](https://github.com/vuejs/vitepress/commit/179ee621d99b3c14e2e098e3b786465cbeaeab9a)), closes [#4419](https://github.com/vuejs/vitepress/issues/4419)
- **theme:** sidebar alignment when scrollbar is there on page ([0ee7158](https://github.com/vuejs/vitepress/commit/0ee71588de2b1691b1a9287aa1daa729197fd3ca)), closes [#5027](https://github.com/vuejs/vitepress/issues/5027)
### Features
- **client:** emit `vitepress:codeGroupTabActivate` custom event when a code group tab is activated ([dfb02a4](https://github.com/vuejs/vitepress/commit/dfb02a479f19afbee9e292b15c3c2beef271e57f)), closes [#5023](https://github.com/vuejs/vitepress/issues/5023)
## [2.0.0-alpha.13](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.12...v2.0.0-alpha.13) (2025-11-13)
### Bug Fixes
- **client,a11y:** improve focus handling and scrolling behavior in router ([#4943](https://github.com/vuejs/vitepress/issues/4943)) ([d46107f](https://github.com/vuejs/vitepress/commit/d46107fa254d662d297b1362aa0d3b898ef96e2c))
- disable markdown-it-attrs for fenced code blocks ([0899618](https://github.com/vuejs/vitepress/commit/089961855653f862b71747e8179ef2647e06d626))
- git log parsing when there are empty commits in history ([#4965](https://github.com/vuejs/vitepress/issues/4965)) ([612c458](https://github.com/vuejs/vitepress/commit/612c45895df79a0c0e87ca040564bfe88ce04f62))
- print full path in dead links check ([2b77fb3](https://github.com/vuejs/vitepress/commit/2b77fb3a72058129edbaddd3c6f0f6ee24f983d5)), closes [#4919](https://github.com/vuejs/vitepress/issues/4919)
- rename `markdown.cjkFriendly` to `markdown.cjkFriendlyEmphasis` ([bce0b53](https://github.com/vuejs/vitepress/commit/bce0b53659fa3a57b2ed8431a0861939dadd118a)), closes [#4952](https://github.com/vuejs/vitepress/issues/4952)
- respect markdown.cache = false on build too ([6d7422f](https://github.com/vuejs/vitepress/commit/6d7422f8fa321c641b1d5be3fa0c382400a2b78f))
- simplify lang extraction logic; use markdown-it plugins in type-safe manner; bump deps ([4e548f5](https://github.com/vuejs/vitepress/commit/4e548f542469a366f327cdef1530bdb1a31542ad))
- **theme:** add lang and dir attributes to language picker ([f0b29d7](https://github.com/vuejs/vitepress/commit/f0b29d7ef32a33f61c355d19561176411ede4b48))
- **theme:** adjust margin of code blocks inside containers ([82fac5d](https://github.com/vuejs/vitepress/commit/82fac5d22c9e2b28d18dafcd458741a4b4d7a86b)), closes [#4921](https://github.com/vuejs/vitepress/issues/4921)
- **theme:** avoid use of `:where` in selector list for now ([c2eaccd](https://github.com/vuejs/vitepress/commit/c2eaccd0d2109a6c64cee9fe615e48daaf4eda0e)), closes [#4923](https://github.com/vuejs/vitepress/issues/4923)
- **theme:** disable whitespace wrapping for VPBadge ([#4968](https://github.com/vuejs/vitepress/issues/4968)) ([113d230](https://github.com/vuejs/vitepress/commit/113d2304784586028d9733036ccb585374731397))
- **theme:** use nav height css var for curtain top in sidebar ([#4993](https://github.com/vuejs/vitepress/issues/4993)) ([be260fd](https://github.com/vuejs/vitepress/commit/be260fda6efc1d6c4b56219d7a17a19ab7a4ba76))
### Features
- export cacheAllGitTimestamps and getGitTimestamp ([31d87e2](https://github.com/vuejs/vitepress/commit/31d87e27387ebdceb22c047cc5f821761276d5f7))
- **i18n,a11y:** change last update logic ([#4935](https://github.com/vuejs/vitepress/issues/4935)) ([187bf25](https://github.com/vuejs/vitepress/commit/187bf250e6496554fca0b070a5aba55484f7fc0b))
- **markdown:** support custom display-name for fenced code blocks ([#4960](https://github.com/vuejs/vitepress/issues/4960)) ([3d61619](https://github.com/vuejs/vitepress/commit/3d61619ec0f0458c7ae04e7954b72a8e2ff399c0))
- prevent `$` symbol selection in shell code ([#5025](https://github.com/vuejs/vitepress/issues/5025)) ([bf2715e](https://github.com/vuejs/vitepress/commit/bf2715ed67f290726fc6d4c85c203ca8f74cc907))
- **theme:** allow passing functions for nav links ([#4963](https://github.com/vuejs/vitepress/issues/4963)) ([34cfa91](https://github.com/vuejs/vitepress/commit/34cfa91b6f14d8adfaa2d3c9f3eb6ad8b889ef1c))
### Performance Improvements
- make a single git call for timestamps instead of calling it for each file ([#4958](https://github.com/vuejs/vitepress/issues/4958)) ([6dfcdd3](https://github.com/vuejs/vitepress/commit/6dfcdd3fe8dc73e7b4ad7783df9530dedac1f6bd))
### BREAKING CHANGES
- `markdown-it-attrs` is disabled for fenced code blocks. For most users no change is required. If you want to add classes to code blocks, do it using shiki transformers instead.
- Rename `cjkFriendly` to `cjkFriendlyEmphasis` in your vitepress config. Most people should be unaffected unless they want to disable the CJK emphasis behavior added v2.0.0-alpha.12.
## [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
- **build/regression:** langAlias not working ([06ae2bf](https://github.com/vuejs/vitepress/commit/06ae2bf3a4ee02351530b0bd055e577ca6509d62)), closes [#4581](https://github.com/vuejs/vitepress/issues/4581)
- don't hardcode `tabindex` attr in table renderer ([#4082](https://github.com/vuejs/vitepress/issues/4082)) ([aadc517](https://github.com/vuejs/vitepress/commit/aadc517c69fb239bdda99173bbc123ace567484b))
- hmr not working for watched files in path loaders ([e271695](https://github.com/vuejs/vitepress/commit/e271695d716247455ca620948f814e6c8ca0e3c4)), closes [#4525](https://github.com/vuejs/vitepress/issues/4525)
- ignore non-text content in permalink generation and fix types of markdown.config ([a8a1800](https://github.com/vuejs/vitepress/commit/a8a1800ae578be88027aa4ec7561ada4d055b888))
- prevent reload on first server start in fresh installations ([d8a884e](https://github.com/vuejs/vitepress/commit/d8a884ed0f754523765058a70149cdbaf6942341))
- properly merge classes in custom containers ([#4128](https://github.com/vuejs/vitepress/issues/4128)) ([8aad617](https://github.com/vuejs/vitepress/commit/8aad617446c03d39a65a0b21e9fce43bc484af1e))
- rebuild dynamic routes cache on server restart ([9f54714](https://github.com/vuejs/vitepress/commit/9f54714e7db69fd4902f1917f927456c71b5a292)), closes [#4525](https://github.com/vuejs/vitepress/issues/4525)
### Features
- allow matching region end in snippets without tag ([#4287](https://github.com/vuejs/vitepress/issues/4287)) ([1a2f81d](https://github.com/vuejs/vitepress/commit/1a2f81de4d6549dd1adf86ae131d1a861158bd2d))
- improve region regexes for snippet plugin ([1a6684c](https://github.com/vuejs/vitepress/commit/1a6684cf1054d326bc1dd6eeb9fb78b150ac2b2a))
- support using header anchors in markdown file inclusion ([#4608](https://github.com/vuejs/vitepress/issues/4608)) ([b99d512](https://github.com/vuejs/vitepress/commit/b99d5123c9b2afdc7461089e03476c34d7816faf)), closes [#4375](https://github.com/vuejs/vitepress/issues/4375) [#4382](https://github.com/vuejs/vitepress/issues/4382)
## [2.0.0-alpha.3](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.2...v2.0.0-alpha.3) (2025-02-24)
### Bug Fixes
- **build:** `--minify` not working as documented ([9b5c037](https://github.com/vuejs/vitepress/commit/9b5c0377cd3474447c84b2901801287f3caf3d82)), closes [#4523](https://github.com/vuejs/vitepress/issues/4523)
- **build:** deterministic code group ids ([#4565](https://github.com/vuejs/vitepress/issues/4565)) ([b930b8d](https://github.com/vuejs/vitepress/commit/b930b8d5310f1691d8d9f009f45b70122e4ce800))
- **markdown:** include content of all tokens in heading ids ([68dff2a](https://github.com/vuejs/vitepress/commit/68dff2af8547ae70f6622ac826affd76f2f6378e)), closes [#4561](https://github.com/vuejs/vitepress/issues/4561)
- **client:** set correct oldURL and newURL for hashchange ([#4573](https://github.com/vuejs/vitepress/issues/4573)) ([d1f2afd](https://github.com/vuejs/vitepress/commit/d1f2afdf0fbb022f12cc12295723b3b7c7ef5cb1))
- **theme:** allow interactions behind scroll shadow ([#4537](https://github.com/vuejs/vitepress/issues/4537)) ([091d584](https://github.com/vuejs/vitepress/commit/091d5840ae15b64e04e8c07fbc0263a2749571bd))
- **theme:** code block contrast ratio ([#4487](https://github.com/vuejs/vitepress/issues/4487)) ([5dccaee](https://github.com/vuejs/vitepress/commit/5dccaeef055beb109919f8990032975a0d630384))
- **build:** fix flaky embedded languages highlighting ([#4566](https://github.com/vuejs/vitepress/issues/4566)) ([1969cf4](https://github.com/vuejs/vitepress/commit/1969cf4f3b93ad105595e4e2f8b030b04eb1c975))
### Features
- **cli:** support custom `srcDir` ([#4270](https://github.com/vuejs/vitepress/issues/4270)) ([518c094](https://github.com/vuejs/vitepress/commit/518c0945f159aae679ef710bb48ae3ab3891cc9f))
- **cli:** support custom npm scripts prefix ([#4271](https://github.com/vuejs/vitepress/issues/4271)) ([e5a0ee8](https://github.com/vuejs/vitepress/commit/e5a0ee8161752a77c5bb9546245a940cb5f28fb8))
- **build:** dynamic routes plugin overhaul ([#4525](https://github.com/vuejs/vitepress/issues/4525)) ([a62ea6a](https://github.com/vuejs/vitepress/commit/a62ea6a832a33b756642b24ad5d38c248e08b554))
- **build:** update to shiki v3 ([#4571](https://github.com/vuejs/vitepress/issues/4571)) ([52c2aa1](https://github.com/vuejs/vitepress/commit/52c2aa178d4b3fa98b863cf28f0ccf6d2aabcd93))
- **build:** use `markdown-it-async`, remove `synckit` ([#4507](https://github.com/vuejs/vitepress/issues/4507)) ([8062235](https://github.com/vuejs/vitepress/commit/80622356f1d648577ee47ee3a44b04bb015ee462))
### BREAKING CHANGES
- markdown-it-async is used instead of markdown-it. If you're using custom content renderer for local search, you'll need to do `await md.renderAsync` instead of `md.render`.
- Internals are modified a bit to better support vite 6 and handle HMR more correctly. For most users this won't need any change on their side.
- shiki is upgraded to v3. There shouldn't be any breaking change but if you see any issue, please report it.
## [2.0.0-alpha.2](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.1...v2.0.0-alpha.2) (2025-01-23)
### Bug Fixes
- fix docsearch navigation and rendering ([e035027](https://github.com/vuejs/vitepress/commit/e0350275b39258a61ee867840ce1c6f5b2cecf2a))
- **types:** support preload built-in shiki languages as string ([#4513](https://github.com/vuejs/vitepress/issues/4513)) ([4f77b4f](https://github.com/vuejs/vitepress/commit/4f77b4fdfdbe945e482348a57731bff5fb4672fc))
### Features
- allow `markdown.config` and `markdown.preConfig` to accept async function ([#4512](https://github.com/vuejs/vitepress/issues/4512)) ([b88ae8d](https://github.com/vuejs/vitepress/commit/b88ae8d4a11a20104b2007c2631eb7aeb123d965))
- support same page navigation in `router.go` and expose decoded hash and query from the `route` object ([#4511](https://github.com/vuejs/vitepress/issues/4511)) ([23d3281](https://github.com/vuejs/vitepress/commit/23d3281ed6f1111ab15708ca1fd86202674f8ef7))
## [2.0.0-alpha.1](https://github.com/vuejs/vitepress/compare/v1.6.2...v2.0.0-alpha.1) (2025-01-22)
### Features
- upgrade vite to v6 ([#4504](https://github.com/vuejs/vitepress/issues/4504)) ([6a2efc3](https://github.com/vuejs/vitepress/commit/6a2efc385c90b088241db05f5263b2f3e1f757cf))
## [1.6.3](https://github.com/vuejs/vitepress/compare/v1.6.2...v1.6.3) (2025-01-22)
### Bug Fixes
- docsearch not rendering properly ([3e4120e](https://github.com/vuejs/vitepress/commit/3e4120e94805156bf63587fd633162433dbaf260))
## [1.6.2](https://github.com/vuejs/vitepress/compare/v1.6.1...v1.6.2) (2025-01-22)
### Bug Fixes
- fix static content removal for lean chunks due to Vue 3.5 changes ([#4508](https://github.com/vuejs/vitepress/issues/4508)) ([8214cae](https://github.com/vuejs/vitepress/commit/8214cae21bb16842d8870d5867e974146c51fd61))
## [1.6.1](https://github.com/vuejs/vitepress/compare/v1.6.0...v1.6.1) (2025-01-20)
### Bug Fixes
- **build:** escape `$` in replace pattern in dynamic routes plugin ([e812916](https://github.com/vuejs/vitepress/commit/e8129167c76104d59d31a77b16dff3458e6af5eb)), closes [#4499](https://github.com/vuejs/vitepress/issues/4499)
- **theme/regression:** broken hero heading at certain viewports ([37dbe89](https://github.com/vuejs/vitepress/commit/37dbe895d4cf813e6eb1289f24c637945eec0d1f))
# [1.6.0](https://github.com/vuejs/vitepress/compare/v1.5.0...v1.6.0) (2025-01-20)
### Bug Fixes
- **build:** out of order css in prod builds ([241d17d](https://github.com/vuejs/vitepress/commit/241d17d9839f06b17c3898b1a8ba0f9fa12da0d1)), closes [#4098](https://github.com/vuejs/vitepress/issues/4098)
- **build:** properly strip vpi-social css declaration in debug mode ([c61182a](https://github.com/vuejs/vitepress/commit/c61182ab278350699b5d50461788478a340790aa))
- **build:** respect `vite.clearScreen` in build ([8ea776a](https://github.com/vuejs/vitepress/commit/8ea776addc2c3bcabf3c707a9a81d6e0080a8fcb)), closes [#4468](https://github.com/vuejs/vitepress/issues/4468)
- **build:** specify mode for iconify ([8a5e8ea](https://github.com/vuejs/vitepress/commit/8a5e8ea4f5b7cba0a6c909d8949f0c20426104a6))
- **theme:** apply `externalLinkIcon` option on `VPHome` ([#4492](https://github.com/vuejs/vitepress/issues/4492)) ([fe48943](https://github.com/vuejs/vitepress/commit/fe48943640895d859811b81f86d78c3e510dbe54))
- **theme:** don't show external link icon for images ([096bba1](https://github.com/vuejs/vitepress/commit/096bba19fb61c4b2f8f527046b4b0fe2e91c6bd6))
- **theme:** ignore footnote-ref for outline ([1832617](https://github.com/vuejs/vitepress/commit/183261753b04c2c96ddb8c10e520c748c6d3e613)), closes [#4402](https://github.com/vuejs/vitepress/issues/4402)
- **theme:** includes text to h1 tag for hero page ([#4472](https://github.com/vuejs/vitepress/issues/4472)) ([bd896c6](https://github.com/vuejs/vitepress/commit/bd896c638f8046f6546b5b32e8f98f3707aa8d05)), closes [#4453](https://github.com/vuejs/vitepress/issues/4453)
### Features
- **build:** export normalize function from shared chunk ([616f63f](https://github.com/vuejs/vitepress/commit/616f63f5f08a57347f2800e2d147d5bcd1cd072d)), closes [#4401](https://github.com/vuejs/vitepress/issues/4401)
- **theme:** allow customizing skip to content label ([ff254dc](https://github.com/vuejs/vitepress/commit/ff254dcbe6f2bcc89c34d2d2f4050229dc094400)), closes [#4288](https://github.com/vuejs/vitepress/issues/4288)
- **theme:** export VPNavBarSearch ([23522ab](https://github.com/vuejs/vitepress/commit/23522ab83ff33802d382fa066578dd87eb06789d)), closes [#4476](https://github.com/vuejs/vitepress/issues/4476)
- **theme:** export VPFeatures ([#4356](https://github.com/vuejs/vitepress/issues/4356)) ([6442e17](https://github.com/vuejs/vitepress/commit/6442e174838aec9668325bb1199419908e7dd728))
### Miscellaneous
- **build:** shiki transformers now use v3 [matching algorithm](https://shiki.style/packages/transformers#matching-algorithm) ([373f9b9](https://github.com/vuejs/vitepress/commit/373f9b933ee44f33a15ebdcfcb6db6dfac52f739))
# [1.5.0](https://github.com/vuejs/vitepress/compare/v1.4.5...v1.5.0) (2024-11-04)
### Features
- on-demand social icons ([#4339](https://github.com/vuejs/vitepress/issues/4339)) ([05f2f0d](https://github.com/vuejs/vitepress/commit/05f2f0d26153ace74b6c023184224d4fada137c2)), closes [#4256](https://github.com/vuejs/vitepress/issues/4256) [#4135](https://github.com/vuejs/vitepress/issues/4135) [#4076](https://github.com/vuejs/vitepress/issues/4076) [#3809](https://github.com/vuejs/vitepress/issues/3809) [#3750](https://github.com/vuejs/vitepress/issues/3750) [#1214](https://github.com/vuejs/vitepress/issues/1214) [#2768](https://github.com/vuejs/vitepress/issues/2768) [#2861](https://github.com/vuejs/vitepress/issues/2861)
## [1.4.5](https://github.com/vuejs/vitepress/compare/v1.4.4...v1.4.5) (2024-11-03)
### Bug Fixes
- lang lazy load not working with twoslash ([fc92a77](https://github.com/vuejs/vitepress/commit/fc92a77a5d871b5252bcb82639f5c3551d5c70bb)), closes [#4334](https://github.com/vuejs/vitepress/issues/4334)
- typo in missing language check ([dcb8450](https://github.com/vuejs/vitepress/commit/dcb8450f1166d7731c26a0eb5ec6d931bc283172))
## [1.4.3](https://github.com/vuejs/vitepress/compare/v1.4.2...v1.4.3) (2024-10-31)
### Performance Improvements
- lazy load shiki languages ([#4326](https://github.com/vuejs/vitepress/issues/4326)) ([8299778](https://github.com/vuejs/vitepress/commit/829977876a21da4f0af5d27593a2d81eb9af0c33))
## [1.4.2](https://github.com/vuejs/vitepress/compare/v1.4.1...v1.4.2) (2024-10-29)
### Bug Fixes
- cache markdown-it instance and properly dispose shiki on config reload ([#4321](https://github.com/vuejs/vitepress/issues/4321)) ([45968cd](https://github.com/vuejs/vitepress/commit/45968cdc509e04f8e191d28ba7d8d97b08fc578e)) ([acfe97f](https://github.com/vuejs/vitepress/commit/acfe97f60872d251c75c5985ca9841f84392850d))
- **regression:** hmr not working with markdown includes due to wrong cache key ([615aed5](https://github.com/vuejs/vitepress/commit/615aed5df700ad98f82a74fbc785d290d1c5a018)), closes [#4289](https://github.com/vuejs/vitepress/issues/4289) [#4303](https://github.com/vuejs/vitepress/issues/4303)
- remove explicit chinese fonts ([#4286](https://github.com/vuejs/vitepress/issues/4286)) ([668e9f7](https://github.com/vuejs/vitepress/commit/668e9f7050f236d571fe2fc2f41e5548d974b503)) ([b893550](https://github.com/vuejs/vitepress/commit/b8935502fbb590449e7d094bdde9c9ae1ac67d0c)), closes [#4286](https://github.com/vuejs/vitepress/issues/4286)
- **theme/a11y:** don't select search result unless mouse is actually moved ([e638d85](https://github.com/vuejs/vitepress/commit/e638d855cfc8e4e0c9b95c284548ae31233139f5)), closes [#4297](https://github.com/vuejs/vitepress/issues/4297)
- **theme:** add types for `VPLink`, `VPSocialLink` and `VPSocialLinks` exports ([#4284](https://github.com/vuejs/vitepress/issues/4284)) ([fcae4d5](https://github.com/vuejs/vitepress/commit/fcae4d5554df2130b9a7e5ad8e0cc83eccf88bec))
- **theme:** don't escape html in `siteTitle` ([#4308](https://github.com/vuejs/vitepress/issues/4308)) ([bd690d6](https://github.com/vuejs/vitepress/commit/bd690d6a9b895f15d5906d245b404f02cfce7489))
## [1.4.1](https://github.com/vuejs/vitepress/compare/v1.4.0...v1.4.1) (2024-10-13)
### Bug Fixes
- broken rewrites on windows ([#4268](https://github.com/vuejs/vitepress/issues/4268)) ([b46d6d3](https://github.com/vuejs/vitepress/commit/b46d6d3a204f5ce347647bfd1ab8073bf313afd6))
- **client:** use `usePreferredDark` with `appearance: "force-auto"` ([#4263](https://github.com/vuejs/vitepress/issues/4263)) ([3e8fc40](https://github.com/vuejs/vitepress/commit/3e8fc40c3621da1ef35645d376dab7765b35bb40))
- **client:** wrong script async check ([461a5b0](https://github.com/vuejs/vitepress/commit/461a5b001d29f95169f60fe28bc610e3f6e8fd66))
- **theme:** bind missing no icon prop in the menu link component [#4260](https://github.com/vuejs/vitepress/issues/4260) ([b96712c](https://github.com/vuejs/vitepress/commit/b96712c0744f9ac7ebd65cf4087b2e9fd0d6762b))
- **theme:** improve local search input a11y ([#4066](https://github.com/vuejs/vitepress/issues/4066)) ([92b92ae](https://github.com/vuejs/vitepress/commit/92b92aefcab9fbb28b51da70ee8ab21724098277))
### Features
- **experimental:** support passing function for rewrites ([#4274](https://github.com/vuejs/vitepress/issues/4274)) ([8436472](https://github.com/vuejs/vitepress/commit/8436472c7874cb16caf9432660b395ca9ba68f9d))
# [1.4.0](https://github.com/vuejs/vitepress/compare/v1.3.4...v1.4.0) (2024-10-07)
### Bug Fixes
@ -2049,7 +2386,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.
@ -2067,7 +2403,6 @@ This version uses Vue 3.2.0.
### BREAKING CHANGES
- The following methods are removed.
- `useSiteData`
- `useSiteDataByRoute`
- `usePageData`

@ -1,7 +1,8 @@
# 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)
---

@ -165,13 +165,21 @@ export default defineConfig({
search: {
provider: 'local',
options: {
_render(src, env, md) {
const html = md.render(src, env)
async _render(src, env, md) {
const html = await md.renderAsync(src, env)
if (env.frontmatter?.search === false) return ''
if (env.relativePath.startsWith('local-search/excluded')) return ''
return html
}
}
}
},
vite: {
server: {
watch: {
usePolling: true,
interval: 100
}
}
}
})

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

@ -1,4 +1,4 @@
import fs from 'fs'
import fs from 'node:fs'
import { defineLoader } from 'vitepress'
type Data = Record<string, boolean>[]

@ -43,8 +43,7 @@ describe('static data file support in vite 3', () => {
`)
})
// TODO: make it `.runIf(!process.env.VITE_TEST_BUILD)` -- it currently works, but is skipped to avoid vite's ecosystem-ci from failing (https://github.com/vitejs/vite/pull/16471#issuecomment-2308437187)
test.skip('hmr works', async () => {
test.runIf(!process.env.VITE_TEST_BUILD)('hmr works', async () => {
const a = fileURLToPath(new URL('./data/a.json', import.meta.url))
const b = fileURLToPath(new URL('./data/b.json', import.meta.url))
@ -53,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')
@ -68,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 {
@ -84,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')

@ -1,8 +1,14 @@
export default {
async paths() {
return [
{ params: { id: 'foo' }, content: `# Foo` },
{ params: { id: 'bar' }, content: `# Bar` }
]
import { defineRoutes } from 'vitepress'
import paths from './paths'
export default defineRoutes({
async paths(watchedFiles: string[]) {
// console.log('watchedFiles', watchedFiles)
return paths
},
watch: ['../data-loading/**/*.json'],
async transformPageData(pageData) {
// console.log('transformPageData', pageData.filePath)
pageData.title += ' - transformed'
}
}
})

@ -0,0 +1,4 @@
export default [
{ params: { id: 'foo' }, content: `# Foo` },
{ params: { id: 'bar' }, content: `# Bar` }
]

@ -0,0 +1,27 @@
# header 1
header 1 content
## header 1.1
header 1.1 content
### header 1.1.1
header 1.1.1 content
### header 1.1.2
header 1.1.2 content
## header 1.2
header 1.2 content
### header 1.2.1
header 1.2.1 content
### header 1.2.2
header 1.2.2 content

@ -213,6 +213,10 @@ export default config
<!--@include: ./region-include.md#range-region{5,}-->
## Markdown File Inclusion with Header
<!--@include: ./header-include.md#header-1-1-->
## Image Lazy Loading
![vitepress logo](/vitepress.png)
![vitepress logo](/vitepress.png)

@ -64,8 +64,61 @@ describe('Emoji', () => {
describe('Table of Contents', () => {
test('render toc', async () => {
const items = page.locator('#table-of-contents + nav ul li')
const count = await items.count()
expect(count).toBe(44)
expect(
await items.evaluateAll((elements) =>
elements.map((el) => el.childNodes[0].textContent)
)
).toMatchInlineSnapshot(`
[
"Links",
"Internal Links",
"External Links",
"GitHub-Style Tables",
"Emoji",
"Table of Contents",
"Custom Containers",
"Default Title",
"Custom Title",
"Line Highlighting in Code Blocks",
"Single Line",
"Multiple single lines, ranges",
"Comment Highlight",
"Line Numbers",
"Import Code Snippets",
"Basic Code Snippet",
"Specify Region",
"With Other Features",
"Code Groups",
"Basic Code Group",
"With Other Features",
"Markdown File Inclusion",
"Region",
"Markdown At File Inclusion",
"Markdown Nested File Inclusion",
"Region",
"After Foo",
"Sub sub",
"Sub sub sub",
"Markdown File Inclusion with Range",
"Region",
"Markdown File Inclusion with Range without Start",
"Region",
"Markdown File Inclusion with Range without End",
"Region",
"Markdown At File Region Snippet",
"Region Snippet",
"Markdown At File Range Region Snippet",
"Range Region Line 2",
"Markdown At File Range Region Snippet without start",
"Range Region Line 1",
"Markdown At File Range Region Snippet without end",
"Range Region Line 3",
"Markdown File Inclusion with Header",
"header 1.1.1",
"header 1.1.2",
"Image Lazy Loading",
]
`)
})
})

@ -1,8 +1,8 @@
import getPort from 'get-port'
import type { Server } from 'node:net'
import { chromium, type BrowserServer } from 'playwright-chromium'
import { build, createServer, serve } from 'vitepress'
import type { ViteDevServer } from 'vite'
import type { Server } from 'net'
import { build, createServer, serve } from 'vitepress'
let browserServer: BrowserServer
let server: ViteDevServer | Server

@ -1,9 +1,9 @@
import fs from 'fs-extra'
import getPort from 'get-port'
import { nanoid } from 'nanoid'
import path from 'path'
import path from 'node:path'
import { fileURLToPath, URL } from 'node:url'
import { chromium } from 'playwright-chromium'
import { fileURLToPath, URL } from 'url'
import { createServer, scaffold, ScaffoldThemeType } from 'vitepress'
const tempDir = fileURLToPath(new URL('./.temp', import.meta.url))

@ -1,4 +1,9 @@
import { dedent, rawPathToToken } from 'node/markdown/plugins/snippet'
import {
dedent,
findRegion,
rawPathToToken
} from 'node/markdown/plugins/snippet'
import { expect } from 'vitest'
const removeEmptyKeys = <T extends Record<string, unknown>>(obj: T) => {
return Object.fromEntries(
@ -94,9 +99,228 @@ describe('node/markdown/plugins/snippet', () => {
})
})
test('rawPathToToken', () => {
rawPathTokenMap.forEach(([rawPath, token]) => {
describe('rawPathToToken', () => {
test.each(rawPathTokenMap)('%s', (rawPath, token) => {
expect(removeEmptyKeys(rawPathToToken(rawPath))).toEqual(token)
})
})
describe('findRegion', () => {
it('returns null when no region markers are present', () => {
const lines = ['function foo() {', ' console.log("hello");', '}']
expect(findRegion(lines, 'foo')).toBeNull()
})
it('ignores non-matching region names', () => {
const lines = [
'// #region regionA',
'some code here',
'// #endregion regionA'
]
expect(findRegion(lines, 'regionC')).toBeNull()
})
it('returns null if a region start marker exists without a matching end marker', () => {
const lines = [
'// #region missingEnd',
'console.log("inside region");',
'console.log("still inside");'
]
expect(findRegion(lines, 'missingEnd')).toBeNull()
})
it('returns null if an end marker exists without a preceding start marker', () => {
const lines = [
'// #endregion ghostRegion',
'console.log("stray end marker");'
]
expect(findRegion(lines, 'ghostRegion')).toBeNull()
})
it('detects C#/JavaScript style region markers with matching tags', () => {
const lines = [
'Console.WriteLine("Before region");',
'#region hello',
'Console.WriteLine("Hello, World!");',
'#endregion hello',
'Console.WriteLine("After region");'
]
const result = findRegion(lines, 'hello')
expect(result).not.toBeNull()
if (result) {
expect(lines.slice(result.start, result.end).join('\n')).toBe(
'Console.WriteLine("Hello, World!");'
)
}
})
it('detects region markers even when the end marker omits the region name', () => {
const lines = [
'Console.WriteLine("Before region");',
'#region hello',
'Console.WriteLine("Hello, World!");',
'#endregion',
'Console.WriteLine("After region");'
]
const result = findRegion(lines, 'hello')
expect(result).not.toBeNull()
if (result) {
expect(lines.slice(result.start, result.end).join('\n')).toBe(
'Console.WriteLine("Hello, World!");'
)
}
})
it('handles indented region markers correctly', () => {
const lines = [
' Console.WriteLine("Before region");',
' #region hello',
' Console.WriteLine("Hello, World!");',
' #endregion hello',
' Console.WriteLine("After region");'
]
const result = findRegion(lines, 'hello')
expect(result).not.toBeNull()
if (result) {
expect(lines.slice(result.start, result.end).join('\n')).toBe(
' Console.WriteLine("Hello, World!");'
)
}
})
it('detects TypeScript style region markers', () => {
const lines = [
'let regexp: RegExp[] = [];',
'// #region foo',
'let start = -1;',
'// #endregion foo'
]
const result = findRegion(lines, 'foo')
expect(result).not.toBeNull()
if (result) {
expect(lines.slice(result.start, result.end).join('\n')).toBe(
'let start = -1;'
)
}
})
it('detects CSS style region markers', () => {
const lines = [
'.body-content {',
'/* #region foo */',
' padding-left: 15px;',
'/* #endregion foo */',
' padding-right: 15px;',
'}'
]
const result = findRegion(lines, 'foo')
expect(result).not.toBeNull()
if (result) {
expect(lines.slice(result.start, result.end).join('\n')).toBe(
' padding-left: 15px;'
)
}
})
it('detects HTML style region markers', () => {
const lines = [
'<div>Some content</div>',
'<!-- #region foo -->',
' <h1>Hello world</h1>',
'<!-- #endregion foo -->',
'<div>Other content</div>'
]
const result = findRegion(lines, 'foo')
expect(result).not.toBeNull()
if (result) {
expect(lines.slice(result.start, result.end).join('\n')).toBe(
' <h1>Hello world</h1>'
)
}
})
it('detects Visual Basic style region markers (with case-insensitive "End")', () => {
const lines = [
'Console.WriteLine("VB")',
'#Region VBRegion',
' Console.WriteLine("Inside region")',
'#End Region VBRegion',
'Console.WriteLine("Done")'
]
const result = findRegion(lines, 'VBRegion')
expect(result).not.toBeNull()
if (result) {
expect(lines.slice(result.start, result.end).join('\n')).toBe(
' Console.WriteLine("Inside region")'
)
}
})
it('detects Bat style region markers', () => {
const lines = ['::#region foo', 'echo off', '::#endregion foo']
const result = findRegion(lines, 'foo')
expect(result).not.toBeNull()
if (result) {
expect(lines.slice(result.start, result.end).join('\n')).toBe(
'echo off'
)
}
})
it('detects C/C++ style region markers using #pragma', () => {
const lines = [
'#pragma region foo',
'int a = 1;',
'#pragma endregion foo'
]
const result = findRegion(lines, 'foo')
expect(result).not.toBeNull()
if (result) {
expect(lines.slice(result.start, result.end).join('\n')).toBe(
'int a = 1;'
)
}
})
it('returns the first complete region when multiple regions exist', () => {
const lines = [
'// #region foo',
'first region content',
'// #endregion foo',
'// #region foo',
'second region content',
'// #endregion foo'
]
const result = findRegion(lines, 'foo')
expect(result).not.toBeNull()
if (result) {
expect(lines.slice(result.start, result.end).join('\n')).toBe(
'first region content'
)
}
})
it('handles nested regions with different names properly', () => {
const lines = [
'// #region foo',
"console.log('line before nested');",
'// #region bar',
"console.log('nested content');",
'// #endregion bar',
'// #endregion foo'
]
const result = findRegion(lines, 'foo')
expect(result).not.toBeNull()
if (result) {
const extracted = lines.slice(result.start, result.end).join('\n')
const expected = [
"console.log('line before nested');",
'// #region bar',
"console.log('nested content');",
'// #endregion bar'
].join('\n')
expect(extracted).toBe(expected)
}
})
})
})

@ -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 })
}

@ -0,0 +1,72 @@
import { ModuleGraph } from 'node/utils/moduleGraph'
describe('node/utils/moduleGraph', () => {
let graph: ModuleGraph
beforeEach(() => {
graph = new ModuleGraph()
})
it('should correctly delete a module and its dependents', () => {
graph.add('A', ['B', 'C'])
graph.add('B', ['D'])
graph.add('C', [])
graph.add('D', [])
expect(graph.delete('D')).toEqual(new Set(['D', 'B', 'A']))
})
it('should handle shared dependencies correctly', () => {
graph.add('A', ['B', 'C'])
graph.add('B', ['D'])
graph.add('C', ['D']) // Shared dependency
graph.add('D', [])
expect(graph.delete('D')).toEqual(new Set(['A', 'B', 'C', 'D']))
})
it('merges dependencies correctly', () => {
// Add module A with dependency B
graph.add('A', ['B'])
// Merge new dependency C into module A (B should remain)
graph.add('A', ['C'])
// Deleting B should remove A as well, since A depends on B.
expect(graph.delete('B')).toEqual(new Set(['B', 'A']))
})
it('handles cycles gracefully', () => {
// Create a cycle: A -> B, B -> C, C -> A.
graph.add('A', ['B'])
graph.add('B', ['C'])
graph.add('C', ['A'])
// Deleting any module in the cycle should delete all modules in the cycle.
expect(graph.delete('A')).toEqual(new Set(['A', 'B', 'C']))
})
it('cleans up dependencies when deletion', () => {
// Setup A -> B relationship.
graph.add('A', ['B'])
graph.add('B', [])
// Deleting B should remove both B and A from the graph.
expect(graph.delete('B')).toEqual(new Set(['B', 'A']))
// After deletion, add modules again.
graph.add('C', [])
graph.add('A', ['C']) // Now A depends only on C.
expect(graph.delete('C')).toEqual(new Set(['C', 'A']))
})
it('handles independent modules', () => {
// Modules with no dependencies.
graph.add('X', [])
graph.add('Y', [])
// Deletion of one should only remove that module.
expect(graph.delete('X')).toEqual(new Set(['X']))
expect(graph.delete('Y')).toEqual(new Set(['Y']))
})
})

@ -1,7 +1,7 @@
import { dirname, resolve } from 'path'
import { fileURLToPath } from 'url'
import { defineConfig } from 'vitest/config'
import vue from '@vitejs/plugin-vue'
import { dirname, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
import { defineConfig } from 'vitest/config'
const dir = dirname(fileURLToPath(import.meta.url))

@ -1,4 +1,4 @@
<svg width="160" height="192" viewBox="0 0 160 192" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg viewBox="0 0 160 192" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1288_1252)">
<path d="M0.12699 43.8989C-0.863275 37.1255 4.04575 30.863 11.0915 29.911L113.152 16.1221C120.197 15.1702 126.712 19.8893 127.702 26.6627L147.873 164.635C148.863 171.409 143.954 177.671 136.908 178.623L39.1006 191.837C29.7063 193.107 21.0203 186.814 19.7001 177.784L0.12699 43.8989Z" fill="url(#paint0_linear_1288_1252)"/>
<path d="M10.1376 30.5728C9.06487 22.8787 14.3827 15.7647 22.0152 14.6834L124.678 0.138664C132.31 -0.942678 139.367 4.41806 140.44 12.1122L159.862 151.427C160.935 159.121 155.617 166.235 147.985 167.317L45.3224 181.861C37.6899 182.943 30.6329 177.582 29.5602 169.888L10.1376 30.5728Z" fill="url(#paint1_linear_1288_1252)"/>

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

@ -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')

9
client.d.ts vendored

@ -3,3 +3,12 @@
/// <reference types="vite/client" />
export * from './dist/client/index.js'
declare global {
interface WindowEventMap {
'vitepress:codeGroupTabActivate': Event & {
/** code block element that was activated */
detail: Element
}
}
}

@ -0,0 +1,8 @@
{
"plugins": {
"postcss-rtlcss": {
"ltrPrefix": ":where([dir=\"ltr\"])",
"rtlPrefix": ":where([dir=\"rtl\"])"
}
}
}

@ -0,0 +1,174 @@
import {
defineConfig,
resolveSiteDataByRoute,
type HeadConfig
} from 'vitepress'
import {
groupIconMdPlugin,
groupIconVitePlugin,
localIconLoader
} from 'vitepress-plugin-group-icons'
import llmstxt from 'vitepress-plugin-llms'
const prod = !!process.env.NETLIFY
export default defineConfig({
title: 'VitePress',
rewrites: {
'en/:rest*': ':rest*'
},
lastUpdated: true,
cleanUrls: true,
metaChunk: true,
markdown: {
math: true,
codeTransformers: [
// We use `[!!code` in demo to prevent transformation, here we revert it back.
{
postprocess(code) {
return code.replace(/\[\!\!code/g, '[!code')
}
}
],
config(md) {
// TODO: remove when https://github.com/vuejs/vitepress/issues/4431 is fixed
const fence = md.renderer.rules.fence!
md.renderer.rules.fence = function (tokens, idx, options, env, self) {
const { localeIndex = 'root' } = env
const codeCopyButtonTitle = (() => {
switch (localeIndex) {
case 'es':
return 'Copiar código'
case 'fa':
return 'کپی کد'
case 'ko':
return '코드 복사'
case 'pt':
return 'Copiar código'
case 'ru':
return 'Скопировать код'
case 'zh':
return '复制代码'
case 'ja':
return 'コードをコピー'
default:
return 'Copy code'
}
})()
return fence(tokens, idx, options, env, self).replace(
'<button title="Copy Code" class="copy"></button>',
`<button title="${codeCopyButtonTitle}" class="copy"></button>`
)
}
md.use(groupIconMdPlugin)
}
},
sitemap: {
hostname: 'https://vitepress.dev',
transformItems(items) {
return items.filter((item) => !item.url.includes('migration'))
}
},
head: [
[
'link',
{ rel: 'icon', type: 'image/svg+xml', href: '/vitepress-logo-mini.svg' }
],
[
'link',
{ rel: 'icon', type: 'image/png', href: '/vitepress-logo-mini.png' }
],
['meta', { name: 'theme-color', content: '#5f67ee' }],
['meta', { property: 'og:type', content: 'website' }],
['meta', { property: 'og:site_name', content: 'VitePress' }],
[
'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: ''
}
]
],
themeConfig: {
logo: { src: '/vitepress-logo-mini.svg', width: 24, height: 24 },
socialLinks: [
{ icon: 'github', link: 'https://github.com/vuejs/vitepress' }
],
search: {
provider: 'algolia',
options: {
appId: '8J64VVRP8K',
apiKey: '52f578a92b88ad6abde815aae2b0ad7c',
indexName: 'vitepress',
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'
),
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,20 +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'
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 }
}
})

@ -1,77 +0,0 @@
import { defineConfig } from 'vitepress'
import { search as zhSearch } from './zh'
import { search as ptSearch } from './pt'
import { search as ruSearch } from './ru'
import { search as esSearch } from './es'
import { search as koSearch } from './ko'
export const shared = defineConfig({
title: 'VitePress',
rewrites: {
'en/:rest*': ':rest*'
},
lastUpdated: true,
cleanUrls: true,
metaChunk: true,
markdown: {
math: true,
codeTransformers: [
// We use `[!!code` in demo to prevent transformation, here we revert it back.
{
postprocess(code) {
return code.replace(/\[\!\!code/g, '[!code')
}
}
]
},
sitemap: {
hostname: 'https://vitepress.dev',
transformItems(items) {
return items.filter((item) => !item.url.includes('migration'))
}
},
/* prettier-ignore */
head: [
['link', { rel: 'icon', type: 'image/svg+xml', href: '/vitepress-logo-mini.svg' }],
['link', { rel: 'icon', type: 'image/png', href: '/vitepress-logo-mini.png' }],
['meta', { name: 'theme-color', content: '#5f67ee' }],
['meta', { 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:url', content: 'https://vitepress.dev/' }],
['script', { src: 'https://cdn.usefathom.com/script.js', 'data-site': 'AZBRSFGG', 'data-spa': 'auto', defer: '' }]
],
themeConfig: {
logo: { src: '/vitepress-logo-mini.svg', width: 24, height: 24 },
socialLinks: [
{ icon: 'github', link: 'https://github.com/vuejs/vitepress' }
],
search: {
provider: 'algolia',
options: {
appId: '8J64VVRP8K',
apiKey: '52f578a92b88ad6abde815aae2b0ad7c',
indexName: 'vitepress',
locales: {
...zhSearch,
...ptSearch,
...ruSearch,
...esSearch,
...koSearch
}
}
},
carbonAds: { code: 'CEBDT27Y', placement: 'vuejsorg' }
}
})

@ -0,0 +1,5 @@
import Theme from 'vitepress/theme'
import 'virtual:group-icons.css'
import './styles.css'
export default Theme

@ -0,0 +1,43 @@
:root:where(:lang(fa)) {
--vp-font-family-base:
'Vazirmatn', 'Inter', ui-sans-serif, system-ui, sans-serif,
'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
}
:root {
--vp-home-hero-name-color: transparent;
--vp-home-hero-name-background: -webkit-linear-gradient(
120deg,
#bd34fe 30%,
#41d1ff
);
--vp-home-hero-image-background-image: linear-gradient(
-45deg,
#bd34fe 50%,
#47caff 50%
);
--vp-home-hero-image-filter: blur(44px);
}
@media (min-width: 640px) {
:root {
--vp-home-hero-image-filter: blur(56px);
}
}
@media (min-width: 960px) {
:root {
--vp-home-hero-image-filter: blur(68px);
}
}
.VPHero .VPImage {
filter: drop-shadow(-2px 4px 6px rgba(0, 0, 0, 0.2));
padding: 18px;
}
/* used in reference/default-theme-search */
img[src='/search.png'] {
width: 100%;
aspect-ratio: 1 / 1;
}

@ -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'

@ -49,8 +49,7 @@ interface EnhanceAppContext {
The theme entry file should export the theme as its default export:
```js
// .vitepress/theme/index.js
```js [.vitepress/theme/index.js]
// You can directly import Vue files in the theme entry
// VitePress is pre-configured with @vitejs/plugin-vue.
@ -72,8 +71,7 @@ Inside your layout component, it works just like a normal Vite + Vue 3 applicati
The most basic layout component needs to contain a [`<Content />`](../reference/runtime-api#content) component:
```vue
<!-- .vitepress/theme/Layout.vue -->
```vue [.vitepress/theme/Layout.vue]
<template>
<h1>Custom Layout!</h1>
@ -172,8 +170,7 @@ If you wish to distribute the theme as an npm package, follow these steps:
To consume an external theme, import and re-export it from the custom theme entry:
```js
// .vitepress/theme/index.js
```js [.vitepress/theme/index.js]
import Theme from 'awesome-vitepress-theme'
export default Theme
@ -181,8 +178,7 @@ export default Theme
If the theme needs to be extended:
```js
// .vitepress/theme/index.js
```js [.vitepress/theme/index.js]
import Theme from 'awesome-vitepress-theme'
export default {
@ -195,8 +191,7 @@ export default {
If the theme requires special VitePress config, you will need to also extend it in your own config:
```ts
// .vitepress/config.ts
```ts [.vitepress/config.ts]
import baseConfig from 'awesome-vitepress-theme/config'
export default {
@ -207,8 +202,7 @@ export default {
Finally, if the theme provides types for its theme config:
```ts
// .vitepress/config.ts
```ts [.vitepress/config.ts]
import baseConfig from 'awesome-vitepress-theme/config'
import { defineConfigWithTheme } from 'vitepress'
import type { ThemeConfig } from 'awesome-vitepress-theme'

@ -8,8 +8,7 @@ Data loaders can be used to fetch remote data, or generate metadata based on loc
A data loader file must end with either `.data.js` or `.data.ts`. The file should provide a default export of an object with the `load()` method:
```js
// example.data.js
```js [example.data.js]
export default {
load() {
return {
@ -84,8 +83,7 @@ export default {
When building a content focused site, we often need to create an "archive" or "index" page: a page where we list all available entries in our content collection, for example blog posts or API pages. We **can** implement this directly with the data loader API, but since this is such a common use case, VitePress also provides a `createContentLoader` helper to simplify this:
```js
// posts.data.js
```js [posts.data.js]
import { createContentLoader } from 'vitepress'
export default createContentLoader('posts/*.md', /* options */)
@ -135,8 +133,7 @@ import { data as posts } from './posts.data.js'
The default data may not suit all needs - you can opt-in to transform the data using options:
```js
// posts.data.js
```js [posts.data.js]
import { createContentLoader } from 'vitepress'
export default createContentLoader('posts/*.md', {
@ -162,8 +159,7 @@ Check out how it is used in the [Vue.js blog](https://github.com/vuejs/blog/blob
The `createContentLoader` API can also be used inside [build hooks](../reference/site-config#build-hooks):
```js
// .vitepress/config.js
```js [.vitepress/config.js]
export default {
async buildEnd() {
const posts = await createContentLoader('posts/*.md').load()

@ -10,7 +10,7 @@ The following guides are based on some shared assumptions:
- You are using the default build output directory (`.vitepress/dist`).
- VitePress is installed as a local dependency in your project, and you have set up the following scripts in your `package.json`:
```json
```json [package.json]
{
"scripts": {
"docs:build": "vitepress build docs",
@ -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.
@ -121,7 +121,7 @@ Don't enable options like _Auto Minify_ for HTML code. It will remove comments f
1. Create a file named `deploy.yml` inside `.github/workflows` directory of your project with some content like this:
```yaml
```yaml [.github/workflows/deploy.yml]
# Sample workflow for building and deploying a VitePress site to GitHub Pages
#
name: Deploy VitePress site to Pages
@ -153,15 +153,17 @@ Don't enable options like _Auto Minify_ for HTML code. It will remove comments f
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
fetch-depth: 0 # Not needed if lastUpdated is not enabled
# - uses: pnpm/action-setup@v3 # Uncomment this if you're using pnpm
# - uses: pnpm/action-setup@v4 # 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
uses: actions/setup-node@v6
with:
node-version: 20
node-version: 24
cache: npm # or pnpm / yarn
- name: Setup Pages
uses: actions/configure-pages@v4
@ -202,7 +204,7 @@ Don't enable options like _Auto Minify_ for HTML code. It will remove comments f
2. Create a file named `.gitlab-ci.yml` in the root of your project with the content below. This will build and deploy your site whenever you make changes to your content:
```yaml
```yaml [.gitlab-ci.yml]
image: node:18
pages:
cache:
@ -235,7 +237,7 @@ Don't enable options like _Auto Minify_ for HTML code. It will remove comments f
`firebase.json`:
```json
```json [firebase.json]
{
"hosting": {
"public": "docs/.vitepress/dist",
@ -246,7 +248,7 @@ Don't enable options like _Auto Minify_ for HTML code. It will remove comments f
`.firebaserc`:
```json
```json [.firebaserc]
{
"projects": {
"default": "<YOUR_FIREBASE_ID>"
@ -274,7 +276,7 @@ Don't enable options like _Auto Minify_ for HTML code. It will remove comments f
2. Create a file called `static.json` in the root of your project with the below content:
```json
```json [static.json]
{
"root": "docs/.vitepress/dist"
}
@ -292,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`.

@ -22,8 +22,7 @@ Before proceeding, make sure to first read [Using a Custom Theme](./custom-theme
The default theme CSS is customizable by overriding root level CSS variables:
```js
// .vitepress/theme/index.js
```js [.vitepress/theme/index.js]
import DefaultTheme from 'vitepress/theme'
import './custom.css'
@ -46,8 +45,7 @@ VitePress uses [Inter](https://rsms.me/inter/) as the default font, and will inc
To avoid including Inter in the build output, import the theme from `vitepress/theme-without-fonts` instead:
```js
// .vitepress/theme/index.js
```js [.vitepress/theme/index.js]
import DefaultTheme from 'vitepress/theme-without-fonts'
import './my-fonts.css'
@ -68,12 +66,11 @@ If you are using optional components like the [Team Page](../reference/default-t
If your font is a local file referenced via `@font-face`, it will be processed as an asset and included under `.vitepress/dist/assets` with hashed filename. To preload this file, use the [transformHead](../reference/site-config#transformhead) build hook:
```js
// .vitepress/config.js
```js [.vitepress/config.js]
export default {
transformHead({ assets }) {
// adjust the regex accordingly to match your font
const myFontFile = assets.find(file => /font-name\.\w+\.woff2/)
const myFontFile = assets.find(file => /font-name\.[\w-]+\.woff2/.test(file))
if (myFontFile) {
return [
[
@ -94,8 +91,7 @@ export default {
## Registering Global Components
```js
// .vitepress/theme/index.js
```js [.vitepress/theme/index.js]
import DefaultTheme from 'vitepress/theme'
/** @type {import('vitepress').Theme} */
@ -109,8 +105,7 @@ export default {
```
If you're using TypeScript:
```ts
// .vitepress/theme/index.ts
```ts [.vitepress/theme/index.ts]
import type { Theme } from 'vitepress'
import DefaultTheme from 'vitepress/theme'
@ -129,8 +124,7 @@ Since we are using Vite, you can also leverage Vite's [glob import feature](http
The default theme's `<Layout/>` component has a few slots that can be used to inject content at certain locations of the page. Here's an example of injecting a component into the before outline:
```js
// .vitepress/theme/index.js
```js [.vitepress/theme/index.js]
import DefaultTheme from 'vitepress/theme'
import MyLayout from './MyLayout.vue'
@ -142,8 +136,7 @@ export default {
}
```
```vue
<!--.vitepress/theme/MyLayout.vue-->
```vue [.vitepress/theme/MyLayout.vue]
<script setup>
import DefaultTheme from 'vitepress/theme'
@ -161,8 +154,7 @@ const { Layout } = DefaultTheme
Or you could use render function as well.
```js
// .vitepress/theme/index.js
```js [.vitepress/theme/index.js]
import { h } from 'vue'
import DefaultTheme from 'vitepress/theme'
import MyComponent from './MyComponent.vue'
@ -224,9 +216,7 @@ Full list of slots available in the default theme layout:
You can extend the default theme to provide a custom transition when the color mode is toggled. An example:
```vue
<!-- .vitepress/theme/Layout.vue -->
```vue [.vitepress/theme/Layout.vue]
<script setup lang="ts">
import { useData } from 'vitepress'
import DefaultTheme from 'vitepress/theme'
@ -262,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)`
}
)
@ -329,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
```
:::
@ -120,8 +100,7 @@ By default, VitePress stores its dev server cache in `.vitepress/cache`, and the
The config file (`.vitepress/config.js`) allows you to customize various aspects of your VitePress site, with the most basic options being the title and description of the site:
```js
// .vitepress/config.js
```js [.vitepress/config.js]
export default {
// site-level options
title: 'VitePress',
@ -147,7 +126,7 @@ VitePress also provides the ability to generate clean URLs, rewrite paths, and d
The tool should have also injected the following npm scripts to your `package.json` if you allowed it to do so during the setup process:
```json
```json [package.json]
{
...
"scripts": {

@ -13,7 +13,7 @@ docs/
Then in `docs/.vitepress/config.ts`:
```ts
```ts [docs/.vitepress/config.ts]
import { defineConfig } from 'vitepress'
export default defineConfig({
@ -77,8 +77,7 @@ However, VitePress won't redirect `/` to `/en/` by default. You'll need to confi
**Pro tip:** If using the above approach, you can use `nf_lang` cookie to persist user's language choice:
```ts
// docs/.vitepress/theme/index.ts
```ts [docs/.vitepress/theme/index.ts]
import DefaultTheme from 'vitepress/theme'
import Layout from './Layout.vue'
@ -88,11 +87,10 @@ export default {
}
```
```vue
<!-- docs/.vitepress/theme/Layout.vue -->
```vue [docs/.vitepress/theme/Layout.vue]
<script setup lang="ts">
import DefaultTheme from 'vitepress/theme'
import { useData } from 'vitepress'
import { useData, inBrowser } from 'vitepress'
import { watchEffect } from 'vue'
const { lang } = useData()

@ -22,7 +22,7 @@ Both internal and external links get special treatment.
### Internal Links
Internal links are converted to router link for SPA navigation. Also, every `index.md` contained in each sub-directory will automatically be converted to `index.html`, with corresponding URL `/`.
Internal links are converted to router links for SPA navigation. Also, every `index.md` contained in each sub-directory will automatically be converted to `index.html`, with corresponding URL `/`.
For example, given the following directory structure:
@ -187,7 +187,7 @@ You may set custom title by appending the text right after the "type" of the con
Danger zone, do not proceed
:::
::: details Click me to view the code
::: details Click me to toggle the code
```js
console.log('Hello, VitePress!')
```
@ -200,7 +200,7 @@ console.log('Hello, VitePress!')
Danger zone, do not proceed
:::
::: details Click me to view the code
::: details Click me to toggle the code
```js
console.log('Hello, VitePress!')
```
@ -225,6 +225,28 @@ export default defineConfig({
})
```
### Additional Attributes
You can add additional attributes to the custom containers. We use [markdown-it-attrs](https://github.com/arve0/markdown-it-attrs) for this feature, and it is supported on almost all markdown elements. For example, you can set the `open` attribute to make the details block open by default:
**Input**
````md
::: details Click me to toggle the code {open}
```js
console.log('Hello, VitePress!')
```
:::
````
**Output**
::: details Click me to toggle the code {open}
```js
console.log('Hello, VitePress!')
```
:::
### `raw`
This is a special container that can be used to prevent style and router conflicts with VitePress. This is especially useful when you're documenting component libraries. You might also wanna check out [whyframe](https://whyframe.dev/docs/integrations/vitepress) for better isolation.
@ -233,7 +255,7 @@ This is a special container that can be used to prevent style and router conflic
```md
::: raw
Wraps in a <div class="vp-raw">
Wraps in a `<div class="vp-raw">`
:::
```
@ -255,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/]
})
```
@ -343,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
@ -759,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:
@ -802,7 +824,7 @@ It also supports selecting a line range:
**Input**
```md
```md:line-numbers
# Docs
## Basics
@ -812,7 +834,7 @@ It also supports selecting a line range:
**Part file** (`parts/basics.md`)
```md
```md:line-numbers
Some getting started stuff.
### Configuration
@ -822,7 +844,7 @@ Can be created using `.foorc.json`.
**Equivalent code**
```md
```md:line-numbers
# Docs
## Basics
@ -838,7 +860,7 @@ You can also use a [VS Code region](https://code.visualstudio.com/docs/editor/co
**Input**
```md
```md:line-numbers
# Docs
## Basics
@ -849,7 +871,7 @@ You can also use a [VS Code region](https://code.visualstudio.com/docs/editor/co
**Part file** (`parts/basics.md`)
```md
```md:line-numbers
<!-- #region basic-usage -->
## Usage Line 1
@ -861,7 +883,7 @@ You can also use a [VS Code region](https://code.visualstudio.com/docs/editor/co
**Equivalent code**
```md
```md:line-numbers
# Docs
## Basics
@ -875,6 +897,53 @@ You can also use a [VS Code region](https://code.visualstudio.com/docs/editor/co
Note that this does not throw errors if your file is not present. Hence, when using this feature make sure that the contents are being rendered as expected.
:::
Instead of VS Code regions, you can also use header anchors to include a specific section of the file. For example, if you have a header in your markdown file like this:
```md
## My Base Section
Some content here.
### My Sub Section
Some more content here.
## Another Section
Content outside `My Base Section`.
```
You can include the `My Base Section` section like this:
```md
## My Extended Section
<!--@include: ./parts/basics.md#my-base-section-->
```
**Equivalent code**
```md
## My Extended Section
Some content here.
### My Sub Section
Some more content here.
```
Here, `my-base-section` is the generated id of the heading element. In case it's not easily guessable, you can open the part file in your browser and click on the heading anchor (`#` symbol left to the heading when hovered) to see the id in the URL bar. Or use browser dev tools to inspect the element. Alternatively, you can also specify the id to the part file like this:
```md
## My Base Section {#custom-id}
```
and include it like this:
```md
<!--@include: ./parts/basics.md#custom-id-->
```
## Math Equations
This is currently opt-in. To enable it, you need to install `markdown-it-mathjax3` and set `markdown.math` to `true` in your config file:
@ -883,8 +952,7 @@ This is currently opt-in. To enable it, you need to install `markdown-it-mathjax
npm add -D markdown-it-mathjax3
```
```ts
// .vitepress/config.ts
```ts [.vitepress/config.ts]
export default {
markdown: {
math: true

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

@ -50,8 +50,7 @@ if (!import.meta.env.SSR) {
Since [`Theme.enhanceApp`](./custom-theme#theme-interface) can be async, you can conditionally import and register Vue plugins that access browser APIs on import:
```js
// .vitepress/theme/index.js
```js [.vitepress/theme/index.js]
/** @type {import('vitepress').Theme} */
export default {
// ...
@ -65,8 +64,7 @@ export default {
```
If you're using TypeScript:
```ts
// .vitepress/theme/index.ts
```ts [.vitepress/theme/index.ts]
import type { Theme } from 'vitepress'
export default {

@ -254,3 +254,38 @@ import ComponentInHeader from '../../components/ComponentInHeader.vue'
padding: 0 20px;
}
</style>
## VS Code IntelliSense Support
<!-- Based on https://github.com/vuejs/language-tools/pull/4321 -->
Vue provides IntelliSense support out of the box via the [Vue - Official VS Code plugin](https://marketplace.visualstudio.com/items?itemName=Vue.volar). However, to enable it for `.md` files, you need to make some adjustments to the configuration files.
1. Add `.md` pattern to the `include` and `vueCompilerOptions.vitePressExtensions` options in the tsconfig/jsconfig file:
::: code-group
```json [tsconfig.json]
{
"include": [
"docs/**/*.ts",
"docs/**/*.vue",
"docs/**/*.md",
],
"vueCompilerOptions": {
"vitePressExtensions": [".md"],
},
}
```
:::
2. Add `markdown` to the `vue.server.includeLanguages` option in the VS Code setting:
::: code-group
```json [.vscode/settings.json]
{
"vue.server.includeLanguages": ["vue", "markdown"]
}
```
:::

@ -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=/%22vitepress%22:+/+path:/(?:package%7Cdeno)%5C.jsonc?$/+NOT+is:fork+NOT+is:archived&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,15 +8,15 @@ 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
image:
src: /vitepress-logo-large.webp
src: /vitepress-logo-large.svg
alt: VitePress
features:
@ -36,25 +33,3 @@ features:
title: Ship Fast Sites
details: Fast initial load with static HTML, fast post-load navigation with client-side routing.
---
<style>
:root {
--vp-home-hero-name-color: transparent;
--vp-home-hero-name-background: -webkit-linear-gradient(120deg, #bd34fe 30%, #41d1ff);
--vp-home-hero-image-background-image: linear-gradient(-45deg, #bd34fe 50%, #47caff 50%);
--vp-home-hero-image-filter: blur(44px);
}
@media (min-width: 640px) {
:root {
--vp-home-hero-image-filter: blur(56px);
}
}
@media (min-width: 960px) {
:root {
--vp-home-hero-image-filter: blur(68px);
}
}
</style>

@ -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
@ -228,6 +228,7 @@ You may define this option to show your social account links with icons in nav.
export default {
themeConfig: {
socialLinks: [
// You can add any icon from simple-icons (https://simpleicons.org/):
{ icon: 'github', link: 'https://github.com/vuejs/vitepress' },
{ icon: 'twitter', link: '...' },
// You can also add custom icons by passing SVG as string:
@ -246,24 +247,10 @@ export default {
```ts
interface SocialLink {
icon: SocialLinkIcon
icon: string | { svg: string }
link: string
ariaLabel?: string
}
type SocialLinkIcon =
| 'discord'
| 'facebook'
| 'github'
| 'instagram'
| 'linkedin'
| 'mastodon'
| 'npm'
| 'slack'
| 'twitter'
| 'x'
| 'youtube'
| { svg: string }
```
## footer
@ -457,9 +444,51 @@ Can be used to customize the label of the return to top button. This label is on
Can be used to customize the aria-label of the language toggle button in navbar. This is only used if you're using [i18n](../guide/i18n).
## skipToContentLabel
- Type: `string`
- Default: `Skip to content`
Can be used to customize the label of the skip to content link. This link is shown when the user is navigating the site using a keyboard.
## externalLinkIcon
- Type: `boolean`
- 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@v5
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
@ -165,8 +167,7 @@ Refer [`socialLinks`](./default-theme-config#sociallinks).
You can include custom components in the navigation bar by using the `component` option. The `component` key should be the Vue component name, and must be registered globally using [Theme.enhanceApp](../guide/custom-theme#theme-interface).
```js
// .vitepress/config.js
```js [.vitepress/config.js]
export default {
themeConfig: {
nav: [
@ -192,8 +193,7 @@ export default {
Then, you need to register the component globally:
```js
// .vitepress/theme/index.js
```js [.vitepress/theme/index.js]
import DefaultTheme from 'vitepress/theme'
import MyCustomComponent from './components/MyCustomComponent.vue'

@ -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'
@ -24,7 +24,11 @@ Example result:
![screenshot of the search modal](/search.png)
Alternatively, you can use [Algolia DocSearch](#algolia-search) or some community plugins like <https://www.npmjs.com/package/vitepress-plugin-search> or <https://www.npmjs.com/package/vitepress-plugin-pagefind>.
Alternatively, you can use [Algolia DocSearch](#algolia-search) or some community plugins like:
- <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}
@ -120,9 +124,9 @@ export default defineConfig({
/**
* @param {string} src
* @param {import('vitepress').MarkdownEnv} env
* @param {import('markdown-it')} md
* @param {import('markdown-it-async')} md
*/
_render(src, env, md) {
async _render(src, env, md) {
// return html string
}
}
@ -145,8 +149,8 @@ export default defineConfig({
search: {
provider: 'local',
options: {
_render(src, env, md) {
const html = md.render(src, env)
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
@ -158,7 +162,7 @@ export default defineConfig({
```
::: warning Note
In case a custom `_render` function is provided, you need to handle the `search: false` frontmatter yourself. Also, the `env` object won't be completely populated before `md.render` is called, so any checks on optional `env` properties like `frontmatter` should be done after that.
In case a custom `_render` function is provided, you need to handle the `search: false` frontmatter yourself. Also, the `env` object won't be completely populated before `md.renderAsync` is called, so any checks on optional `env` properties like `frontmatter` should be done after that.
:::
#### Example: Transforming content - adding anchors
@ -171,10 +175,10 @@ export default defineConfig({
search: {
provider: 'local',
options: {
_render(src, env, md) {
const html = md.render(src, env)
async _render(src, env, md) {
const html = await md.renderAsync(src, env)
if (env.frontmatter?.title)
return md.render(`# ${env.frontmatter.title}`) + html
return await md.renderAsync(`# ${env.frontmatter.title}`) + html
return html
}
}
@ -229,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: '搜索历史',
@ -240,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: '搜索提供者'
}
}
}
@ -270,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:
@ -377,10 +449,3 @@ new Crawler({
}
})
```
<style>
img[src="/search.png"] {
width: 100%;
aspect-ratio: 1 / 1;
}
</style>

@ -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
---
```

@ -114,7 +114,7 @@ interface Router {
/**
* Called after the route changes.
*/
onAfterRouteChanged?: (to: string) => Awaitable<void>
onAfterRouteChange?: (to: string) => Awaitable<void>
}
```

@ -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:
@ -333,7 +333,7 @@ export default {
- Type: `string`
- Default: `/`
The base URL the site will be deployed at. You will need to set this if you plan to deploy your site under a sub path, for example, GitHub pages. If you plan to deploy your site to `https://foo.github.io/bar/`, then you should set base to `'/bar/'`. It should always start and end with a slash.
The base URL the site will be deployed at. You will need to set this if you plan to deploy your site under a sub path, for example, GitHub pages. If you plan to deploy your site to `https://foo.github.io/bar/`, then you should set base to `'/bar/'`. It should always start and end with a slash. Relative bases are not supported.
The base is automatically prepended to all the URLs that start with / in other options, so you only need to specify it once.
@ -387,7 +387,7 @@ export default {
### srcExclude
- Type: `string`
- Type: `string[]`
- Default: `undefined`
A [glob pattern](https://github.com/mrmlnc/fast-glob#pattern-syntax) for matching markdown files that should be excluded as source content.
@ -439,7 +439,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',
@ -48,14 +53,15 @@ export const es = defineConfig({
sidebarMenuLabel: 'Menu Lateral',
darkModeSwitchLabel: 'Tema Oscuro',
lightModeSwitchTitle: 'Cambiar a modo claro',
darkModeSwitchTitle: 'Cambiar a modo oscuro'
darkModeSwitchTitle: 'Cambiar a modo oscuro',
skipToContentLabel: 'Saltar al contenido'
}
})
function nav(): DefaultTheme.NavItem[] {
return [
{
text: 'Guia',
text: 'Guía',
link: '/es/guide/what-is-vitepress',
activeMatch: '/es/guide/'
},
@ -67,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'
@ -86,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' }
@ -129,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'
}
@ -160,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' }
]
}
@ -169,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: {
@ -179,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',
@ -190,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'
}
}
}

@ -49,8 +49,7 @@ interface EnhanceAppContext {
El archivo de entrada del tema debe exportar el tema como su exportación por defecto:
```js
// .vitepress/theme/index.js
```js [.vitepress/theme/index.js]
// Puede importar archivos Vue directamente en el archivo de entrada del tema
// VitePress ya está preconfigurado con @vitejs/plugin-vue.
@ -72,8 +71,7 @@ Dentro de su componente de layout, el funciona como una aplicación Vite + Vue 3
El componente de layout más básico necesita un componente [`<Content />`](../reference/runtime-api#content):
```vue
<!-- .vitepress/theme/Layout.vue -->
```vue [.vitepress/theme/Layout.vue]
<template>
<h1>Layout Personalizado!</h1>
@ -172,8 +170,7 @@ Si desea distribuir su tema como un paquete npm, siga estos pasos:
Para consumir un tema extereno, importelo e reexportelo a partir del archivo de entrada del tema personalizado:
```js
// .vitepress/theme/index.js
```js [.vitepress/theme/index.js]
import Theme from 'awesome-vitepress-theme'
export default Theme
@ -181,8 +178,7 @@ export default Theme
Si el tema necesita ser extendido:
```js
// .vitepress/theme/index.js
```js [.vitepress/theme/index.js]
import Theme from 'awesome-vitepress-theme'
export default {

@ -8,8 +8,7 @@ Los cargadores de datos pueden ser usados para buscar datos remotos o generar me
Un archivo de cargados de datos debe terminar con `.data.js` o `.data.ts`. El archivo debe proporcionar una exportación por defecto de un objeto con el método `load()`:
```js
// example.data.js
```js [example.data.js]
export default {
load() {
return {
@ -83,8 +82,7 @@ export default {
Al construir un sitio enfocado en contenido, frecuentemente necesitamos crear una página de "archivo" o "índice": una página donde listamos todas las entradas disponibles en nuestra colección de contenido, por ejemplo, articulos de blog o páginas de API. Nosotros **podemos** implementar esto directamente con el API de cargador de datos, pero como este es un caso de uso tan común, VitePress también proporciona un auxiliar `createContentLoader` para simplificar esto:
```js
// posts.data.js
```js [posts.data.js]
import { createContentLoader } from 'vitepress'
export default createContentLoader('posts/*.md', /* opciones */)
@ -134,8 +132,7 @@ import { data as posts } from './posts.data.js'
Los datos por defecto pueden no atender todas las necesidades - puede optar por transformar los datos usando opciones:
```js
// posts.data.js
```js [posts.data.js]
import { createContentLoader } from 'vitepress'
export default createContentLoader('posts/*.md', {
@ -161,8 +158,7 @@ Vea cómo es usado en el [blog Vue.js](https://github.com/vuejs/blog/blob/main/.
El API `createContentLoader` también puede ser usada dentro de los [build hooks](../reference/site-config#build-hooks):
```js
// .vitepress/config.js
```js [.vitepress/config.js]
export default {
async buildEnd() {
const posts = await createContentLoader('posts/*.md').load()

@ -10,7 +10,7 @@ Las siguientes orientaciones están basadas en algunos supuestos:
- Está usando la directorio por defecto para el build (`.vitepress/dist`).
- VitePress está instalado como una dependencia local en su proyecto, y usted configuró los siguientes scripts en su `package.json`:
```json
```json [package.json]
{
"scripts": {
"docs:build": "vitepress build docs",
@ -65,7 +65,7 @@ Este hash `4f283b18` es generado a partir del contenido de este archivo. La mism
Cache-Control: max-age=31536000,immutable
```
::: detralles Ejemplo de archivo `_headers` do Netlify
::: details Ejemplo de archivo `_headers` do Netlify
```
/assets/*
@ -79,7 +79,7 @@ Nota: el archivo `_headers` debe ser colocado en [diretório public](./asset-han
:::
::: detalles de Ejemplo de configuración Vercel em `vercel.json`
::: details de Ejemplo de configuración Vercel em `vercel.json`
```json
{
@ -121,7 +121,7 @@ No active opciones como _Auto Minify_ para código HTML. Eso removera comentario
1. Cree un archivo llamado `deploy.yml` dentro del directorio `.github/workflows` do seu projeto com algum conteúdo como este:
```yaml
```yaml [.github/workflows/deploy.yml]
# Ejemplo de flujo de trabajo para compilar e implantar un sitio VitePress en GitHub Pages
#
name: Implante el sitio VitePress en Pages
@ -153,15 +153,17 @@ No active opciones como _Auto Minify_ para código HTML. Eso removera comentario
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
fetch-depth: 0 # No necesario se lastUpdated no estuviera habilitado
# - uses: pnpm/action-setup@v3 # Desconecte eso si estuviera usando pnpm
# - uses: pnpm/action-setup@v4 # Desconecte eso si estuviera usando pnpm
# with:
# version: 9
# - uses: oven-sh/setup-bun@v1 # Desconecte eso se estuviera usando Bun
- name: Setup Node
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: 20
node-version: 24
cache: npm # o pnpm / yarn
- name: Setup Pages
uses: actions/configure-pages@v4
@ -203,7 +205,7 @@ No active opciones como _Auto Minify_ para código HTML. Eso removera comentario
2. Cree un archivo llamado `.gitlab-ci.yml` en la raiz del proyecto con el contenido abajo. Esto construirá e implantará su sitio siempre que haga alteraciones en el contenido.
```yaml
```yaml [.gitlab-ci.yml]
image: node:18
pages:
cache:
@ -236,7 +238,7 @@ No active opciones como _Auto Minify_ para código HTML. Eso removera comentario
`firebase.json`:
```json
```json [firebase.json]
{
"hosting": {
"public": "docs/.vitepress/dist",
@ -247,7 +249,7 @@ No active opciones como _Auto Minify_ para código HTML. Eso removera comentario
`.firebaserc`:
```json
```json [.firebaserc]
{
"projects": {
"default": "<SU_ID_FIREBASE>"
@ -275,7 +277,7 @@ No active opciones como _Auto Minify_ para código HTML. Eso removera comentario
2. Cree un archivo llamado `static.json` en la raiz de su proyecto con el contenido abajo:
```json
```json [static.json]
{
"root": "docs/.vitepress/dist"
}

@ -22,8 +22,7 @@ Antes de seguir, asegurese de leer primero [Usando un Tema Personalizado](./cust
El CSS del tema por defecto puede ser personalizado substuyendo las variables CSS a nivel de la raiz:
```js
// .vitepress/theme/index.js
```js [.vitepress/theme/index.js]
import DefaultTheme from 'vitepress/theme'
import './custom.css'
@ -46,8 +45,7 @@ VitePress usa [Inter](https://rsms.me/inter/) como fuente por defecto e incluir
Para evitar la inclusión de Inter en la salida de compilación, importe el tema de `vitepress/theme-without-fonts`:
```js
// .vitepress/theme/index.js
```js [.vitepress/theme/index.js]
import DefaultTheme from 'vitepress/theme-without-fonts'
import './my-fonts.css'
@ -68,12 +66,11 @@ Si está usando componentes opcionales como los componentes de la [Página del e
Si su fuente es un archivo local referenciado via `@font-face`, ella será procesada como un asset e incluida en `.vitepress/dist/assets` con un nombre de archivo hash. Para pre-cargar ese archivo, use el hook de construcción [transformHead](../reference/site-config#transformhead):
```js
// .vitepress/config.js
```js [.vitepress/config.js]
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 [
[
@ -94,8 +91,7 @@ export default {
## Registrando Componentes Globales {#registering-global-components}
```js
// .vitepress/theme/index.js
```js [.vitepress/theme/index.js]
import DefaultTheme from 'vitepress/theme'
/** @type {import('vitepress').Theme} */
@ -109,8 +105,7 @@ export default {
```
Si está usando TypeScript:
```ts
// .vitepress/theme/index.ts
```ts [.vitepress/theme/index.ts]
import type { Theme } from 'vitepress'
import DefaultTheme from 'vitepress/theme'
@ -129,8 +124,7 @@ Como estamos usando Vite, puede también aprovechar la [funcionalidad de importa
El componente `<Layout/>` del tema por defecto posee algunos _slots_ que pueden ser usados para inyectar contenido en lugares específicos de la página. Aqui un ejemplo de como inyectar un componente antes del esquema:
```js
// .vitepress/theme/index.js
```js [.vitepress/theme/index.js]
import DefaultTheme from 'vitepress/theme'
import MyLayout from './MyLayout.vue'
@ -142,8 +136,7 @@ export default {
}
```
```vue
<!--.vitepress/theme/MyLayout.vue-->
```vue [.vitepress/theme/MyLayout.vue]
<script setup>
import DefaultTheme from 'vitepress/theme'
@ -161,8 +154,7 @@ const { Layout } = DefaultTheme
O puede también usar la función _render_.
```js
// .vitepress/theme/index.js
```js [.vitepress/theme/index.js]
import { h } from 'vue'
import DefaultTheme from 'vitepress/theme'
import MyComponent from './MyComponent.vue'
@ -223,9 +215,7 @@ Lista completa de _slots_ disponibles en el layout del tema por defecto:
Puede extender el tema por defecto para proporcionar una transición personalizada cuando el modo de color es alternado. Un ejemplo:
```vue
<!-- .vitepress/theme/Layout.vue -->
```vue [.vitepress/theme/Layout.vue]
<script setup lang="ts">
import { useData } from 'vitepress'
import DefaultTheme from 'vitepress/theme'
@ -261,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
```
:::
::: detalles 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
```
:::
@ -116,8 +100,7 @@ Por defecto, VitePress almacena el caché del servidor de desarrollo en `.vitepr
El archivo de configuración (`.vitepress/config.js`) permite que personalice vários aspectos de su sitio VitePress, con las opciones más básicas siendo el titulo y la descripción del sitio:
```js
// .vitepress/config.js
```js [.vitepress/config.js]
export default {
// opciones a nivel del sitio
title: 'VitePress',
@ -143,7 +126,7 @@ VitePress también proporciona la habilidad de generar URLs limpias, retambém f
La herramienta debe tener también inyectado los siguientes scripts npm en su `package.json` si permitió esto durante el proceso de instalación:
```json
```json [package.json]
{
...
"scripts": {

@ -13,7 +13,7 @@ docs/
En seguida, en el archivo `docs/.vitepress/config.ts`:
```ts
```ts [docs/.vitepress/config.ts]
import { defineConfig } from 'vitepress'
export default defineConfig({
@ -77,8 +77,7 @@ Sin embargo, VitePress no redireccionará `/` para `/en/` por defecto. Necesitar
**Consejo profesional:** Si está usando la forma descrita arriba, puede usar el cookie `nf_lang` para persistir la selección de idioma del usuario:
```ts
// docs/.vitepress/theme/index.ts
```ts [docs/.vitepress/theme/index.ts]
import DefaultTheme from 'vitepress/theme'
import Layout from './Layout.vue'
@ -88,11 +87,10 @@ export default {
}
```
```vue
<!-- docs/.vitepress/theme/Layout.vue -->
```vue [docs/.vitepress/theme/Layout.vue]
<script setup lang="ts">
import DefaultTheme from 'vitepress/theme'
import { useData } from 'vitepress'
import { useData, inBrowser } from 'vitepress'
import { watchEffect } from 'vue'
const { lang } = useData()

@ -234,7 +234,7 @@ Este es un recipiente especial que puee ser usado para evitar conflictos de esti
```md
::: raw
Envuelve en un <div class="vp-raw">
Envuelve en un `<div class="vp-raw">`
:::
```
@ -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/]
})
```
@ -847,8 +847,7 @@ Esto es actualmente opcional. Para activarlo, necesita instalar `markdown-it-mat
npm add -D markdown-it-mathjax3
```
```ts
// .vitepress/config.ts
```ts [.vitepress/config.ts]
export default {
markdown: {
math: true

@ -175,8 +175,7 @@ packages/pkg-b/src/pkg-b-docs.md --> /pkg-b/index.html
Puede realizar esto configurando la opción [`rewrites`](../reference/site-config#rewrites) así:
```ts
// .vitepress/config.js
```ts [.vitepress/config.js]
export default {
rewrites: {
'packages/pkg-a/src/pkg-a-docs.md': 'pkg-a/index.md',

@ -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,26 +38,25 @@ 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
```js [.vitepress/theme/index.js]
/** @type {import('vitepress').Theme} */
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)
}
}
@ -65,15 +64,14 @@ export default {
```
Si está usando TypeScript:
```ts
// .vitepress/theme/index.ts
```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-que-accede-window-en-la-importacion')
const plugin = await import('plugin-que-accede-a-window-en-la-importacion')
app.use(plugin.default)
}
}
@ -82,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>
@ -98,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>
@ -107,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:
@ -254,3 +254,36 @@ import ComponentInHeader from '../../components/ComponentInHeader.vue'
padding: 0 20px;
}
</style>
## Soporte de IntelliSense en VS Code
<!-- Based on https://github.com/vuejs/language-tools/pull/4321 -->
Vue ofrece soporte para IntelliSense de forma predeterminada mediante el [Plugin oficial de Vue para VS Code](https://marketplace.visualstudio.com/items?itemName=Vue.volar). Sin embargo, para habilitarlo en archivos `.md`, es necesario realizar algunos ajustes en los archivos de configuración.
1. Agrega el patrón `.md` a las opciones `include` y `vueCompilerOptions.vitePressExtensions` en el archivo tsconfig/jsconfig:
::: code-group
```json [tsconfig.json]
{
"include": [
"docs/**/*.ts",
"docs/**/*.vue",
"docs/**/*.md",
],
"vueCompilerOptions": {
"vitePressExtensions": [".md"],
},
}
```
:::
2. Agrega `markdown` a la opción `vue.server.includeLanguages` en el archivo de configuración de VS Code
::: code-group
```json [.vscode/settings.json]
{
"vue.server.includeLanguages": ["vue", "markdown"]
}
```
:::

@ -1,9 +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>
@ -11,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=/%22vitepress%22:+/+path:/(?:package%7Cdeno)%5C.jsonc?$/+NOT+is:fork+NOT+is:archived&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,15 +8,15 @@ 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
image:
src: /vitepress-logo-large.webp
src: /vitepress-logo-large.svg
alt: VitePress
features:
@ -36,25 +33,3 @@ features:
title: Entrega rápida de sitios
details: Carga inicial rápida con HTML estático, navegación rápida con enrutamiento del lado del cliente.
---
<style>
:root {
--vp-home-hero-name-color: transparent;
--vp-home-hero-name-background: -webkit-linear-gradient(120deg, #bd34fe 30%, #41d1ff);
--vp-home-hero-image-background-image: linear-gradient(-45deg, #bd34fe 50%, #47caff 50%);
--vp-home-hero-image-filter: blur(44px);
}
@media (min-width: 640px) {
:root {
--vp-home-hero-image-filter: blur(56px);
}
}
@media (min-width: 960px) {
:root {
--vp-home-hero-image-filter: blur(68px);
}
}
</style>

@ -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
@ -233,24 +233,10 @@ export default {
```ts
interface SocialLink {
icon: SocialLinkIcon
icon: string | { svg: string }
link: string
ariaLabel?: string
}
type SocialLinkIcon =
| 'discord'
| 'facebook'
| 'github'
| 'instagram'
| 'linkedin'
| 'mastodon'
| 'npm'
| 'slack'
| 'twitter'
| 'x'
| 'youtube'
| { svg: string }
```
## footer

@ -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

@ -113,9 +113,9 @@ export default defineConfig({
/**
* @param {string} src
* @param {import('vitepress').MarkdownEnv} env
* @param {import('markdown-it')} md
* @param {import('markdown-it-async')} md
*/
_render(src, env, md) {
async _render(src, env, md) {
// retorne un string HTML
}
}
@ -138,8 +138,8 @@ export default defineConfig({
search: {
provider: 'local',
options: {
_render(src, env, md) {
const html = md.render(src, env)
async _render(src, env, md) {
const html = await md.renderAsync(src, env)
if (env.frontmatter?.search === false) return ''
if (env.relativePath.startsWith('algum/caminho')) return ''
return html
@ -151,7 +151,7 @@ export default defineConfig({
```
::: warning Nota
En este caso, una función `_render` se proporciona, es necesario manipular el `search: false` desde el frente por su cuenta. Además, el objeto `env` no estará completamente poblado antes que `md.render` se llama, luego verifica las propiedades opcionales `env`, como `frontmatter`, debe hacerse después de eso.
En este caso, una función `_render` se proporciona, es necesario manipular el `search: false` desde el frente por su cuenta. Además, el objeto `env` no estará completamente poblado antes que `md.renderAsync` se llama, luego verifica las propiedades opcionales `env`, como `frontmatter`, debe hacerse después de eso.
:::
#### Ejemplo: Transformar contenido - agregar anclajes {#example-transforming-content-adding-anchors}
@ -164,10 +164,10 @@ export default defineConfig({
search: {
provider: 'local',
options: {
_render(src, env, md) {
const html = md.render(src, env)
async _render(src, env, md) {
const html = await md.renderAsync(src, env)
if (env.frontmatter?.title)
return md.render(`# ${env.frontmatter.title}`) + html
return await md.renderAsync(`# ${env.frontmatter.title}`) + html
return html
}
}
@ -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}
@ -370,10 +416,3 @@ new Crawler({
}
})
```
<style>
img[src="/search.png"] {
width: 100%;
aspect-ratio: 1 / 1;
}
</style>

@ -181,37 +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>
```

@ -106,7 +106,7 @@ interface Router {
/**
* Llamado después del cambio de ruta.
*/
onAfterRouteChanged?: (to: string) => Awaitable<void>
onAfterRouteChange?: (to: string) => Awaitable<void>
}
```

@ -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:
@ -352,7 +352,7 @@ export default {
Cuando se establece en `true`, VitePress eliminará el `.html` al final de las URLs. Consulte también [Generar URL Limpia](../guide/routing#generating-clean-url).
::: Alerta de Soporte de Servidor Requerido
::: warning Soporte de Servidor Requerido
Habilitar esto puede requerir configurar adicional en su plataforma de alojamiento. Para funcionar, su servidor debe poder servir `/foo.html` cuando visite `/foo` **sin redirección**.
:::
@ -439,7 +439,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.
@ -594,7 +594,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`.
:::
@ -662,7 +662,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.
:::
@ -679,7 +679,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.
:::

@ -0,0 +1,258 @@
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',
// 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() }
},
editLink: {
pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',
text: 'ویرایش این صفحه در گیت‌هاب'
},
footer: {
message: 'انتشار یافته تحت لایسنس MIT',
copyright: 'حق نسخه‌برداری © 2019-کنون Evan You'
},
docFooter: {
prev: 'قبلی',
next: 'بعدی'
},
outline: {
label: 'در این صفحه'
},
lastUpdated: {
text: 'آخرین به‌روزرسانی‌'
},
notFound: {
title: 'صفحه پیدا نشد',
quote:
'اما اگر جهت خود را تغییر ندهید و همچنان به جستجو ادامه دهید، ممکن است در نهایت به جایی برسید که در حال رفتن به آن هستید.',
linkLabel: 'برو به خانه',
linkText: 'من را به خانه ببر'
},
langMenuLabel: 'تغییر زبان',
returnToTopLabel: 'بازگشت به بالا',
sidebarMenuLabel: 'منوی جانبی',
darkModeSwitchLabel: 'تم تاریک',
lightModeSwitchTitle: 'رفتن به حالت روشن',
darkModeSwitchTitle: 'رفتن به حالت تاریک',
siteTitle: 'ویت‌پرس'
}
})
function nav(): DefaultTheme.NavItem[] {
return [
{
text: 'راهنما',
link: 'fa/guide/what-is-vitepress',
activeMatch: '/guide/'
},
{
text: 'مرجع',
link: 'fa/reference/site-config',
activeMatch: '/reference/'
},
{
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'
},
{
text: 'مشارکت',
link: 'https://github.com/vuejs/vitepress/blob/main/.github/contributing.md'
}
]
}
]
}
function sidebarGuide(): DefaultTheme.SidebarItem[] {
return [
{
text: 'معرفی',
collapsed: false,
items: [
{ text: 'ویت‌پرس چیست؟', link: 'what-is-vitepress' },
{ text: 'شروع کار', link: 'getting-started' },
{ text: 'مسیریابی', link: 'routing' },
{ text: 'استقرار', link: 'deploy' }
]
},
{
text: 'نوشتن',
collapsed: false,
items: [
{ text: 'افزونه‌های Markdown', link: 'markdown' },
{ text: 'مدیریت منابع', link: 'asset-handling' },
{ text: 'Frontmatter', link: 'frontmatter' },
{ text: 'استفاده از Vue در Markdown', link: 'using-vue' },
{ text: 'بین‌المللی سازی', link: 'i18n' }
]
},
{
text: 'شخصی‌سازی',
collapsed: false,
items: [
{ text: 'استفاده از تم شخصی', link: 'custom-theme' },
{
text: 'گسترش تم پیش‌فرض',
link: 'extending-default-theme'
},
{ text: 'بارگیری داده در زمان Build', link: 'data-loading' },
{ text: 'سازگاری SSR', link: 'ssr-compat' },
{ text: 'اتصال به CMS', link: 'cms' }
]
},
{
text: 'آزمایشی',
collapsed: false,
items: [
{ text: 'حالت MPA', link: 'mpa-mode' },
{ text: 'جنریت کردن Sitemap', link: 'sitemap-generation' }
]
},
{ text: 'پیکربندی و مرجع API', base: 'fa/reference/', link: 'site-config' }
]
}
function sidebarReference(): DefaultTheme.SidebarItem[] {
return [
{
text: 'مرجع',
base: 'fa/reference/',
items: [
{ text: 'پیکربندی Site', link: 'site-config' },
{ text: 'پیکربندی Frontmatter', link: 'frontmatter-config' },
{ text: 'Runtime API', link: 'runtime-api' },
{ text: 'CLI', link: 'cli' },
{
text: 'تم پیش‌فرض',
base: 'fa/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: 'Timestamp آخرین به‌روزرسانی', 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: 'از هوش مصنوعی بپرسید: ',
placeholderTextAskAiStreaming: 'در حال پاسخ...',
searchInputLabel: 'جستجو',
backToKeywordSearchButtonText: 'بازگشت به جستجوی کلیدواژه',
backToKeywordSearchButtonAriaLabel: 'بازگشت به جستجوی کلیدواژه'
},
startScreen: {
recentSearchesTitle: 'جستجوهای اخیر',
noRecentSearchesText: 'هیچ جستجوی اخیر',
saveRecentSearchButtonTitle: 'ذخیره در تاریخچه جستجو',
removeRecentSearchButtonTitle: 'حذف از تاریخچه جستجو',
favoriteSearchesTitle: 'علاقه‌مندی‌ها',
removeFavoriteSearchButtonTitle: 'حذف از علاقه‌مندی‌ها',
recentConversationsTitle: 'گفتگوهای اخیر',
removeRecentConversationButtonTitle: 'حذف این گفتگو از تاریخچه'
},
errorScreen: {
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: 'انتخاب',
submitQuestionText: 'ارسال پرسش',
selectKeyAriaLabel: 'کلید Enter',
navigateText: 'حرکت',
navigateUpKeyAriaLabel: 'کلید جهت بالا',
navigateDownKeyAriaLabel: 'کلید جهت پایین',
closeText: 'بستن',
backToSearchText: 'بازگشت به جستجو',
closeKeyAriaLabel: 'کلید Escape',
poweredByText: 'جستجو توسط'
}
}
}
}
}

@ -0,0 +1,63 @@
# مدیریت منابع {#asset-handling}
## ارجاع به منابع ایستا {#referencing-static-assets}
تمام فایل‌های Markdown به کامپوننت‌های Vue تبدیل و توسط [Vite](https://vitejs.dev/guide/assets.html) پردازش می‌شوند. شما می‌توانید، **و باید**، هر نوع دارایی را با استفاده از URLهای نسبی مرجع قرار دهید:
```md
![تصویر](./image.png)
```
شما می‌توانید منابع ایستا را در فایل‌های Markdown خود، کامپوننت‌های `*.vue` در قالب، استایل‌ها و فایل‌های `.css` ساده، با استفاده از مسیرهای عمومی مطلق (براساس ریشه پروژه) یا مسیرهای نسبی (براساس سیستم فایل شما) ارجاع دهید. روش دوم مشابه رفتاری است که در صورت استفاده از Vite، Vue CLI یا `file-loader` webpack با آن آشنا هستید.
انواع شایع تصویر، رسانه و فایل فونت به طور خودکار شناسایی و به عنوان منابع درج می‌شوند.
::: tip فایل‌های لینک شده به عنوان دارایی محسوب نمی‌شوند
PDFها یا سند‌های دیگر که از طریق پیوندها در فایل‌های Markdown ارجاع داده شده‌اند به طور خودکار به عنوان دارایی در نظر گرفته نمی‌شوند. برای دسترسی به فایل‌های لینک شده، باید آن‌ها را به صورت دستی در دایرکتوری [`public`](#the-public-directory) پروژه قرار دهید.
:::
تمام منابع ارجاع داده شده، شامل آن‌هایی که از مسیرهای مطلق استفاده می‌کنند، در مرحله تولید به دایرکتوری خروجی با نام فایلی بر اساس یک هش کپی خواهند شد. دارایی‌هایی که هرگز ارجاع نداده شوند، کپی نخواهند شد. منابع تصویر کوچک‌تر از 4 کیلوبایت به صورت base64 درون خطی می‌شوند - این می‌تواند از طریق گزینه پیکربندی [`vite`](../reference/site-config#vite) تنظیم شود.
تمام ارجاع‌های مسیر **ایستا**، شامل مسیرهای مطلق، باید بر اساس ساختار دایرکتوری کاری شما تعیین شوند.
## دایرکتوری عمومی {#the-public-directory}
گاهی اوقات ممکن است نیاز داشته باشید منابع ایستا را فراهم کنید که به صورت مستقیم در هیچ‌یک از Markdown یا کامپوننت‌های قالب شما ارجاع نشده‌اند، یا ممکن است بخواهید برخی فایل‌ها را با نام اصلی خود سرویس دهید. به عنوان مثال، فایل‌هایی مانند `robots.txt`، آیکون‌های fav، و آیکون‌های PWA.
شما می‌توانید این فایل‌ها را در دایرکتوری `public` تحت [دایرکتوری منبع](./routing#source-directory) قرار دهید. به عنوان مثال، اگر ریشه پروژه شما `./docs` است و از محل پیش‌فرض دایرکتوری منبع استفاده می‌کنید، آنگاه دایرکتوری عمومی شما `./docs/public` خواهد بود.
منابع قرار داده شده در `public` به صورت اصلی در ریشه دایرکتوری خروجی کپی خواهند شد.
توجه داشته باشید که باید به فایل‌های قرار داده شده در `public` با استفاده از مسیر مطلق ریشه ارجاع دهید - به عنوان مثال، `public/icon.png` همیشه باید به عنوان `/icon.png` در کد منبع ارجاع داده شود.
## URL پایه {#base-url}
اگر وب‌سایت شما به URL غیر ریشه استقرار می‌یابد، باید گزینه `base` را در `.vitepress/config.js` تنظیم کنید. به عنوان مثال، اگر قصد دارید وب‌سایت خود را به `https://foo.github.io/bar/` استقرار دهید، آنگاه `base` باید به `'/bar/'` تنظیم شود (همیشه باید با یک خط شروع و پایان یابد).
تمام مسیرهای دارایی ایستا شما به صورت خودکار پردازش می‌شوند تا با ارزش‌های `base` مختلف تطبیق یابند. به عنوان مثال، اگر به یک ارجاع مطلق به یک دارایی زیر `public` در Markdown خود اشاره کرده‌اید:
```md
![تصویر](/image-inside-public.png)
```
در این حالت، شما **نیازی ندارید** که آن را به روز کنید وقتی که مقدار پیکربندی `base` را تغییر می‌دهید.
اما، اگر شما در حال نویسندگی یک کامپوننت قالب هستید که به صورت پویا به منابع لینک می‌دهد، به عنوان مثال یک تصویر که `src` آن براساس مقدار پیکربندی قالب است:
```vue
<img :src="theme.logoPath" />
```
در این حالت، توصیه می‌شود که مسیر را با استفاده از کمکی [`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}
اتصال ویت‌پرس به یک سیستم مدیریت محتوا به طور عمده بر اساس [مسیریابی پویا](./routing#dynamic-routes) خواهد بود. حتماً قبل از شروع، با روش کار آن آشنا شوید.
از آنجایی که هر سیستم مدیریت محتوا به طریقی متفاوت کار می‌کند، در اینجا تنها می‌توانیم یک جریان کاری عمومی را ارائه دهیم که شما باید آن را برای حالت خاص خودتان سفارشی کنید.
1. اگر سیستم مدیریت محتوا نیاز به احراز هویت دارد، یک فایل `.env` برای ذخیره توکن‌های API خود ایجاد کنید و آن را بارگذاری کنید:
```js
// posts/[id].paths.js
import { loadEnv } from 'vitepress'
const env = loadEnv('', process.cwd())
```
2. داده‌های مورد نیاز را از سیستم مدیریت محتوا بازیابی کرده و به شکل داده‌های مسیر مناسب فرمت کنید:
```js
export default {
async paths() {
// از کتابخانه مشتری مربوط به سیستم مدیریت محتوا استفاده کنید اگر نیاز دارید
const data = await (await fetch('https://my-cms-api', {
headers: {
// توکن در صورت لزوم
}
})).json()
return data.map(entry => {
return {
params: { id: entry.id, /* عنوان، نویسندگان، تاریخ و غیره */ },
content: entry.content
}
})
}
}
```
3. نمایش محتوا در صفحه:
```md
# {{ $params.title }}
- نوشته شده توسط {{ $params.author }} در تاریخ {{ $params.date }}
<!-- @content -->
```
## راهنماهای ادغام {#integration-guides}
اگر راهنمایی درباره ادغام ویت‌پرس با یک سیستم مدیریت محتوا خاص نوشته‌اید، لطفاً از لینک "ویرایش این صفحه" زیر استفاده کنید تا آن را ارسال کنید!

@ -0,0 +1,220 @@
---
outline: deep
---
# استفاده از یک تم سفارشی {#using-a-custom-theme}
## Resolve کردن تم {#theme-resolving}
می‌توانید با ایجاد یک فایل `.vitepress/theme/index.js` یا `.vitepress/theme/index.ts` (فایل ورودی تم) تم سفارشی را فعال کنید:
```
.
├─ docs # ریشه پروژه
│ ├─ .vitepress
│ │ ├─ theme
│ │ │ └─ index.js # ورودی تم
│ │ └─ config.js # فایل پیکربندی
│ └─ index.md
└─ package.json
```
وقتی ویت‌پرس حضور یک فایل ورودی تم را شناسایی کند، همواره از تم سفارشی به جای تم پیش‌فرض استفاده می‌کند. با این حال، شما می‌توانید [تم پیش‌فرض را گسترش دهید](./extending-default-theme) تا سفارشی‌سازی‌های پیشرفته‌تری را روی آن اعمال کنید.
## رابط تم {#theme-interface}
یک تم سفارشی ویت‌پرس به عنوان یک شی تعریف می‌شود که شامل رابط زیر است:
```ts
interface Theme {
/**
* کامپوننت لایه‌ی ریشه برای هر صفحه
* @required
*/
Layout: Component
/**
* تقویت نمونه Vue اپلیکیشن
* @optional
*/
enhanceApp?: (ctx: EnhanceAppContext) => Awaitable<void>
/**
* گسترش یک تم دیگر، با فراخوانی `enhanceApp` آن پیش از ما
* @optional
*/
extends?: Theme
}
interface EnhanceAppContext {
app: App // نمونه Vue اپلیکیشن
router: Router // نمونه روتر ویت‌پرس
siteData: Ref<SiteData> // متادیتاهای سطح سایت
}
```
فایل ورودی تم باید تم را به عنوان export پیش‌فرض خود export کند:
```js [.vitepress/theme/index.js]
// شما می‌توانید فایل‌های Vue را مستقیماً در ورودی تم وارد کنید
// ویت‌پرس با @vitejs/plugin-vue پیش‌تنظیم شده است.
import Layout from './Layout.vue'
export default {
Layout,
enhanceApp({ app, router, siteData }) {
// ...
}
}
```
export پیش‌فرض تنها قراردادی برای یک تم سفارشی است و تنها ویژگی `Layout` لازم است. بنابراین، به شیء تم ویت‌پرس می‌توان به عنوان یک کامپوننت Vue ساده ترتیب داد.
درون کامپوننت لایه‌ی خود، دقیقاً مانند یک برنامه Vite + Vue 3 عادی عمل می‌کند. با این وجود، توجه داشته باشید که تم همچنین باید [سازگار با SSR](./ssr-compat) باشد.
## ساخت یک لایه {#building-a-layout}
بیشترین لایه‌ی پایه‌ای نیازمند دارای یک کامپوننت `<Content />` است:
```vue [.vitepress/theme/Layout.vue]
<template>
<h1>طرح سفارشی!</h1>
<!-- اینجا محتوای markdown نمایش داده می‌شود -->
<Content />
</template>
```
لایه‌ی بالا به سادگی تمام محتوای markdown هر صفحه را به عنوان HTML نمایش می‌دهد. اولین بهبودی که می‌توانیم اعمال کنیم، مدیریت خطاهای 404 است:
```vue{1-4,9-12}
<script setup>
import { useData } from 'vitepress'
const { page } = useData()
</script>
<template>
<h1>طرح سفارشی!</h1>
<div v-if="page.isNotFound">
صفحه 404 سفارشی!
</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>طرح سفارشی!</h1>
<div v-if="page.isNotFound">
صفحه 404 سفارشی!
</div>
<div v-if="frontmatter.layout === 'home'">
صفحه خانه سفارشی!
</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>طرح سفارشی!</h1>
<NotFound v-if="page.isNotFound" />
<Home v-if="frontmatter.layout === 'home'" />
<Page v-else /> <!-- <Page /> با `<Content />` را نمایش می‌دهد -->
</template>
```
برای همه چیزی که در کامپوننت‌های تم موجود است، به [مستندات API اجرایی](../reference/runtime-api) مراجعه کنید. به علاوه، شما می‌توانید از [بارگذاری داده در زمان ساخت](./data-loading) استفاده کنید تا لایه‌های مبتنی بر داده را تولید کنید - به عنوان مثال، یک صفحه که تمام پست‌های وبلاگ در پروژه فعلی را لیست می‌کند.
## توزیع یک تم سفارشی {#distributing-a-custom-theme}
آسان‌ترین روش برای توزیع یک تم سفارشی ارائه آن به عنوان [قالب مخزن در GitHub](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-template-repository) است.
اگر می‌خواهید تم را به عنوان یک بسته npm توزیع کنید، مراحل زیر را دنبال کنید:
1. شیء تم را به عنوان export پیش‌فرض در ورودی بسته‌تان export کنید.
2. اگر امکان دارد، تعریف نوع پیکربندی تم خود را به عنوان `ThemeConfig` export کنید.
3. اگر تم شما نیاز به تنظیم پیکربندی ویت‌پرس دارد، پیکربندی را تحت یک زیر‌مسیر بسته (مانند `my-theme/config`) export کنید تا کاربر بتواند آن را گسترش دهد.
4. گزینه‌های پیکربندی تم را مستند کنید (هم از طریق فایل پیکربندی و هم از طریق frontmatter).
5. دستورالعمل‌های روشنی برای مصرف تم خود ارائه دهید (مانند زیر).
## مصرف یک تم سفارشی {#consuming-a-custom-theme}
برای مصرف یک تم خارجی، آن را از ورودی تم سفارشی وارد و دوباره export کنید:
```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) {
// ...
}
}
```
اگر تم نیاز به پیکربندی خاص ویت‌پرس دارد، شما همچنین باید آن را در پیکربندی خود گسترش دهید:
```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,246 @@
# بارگذاری داده در زمان ساخت {#build-time-data-loading}
ویت‌پرس یک ویژگی به نام **بارگذارهای داده** ارائه می‌دهد که به شما این امکان را می‌دهد که داده‌های دلخواه را بارگیری کنید و آن‌ها را از صفحات یا اجزا وارد کنید. بارگذاری داده فقط **در زمان ساخت** اجرا می‌شود: داده‌های حاصل به صورت JSON در بسته JavaScript نهایی سریالیزه می‌شوند.
بارگذارهای داده می‌توانند برای بارگیری داده‌های از راه دور یا تولید فراداده‌ها بر اساس فایل‌های محلی استفاده شوند. به عنوان مثال، می‌توانید از بارگذارهای داده استفاده کنید تا تمام صفحات API محلی خود را تجزیه کنید و به طور خودکار یک فهرست از تمام ورودی‌های API تولید کنید.
## استفاده ابتدایی {#basic-usage}
یک فایل بارگذار داده باید با `.data.js` یا `.data.ts` پایان یابد. فایل باید یک صادرات پیش‌فرض از یک شی با متد `load()` داشته باشد:
```js [example.data.js]
export default {
load() {
return {
hello: 'world'
}
}
}
```
ماژول بارگذار فقط در Node.js ارزیابی می‌شود، بنابراین شما می‌توانید API ‌های Node و وابستگی‌های npm را به عنوان نیازهای خود وارد کنید.
سپس می‌توانید داده را از این فایل در صفحات `.md` و اجزا `.vue` با استفاده از صادرات نام‌گذاری شده `data` وارد کنید:
```vue
<script setup>
import { data } from './example.data.js'
</script>
<pre>{{ data }}</pre>
```
خروجی:
```json
{
"hello": "world"
}
```
شما متوجه خواهید شد که بارگذار داده خودش داده را صادر نمی‌کند. ویت‌پرس پشت صحنه متد `load()` را فراخوانی می‌کند و به طور ضمنی نتیجه را از طریق صادرات نام‌گذاری شده `data` ارائه می‌دهد.
این کار حتی اگر بارگذار async باشد انجام می‌شود:
```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) {
// watchedFiles یک آرایه از مسیرهای مطلق فایل‌های تطابق یافته خواهد بود.
// تولید یک آرایه از فراداده‌های پست وبلاگ که می‌تواند برای نمایش
// یک لیست در طرح استفاده شود
return watchedFiles.map((file) => {
return parse(fs.readFileSync(file, 'utf-8'), {
columns: true,
skip_empty_lines: true
})
})
}
}
```
## `createContentLoader` {#createcontentloader}
وقتی که در حال ساختن یک سایت متمرکز بر محتوا هستیم، اغلب نیاز به ایجاد یک "بایگانی" یا "فهرست" صفحه داریم: یک صفحه که ما همه ورودی‌های موجود در مجموعه محتوای خود را لیست می‌کنیم، به عنوان مثال پست‌های وبلاگ یا صفحات API. ما می‌توانیم این کار را مستقیماً با API بارگذار داده انجام دهیم، اما از آنجا که این یک حالت استفاده رایج است، ویت‌پرس همچنین یک کمک‌کننده به نام `createContentLoader` را فراهم می‌کند تا این فرآیند را ساده‌تر کند:
```js [posts.data.js]
import { createContentLoader } from 'vitepress'
export default createContentLoader('posts/*.md', /* گزینه‌ها */)
```
کمک‌کننده یک الگوی glob را نسبت به [دایرکتوری منبع](./routing#source-directory) مشخص می‌کند و یک شی `{ watch، load }` را که می‌تواند به عنوان صادرات پیش‌فرض در یک فایل بارگذار داده استفاده شود، برمی‌گرداند. همچنین پیاده‌سازی حافظه پنهانی بر اساس برچسب‌های تغییر مدیریت
می‌کند تا عملکرد توسعه را بهبود بخشد.
لطفاً توجه داشته باشید که بارگذار فقط با فایل‌های Markdown کار می‌کند - فایل‌های غیر-Markdown تطابق یافته حذف می‌شوند.
داده بارگذاری شده یک آرایه با نوع `ContentData[]` خواهد بود:
```ts
interface ContentData {
// آدرس URL برای صفحه. به عنوان مثال /posts/hello.html (شامل پایه نمی‌شود)
// تکرار دستی یا استفاده از `transform` سفارشی برای نرمال کردن مسیرها
url: string
// اطلاعات frontmatter صفحه
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>همه پست‌های وبلاگ</h1>
<ul>
<li v-for="post of posts">
<a :href="post.url">{{ post.frontmatter.title }}</a>
<span>توسط {{ post.frontmatter.author }}</span>
</li>
</ul>
</template>
```
### گزینه‌ها {#options}
احتمالاً داده پیش‌فرض به تمام نیازها پاسخ نمی‌دهد - شما می‌توانید با استفاده از گزینه‌ها به تبدیل داده‌ها مشترک شوید:
```js [posts.data.js]
import { createContentLoader } from 'vitepress'
export default createContentLoader('posts/*.md', {
includeSrc: true, // آیا منبع اصلی مارک‌داون را اضافه کنیم؟
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 // منبع اصلی مارک‌داون
page.html // صفحه HTML کامل
page.excerpt // خلاصه HTML (محتوای بالای اولین `---`)
return {/* ... */}
})
}
})
```
بررسی کنید که چگونه در [وبلاگ Vue.js](https://github.com/vuejs/blog/blob/main/.vitepress/theme/posts.data.ts) استفاده شده است.
API `createContentLoader` همچنین می‌تواند در داخل [هوک‌های ساخت](../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[]> {
/**
* آیا منبع اصلی را اضافه کنیم؟
* @default false
*/
includeSrc?: boolean
/**
* آیا منبع را به HTML تبدیل کرده و در داده شامل کنیم؟
* @default false
*/
render?: boolean
/**
* اگر `boolean` باشد، آیا باید خلاصه را تجزیه و شامل کنیم؟ (به صورت HTML)
*
* اگر `function` باشد، کنترل نحوه استخراج خلاصه از محتوا.
*
* اگر `string` باشد، تعیین کنید که چگونه جداکننده سفارشی باید برای استخراج خلاصه استفاده شود.
* جداکننده پیش‌فرض `---` است اگر `excerpt` `true` باشد.
*
* @see https://github.com/jonschlinkert/gray-matter#optionsexcerpt
* @see https://github.com/jonschlinkert/gray-matter#optionsexcerpt_separator
*
* @default false
*/
excerpt?:
| boolean
| ((file: { data: { [key: string]: any }; content: string; excerpt?: string }, options?: any) => void)
| string
/**
* تبدیل داده. توجه داشته باشید که داده به عنوان JSON در بسته مشتری درج خواهد شد
* اگر از اجزا یا فایل‌های مارک‌داون وارد شود.
*/
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,337 @@
---
outline: deep
---
# استقرار وب‌سایت ویت‌پرس شما {#deploy-your-vitepress-site}
راهنماهای زیر بر اساس برخی فرضیات مشترک است:
- وب‌سایت ویت‌پرس در دایرکتوری `docs` پروژه شما قرار دارد.
- شما از دایرکتوری خروجی پیش‌فرض ساخته‌شده (`.vitepress/dist`) استفاده می‌کنید.
- ویت‌پرس به‌عنوان یک وابستگی محلی در پروژه شما نصب شده است و شما اسکریپت‌های زیر را در `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` یک سرور وب ایستا محلی راه‌اندازی می‌کند که دایرکتوری خروجی `.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/`، در این صورت باید گزینه [`base`](../reference/site-config#base) را به `'/blog/'` در پیکربندی ویت‌پرس تنظیم کنید.
**مثال:** اگر از صفحات GitHub (یا GitLab) استفاده می‌کنید و به `user.github.io/repo/` انتشار می‌دهید، آنگاه `base` را به `/repo/` تنظیم کنید.
## سربرگ‌های حافظه نهان HTTP {#http-cache-headers}
اگر شما کنترلی بر روی سربرگ‌های HTTP در سرور تولیدی خود دارید، می‌توانید سربرگ‌های `cache-control` را پیکربندی کنید تا بهبود عملکرد در بازدیدهای تکراری داشته باشید.
بسیاری از فایل‌های ایستا (مانند JavaScript، CSS و سایر فایل‌های وارد شده که در `public` نیستند) از نام‌های فایل با هش استفاده می‌کنند. اگر پیش‌نمایش تولیدی را با استفاده از تب شبکه ابزارهای توسعه مرورگر خود بررسی کنید، فایل‌هایی مانند `app.4f283b18.js` را خواهید دید.
این هش `4f283b18` از محتوای این فایل تولید شده است. اگر محتوا تغییر کند، URLها نیز تغییر می‌کنند. این به این معنی است که می‌توانید برای این فایل‌ها سربرگ‌های حافظه نهان قدرتمند را استفاده کنید. همه این فایل‌ها در زیردایرکتوری `assets/` در دایرکتوری خروجی قرار می‌گیرند، بنابراین می‌توانید برای آن‌ها سربرگ زیر را پیکربندی کنید:
```
Cache-Control: max-age=31536000,immutable
```
::: details مثال فایل `_headers` برای Netlify
```
/assets/*
cache-control: max-age=31536000
cache-control: immutable
```
توجه: فایل `_headers` باید در [دایرکتوری عمومی](./asset-handling#the-public-directory) قرار گیرد - در این مورد، `docs/public/_headers` - تا کپی شود بطور صحیح به دایرکتوری خروجی.
[مستندات سربرگ‌های سفارشی Netlify](https://docs.netlify.com/routing/headers/)
:::
::: details پیکربندی مثال Vercel در `vercel.json`
```json
{
"headers": [
{
"source": "/assets/(.*)",
"headers": [
{
"key": "Cache-Control",
"value": "max-age=31536000, immutable"
}
]
}
]
}
```
توجه: فایل `vercel.json` باید در ریشه مخزن شما قرار گیرد.
[مستندات Vercel در مورد پیکربندی سربرگ‌ها](https://vercel.com/docs/concepts/projects/project-configuration#headers)
:::
## راهنمای‌های پلتفرم {#platform-guides}
### Netlify / Vercel / Cloudflare Pages / AWS Amplify / Render {#netlify-vercel-cloudflare-pages-aws-amplify-render}
یک پروژه جدید راه‌اندازی کرده و این تنظیمات را با استفاده از داشبورد خود تغییر دهید:
- **دستور ساخت:** `npm run docs:build`
- **دایرکتوری خروجی:** `docs/.vitepress/dist`
- **نسخه Node:** `18` (یا بالاتر)
::: warning هشدار
گزینه‌هایی مانند _Auto Minify_ را برای کد HTML فعال نکنید. این گزینه‌ها ممکن است توضیحاتی را که به Vue معنا دارد، از خروجی حذف کنند. ممکن است خطاهای ناسازگاری را در اجرا ببینید اگر حذف شوند.
:::
### صفحات GitHub {#github-pages}
1. یک فایل به نام `deploy.yml` در دایرکتوری `.github/workflows` پروژه خود ایجاد کنید با محتوایی مانند زیر:
```yaml [.github/workflows/deploy.yml]
# Sample workflow for building and deploying a ویت‌پرس site to GitHub Pages
#
name: Deploy ویت‌پرس 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@v5
with:
fetch-depth: 0 # Not needed if lastUpdated is not enabled
# - uses: pnpm/action-setup@v4 # Uncomment this if you're using pnpm
# - uses: oven-sh/setup-bun@v1 # Uncomment this if you're using Bun
- name: Setup Node
uses: actions/setup-node@v6
with:
node-version: 24
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 ویت‌پرس
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 هشدار
مطمئن شوید که گزینه `base` در ویت‌پرس به‌درستی پیکربندی شده است. برای اطلاعات بیشتر به [تنظیم مسیر پایه عمومی](#setting-a-public-base-path) مراجعه کنید.
:::
2. در تنظیمات مخزن خود در زیرمنوی "Build and deployment > Source" در "Github Actions" را انتخاب کنید.
3. تغییرات خود را به شاخه `main` ارسال کنید و منتظر GitHub Actions workflow بمانید. شما باید وب‌سایت خود را در `https://<username>.github.io/[repository]/` یا `https://<custom-domain>/` بسته به تنظیمات خود دیده شده است. وب‌سایت شما به‌طور خودکار در هر بار فشرده‌سازی به شاخه `main` ارسال می‌شود.
### صفحات GitLab {#gitlab-pages}
1. `outDir` را در پیکربندی ویت‌پرس به `../public` تنظیم کنید. گزینه `base` را به `'/<repository>/'` تنظیم کنید اگر می‌خواهید در `https://<username>.gitlab.io/<repository>/` انتشار دهید.
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}
به [ایجاد و انتشار یک برنامه ویت‌پرس در Edgio](https://docs.edg.io/guides/vitepress) مراجعه کنید.
### Kinsta Static Site Hosting {#kinsta-static-site-hosting}
شما می‌توانید وب‌سایت ویت‌پرس خود را بر روی [Kinsta](https://kinsta.com/static-site-hosting/) با دنبال کردن این [دستورالعمل‌ها](https://kinsta.com/docs/vitepress-static-site-example/) انتشار دهید.
### Stormkit
شما می‌توانید پروژه ویت‌پرس خود را به [Stormkit](https://www.stormkit.io) با دنبال کردن این [دستورالعمل‌ها](https://stormkit.io/blog/how-to-deploy-vitepress) انتشار دهید.
### Nginx
اینجا یک مثال از پیکربندی بلوک سرور Nginx است. این تنظیم شامل فشرده‌سازی gzip برای فایل‌های متن معمولی، قوانین برای سرویس فایل‌های ایستا سایت ویت‌پرس شما با هدرهای مناسب برای حافظه‌نگهداری مناسب است و همچنین مدیریت `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";
}
}
}
```
این پیکربندی فرض می‌کند که سایت ویت‌پرس ساخته شده شما در دایرکتوری `/app` در سرور شما قرار دارد. دستورالعمل `root` را از ابزارهای مربوطه استفاده کنید اگر فایل‌های سایت شما در جای دیگری قرار دارد.
::: warning هشدار
مسیر تنظیمات try_files نباید به طور پیش‌فرض به index.html مانند برنامه‌های دیگر Vue مشخص شود. این کار باعث وضعیت نامعتبر صفحه می‌شود.
:::
اطلاعات بیشتر را در [مستندات رسمی nginx](https://nginx.org/en/docs/)، در این مسائل [#2837](https://github.com/vuejs/vitepress/discussions/2837)، [#3235](https://github.com/vuejs/vitepress/issues/3235) و همچنین در این [پست وبلاگ](https://blog.mehdi.cc/articles/vitepress-cleanurls-on-nginx-environment#readings) از Mehdi Merah پیدا کنید.

@ -0,0 +1,334 @@
---
outline: deep
---
# گسترش تم پیش‌فرض {#extending-the-default-theme}
تم پیش‌فرض ویت‌پرس برای مستندات بهینه‌سازی شده است و قابلیت سفارشی‌سازی دارد. برای دریافت لیست جامع گزینه‌ها، به [نمای کلی از تنظیمات تم پیش‌فرض](../reference/default-theme-config) مراجعه کنید.
با این حال، مواردی وجود دارد که فقط با تنظیمات کافی نخواهد بود. به عنوان مثال:
1. نیاز به تنظیم استایل CSS دارید؛
2. نیاز به اصلاح نمونه برنامه Vue، به عنوان مثال برای ثبت مولفه‌های عمومی؛
3. نیاز به درج محتوای سفارشی در تم از طریق slotهای طرح.
این سفارش‌های پیشرفته نیازمند استفاده از یک تم سفارشی هستند که از تم پیش‌فرض "گسترش" می‌کند.
::: 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}
ویت‌پرس از [Inter](https://rsms.me/inter/) به عنوان فونت پیش‌فرض استفاده می‌کند و فونت‌ها را در خروجی ساخته‌شده شامل می‌شود. این فونت همچنین در محصولات خودکار پیش‌بارگذاری می‌شود. با این حال، این ممکن است مطلوب نباشد اگر می‌خواهید از یک فونت اصلی مختلف استفاده کنید.
برای جلوگیری از شامل شدن Inter در خروجی ساخته‌شده، تم را به جای `vitepress/theme-without-fonts` وارد کنید:
```js [.vitepress/theme/index.js]
import DefaultTheme from 'vitepress/theme-without-fonts'
import './my-fonts.css'
export default DefaultTheme
```
```css
/* .vitepress/theme/custom.css */
:root {
--vp-font-family-base: /* فونت متن عادی */
--vp-font-family-mono: /* فونت کد */
}
```
::: warning هشدار
اگر از مولفه‌های اختیاری مانند مولفه‌های [صفحه تیم](../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 }) {
// منظور شده برای همسان سازی font خود، regex مورد نیاز را تنظیم کنید
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 استفاده می‌کنیم، می‌توانید از ویژگی [import glob](https://vitejs.dev/guide/features.html#glob-import) در Vite برای خودکار ثبت یک پوشه از مولفه‌ها استفاده کنید.
## slot ‌های طرح {#layout-slots}
کامپوننت `<Layout/>` تم پیش‌فرض چندین slot دارد که می‌توانید محتوا را در موقعیت‌های مختلف صفحه در آن‌ها درج کنید. در زیر مثالی از درج یک کامپوننت در قبل از طرح داده شده است:
```js [.vitepress/theme/index.js]
import DefaultTheme from 'vitepress/theme'
import MyLayout from './MyLayout.vue'
export default {
extends: DefaultTheme,
// جایگزینی Layout با یک کامپوننت پوشه‌بندی که slotها را درج می‌کند
Layout: MyLayout
}
```
```vue [.vitepress/theme/MyLayout.vue]
<script setup>
import DefaultTheme from 'vitepress/theme'
const { Layout } = DefaultTheme
</script>
<template>
<Layout>
<template #aside-outline-before>
محتوای سفارشی بالای نوار کناری من
</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)
})
}
}
```
لیست کاملی از slotهای موجود در طرح پیش‌فرض:
- وقتی `layout: 'doc'` (پیش‌فرض) از طریق frontmatter فعال است:
- `doc-top`
- `doc-bottom`
- `doc-footer-before`
- `doc-before`
- `doc-after`
- `sidebar-nav-before`
- `sidebar-nav-after`
- `aside-top`
- `aside-bottom`
- `aside-outline-before`
- `aside-outline-after`
- `aside-ads-before`
- `aside-ads-after`
- وقتی `layout: 'home'` از طریق frontmatter فعال است:
- `home-hero-before`
- `home-hero-info-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'` از طریق frontmatter فعال است:
- `page-top`
- `page-bottom`
- در صفحه یافت نشد (404):
- `not-found`
- همیشه:
- `layout-top`
- `layout-bottom`
- `nav-bar-title-before`
- `nav-bar-title-after`
- `nav-bar-content-before`
- `nav-bar-content-after`
- `nav-screen-content-before`
- `nav-screen-content-after`
## استفاده از API انتقال نمایش {#using-view-transitions-api}
### در تغییر ظاهر {#on-appearance-toggle}
شما می‌توانید تم پیش‌فرض را گسترش دهید تا هنگام تغییر حالت رنگ، یک انتقال سفارشی را فراهم کند. به عنوان مثال:
```vue [.vitepress/theme/Layout.vue]
<script setup lang="ts">
import { useData } from 'vitepress'
import DefaultTheme from 'vitepress/theme'
import { nextTick, provide } from 'vue'
const { isDark } = useData()
const enableTransitions = () =>
'startViewTransition' in document &&
window.matchMedia('(prefers-reduced-motion: no-preference)').matches
provide('toggle-appearance', async ({ clientX: x, clientY: y }: MouseEvent) => {
if (!enableTransitions()) {
isDark.value = !isDark.value
return
}
const clipPath = [
`circle(0px at ${x}px ${y}px)`,
`circle(${Math.hypot(
Math.max(x, innerWidth - x),
Math.max(y, innerHeight - y)
)}px at ${x}px ${y}px)`
]
await document.startViewTransition(async () => {
isDark.value = !isDark.value
await nextTick()
}).ready
document.documentElement.animate(
{ clipPath: isDark.value ? clipPath.reverse() : clipPath },
{
duration: 300,
easing: 'ease-in',
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.webp)
</details>
برای جزئیات بیشتر در مورد انتقال‌های نمایش به [اسناد کروم](https://developer.chrome.com/docs/web-platform/view-transitions/) مراجعه کنید.
### در تغییر مسیر {#on-route-change}
به زودی.
## جایگزینی کامپوننت‌های داخلی {#overriding-internal-components}
شما می‌توانید با استفاده از [alias های 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('./components/CustomNavBar.vue', import.meta.url)
)
}
]
}
}
})
```
برای دریافت نام دقیق کامپوننت به [کد منبع ما](https://github.com/vuejs/vitepress/tree/main/src/client/theme-default/components) مراجعه کنید. از آنجا که کامپوننت‌ها داخلی هستند، احتمال آنکه نام آن‌ها بین انتشارات کوچک تغییر کند، وجود دارد.

@ -0,0 +1,48 @@
# Frontmatter
## استفاده {#usage}
ویت‌پرس پشتیبانی از frontmatter YAML در تمام فایل‌های Markdown را دارد و آن‌ها را با استفاده از [gray-matter](https://github.com/jonschlinkert/gray-matter) تجزیه می‌کند. Frontmatter باید در بالای فایل Markdown قرار داشته باشد (قبل از هر عنصر از جمله برچسب‌های `<script>`) و باید به صورت YAML معتبر واقع در بین خطوط خط کشیده شود. به عنوان مثال:
```md
---
title: مستندات با ویت‌پرس
editLink: true
---
```
بسیاری از گزینه‌های پیکربندی سایت یا پیش‌فرض در تمام frontmatter گزینه‌های متناظر دارند. شما می‌توانید از frontmatter برای لغو عملکرد خاص برای صفحه فعلی استفاده کنید. برای جزئیات بیشتر، به [مرجع پیکربندی Frontmatter](../reference/frontmatter-config) مراجعه کنید.
همچنین می‌توانید داده‌های اختصاصی frontmatter خود را تعریف کنید تا در بیانیه‌های پویا Vue در صفحه استفاده شود.
## دسترسی به داده‌های Frontmatter {#accessing-frontmatter-data}
داده‌های frontmatter می‌توانند از طریق متغیر global ویژه `$frontmatter` دسترسی داشته باشند:
اینجا یک مثال از نحوه استفاده از آن در فایل Markdown شما است:
```md
---
title: مستندات با ویت‌پرس
editLink: true
---
# {{ $frontmatter.title }}
محتوای راهنما
```
شما همچنین می‌توانید داده‌های frontmatter صفحه فعلی را در `<script setup>` با استفاده از راهنمای [`useData()`](../reference/runtime-api#usedata) به دست آورید.
## فرمت‌های جایگزین Frontmatter {#alternative-frontmatter-formats}
ویت‌پرس همچنین از نحوه نوشتاری frontmatter JSON با استفاده از تکیه‌گاه‌های آغازین و پایانی در آکولاد پشتیبانی می‌کند:
```json
---
{
"title": "عنوان",
"editLink": true
}
---
```

@ -0,0 +1,203 @@
# شروع کار {#getting-started}
## تست آنلاین {#try-it-online}
می‌توانید ویت‌پرس را مستقیماً در مرورگر خود در [StackBlitz](https://vitepress.new) امتحان کنید.
## نصب {#installation}
### پیش‌نیازها {#prerequisites}
- [Node.js](https://nodejs.org/) نسخه 18 یا بالاتر.
- ترمینال برای دسترسی به ویت‌پرس از طریق رابط خط فرمان (CLI).
- ویرایشگر متنی با پشتیبانی از [Markdown](https://en.wikipedia.org/wiki/Markdown).
- [VSCode](https://code.visualstudio.com/) به همراه [افزونه رسمی Vue](https://marketplace.visualstudio.com/items?itemName=Vue.volar).
ویت‌پرس می‌تواند به صورت مستقل استفاده شود یا در یک پروژه موجود نصب شود. در هر دو حالت، می‌توانید آن را با دستور زیر نصب کنید:
::: 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 نکته
ویت‌پرس یک بسته فقط ESM است. از `require()` برای وارد کردن آن استفاده نکنید و اطمینان حاصل کنید که نزدیک‌ترین `package.json` شما شامل `"type": "module"` است، یا پسوند فایل‌های مربوطه خود مانند `.vitepress/config.js` را به `.mjs`/`.mts` تغییر دهید. برای جزئیات بیشتر به [راهنمای عیب‌یابی Vite](http://vitejs.dev/guide/troubleshooting.html#this-package-is-esm-only) مراجعه کنید. همچنین، در زمینه‌های async CJS می‌توانید از `await import('vitepress')` استفاده کنید.
:::
### Wizard راه‌اندازی
ویت‌پرس با یک جادوگر راه‌اندازی خط فرمان ارائه می‌شود که به شما کمک می‌کند یک پروژه پایه را بسازید. پس از نصب، با اجرای دستور زیر جادوگر را راه‌اندازی کنید:
::: 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 به عنوان peer dependency
اگر قصد دارید سفارشی‌سازی‌هایی که از کامپوننت‌ها یا APIهای Vue استفاده می‌کنند را انجام دهید، باید `vue` را به عنوان dependency نیز نصب کنید.
:::
## ساختار فایل‌ها {#file-structure}
اگر در حال ساخت یک سایت مستقل ویت‌پرس هستید، می‌توانید سایت را در دایرکتوری فعلی خود (`./`) بسازید. اما، اگر ویت‌پرس را در یک پروژه موجود به همراه سایر کدهای منبع نصب می‌کنید، توصیه می‌شود سایت را در یک دایرکتوری تودرتو (مثلاً `./docs`) بسازید تا از بقیه پروژه جدا باشد.
فرض کنیم که پروژه ویت‌پرس را در `./docs` ساخته‌اید، ساختار فایل‌های تولید شده باید به این شکل باشد:
```
.
├─ docs
│ ├─ .vitepress
│ │ └─ config.js
│ ├─ api-examples.md
│ ├─ markdown-examples.md
│ └─ index.md
└─ package.json
```
دایرکتوری `docs` به عنوان **ریشه پروژه** سایت ویت‌پرس در نظر گرفته می‌شود. دایرکتوری `.vitepress` محل ذخیره فایل‌های پیکربندی ویت‌پرس، حافظه نهان سرور توسعه، خروجی ساخت و کد سفارشی‌سازی تم اختیاری است.
::: tip نکته
به طور پیش‌فرض، ویت‌پرس حافظه نهان سرور توسعه خود را در `.vitepress/cache` و خروجی ساخت تولیدی را در `.vitepress/dist` ذخیره می‌کند. اگر از Git استفاده می‌کنید، باید آنها را به فایل `.gitignore` خود اضافه کنید. این مکان‌ها همچنین قابل [پیکربندی](../reference/site-config#outdir) هستند.
:::
### فایل پیکربندی {#the-config-file}
فایل پیکربندی (`.vitepress/config.js`) به شما اجازه می‌دهد جنبه‌های مختلف سایت ویت‌پرس خود را سفارشی کنید، با گزینه‌های پایه‌ای مانند عنوان و توضیحات سایت:
```js [.vitepress/config.js]
export default {
// گزینه‌های سطح سایت
title: 'ویت‌پرس',
description: 'فقط در حال بازی کردن.',
themeConfig: {
// گزینه‌های سطح تم
}
}
```
همچنین می‌توانید رفتار تم را از طریق گزینه `themeConfig` پیکربندی کنید. برای جزئیات کامل درباره همه گزینه‌های پیکربندی، به [راهنمای پیکربندی](../reference/site-config) مراجعه کنید.
### فایل‌های منبع {#source-files}
فایل‌های Markdown خارج از دایرکتوری `.vitepress` به عنوان **فایل‌های منبع** در نظر گرفته می‌شوند.
ویت‌پرس از **مسیر یابی مبتنی بر فایل** استفاده می‌کند: هر فایل `.md` به یک فایل `.html` متناظر با همان مسیر کامپایل می‌شود. برای مثال، `index.md` به `index.html` کامپایل می‌شود و می‌تواند در مسیر ریشه `/` سایت ویت‌پرس نتیجه‌گیری شده بازدید شود.
ویت‌پرس همچنین قابلیت تولید 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، می‌توانید ویت‌پرس را مستقیماً با دستور زیر اجرا کنید:
::: 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، به بخش "نوشتن" راهنما مراجعه کنید. یک مکان عالی برای شروع یادگیری درباره [افزونه‌های Markdown](./markdown) است.
- برای کشف ویژگی‌های ارائه شده توسط تم پیش‌فرض مستندات، به [مرجع پیکربندی تم پیش‌فرض](../reference/default-theme-config) مراجعه کنید.
- اگر می‌خواهید ظاهر سایت خود را بیشتر سفارشی کنید، بررسی کنید که چگونه [تم پیش‌فرض را گسترش دهید](./extending-default-theme) یا [یک تم سفارشی بسازید](./custom-theme).
- هنگامی که سایت مستندات شما شکل گرفت، حتماً [راهنمای استقرار](./deploy) را بخوانید.

@ -0,0 +1,111 @@
# بین‌المللی‌سازی {#internationalization}
برای استفاده از ویژگی‌های داخلی بین‌المللی‌سازی، نیاز است که یک ساختار دایرکتوری به شکل زیر ایجاد کنید:
```
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: 'انگلیسی',
lang: 'en'
},
fr: {
label: 'فرانسوی',
lang: 'fr', // اختیاری، به عنوان `lang` در `html` tag اضافه خواهد شد
link: '/fr/guide' // پیش‌فرض /fr/ -- در منوی ترجمه‌ها نمایش داده می‌شود، می‌تواند خارجی باشد
// سایر ویژگی‌های مختص به هر زبان...
}
}
})
```
می‌توانید خصوصیات زیر را برای هر زبان (شامل ریشه) نیز تغییر دهید:
```ts
interface LocaleSpecificConfig<ThemeConfig = any> {
lang?: string
dir?: string
title?: string
titleTemplate?: string | boolean
description?: string
head?: HeadConfig[] // با ورودی‌های head موجود ادغام خواهد شد، meta tags تکراری به طور خودکار حذف می‌شوند
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
```
با این حال، ویت‌پرس به طور پیش‌فرض به `/` به `/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 } 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'` را در پیکربندی مشخص کنید و از پلاگین‌های PostCSS RTLCSS مانند <https://github.com/MohammadYounes/rtlcss>، <https://github.com/vkalinichev/postcss-rtl> یا <https://github.com/elchininet/postcss-rtlcss> استفاده کنید. باید پلاگین PostCSS خود را به کارگیری `:where([dir="ltr"])` و `:where([dir="rtl"])` به عنوان پیشوندها جلوگیری از مشکلات اولویت CSS استفاده کنید.

@ -0,0 +1,921 @@
# افزونه‌های Markdown {#markdown-extensions}
ویت‌پرس با افزونه‌های markdown داخلی ارائه شده است.
## لینک‌های هدر {#header-anchors}
هدرها به طور خودکار لینک‌های anchor دریافت می‌کنند. نمایش anchor ها با استفاده از گزینه `markdown.anchor` قابل پیکربندی است.
### anchor های سفارشی {#custom-anchors}
برای مشخص کردن تگ anchor سفارشی برای یک هدینگ به جای استفاده از تگ خودکار، یک پسوند به هدینگ اضافه کنید:
```
# Using custom anchors {#my-anchor}
```
این به شما امکان می‌دهد که به جای استفاده از به جای استفاده از `#using-custom-anchors`، به هدینگ به عنوان `#my-anchor` لینک دهید.
## لینک‌ها {#links}
هم لینک‌های داخلی و هم خارجی با دستورالعمل‌های خاصی ارائه می‌شوند.
### لینک‌های داخلی {#internal-links}
لینک‌های داخلی به لینک روتر برای ناوبری SPA تبدیل می‌شوند. همچنین، هر `index.md` موجود در هر زیرپوشه به طور خودکار به `index.html` تبدیل می‌شود، با URL متناظر `/`.
به عنوان مثال، با توجه به ساختار پوشه زیر:
```
.
├─ index.md
├─ foo
│ ├─ index.md
│ ├─ one.md
│ └─ two.md
└─ bar
├─ index.md
├─ three.md
└─ four.md
```
و با فرض این که شما در `foo/one.md` هستید:
```md
[Home](/) <!-- sends the user to the root index.md -->
[foo](/foo/) <!-- sends the user to index.html of directory foo -->
[foo heading](./#heading) <!-- anchors user to a heading in the foo index file -->
[bar - three](../bar/three) <!-- you can omit extension -->
[bar - three](../bar/three.md) <!-- you can append .md -->
[bar - four](../bar/four.html) <!-- or you can append .html -->
```
### پسوند صفحه {#page-suffix}
صفحات و لینک‌های داخلی به طور پیش‌فرض با پسوند `.html` تولید می‌شوند.
### لینک‌های خارجی {#external-links}
لینک‌های خروجی به طور خودکار دارای `target="_blank" rel="noreferrer"` هستند:
- [vuejs.org](https://vuejs.org)
- [ویت‌پرس در GitHub](https://github.com/vuejs/vitepress)
## Frontmatter {#frontmatter}
[YAML frontmatter](https://jekyllrb.com/docs/front-matter/) به طور پیش‌فرض پشتیبانی می‌شود:
```yaml
---
title: عنوان صفحه
lang: fa-IR
---
```
این داده‌ها برای بقیه صفحه در دسترس خواهد بود، همراه با تمامی اجزاهای سفارشی و تم.
برای اطلاعات بیشتر، به [Frontmatter](../reference/frontmatter-config) مراجعه کنید.
## جداول مانند Github {#github-style-tables}
**ورودی**
```md
| Tables | Are | Cool |
| ------------- | :-----------: | ----: |
| col 3 is | right-aligned | $1600 |
| col 2 is | centered | $12 |
| zebra stripes | are neat | $1 |
```
**خروجی**
| Tables | Are | Cool |
| ------------- | :-----------: | ----: |
| col 3 is | right-aligned | $1600 |
| col 2 is | centered | $12 |
| zebra stripes | are neat | $1 |
## اموجی :tada: {#emoji}
**ورودی**
```
:tada: :100:
```
**خروجی**
:tada: :100:
یک [لیست از همه اموجی ها](https://github.com/markdown-it/markdown-it-emoji/blob/master/lib/data/full.mjs) در دسترس است.
## فهرست مطالب {#table-of-contents}
**ورودی**
```
[[toc]]
```
**خروجی**
[[toc]]
نحوه پردازش فهرست مطالب با استفاده از گزینه `markdown.toc` قابل پیکربندی است.
## کانتینرهای سفارشی {#custom-containers}
کانتینرهای سفارشی می‌توانند توسط انواع، عناوین و محتویات خود تعریف شوند.
### عنوان پیش‌فرض {#default-title}
**ورودی**
```md
::: info
این یک جعبه اطلاعات است.
:::
::: tip
این یک نکته است.
:::
::: warning
این یک هشدار است.
:::
::: danger
این یک هشدار خطرناک است.
:::
::: details
این یک بلوک جزئیات است.
:::
```
**خروجی**
::: info اطلاعات
این یک جعبه اطلاعات است.
:::
::: tip نکته
این یک نکته است.
:::
::: warning هشدار
این یک هشدار است.
:::
::: danger خطر
این یک هشدار خطرناک است.
:::
::: details جزئیات
این یک بلوک جزئیات است.
:::
### عنوان سفارشی {#custom-title}
می‌توانید عنوان سفارشی را با اضافه کردن متن به انتهای نوع کانتینر تنظیم کنید.
**ورودی**
````md
::: danger ایست!
منطقه خطرناک، ادامه ندهید
:::
::: details برای مشاهده کد کلیک کنید
```js
console.log('Hello, ویت‌پرس!')
```
:::
````
**خروجی**
::: danger ایست!
منطقه خطرناک، ادامه ندهید
:::
::: details برای مشاهده کد کلیک کنید
```js
console.log('Hello, ویت‌پرس!')
```
:::
این همچنین امکان دارد که شما عنوان‌های سفارشی را به صورت global تنظیم کنید با اضافه کردن محتوای زیر به تنظیمات سایت. این امکان خاصا اگر به زبان انگلیسی نوشته نمی‌شود، بسیار مفید است:
```ts
// config.ts
export default defineConfig({
// ...
markdown: {
container: {
tipLabel: 'نکته',
warningLabel: 'اخطار',
dangerLabel: 'خطر',
infoLabel: 'اطلاعات',
detailsLabel: 'جزئیات'
}
}
// ...
})
```
### `raw` {#raw}
این یک کانتینر ویژه است که می‌تواند برای جلوگیری از تداخل استایل و روتر با ویت‌پرس استفاده شود. این به ویژه زمانی مفید است که شما کتابخانه‌های کامپوننت را مستند کنید. می‌توانید همچنین [whyframe](https://whyframe.dev/docs/integrations/vitepress) را برای ایزوله‌تر شدن بیشتر بررسی کنید.
**نحوه استفاده**
```md
::: raw
بسته‌بندی در یک `<div class="vp-raw">`
:::
```
کلاس `vp-raw` می‌تواند به صورت مستقیم بر روی عناصر استفاده شود. ایزوله‌سازی استایل در حال حاضر انتخابی است:
- `postcss` را با مدیر بسته‌های مورد علاقه‌تان نصب کنید:
```sh
$ npm add -D postcss
```
- یک فایل با نام `docs/postcss.config.mjs` ایجاد کنید و کد زیر را به آن اضافه کنید:
```js
import { postcssIsolateStyles } from 'vitepress'
export default {
plugins: [postcssIsolateStyles()]
}
```
می‌توانید گزینه‌های آن را به این صورت پاس بدهید:
```js
postcssIsolateStyles({
includeFiles: [/custom\.css/] // به طور پیش‌فرض [/vp-doc\.css/, /base\.css/]
})
```
## هشدارهای GitHub {#github-flavored-alerts}
ویت‌پرس همچنین [هشدارهای GitHub](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts) را برای نمایش به عنوان تماس‌ها پشتیبانی می‌کند. آن‌ها به همان شکلی که [کانتینرهای سفارشی](#custom-containers) نمایش داده می‌شوند.
```md
> [!NOTE]
> اطلاعاتی که کاربران باید به آن توجه کنند، حتی اگر سریع بخوانند.
> [!TIP]
> اطلاعات اختیاری برای کمک به کاربر برای موفقیت بیشتر.
> [!IMPORTANT]
> اطلاعات حیاتی برای موفقیت کاربران.
> [!WARNING]
> محتوای بحرانی که نیاز به توجه فوری کاربر دارد به دلیل خطرات پتانسیلی.
> [!CAUTION]
> پیامدهای منفی احتمالی یک عمل.
```
> [!NOTE]
> اطلاعاتی که کاربران باید به آن توجه کنند، حتی اگر سریع بخوانند.
> [!TIP]
> اطلاعات اختیاری برای کمک به کاربر برای موفقیت بیشتر.
> [!IMPORTANT]
> اطلاعات حیاتی برای موفقیت کاربران.
> [!WARNING]
> محتوای بحرانی که نیاز به توجه فوری کاربر دارد به دلیل خطرات پتانسیلی.
> [!CAUTION]
> پیامدهای منفی احتمالی یک عمل.
## Syntax Highlighting در بلوک‌های کد {#syntax-highlighting-in-code-blocks}
ویت‌پرس از [Shiki](https://github.com/shikijs/shiki) برای syntax highlighting زبان در بلوک‌های کد Markdown با استفاده از متن رنگی استفاده می‌کند. Shiki از تنوع وسیعی از زبان‌های برنامه‌نویسی پشتیبانی می‌کند. تنها کافی است که یک نام مستعار زبان معتبر به بکتیک‌ها ابتدایی کد اضافه کنید:
**ورودی**
````
```js
export default {
name: 'MyComponent',
// ...
}
```
````
````
```html
<ul>
<li v-for="todo in todos" :key="todo.id">
{{ todo.text }}
</li>
</ul>
```
````
**خروجی**
```js
export default {
name: 'MyComponent'
// ...
}
```
```html
<ul>
<li v-for="todo in todos" :key="todo.id">
{{ todo.text }}
</li>
</ul>
```
یک [لیست از زبان‌های معتبر](https://shiki.style/languages) در مخزن Shiki موجود است.
همچنین می‌توانید تم syntax highlighting را در تنظیمات برنامه سفارشی کنید. لطفاً به [گزینه‌های Markdown](../reference/site-config#markdown) برای جزئیات بیشتر مراجعه کنید.
## برجسته‌سازی خطوط در بلوک‌های کد {#line-highlighting-in-code-blocks}
**ورودی**
````
```js{4}
export default {
data () {
return {
msg: 'برجسته‌سازی شده!'
}
}
}
```
````
**خروجی**
```js{4}
export default {
data () {
return {
msg: 'برجسته‌سازی شده!'
}
}
}
```
علاوه بر یک خط، می‌توانید چندین خط تکی، محدوده‌ها یا هر دو را نیز مشخص کنید:
- محدوده‌های خط: به عنوان مثال `{5-8}`, `{3-10}`, `{10-17}`
- چند خط تک: به عنوان مثال `{4,7,9}`
- محدوده‌های خط و خط‌های تک: به عنوان مثال `{4,7-13,16,23-27,40}`
**ورودی**
````
```js{1,4-6}
const message = 'Hello, World!';
console.log(message);
```
````
**خروجی**
```js{1,4-6}
const message = 'Hello, World!';
console.log(message);
```
## فکوس در بلاک‌های کد {#focus-in-code-blocks}
افزودن کامنت `// [!code focus]` به یک خط، روی آن فکوس می‌کند و بخش‌های دیگر کد را مات می‌کند.
به‌علاوه، می‌توانید با استفاده از `// [!code focus:<lines>]` تعدادی خط را برای فکوس تعیین کنید.
**ورودی**
````
```js
export default {
data () {
return {
msg: 'Focused!' // [!!code focus]
}
}
}
```
````
**خروجی**
```js
export default {
data() {
return {
msg: 'Focused!' // [!code focus]
}
}
}
```
## تفاوت‌های رنگی در بلاک‌های کد {#colored-diffs-in-code-blocks}
افزودن کامنت `// [!code --]` یا `// [!code ++]` به یک خط، یک تفاوت را در آن خط ایجاد می‌کند، با حفظ رنگ‌های بلاک کد.
**ورودی**
````
```js
export default {
data () {
return {
msg: 'Removed' // [!!code --]
msg: 'Added' // [!!code ++]
}
}
}
```
````
**خروجی**
```js
export default {
data () {
return {
msg: 'Removed' // [!code --]
msg: 'Added' // [!code ++]
}
}
}
```
## خطاها و هشدارها در بلاک‌های کد {#errors-and-warnings-in-code-blocks}
افزودن کامنت `// [!code warning]` یا `// [!code error]` به یک خط، آن را مطابق با نوع، رنگ می‌کند.
**ورودی**
````
```js
export default {
data () {
return {
msg: 'Error', // [!!code error]
msg: 'Warning' // [!!code warning]
}
}
}
```
````
**خروجی**
```js
export default {
data() {
return {
msg: 'Error', // [!code error]
msg: 'Warning' // [!code warning]
}
}
}
```
## شماره‌گذاری خطوط {#line-numbers}
می‌توانید با استفاده از تنظیمات، شماره‌گذاری خطوط را برای هر بلاک کد فعال کنید:
```js
export default {
markdown: {
lineNumbers: true
}
}
```
لطفاً [گزینه‌های markdown](../reference/site-config#markdown) را برای جزئیات بیشتر ببینید.
می‌توانید با استفاده از `:line-numbers` / `:no-line-numbers` در بلاک‌های کد شماره‌گذاری خطوط را نادیده بگیرید یا تنظیمات اصلی را با `=` پس از `:line-numbers` سفارشی کنید. به عنوان مثال، `:line-numbers=2` به معنای شروع شماره‌گذاری از خط `2` است.
**ورودی**
````md
```ts {1}
// شماره‌گذاری خطوط به طور پیش‌فرض غیرفعال است
const line2 = 'این خط ۲ است'
const line3 = 'این خط ۳ است'
```
```ts:line-numbers {1}
// شماره‌گذاری خطوط فعال است
const line2 = 'این خط ۲ است'
const line3 = 'این خط ۳ است'
```
```ts:line-numbers=2 {1}
// شماره‌گذاری خطوط فعال است و از خط ۲ شروع می‌شود
const line3 = 'این خط ۳ است'
const line4 = 'این خط ۴ است'
```
````
**خروجی**
```ts {1}
// شماره‌گذاری خطوط به طور پیش‌فرض غیرفعال است
const line2 = 'این خط ۲ است'
const line3 = 'این خط ۳ است'
```
```ts:line-numbers {1}
// شماره‌گذاری خطوط فعال است
const line2 = 'این خط ۲ است'
const line3 = 'این خط ۳ است'
```
```ts:line-numbers=2 {1}
// شماره‌گذاری خطوط فعال است و از خط ۲ شروع می‌شود
const line3 = 'این خط ۳ است'
const line4 = 'این خط ۴ است'
```
## وارد کردن Snippet کد {#import-code-snippets}
می‌توانید snippet های کد را از فایل‌های موجود با استفاده از دستور زیر وارد کنید:
```md
<<< @/filepath
```
این دستور [highlight کردن خط](#line-highlighting-in-code-blocks) را نیز پشتیبانی می‌کند:
```md
<<< @/filepath{highlightLines}
```
**ورودی**
```md
<<< @/snippets/snippet.js{2}
```
**فایل کد**
<<< @/snippets/snippet.js
**خروجی**
<<< @/snippets/snippet.js{2}
::: tip نکته
مقدار `@` با ریشه منبع مطابقت دارد. به‌طور پیش‌فرض، این ریشه پروژه ویت‌پرس است، مگر اینکه `srcDir` پیکربندی شده باشد. به‌طور جایگزینی، می‌توانید از مسیرهای نسبی وارد کنید:
```md
<<< ../snippets/snippet.js
```
:::
همچنین می‌توانید [ناحیه VS Code](https://code.visualstudio.com/docs/editor/codebasics#_folding) را برای اضافه کردن قسمت مربوطه فایل کد استفاده کنید. می‌توانید نام ناحیه سفارشی را پس از `#` به دنبال مسیر فایل تعیین کنید:
**ورودی**
```md
<<< @/snippets/snippet-with-region.js#snippet{1}
```
**فایل کد**
<<< @/snippets/snippet-with-region.js
**خروجی**
<<< @/snippets/snippet-with-region.js#snippet{1}
همچنین می‌توانید زبان را داخل آکولادها (`{}`) مشخص کنید:
```md
<<< @/snippets/snippet.cs{c#}
<!-- با highlight خطوط: -->
<<< @/snippets/snippet.cs{1,2,4-6 c#}
<!-- با شماره‌گذاری خطوط: -->
<<< @/snippets/snippet.cs{1,2,4-6 c#:line-numbers}
```
این قابلیت مفید است اگر زبان منبع نمی‌تواند از پسوند فایل استنتاج شود.
### گروه‌های کد {#code-groups}
می‌توانید چندین بلوک کد را به این شکل گروه‌بندی کنید:
**ورودی**
````md
::: code-group
```js [config.js]
/**
* @type {import('vitepress').UserConfig}
*/
const config = {
// ...
}
export default config
```
```ts [config.ts]
import type { UserConfig } from 'vitepress'
const config: UserConfig = {
// ...
}
export default config
```
:::
````
**خروجی**
::: code-group
```js [config.js]
/**
* @type {import('vitepress').UserConfig}
*/
const config = {
// ...
}
export default config
```
```ts [config.ts]
import type { UserConfig } from 'vitepress'
const config: UserConfig = {
// ...
}
export default config
```
:::
همچنین می‌توانید [قطعات کد](#import-code-snippets) را در گروه‌های کد وارد کنید:
**ورودی**
```md
::: code-group
<!-- به طور پیش‌فرض نام فایل به عنوان عنوان استفاده می‌شود -->
<<< @/snippets/snippet.js
<!-- می‌توانید یک عنوان سفارشی نیز ارائه دهید -->
<<< @/snippets/snippet-with-region.js#snippet{1,2 ts:line-numbers} [قطعه با منطقه]
:::
```
**خروجی**
::: code-group
<<< @/snippets/snippet.js
<<< @/snippets/snippet-with-region.js#snippet{1,2 ts:line-numbers} [قطعه با منطقه]
:::
## ادغام فایل‌های Markdown {#markdown-file-inclusion}
می‌توانید یک فایل Markdown را در یک فایل Markdown دیگر، حتی در صورت وجود تو در تو، وارد کنید.
::: tip نکته
می‌توانید مسیر Markdown را با `@` پیش‌فرض کنید. این به عنوان ریشه منبع عمل می‌کند. به طور پیش‌فرض، ریشه پروژه ویت‌پرس است، مگر اینکه `srcDir` پیکربندی شده باشد.
:::
به عنوان مثال، می‌توانید یک فایل Markdown نسبی را با استفاده از این کد وارد کنید:
**ورودی**
```md
# مستندات
## مبانی
<!--@include: ./parts/basics.md-->
```
**قسمت فایل** (`parts/basics.md`)
```md
بعضی موارد مربوط به شروع کار.
### پیکربندی
می‌توان با استفاده از `.foorc.json` ایجاد شد.
```
**کد معادل**
```md
# مستندات
## مبانی
بعضی موارد مربوط به شروع کار.
### پیکربندی
می‌توان با استفاده از `.foorc.json` ایجاد شد.
```
همچنین از انتخاب یک محدوده خطی پشتیبانی می‌کند:
**ورودی**
```md
# مستندات
## مبانی
<!--@include: ./parts/basics.md{3,}-->
```
**قسمت فایل** (`parts/basics.md`)
```md
بعضی موارد مربوط به شروع کار.
### پیکربندی
می‌توان با استفاده از `.foorc.json` ایجاد شد.
```
**کد معادل**
```md
# مستندات
## مبانی
### پیکربندی
می‌توان با استفاده از `.foorc.json` ایجاد شد.
```
قالب محدوده خطی می‌تواند شامل `{3,}`, `{,10}`, `{1,10}` باشد.
همچنین می‌توانید از [ناحیه VS Code](https://code.visualstudio.com/docs/editor/codebasics#_folding) برای اضافه کردن بخش متناظر فایل کد استفاده کنید. می‌توانید پس از `#` نام ناحیه سفارشی را پس از مسیر فایل دنبال کنید:
**ورودی**
```md
# مستندات
## مبانی
<!--@include: ./parts/basics.md#basic-usage{,2}-->
<!--@include: ./parts/basics.md#basic-usage{5,}-->
```
**قسمت فایل** (`parts/basics.md`)
```md
<!-- #region basic-usage -->
## استفاده خط 1
## استفاده خط 2
## استفاده خط 3
<!-- #endregion basic-usage -->
```
**کد معادل**
```md
# مستندات
## مبانی
## استفاده خط 1
## استفاده خط 3
```
::: warning هشدار
توجه داشته باشید که این اقدام منجر به خطا نمی‌شود اگر فایل شما وجود نداشته باشد. بنابراین، در استفاده از این ویژگی، مطمئن شوید که محتوا به درستی نمایش داده می‌شود.
:::
## معادلات ریاضی {#math-equations}
در حال حاضر این گزینه اختیاری است. برای فعال‌سازی آن، باید `markdown-it-mathjax3` را نصب کرده و `markdown.math` را در فایل پیکربندی خود به `true` تنظیم کنید:
```sh
npm add -D markdown-it-mathjax3
```
```ts [.vitepress/config.ts]
export default {
markdown: {
math: true
}
}
```
**ورودی**
```md
وقتی $a \ne 0$ است، دو حل برای $(ax^2 + bx + c = 0)$ وجود دارد و آن‌ها عبارتند از
$$ x = {-b \pm \sqrt{b^2-4ac} \over 2a} $$
**معادلات مکسول**
| equation | description |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| $\nabla \cdot \vec{\mathbf{B}} = 0$ | تنوع $\vec{\mathbf{B}}$ صفر است |
| $\nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} = \vec{\mathbf{0}}$ | curl $\vec{\mathbf{E}}$ نسبت به نرخ تغییر $\vec{\mathbf{B}}$ نسبی است |
| $\nabla \times \vec{\mathbf{B}} -\, \frac1c\, \frac{\partial\vec{\mathbf{E}}}{\partial t} = \frac{4\pi}{c}\vec{\mathbf{j}} \nabla \cdot \vec{\mathbf{E}} = 4 \pi \rho$ | _چیست؟_ |
```
**خروجی**
وقتی $a \ne 0$ است، دو حل برای $(ax^2 + bx + c = 0)$
وجود دارد و آن‌ها عبارتند از
$$ x = {-b \pm \sqrt{b^2-4ac} \over 2a} $$
**معادلات مکسول**
| equation | description |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| $\nabla \cdot \vec{\mathbf{B}} = 0$ | تنوع $\vec{\mathbf{B}}$ صفر است |
| $\nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} = \vec{\mathbf{0}}$ | curl $\vec{\mathbf{E}}$ نسبت به نرخ تغییر $\vec{\mathbf{B}}$ نسبی است |
| $\nabla \times \vec{\mathbf{B}} -\, \frac1c\, \frac{\partial\vec{\mathbf{E}}}{\partial t} = \frac{4\pi}{c}\vec{\mathbf{j}} \nabla \cdot \vec{\mathbf{E}} = 4 \pi \rho$ | _چیست؟_ |
## بارگذاری lazy تصویر {#image-lazy-loading}
می‌توانید بارگذاری تنبلی را برای هر تصویر اضافه شده از طریق Markdown با تنظیم `lazyLoading` به `true` در فایل پیکربندی فعال کنید:
```js
export default {
markdown: {
image: {
// بارگذاری تنبلی تصویر به طور پیش‌فرض غیرفعال است
lazyLoading: true
}
}
}
```
## پیکربندی پیشرفته {#advanced-configuration}
ویت‌پرس از [markdown-it](https://github.com/markdown-it/markdown-it) به عنوان نمایشگر Markdown استفاده می‌کند. اکثر افزونه‌های فوق را با استفاده از افزونه‌های سفارشی پیاده‌سازی کرده‌ایم. می‌توانید نمونه‌ای بیشتر از نمونه `markdown-it` را با استفاده از گزینه `markdown` در `.vitepress/config.js` سفارشی‌سازی کنید:
```js
import { defineConfig } from 'vitepress'
import markdownItAnchor from 'markdown-it-anchor'
import markdownItFoo from 'markdown-it-foo'
export default defineConfig({
markdown: {
// گزینه‌های markdown-it-anchor
// https://github.com/valeriangalliat/markdown-it-anchor#usage
anchor: {
permalink: markdownItAnchor.permalink.headerLink()
},
// گزینه‌های @mdit-vue/plugin-toc
// https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-toc#options
toc: { level: [1, 2] },
config: (md) => {
// استفاده از افزونه‌های markdown-it بیشتر!
md.use(markdownItFoo)
}
}
})
```
برای دیدن لیست کامل خصوصیات قابل تنظیم، به [مرجع تنظیمات: پیکربندی برنامه](../reference/site-config#markdown) مراجعه کنید.

@ -0,0 +1,23 @@
# مهاجرت از ویت‌پرس 0.x
اگر از نسخه 0.x ویت‌پرس می‌آیید، تغییرات قابل توجهی به دلیل ویژگی‌ها و بهبودهای جدید وجود دارد. لطفاً این راهنما را دنبال کنید تا ببینید چگونه برنامه خود را به ویت‌پرس جدیدتر منتقل کنید.
## پیکربندی برنامه
- ویژگی بین‌المللی‌سازی هنوز اجرا نشده است.
## پیکربندی تم
- گزینه `sidebar` ساختار خود را تغییر داده است.
- کلید `children` حالا به نام `items` نامیده می‌شود.
- در حال حاضر ممکن است مورد بالادستی حاوی `link` نباشد. ما قصد داریم این گزینه را بازگردانیم.
- `repo`، `repoLabel`، `docsDir`، `docsBranch`، `editLinks`، `editLinkText` به منظور API انعطاف‌پذیرتر حذف شده‌اند.
- برای اضافه کردن لینک GitHub با آیکون به نوار ناوبری، از ویژگی [پیوندهای اجتماعی](../reference/default-theme-nav#navigation-links) استفاده کنید.
- برای اضافه کردن ویژگی "ویرایش این صفحه"، از ویژگی [پیوند ویرایش](../reference/default-theme-edit-link) استفاده کنید.
- گزینه `lastUpdated` حالا به `config.lastUpdated` و `themeConfig.lastUpdatedText` تقسیم شده است.
- `carbonAds.carbon` به `carbonAds.code` تغییر کرده است.
## پیکربندی Frontmatter
- گزینه `home: true` به `layout: home` تغییر کرده است. همچنین، تنظیمات مربوط به صفحه اصلی بسیار تغییر کرده‌اند تا ویژگی‌های اضافی را ارائه دهند. برای جزئیات بیشتر، [راهنمای صفحه اصلی](../reference/default-theme-home-page) را ببینید.
- گزینه `footer` به [`themeConfig.footer`](../reference/default-theme-config#footer) منتقل شده است.

@ -0,0 +1,30 @@
# مهاجرت از VuePress
## پیکربندی
### نوار کناری
نوار کناری دیگر به طور خودکار از frontmatter پر نمی‌شود. شما می‌توانید [frontmatter را خودتان بخوانید](https://github.com/vuejs/vitepress/issues/572#issuecomment-1170116225) تا نوار کناری به طور پویا پر شود. ابزارهای [اضافی برای این منظور](https://github.com/vuejs/vitepress/issues/96) ممکن است در آینده ارائه شود.
## Markdown
### تصاویر
برخلاف VuePress، ویت‌پرس وقتی شما از تصویر استاتیک استفاده می‌کنید، [`base`](./asset-handling#base-url) پیکربندی شما را به طور خودکار مدیریت می‌کند.
بنابراین، اکنون می‌توانید تصاویر را بدون استفاده از تگ `img` نمایش دهید.
```diff
- <img :src="$withBase('/foo.png')" alt="foo">
+ ![foo](/foo.png)
```
::: warning
برای تصاویر پویا، همچنان نیاز به استفاده از `withBase` به طوری که در [راهنمای Base URL](./asset-handling#base-url) نشان داده شده است، دارید.
:::
از عبارت `!<img.*withBase\('(.*)'\).*alt="([^"]*)".*>` برای جستجو و جایگزینی با `![$2]($1)` استفاده کنید تا تمام تصاویر را با سینتکس `![](...)` جایگزین کنید.
---
ادامه دارد...

@ -0,0 +1,23 @@
# حالت MPA <Badge type="warning" text="آزمایشی" /> {#mpa-mode}
حالت MPA (برنامه چند صفحه) می‌تواند از طریق خط فرمان با `vitepress build --mpa` فعال شود، یا از طریق تنظیمات با گزینه `mpa: true`.
در حالت MPA، همه صفحات به طور پیش‌فرض بدون هیچ جاوااسکریپتی رندر می‌شوند. به همین دلیل، سایت تولیدی احتمالاً امتیاز بهتری از ابزارهای آزمایشی در اولین بازدید دریافت خواهد کرد.
با این حال، به دلیل عدم وجود مسیریابی SPA، لینک‌های متقاطع به بازنشانی کامل صفحه منتهی می‌شوند. ناوبری پس از بارگیری در حالت MPA حساسیت به همان اندازه با حالت SPA نخواهد داشت.
همچنین توجه داشته باشید که عدم وجود JS به طور پیش‌فرض به این معنی است که شما اساساً Vue را به عنوان یک زبان قالب‌بندی سمت سرور استفاده می‌کنید. هیچ کنترل کننده رویدادی در مرورگر اضافه نمی‌شود، بنابراین هیچ تعاملی وجود نخواهد داشت. برای بارگیری JS سمت کلاینت، شما باید از تگ خاص `<script client>` استفاده کنید:
```html
<script client>
document.querySelector('h1').addEventListener('click', () => {
console.log('JavaScript سمت کلاینت!')
})
</script>
# سلام
```
`<script client>` یک ویژگی تنها برای ویت‌پرس است، نه یک ویژگی Vue. این در هر دو فایل `.md` و `.vue` کار می‌کند، اما فقط در حالت MPA. اسکریپت‌های کلاینت در تمام اجزای تم با هم بسته می‌شوند، در حالی که اسکریپت کلاینت برای یک صفحه خاص، فقط برای آن صفحه تقسیم می‌شود.
توجه داشته باشید که `<script client>` به عنوان **کد مؤلفه مؤلفه Vue** ارزیابی نمی‌شود: به عنوان یک ماژول جاوااسکریپت معمولی پردازش می‌شود. به همین دلیل، حالت MPA فقط باید در صورتی استفاده شود که سایت شما به تعامل کمینه‌ای از جانب کلاینت نیاز دارد.

@ -0,0 +1,376 @@
---
outline: deep
---
# مسیریابی {#routing}
## مسیریابی مبتنی بر فایل {#file-based-routing}
ویت‌پرس از مسیریابی مبتنی بر فایل استفاده می‌کند که به این معنی است که صفحات 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 نهایی می‌توانند بر روی هر سرور وبی که قادر به ارائه فایل‌های ایستا است، میزبانی شوند.
## ریشه و دایرکتوری منبع {#root-and-source-directory}
در ساختار فایل پروژه ویت‌پرس، دو مفهوم مهم وجود دارد: **ریشه پروژه** و **دایرکتوری منبع**.
### ریشه پروژه {#project-root}
ریشه پروژه جایی است که ویت‌پرس سعی می‌کند برای دایرکتوری ویژه `.vitepress` را بررسی کند. دایرکتوری `.vitepress` مکانی رزرو شده برای فایل پیکربندی، حافظه نهان سرور توسعه، خروجی ساخت، و کد سفارشی‌سازی موضوع اختیاری ویت‌پرس است.
زمانی که شما دستور `vitepress dev` یا `vitepress build` را از خط فرمان اجرا می‌کنید، ویت‌پرس از دایرکتوری کاری فعلی به عنوان ریشه پروژه استفاده می‌کند. برای مشخص کردن یک زیردایرکتوری به عنوان ریشه، باید مسیر نسبی را به دستور ارسال کنید. به عنوان مثال، اگر پروژه ویت‌پرس شما در `./docs` قرار دارد، باید دستور `vitepress dev docs` را اجرا کنید:
```
.
├─ docs # ریشه پروژه
│ ├─ .vitepress # دایرکتوری پیکربندی
│ ├─ getting-started.md
│ └─ index.md
└─ ...
```
```sh
vitepress dev docs
```
این عمل به نتیجه زیر منجر می‌شود:
```
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های نهایی را بر اساس پیکربندی شما تولید کند.
```md
<!-- درست -->
[شروع کار](./getting-started)
[شروع کار](../guide/getting-started)
<!-- نادرست -->
[شروع کار](./getting-started.md)
[شروع کار](./getting-started.html)
```
جهت آشنایی بیشتر با لینک‌دهی به منابع مانند تصاویر به [مدیریت منابع](./asset-handling) مراجعه کنید.
### لینک‌دهی به صفحات غیر ویت‌پرس {#linking-to-non-vitepress-pages}
اگر می‌خواهید به یک صفحه در وب‌سایت خود لینک دهید که توسط ویت‌پرس تولید نشده است، باید یا از URL کامل (باز می‌شود در یک تب جدید) استفاده کنید، یا هدف را به طور صریح مشخص کنید:
**ورودی**
```md
[لینک به pure.html](/pure.html){target="_self"}
```
**خروجی**
[لینک به pure.html](/pure.html){target="_self"}
::: tip توجه
در لینک‌های Markdown، `base` به طور خودکار به URL پیشوند داده می‌شود. این بدان معنی است که اگر می‌خواهید به صفحه‌ای خارج از پایه خود لینک دهید، باید چیزی شبیه `../../pure.html` را در لینک استفاده کنید (توسط مرورگر نسبت به صفحه فعلی حل می‌شود).
در غیر این صورت، می‌توانید به طور مستقیم از anchor tag syntax استفاده کنید:
```md
<a href="/pure.html" target="_self">لینک به pure.html</a>
```
:::
## تولید URLهای تمیز {#generating-clean-url}
::: warning نیازمندی پشتیبانی سرور
برای ارائه URLهای تمیز با ویت‌پرس، نیاز به پشتیبانی سمت سرور وجود دارد.
:::
به طور پیش‌فرض، ویت‌پرس لینک‌های ورودی را به URLهایی با پسوند `.html` حل می‌کند. با این حال، برخی از کاربران ممکن است از URLهای "تمیز" بدون پسوند `.html` استفاده کنند - به عنوان مثال، `example.com/path` به جای `example.com/path.html`.
برخی از سرورها یا پلتفرم‌های میزبانی (مانند Netlify، Vercel، GitHub Pages) امکان این را فراهم می‌کنند که یک URL مانند `/foo` به `/foo.html` نگاشت شود اگر موجود باشد، بدون انتقال:
- Netlify و GitHub Pages این را به طور پیش‌فرض پشتیبانی می‌کنند.
- Vercel نیاز به فعال‌سازی [`cleanUrls` در `vercel.json`](https://vercel.com/docs/concepts/projects/project-configuration#cleanurls) دارد.
اگر این ویژگی برای شما در دسترس است، می‌توانید از گزینه پیکربندی خود ویت‌پرس به نام [`cleanUrls`](../reference/site-config#cleanurls) استفاده کنید تا:
- لینک‌های ورودی بین صفحات بدون پسوند `.html` تولید شوند.
- اگر مسیر کنونی با `.html` ختم شود، مسیریاب به صورت تغییر مسیر کلاینت به مسیر بدون پسوند انجام می‌دهد.
اگر امکان پیکربندی سرور شما برای این پشتیبانی وجود نداشته باشد، شما باید به صورت دستی به ساختار دایرکتوری زیر رجوع کنید:
```
.
├─ getting-started
│ └─ index.md
├─ installation
│ └─ index.md
└─ index.md
```
## بازنویسی مسیر {#route-rewrites}
می‌توانید نقشه‌بندی بین ساختار دایرکتوری منبع و صفحات تولید شده را سفارشی‌سازی کنید. این ویژگی وقتی مفید است که یک ساختار پروژه پیچیده داشته باشید. به عنوان مثال، فرض کنید یک مونورپو با چند بسته دارید و می‌خواهید مستندات را همراه با فایل‌های منبع قرار دهید مانند این:
```
.
├─ packages
│ ├─ pkg-a
│ │ └─ src
│ │ ├─ pkg-a-code.ts
│ │ └─ pkg-a-docs.md
│ └─ pkg-b
│ └─ src
│ ├─ pkg-b-code.ts
│ └─ pkg-b-docs.md
```
و می‌خواهید صفحات ویت‌پرس به این صورت تولید شوند:
```
packages/pkg-a/src/pkg-a-docs.md --> /pkg-a/index.html
packages/pkg-b/src/pkg-b-docs.md --> /pkg-b/index.html
```
می‌توانید این کار را با پیکربندی گزینه [`rewrites`](../reference/site-config#rewrites) مانند زیر انجام دهید:
```ts [.vitepress/config.js]
export default {
rewrites: {
'packages/pkg-a/src/pkg-a-docs.md': 'pkg-a/index.md',
'packages/pkg-b/src/pkg-b-docs.md': 'pkg-b/index.md'
}
}
```
گزینه `rewrites` همچنین پارامترهای مسیر پویایی را پشتیبانی می‌کند. در مثال بالا، اگر تعداد بسیاری از بسته‌ها داشته باشید، لیست کردن همه مسیرها به شکل زیر ممکن است طولانی باشد. با توجه به اینکه همه دارای ساختار فایل یکسان هستند، می‌توانید پیکربندی را به این صورت ساده‌تر کنید:
```ts
export default {
rewrites: {
'packages/:pkg/src/(.*)': ':pkg/index.md'
}
}
```
مسیرهای بازنویسی با استفاده از بسته `path-to-regexp` ترجمه می‌شوند - برای جزئیات بیشتر به [مستندات آن](https://github.com/pillarjs/path-to-regexp#parameters) مراجعه کنید.
::: warning لینک‌های نسبی با بازنویسی
زمانی که بازنویسی‌ها فعال باشند، **لینک‌های نسبی باید بر اساس مسیرهای بازنویسی باشند**. به عنوان مثال، برای ایجاد یک لینک نسبی از `packages/pkg-a/src/pkg-a-code.md` به `packages/pkg-b/src/pkg-b-code.md`، باید از مورد زیر استفاده کنید:
```md
[لینک به PKG B](../pkg-b/pkg-b-code)
```
:::
## مسیرهای پویا {#dynamic-routes}
می‌توانید صفحات زیادی را با استفاده از یک فایل Markdown و داده‌های پویا تولید کنید. به عنوان مثال، می‌توانید یک فایل `packages/[pkg].md` ایجاد کنید که برای هر بسته در یک پروژه، یک صفحه متناظر تولید می‌کند. در اینجا، بخش `[pkg]` یک پارامتر مسیر است که هر صفحه را از دیگران تمایز می‌دهد.
### فایل بارگیری مسیرها {#paths-loader-file}
از آنجایی که ویت‌پرس یک موتور سایت ایستا است، مسیرهای ممکن باید در زمان ساخت تعیین شوند. بنابراین، یک صفحه مسیر پویا باید همراه با یک **فایل بارگیری مسیرها** همراه باشد. برای `packages/[pkg].md`، به `packages/[pkg].paths.js` (همچنین `.ts` پشتیبانی می‌شود) نیاز داریم:
```
.
└─ packages
├─ [pkg].md # قالب مسیر
└─ [pkg].paths.js # فایل بارگیری
مسیرها
```
فایل بارگیری باید یک شیء با یک متد `paths` به عنوان export پیش‌فرض ارائه دهد. متد `paths` باید آرایه‌ای از اشیاء با خصوصیت `params` را برگرداند. هر یک از این اشیاء یک صفحه متناظر را ایجاد می‌کنند.
با توجه به آرایه `paths` زیر:
```js
// packages/[pkg].paths.js
export default {
paths() {
return [
{ params: { pkg: 'foo' }},
{ params: { pkg: 'bar' }}
]
}
}
```
صفحات HTML تولید شده به شرح زیر خواهد بود:
```
.
└─ packages
├─ foo.html
└─ bar.html
```
### چندین پارامتر {#multiple-params}
یک مسیر پویا می‌تواند شامل چندین پارامتر باشد:
**ساختار فایل**
```
.
└─ 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` global استفاده کند:
```md
- نام بسته: {{ $params.pkg }}
- نسخه: {{ $params.version }}
```
همچنین می‌توانید به پارامترهای کنونی صفحه از طریق [`useData`](../reference/runtime-api#usedata) runtime 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 کلاینت سریال می‌شوند، بنابراین باید از ارسال داده‌های سنگین در پارامترها خودداری کنید، برای مثال محتوای خام Markdown یا HTML از یک CMS از راه دور.
به جای اینکه می‌توانید محتوای چنین محتوایی را در هر صفحه با استفاده از خاصیت `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 {#sitemap-generation}
ویت‌پرس با پشتیبانی بیرونی برای تولید فایل `sitemap.xml` برای سایت شما ارائه می‌شود. برای فعال‌سازی آن، موارد زیر را به فایل `.vitepress/config.js` خود اضافه کنید:
```ts
export default {
sitemap: {
hostname: 'https://example.com'
}
}
```
برای داشتن تگ‌های `<lastmod>` در فایل `sitemap.xml` خود، می‌توانید گزینه [`lastUpdated`](../reference/default-theme-last-updated) را فعال کنید.
## گزینه‌ها {#options}
پشتیبانی از sitemap توسط ماژول [`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}
می‌توانید از هوک `sitemap.transformItems` برای اصلاح موارد sitemap قبل از نوشتن آن‌ها به فایل `sitemap.xml` استفاده کنید. این هوک با یک آرایه از موارد sitemap فراخوانی می‌شود و انتظار دارد که یک آرایه از موارد sitemap بازگردانده شود. مثال:
```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,134 @@
---
outline: deep
---
# تطابق SSR {#ssr-compatibility}
ویت‌پرس، با استفاده از قابلیت‌های رندرینگ سمت سرور (SSR) ارائه شده توسط Vue، اپلیکیشن را در Node.js در هنگام ساخت تولیدی پیش از رندر می‌کند. این بدان معناست که کلیه کدهای سفارشی در اجزای تم به تطابق SSR وابسته هستند.
[بخش SSR در مستندات رسمی Vue](https://vuejs.org/guide/scaling-up/ssr.html) بیشتر در مورد SSR، ارتباط بین SSR / SSG و نکات متداول در نوشتن کد‌های سازگار با SSR توضیح می‌دهد. قانون عمده این است که فقط در `beforeMount` یا `mounted` هوک‌های اجزای Vue از APIهای مرورگر / DOM استفاده کنید.
## `<ClientOnly>` {#clientonly}
اگر از اجزا یا دموهایی استفاده می‌کنید که سازگاری با SSR ندارند (برای مثال حاوی دستورالعمل‌های سفارشی هستند)، می‌توانید آن‌ها را درون کامپوننت داخلی `<ClientOnly>` قرار دهید:
```md
<ClientOnly>
<NonSSRFriendlyComponent />
</ClientOnly>
```
## کتابخانه‌هایی که در هنگام وارد کردن به API مرورگر دسترسی دارند {#libraries-that-access-browser-api-on-import}
بعضی از کتابخانه‌ها یا اجزا در هنگام وارد کردن به APIهای مرورگر **دسترسی دارند**. برای استفاده از کدی که فرض می‌کند محیطی مرورگر در هنگام وارد کردن وجود دارد، باید آن‌ها را به صورت پویا وارد کنید.
### وارد کردن در هوک Mounted {#importing-in-mounted-hook}
```vue
<script setup>
import { onMounted } from 'vue'
onMounted(() => {
import('./lib-that-access-window-on-import').then((module) => {
// استفاده از کد
})
})
</script>
```
### وارد کردن شرطی {#conditional-import}
می‌توانید همچنین وابستگی را با استفاده از `import.meta.env.SSR` (قسمتی از [متغیرهای env Vite](https://vitejs.dev/guide/env-and-mode.html#env-variables)) به شرط وارد کنید:
```js
if (!import.meta.env.SSR) {
import('./lib-that-access-window-on-import').then((module) => {
// استفاده از کد
})
}
```
از آنجا که `Theme.enhanceApp` می‌تواند async باشد، می‌توانید به صورت شرطی پلاگین‌های Vue را که دسترسی به APIهای مرورگر را هنگام وارد کردن دارند، وارد و ثبت کنید:
```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` {#defineclientcomponent}
ویت‌پرس یک کمک‌کننده راحتی برای وارد کردن کامپوننت‌های Vue که هنگام وارد کردن به APIهای مرورگر دسترسی دارند فراهم می‌کند.
```vue
<script setup>
import { defineClientComponent } from 'vitepress'
const ClientComp = defineClientComponent(() => {
return import('component-that-access-window-on-import')
})
</script>
<template>
<ClientComp />
</template>
```
همچنین می‌توانید props/children/slots را به کامپوننت مقصد منتقل کنید:
```vue
<script setup>
import { ref } from 'vue'
import { defineClientComponent } from 'vitepress'
const clientCompRef = ref(null)
const ClientComp = defineClientComponent(
() => import('component-that-access-window-on-import'),
// آرگومان‌ها به h() منتقل می‌شوند - https://vuejs.org/api/render-function.html#h
[
{
ref: clientCompRef
},
{
default: () => 'اسلات پیش‌فرض',
foo: () => h('div', 'فو')
bar: () => [h('span', 'یک'), h('span', 'دو')]
}
],
// تابع بازخورد بعد از بارگذاری کامپوننت، می‌تواند async باشد
() => {
console.log(clientCompRef.value)
}
)
</script>
<template>
<ClientComp />
</template>
```
کامپوننت مقصد فقط در هوک Mounted کامپوننت پوشش وارد می‌شود.

@ -0,0 +1,257 @@
# استفاده از Vue در Markdown {#using-vue-in-markdown}
در ویت‌پرس، هر فایل Markdown به HTML تبدیل شده و سپس به عنوان یک [کامپوننت فایل تکی Vue](https://vuejs.org/guide/scaling-up/sfc.html) پردازش می‌شود. این بدان معنی است که شما می‌توانید از هر ویژگی Vue در داخل Markdown استفاده کنید، شامل قالب‌بندی پویا، استفاده از کامپوننت‌های Vue، یا منطق کامپوننت Vue دلخواه در داخل صفحه با افزودن تگ `<script>`.
مهم است که ویت‌پرس از کامپایلر Vue برای به‌طور خودکار شناسایی و بهینه‌سازی اجزای ثابت محتوای Markdown استفاده می‌کند. محتویات استاتیک به صورت یکنواخت به عنوان placeholder nodes بهینه‌سازی شده و از بارگذاری اولیه در JavaScript صفحه مستثنی می‌شوند. همچنین، در فرآیند hydration سمت کلاینت نیز نادیده گرفته می‌شوند. به طور خلاصه، شما فقط برای اجزای پویا در هر صفحه هزینه می‌پردازید.
::: tip سازگاری با SSR
همه استفاده‌های Vue باید با سازگاری SSR همخوانی داشته باشند. برای جزئیات و راه‌حل‌های متداول، به [سازگاری با SSR](./ssr-compat) مراجعه کنید.
:::
## قالب‌بندی {#templating}
### درون‌یابی(Interpolation) {#interpolation}
هر فایل Markdown ابتدا به HTML تبدیل شده و سپس به عنوان یک کامپوننت Vue به خط لوله فرآیند Vite ارسال می‌شود. این بدان معنی است که می‌توانید از درون‌یابی به سبک Vue در متن استفاده کنید:
**ورودی**
```md
{{ 1 + 1 }}
```
**خروجی**
<div class="language-text"><pre><code>{{ 1 + 1 }}</code></pre></div>
#### دستورالعمل‌ها {#directives}
دستورالعمل‌ها نیز کار می‌کنند (توجه داشته باشید که طراحی، HTML خام همچنین معتبر است):
**ورودی**
```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}
تگ‌های `<script>` و `<style>` در سطح ریشه در فایل‌های Markdown همانند کارکرد آنها در SFC Vue کار می‌کنند، شامل `<script setup>`، `<style module>`، و غیره. تفاوت اصلی در اینجا این است که هیچ تگ `<template>` وجود ندارد: تمام محتویات سطح ریشه دیگر Markdown است. همچنین توجه داشته باشید که همه تگ‌ها باید **پس از** frontmatter قرار گیرند:
```html
---
hello: world
---
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
## محتوای Markdown
تعداد: {{ count }}
<button :class="$style.button" @click="count++">افزایش</button>
<style module>
.button {
color: red;
font-weight: bold;
}
</style>
```
::: warning اجتناب از `<style scoped>` در Markdown
در استفاده از Markdown باید توجه داشت که `<style scoped>` نیازمند افزودن ویژگی‌های خاص به هر عنصر در صفحه فعلی است که باعث بزرگ شدن قابل‌ملاحظه اندازه صفحه می‌شود. هنگام نیاز به قالب‌بندی محلی محدود، استفاده از `<style module>` توصیه می‌شود.
:::
همچنین شما به دسترسی به APIهای runtime ویت‌پرس مانند [`useData` helper](../reference/runtime-api#usedata) دارید که امکان دسترسی به metadata صفحه فعلی را فراهم می‌کند:
**ورودی**
```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}
شما می‌توانید کامپوننت‌های Vue را مستقیماً در فایل‌های Markdown وارد و استفاده کنید.
### وارد کردن در Markdown {#importing-in-markdown}
اگر یک کامپوننت تنها توسط چند صفحه استفاده می‌شود، توصیه می‌شود آنها را به صراحت در جایی که استفاده می‌شوند وارد کنید. این کار امکان تقسیم کد مناسب را فراهم می‌کند و فقط هنگام نمایش صفحات مربوطه بارگذاری می‌شوند:
```md
<script setup>
import CustomComponent from '../components/CustomComponent.vue'
</script>
# مستندات
این یک فایل .md با استفاده از یک کامپوننت اختصاصی است
<CustomComponent />
## مستندات بیشتر
...
```
### ثبت کامپوننت‌ها به صورت Global {#registering-components-globally}
اگر یک کامپوننت بر روی اکثر صفحات استفاده می‌شود، می‌توانید آنها را به صورت global با سفارشی‌سازی نمونه برنامه Vue ثبت کنید. برای مثال، بخش مربوطه را در [گسترش تم پیش‌فرض](./extending-default-theme#registering-global-components) بررسی کنید.
::: warning مهم
اطمینان حاصل کنید که نام یک کامپوننت سفارشی حاوی خط فاصله دارد یا به صورت PascalCase است. در غیر این صورت، به عنوان یک
عنصر داخلی تلقی می‌شود و درون یک تگ `<p>` قرار داده خواهد شد که باعث عدم هم‌سانی‌سازی hydration می‌شود چون `<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/>` |
HTML که توسط `<code>` محصور شده باشد به عنوان آن نمایش داده خواهد شد؛ تنها HTML که **محصور نشده باشد** توسط Vue تجزیه خواهد شد.
::: tip نکته
خروجی HTML توسط [Markdown-it](https://github.com/Markdown-it/Markdown-it) انجام می‌شود، در حالی که سربرگ‌های تجزیه شده توسط ویت‌پرس انجام می‌شود (و برای هر دو نوار کناری و عنوان سند استفاده می‌شود).
:::
## Escaping {#escaping}
شما می‌توانید درون‌یابی‌های Vue را با محصور کردن آنها در یک `<span>` یا عناصر دیگر با دستورالعمل `v-pre` فرار کنید:
**ورودی**
```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}
ویت‌پرس از [پشتیبانی داخلی](https://vitejs.dev/guide/features.html#css-pre-processors) برای پیش‌پردازنده‌های CSS مانند فایل‌های `.scss`، `.sass`، `.less`، `.styl` و `.stylus` پشتیبانی می‌کند. برای استفاده از آنها نیازی به نصب پلاگین‌های خاص 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}
در حال حاضر ویت‌پرس پشتیبانی از SSG برای teleport به body را دارد. برای اهداف دیگر، می‌توانید آنها را درون کامپوننت `<ClientOnly>` یا نشانه تله‌پورت به مکان مناسب در HTML صفحه نهایی خود از طریق [هوک postRender](../reference/site-config#postrender) درج کنید.
<ModalDemo />
::: details جزئیات
<<< @/components/ModalDemo.vue
:::
```md
<ClientOnly>
<Teleport to="#modal">
<div>
// ...
</div>
</Teleport>
</ClientOnly>
```
<script setup>
import ModalDemo from '../../components/ModalDemo.vue'
import ComponentInHeader from '../../components/ComponentInHeader.vue'
</script>
<style>
.escape-demo {
border: 1px solid var(--vp-c-border);
border-radius: 8px;
padding: 0 20px;
}
</style>

@ -0,0 +1,57 @@
# ویت‌پرس چیست؟ {#what-is-vitepress}
ویت‌پرس یک [تولید کننده سایت ایستا](https://en.wikipedia.org/wiki/Static_site_generator) (SSG) است که برای ساخت وب‌سایت‌های سریع و محتوا محور طراحی شده است. به طور خلاصه، ویت‌پرس محتوای منبع شما که به زبان [Markdown](https://en.wikipedia.org/wiki/Markdown) نوشته شده است را گرفته، یک تم بر روی آن اعمال می‌کند و صفحات HTML ایستا تولید می‌کند که به راحتی در هر جایی قابل استقرار هستند.
<div class="tip custom-block" style="padding-top: 8px">
فقط می‌خواهید آن را امتحان کنید؟ به [شروع سریع](./getting-started) بروید.
</div>
## موارد استفاده {#use-cases}
- **مستندسازی**
ویت‌پرس با یک تم پیش‌فرض طراحی شده برای مستندات فنی ارائه می‌شود. این صفحه‌ای که اکنون در حال خواندن آن هستید و همچنین مستندات [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=/%22vitepress%22:+/+path:/(?:package%7Cdeno)%5C.jsonc?$/+NOT+is:fork+NOT+is:archived&type=code) با استفاده از ویت‌پرس ساخته شده‌اند.
[مستندات رسمی Vue.js](https://vuejs.org/) نیز بر پایه ویت‌پرس ساخته شده است، اما از یک تم سفارشی که بین چندین ترجمه مشترک است استفاده می‌کند.
- **وبلاگ‌ها، نمونه کارها و سایت‌های بازاریابی**
ویت‌پرس از [تم‌های کاملاً سفارشی](./custom-theme) پشتیبانی می‌کند، با تجربه توسعه مشابه یک برنامه استاندارد Vite + Vue. با ساختن بر روی Vite، این امکان وجود دارد که مستقیماً از پلاگین‌های Vite از اکوسیستم غنی آن استفاده کنید. علاوه بر این، ویت‌پرس APIهای انعطاف‌پذیری برای [بارگذاری داده](./data-loading) (محلی یا از راه دور) و [تولید پویا مسیرها](./routing#dynamic-routes) ارائه می‌دهد. شما می‌توانید تقریباً هر چیزی را بسازید به شرطی که داده‌ها در زمان ساخت تعیین شوند.
وبلاگ رسمی [Vue.js](https://blog.vuejs.org/) یک وبلاگ ساده است که صفحه فهرست خود را بر اساس محتوای محلی تولید می‌کند.
## تجربه توسعه دهنده {#developer-experience}
ویت‌پرس هدف ارائه یک تجربه عالی برای توسعه دهنده (DX) هنگام کار با محتوای Markdown را دارد.
- **[قدرت گرفته از Vite:](https://vitejs.dev/)** شروع سرور فوری، با بازتاب ویرایش‌ها به صورت آنی (<100ms) بدون بارگذاری مجدد صفحه.
- **[افزونه‌های داخلی Markdown:](./markdown)** استفاده از Frontmatter، جداول، syntax highlighting... هرچه که بخواهید. ویت‌پرس به ویژه ویژگی‌های پیشرفته زیادی برای کار با بلوک‌های کد فراهم می‌کند، که آن را برای مستندات فنی بسیار مناسب می‌کند.
- **[Markdown بهبود یافته با Vue:](./using-vue)** هر صفحه Markdown نیز یک [کامپوننت تک فایل Vue](https://vuejs.org/guide/scaling-up/sfc.html) است، به لطف سازگاری ۱۰۰٪ سینتکسی قالب Vue با HTML. شما می‌توانید از ویژگی‌های قالب‌بندی Vue یا کامپوننت‌های وارد شده Vue برای ایجاد تعامل در محتوای ایستا خود استفاده کنید.
## عملکرد {#performance}
بر خلاف بسیاری از SSGهای سنتی که هر ناوبری منجر به بارگذاری کامل صفحه می‌شود، یک وب‌سایت تولید شده توسط ویت‌پرس در بازدید اولیه HTML ایستا را سرو می‌کند، اما برای ناوبری‌های بعدی در سایت به یک [برنامه تک صفحه‌ای](https://en.wikipedia.org/wiki/Single-page_application) (SPA) تبدیل می‌شود. به نظر ما، این مدل برای عملکرد بهترین تعادل را فراهم می‌کند:
- **بارگذاری اولیه سریع**
بازدید اولیه از هر صفحه، HTML پیش‌پردازش شده ایستا را برای سرعت بارگذاری سریع و بهینه‌سازی SEO سرو می‌کند. سپس صفحه یک بسته JavaScript را بارگذاری می‌کند که صفحه را به یک SPA Vue تبدیل می‌کند ("hydration"). بر خلاف فرضیات رایج که hydration برای SPA کند است، این فرآیند در واقع بسیار سریع است به لطف عملکرد خام Vue 3 و بهینه‌سازی‌های کامپایلر. در [PageSpeed Insights](https://pagespeed.web.dev/report?url=https%3A%2F%2Fvitepress.dev%2F)، سایت‌های معمولی ویت‌پرس حتی در دستگاه‌های موبایل پایین‌رده با شبکه کند به امتیازهای عملکردی تقریباً کامل دست می‌یابند.
- **ناوبری سریع پس از بارگذاری**
مهم‌تر از آن، مدل SPA منجر به تجربه کاربری بهتر **پس از** بارگذاری اولیه می‌شود. ناوبری‌های بعدی در سایت دیگر باعث بارگذاری کامل صفحه نمی‌شوند. در عوض، محتوای صفحه ورودی بارگذاری و به صورت پویا به‌روزرسانی می‌شود. ویت‌پرس همچنین به صورت خودکار تکه‌های صفحه را برای لینک‌هایی که در viewport هستند پیش‌بارگذاری (pre-fetch) می‌کند. در بیشتر موارد، ناوبری پس از بارگذاری به صورت آنی احساس می‌شود.
- **تعامل بدون جریمه**
برای اینکه بتوانید بخش‌های پویا Vue جاسازی شده در داخل Markdown ایستا را hydrated کنید، هر صفحه Markdown به عنوان یک کامپوننت Vue پردازش و به JavaScript کامپایل می‌شود. این ممکن است غیر بهینه به نظر برسد، اما کامپایلر Vue به اندازه کافی هوشمند است که بخش‌های ایستا و پویا را جدا کند، هزینه hydration و اندازه محموله را به حداقل برساند. برای بارگذاری اولیه صفحه، بخش‌های ایستا به صورت خودکار از محموله JavaScript حذف می‌شوند و در حین hydration نادیده گرفته می‌شوند.
## درباره VuePress چه؟ {#what-about-vuepress}
ویت‌پرس جانشین معنوی VuePress است. VuePress اصلی بر پایه Vue 2 و webpack بود. با Vue 3 و Vite در هسته، ویت‌پرس تجربه توسعه بهتر، عملکرد تولید بهتر، تم پیش‌فرض کامل‌تر و API سفارشی‌سازی انعطاف‌پذیرتری ارائه می‌دهد.
تفاوت API بین ویت‌پرس و VuePress عمدتاً در زمینه تم‌سازی و سفارشی‌سازی است. اگر از VuePress 1 با تم پیش‌فرض استفاده می‌کنید، باید مهاجرت به ویت‌پرس نسبتاً ساده باشد.
همچنین تلاش‌هایی برای VuePress 2 انجام شده است، که از Vue 3 و Vite با سازگاری بیشتر با VuePress 1 پشتیبانی می‌کند. با این حال، نگهداری دو SSG به صورت موازی پایدار نیست، بنابراین تیم Vue تصمیم گرفته است که در دراز مدت بر روی ویت‌پرس به عنوان SSG اصلی توصیه شده تمرکز کند.

@ -0,0 +1,35 @@
---
layout: home
hero:
name: ویت‌پرس
text: سازنده سایت‌های ایستا به کمک Vite و Vue
tagline: تبدیل Markdown به مستندات زیبا در چند دقیقه
actions:
- theme: brand
text: ویت‌پرس چیست؟
link: fa/guide/what-is-vitepress
- theme: alt
text: شروع سریع
link: fa/guide/getting-started
- theme: alt
text: گیت‌هاب
link: https://github.com/vuejs/vitepress
image:
src: /vitepress-logo-large.svg
alt: ویت‌پرس
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: استفاده مستقیم از syntax و کامپوننت‌های Vue در Markdown، یا ایجاد تم‌های شخصی به کمک Vue
- icon: 🚀
title: ارسال سایت های سریع
details: بارگذاری اولیه سریع با HTML ایستا، ناوبری سریع پس از بارگیری با مسیریابی سمت کلاینت
---

@ -0,0 +1,73 @@
# رابط خط فرمان {#command-line-interface}
## `vitepress dev` {#vitepress-dev}
شروع سرور توسعه ویت‌پرس با استفاده از دایرکتوری مشخص به عنوان ریشه. به طور پیش‌فرض از دایرکتوری فعلی استفاده می‌شود. دستور `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-build}
ساخت سایت ویت‌پرس برای تولید نهایی.
### استفاده {#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>` | آستانه تبدیل پایه ۶۴ استاتیک به بایت (پیش‌فرض: `4096`) (`number`) |
## `vitepress preview` {#vitepress-preview}
پیش‌نمایش محلی برای ساخت تولیدی را نمایش دهید.
### استفاده {#usage-2}
```sh
vitepress preview [root]
```
### گزینه‌ها {#options-2}
| گزینه | توضیحات |
| --------------- | ---------------------------------------- |
| `--base <path>` | مسیر پایه عمومی (پیش‌فرض: `/`) (`string`) |
| `--port <port>` | تعیین پورت (`number`) |
## `vitepress init` {#vitepress-init}
شروع [جادوگر راه‌اندازی](../guide/getting-started#setup-wizard) در دایرکتوری فعلی.
### استفاده {#usage-3}
```sh
vitepress init
```

@ -0,0 +1,72 @@
# نشان {#badge}
برچسب به شما امکان می‌دهد وضعیت‌های مختلفی را به سربرگ‌های خود اضافه کنید. به عنوان مثال، می‌تواند مفید باشد تا نوع بخش را مشخص کنید یا نسخه‌های پشتیبانی شده را نشان دهید.
## استفاده {#usage}
شما می‌توانید از کامپوننت `Badge` که به صورت جهانی در دسترس است، استفاده کنید.
```html
### عنوان <Badge type="info" text="پیش‌فرض" />
### عنوان <Badge type="tip" text="^1.9.0" />
### عنوان <Badge type="warning" text="بتا" />
### عنوان <Badge type="danger" text="هشدار" />
```
کد بالا به صورت زیر نمایش داده می‌شود:
### عنوان <Badge type="info" text="پیش‌فرض" /> {#title}
### عنوان <Badge type="tip" text="^1.9.0" /> {#title-1}
### عنوان <Badge type="warning" text="بتا" /> {#title-2}
### عنوان <Badge type="danger" text="هشدار" /> {#title-3}
## ارائه دادن محتوای دلخواه {#custom-children}
`<Badge>` می‌پذیرد `children` که در برچسب نمایش داده خواهد شد.
```html
### عنوان <Badge type="info">عنصر سفارشی</Badge>
```
### عنوان <Badge type="info">عنصر سفارشی</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-1}
کامپوننت `<Badge>` پراپ‌های زیر را می‌پذیرد:
```ts
interface Props {
// وقتی `<slot>` ارسال می‌شود، این مقدار نادیده گرفته می‌شود.
text?: string
// پیش‌فرض به `tip`.
type?: 'info' | 'tip' | 'warning' | 'danger'
}
```

@ -0,0 +1,22 @@
# تبلیغات Carbon {#carbon-ads}
ویت‌پرس پشتیبانی داخلی برای [Carbon Ads](https://www.carbonads.net/) را دارد. با تعریف مشخصات تبلیغات Carbon در تنظیمات، ویت‌پرس تبلیغات را در صفحه نمایش می‌دهد.
```js
export default {
themeConfig: {
carbonAds: {
code: 'your-carbon-code',
placement: 'your-carbon-placement'
}
}
}
```
این مقادیر برای فراخوانی اسکریپت CDN Carbon به شکل زیر استفاده می‌شوند.
```js
`//cdn.carbonads.com/carbon.js?serve=${code}&placement=${placement}`
```
برای یادگیری بیشتر درباره پیکربندی تبلیغات Carbon، لطفاً به [وب‌سایت Carbon Ads](https://www.carbonads.net/) مراجعه کنید.

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

Loading…
Cancel
Save