Merge branch 'main' into patch-3

pull/2913/head
Gavin John 2 months ago committed by GitHub
commit c0831fd709
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -37,7 +37,7 @@ body:
attributes:
label: System Info
description: Output of `npx envinfo --system --npmPackages vitepress --binaries --browsers`
render: sh
render: Text
placeholder: System, Binaries, Browsers
validations:
required: true

@ -17,8 +17,9 @@ jobs:
if: github.repository == 'vuejs/vitepress'
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v4
- uses: dessant/lock-threads@v5
with:
issue-inactive-days: 7
pr-inactive-days: 7
exclude-any-issue-labels: 'keep-open'
exclude-any-pr-labels: 'keep-open'

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

@ -0,0 +1,15 @@
name: Close stale issues and PRs
on:
workflow_dispatch:
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v9
with:
days-before-stale: 30
days-before-close: -1
stale-issue-label: stale
stale-pr-label: stale
operations-per-run: 1000

@ -23,17 +23,17 @@ jobs:
strategy:
matrix:
node_version: [18, 20]
node_version: [18, 20, 21]
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v2
uses: pnpm/action-setup@v3
- name: Set node version to ${{ matrix.node_version }}
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node_version }}
cache: pnpm

1
.gitignore vendored

@ -15,3 +15,4 @@ examples-temp
node_modules
pnpm-global
TODOs.md
*.timestamp-*.mjs

@ -1,2 +1,2 @@
shell-emulator=true
resolution-mode=highest
auto-install-peers=false

@ -1,3 +1,414 @@
## [1.1.3](https://github.com/vuejs/vitepress/compare/v1.1.1...v1.1.3) (2024-04-18)
### Bug Fixes
- **build/regression:** markdown backslash escapes not working ([d02d1e9](https://github.com/vuejs/vitepress/commit/d02d1e923aacdb1e8061a3f76af30e8a13518277)), closes [#3808](https://github.com/vuejs/vitepress/issues/3808)
## [1.1.1](https://github.com/vuejs/vitepress/compare/v1.1.0...v1.1.1) (2024-04-18)
### Bug Fixes
- **client:** don't reload page on hash change ([#3777](https://github.com/vuejs/vitepress/issues/3777)) ([74b725a](https://github.com/vuejs/vitepress/commit/74b725a224438ef776fed25ee82274429d94ac83))
- let vue compiler handle entity decoding ([f86ac56](https://github.com/vuejs/vitepress/commit/f86ac56b78da76f3061e6537b897bb13c1ed802d))
- hot updating config file suppresses error logs ([#3592](https://github.com/vuejs/vitepress/issues/3592)) ([cd5adf3](https://github.com/vuejs/vitepress/commit/cd5adf3011d677263c93ce6f8066aaa7870b1dfc))
# [1.1.0](https://github.com/vuejs/vitepress/compare/v1.0.2...v1.1.0) (2024-04-09)
### Bug Fixes
- **client:** hashchange should only be triggered for same page navigations ([#3768](https://github.com/vuejs/vitepress/issues/3768)) ([2a9fc2a](https://github.com/vuejs/vitepress/commit/2a9fc2a26b829bb3f28067ac6f4a41bc1e8b7a1e))
- **client:** emit correct `Event` instance in hashchange event
- **theme:** remove small layout shift on `On this page` button ([#3767](https://github.com/vuejs/vitepress/issues/3767)) ([5f28e74](https://github.com/vuejs/vitepress/commit/5f28e74abfc984cdc7e0d9d9f7b7e15cb2b46923))
### Features
- **client:** add `hash` property to `useData()`
- **theme:** update Inter to version 4 ([#3693](https://github.com/vuejs/vitepress/issues/3693)) ([#3694](https://github.com/vuejs/vitepress/issues/3694)) ([ffafa31](https://github.com/vuejs/vitepress/commit/ffafa31b9204f996f4b819684214fa631c224575))
## [1.0.2](https://github.com/vuejs/vitepress/compare/v1.0.1...v1.0.2) (2024-04-01)
### Bug Fixes
- **theme:** text containing html not showing properly in mobile nav menu ([3c8b4c7](https://github.com/vuejs/vitepress/commit/3c8b4c706051592dd2cca0ae57e293254cbb51ce))
## [1.0.1](https://github.com/vuejs/vitepress/compare/v1.0.0...v1.0.1) (2024-03-22)
### Bug Fixes
- **build:** vendor vue-demi to avoid resolution issues with yarn berry ([#3680](https://github.com/vuejs/vitepress/issues/3680)) ([5d3cb96](https://github.com/vuejs/vitepress/commit/5d3cb96ac364413aa9eb494bc91744bd8f4a2c79))
# [1.0.0](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.45...v1.0.0) (2024-03-21)
### Bug Fixes
- **build:** resolve pattern relative to srcDir instead of root in createContentLoader ([#3638](https://github.com/vuejs/vitepress/issues/3638)) ([59183e9](https://github.com/vuejs/vitepress/commit/59183e9cef112a004c8a8e2b365478af657858b0))
- **localSearch:** remove empty titles that may appear in search results ([#3665](https://github.com/vuejs/vitepress/issues/3665)) ([f7aef3c](https://github.com/vuejs/vitepress/commit/f7aef3ca23dae39e226c85d7bb2579dbf7c758f3))
- **theme:** fixed sidebar expand caret showing when no children are present ([#3657](https://github.com/vuejs/vitepress/issues/3657)) ([e13f932](https://github.com/vuejs/vitepress/commit/e13f93292ce1a2b1d5ba161fddfe947a1824a2b0))
- **theme:** ignore inner-page items in next/prev link ([#3663](https://github.com/vuejs/vitepress/issues/3663)) ([b50a8a1](https://github.com/vuejs/vitepress/commit/b50a8a132577693817a15ab43fc4cc22670a8a65))
- **theme:** local nav separator not visible on pages having no outline ([1909041](https://github.com/vuejs/vitepress/commit/190904171500ad22998c8666080fd58c867a59b5))
### Features
- **theme:** allow selectively disabling external link icon on navbar items ([#3607](https://github.com/vuejs/vitepress/issues/3607)) ([5f6297c](https://github.com/vuejs/vitepress/commit/5f6297cb3df98926154235f31570e75820d4ea16))
# [1.0.0-rc.45](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.44...v1.0.0-rc.45) (2024-03-06)
### Bug Fixes
- **router:** hashchange not emitted in certain cases ([#3637](https://github.com/vuejs/vitepress/issues/3637)) ([f6bd99e...6c0125b](https://github.com/vuejs/vitepress/compare/f6bd99eb1311238e1114301a767634b139327916...6c0125b65513531870f00ebef1ae11096027875a))
### Features
- set `__VITEPRESS__` for easy detection by plugins and other tools ([#3634](https://github.com/vuejs/vitepress/issues/3634)) ([f6bd99e](https://github.com/vuejs/vitepress/commit/f6bd99eb1311238e1114301a767634b139327916))
# [1.0.0-rc.44](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.43...v1.0.0-rc.44) (2024-2-19)
### Reverts
- types for internal components ([e703429](https://github.com/vuejs/vitepress/commit/e7034294731493a198cdd4789198f1c94f21b181))
# [1.0.0-rc.43](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.42...v1.0.0-rc.43) (2024-2-17)
### Bug Fixes
- handle process.env being undefined while process is not ([b63e0a0](https://github.com/vuejs/vitepress/commit/b63e0a0c57f886f49aa7e073ff623c918164bd0b)), closes [#3579](https://github.com/vuejs/vitepress/issues/3579)
- make local search work in combination with vue-i18n ([#3559](https://github.com/vuejs/vitepress/issues/3559)) ([6624bb7](https://github.com/vuejs/vitepress/commit/6624bb748610079b88e2dcef7ea1810833a54a85))
- **theme:** adjust mathjax svg styles ([#3567](https://github.com/vuejs/vitepress/issues/3567)) ([2051100](https://github.com/vuejs/vitepress/commit/20511006dba516ca8c06ed1dd3516547af668a0e))
### Features
- **theme:** auto style markdown content in home page ([#3561](https://github.com/vuejs/vitepress/issues/3561)) ([0903027](https://github.com/vuejs/vitepress/commit/09030272b4a5c8f723b7e11303265f24b7481575))
### Performance Improvements
- **theme:** move svg icons to css ([#3537](https://github.com/vuejs/vitepress/issues/3537)) ([636cca0](https://github.com/vuejs/vitepress/commit/636cca042dfbca006af2d702ddec0a2ff601cb46))
### BREAKING CHANGES
- The default theme now styles the markdown content in the home page. If you have custom styles that rely on the markdown content not being styled, you may need to adjust your styles, or add `markdownStyles: false` to the frontmatter of your home page.
# [1.0.0-rc.42](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.41...v1.0.0-rc.42) (2024-2-6)
### Bug Fixes
- **md:** dont break on nesting blockquotes inside gfm alerts ([8f8a6fe](https://github.com/vuejs/vitepress/commit/8f8a6feb053b3f521a2c90e343dffa7f98bb63b3)), closes [#3512](https://github.com/vuejs/vitepress/issues/3512)
- **theme:** correctly normalize paths ending with "index" ([#3544](https://github.com/vuejs/vitepress/issues/3544)) ([c582a8d](https://github.com/vuejs/vitepress/commit/c582a8d5fd82b84d412c7e6c84e74faeb23beac6))
# [1.0.0-rc.41](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.40...v1.0.0-rc.41) (2024-2-1)
### Bug Fixes
- handle CRLF in snippet plugin ([5811b62](https://github.com/vuejs/vitepress/commit/5811b626576ec4569fa0079d921b8e328d87ca91)), closes [#3499](https://github.com/vuejs/vitepress/issues/3499)
- lazy evaluate known extensions to allow env set in config ([04f794b](https://github.com/vuejs/vitepress/commit/04f794bf55f8191ea9eed62f545b812f346017d8))
### Features
- **home:** add target and rel attribute to home actions ([#3528](https://github.com/vuejs/vitepress/issues/3528)) ([ab39fd8](https://github.com/vuejs/vitepress/commit/ab39fd8592c994fbc6feba5ee369ca1205c50f04))
- rename shiki packages ([#3506](https://github.com/vuejs/vitepress/issues/3506)) ([b8487d3](https://github.com/vuejs/vitepress/commit/b8487d3a97679f5b2eb225ee1eb85754b66fee30))
- wrap site title in span ([#3522](https://github.com/vuejs/vitepress/issues/3522)) ([6b1f951](https://github.com/vuejs/vitepress/commit/6b1f951928a3b9e53dcc9697327b5aba4a5905e2))
- **theme:** add hero slots that are inside container ([#3524](https://github.com/vuejs/vitepres/issues/3524)) ([28870e6](https://github.com/vuejs/vitepress/commit/28870e68faf0ddaa418ffe0d4371316f6b0bcd02))
### BREAKING CHANGES
- vitepress now uses shiki instead of shikiji. If youre on the latest version and using shikiji specific features, you just need to change imports. The shikijiSetup hook is renamed to shikiSetup.
# [1.0.0-rc.40](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.39...v1.0.0-rc.40) (2024-1-22)
### Bug Fixes
- **client:** handle head orphans added in initial load ([#3474](https://github.com/vuejs/vitepress/issues/3474)) ([5e2d853](https://github.com/vuejs/vitepress/commit/5e2d853e1a315216dce5fc98ee2efd15c724a25d))
- **theme:** avoid selecting summary on toggling details ([77a318c](https://github.com/vuejs/vitepress/commit/77a318c2a348d341dd3ea1e1650fcf8ad3abfcd7))
- **theme:** hover color for code links inside custom containers ([#3467](https://github.com/vuejs/vitepress/issues/3467)) ([d529ed4](https://github.com/vuejs/vitepress/commit/d529ed49756841f055024c559d09875501bc6d76))
- **type:** fix missed `VPBadge` type in `theme.d.ts` ([#3470](https://github.com/vuejs/vitepress/issues/3470)) ([fcf828c](https://github.com/vuejs/vitepress/commit/fcf828c2a71892dad5af8d21e405f4d1e2cc280c))
### Features
- support GitHub-flavored alerts ([#3482](https://github.com/vuejs/vitepress/issues/3482)) ([ac87d19](https://github.com/vuejs/vitepress/commit/ac87d19ca1bbc966e5fe1cca5f433f5ea4b11be3))
- support specifying custom extensions to escape routing ([#3466](https://github.com/vuejs/vitepress/issues/3466)) ([c22f5d9](https://github.com/vuejs/vitepress/commit/c22f5d983f3e5d5c4f0ed0683a93ece564487c13))
- **theme:** add npm icon ([#3483](https://github.com/vuejs/vitepress/issues/3483)) ([c882fa1](https://github.com/vuejs/vitepress/commit/c882fa1469a7bd0d6e28196e7a841adf48e803f1))
# [1.0.0-rc.39](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.38...v1.0.0-rc.39) (2024-01-16)
### Bug Fixes
- **theme:** misaligned outline indicator ([#3458](https://github.com/vuejs/vitepress/issues/3458)) ([0ce5ece](https://github.com/vuejs/vitepress/commit/0ce5ece35687bdad7a65d61432419cfe3961a329))
- **theme:** enter key behavior conflict with IME in search box ([#3454](https://github.com/vuejs/vitepress/issues/3454)) ([cd8ee6f](https://github.com/vuejs/vitepress/commit/cd8ee6fb32d8135e78c5827a36b79efad509042c))
- **theme:** use`--vp-c-tip-` CSS variable for badge/block colors with type`tip` ([#3434](https://github.com/vuejs/vitepress/issues/3434)) ([78abf47](https://github.com/vuejs/vitepress/commit/78abf47b8b563d66db9d481a98bbdefac95cc84c))
### Features
- **theme:** export VPBadge ([#3431](https://github.com/vuejs/vitepress/issues/3431)) ([18981c1](https://github.com/vuejs/vitepress/commit/18981c1d1c74a4f4ca379a88b00c02ba5eace6db))
# [1.0.0-rc.36](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.35...v1.0.0-rc.36) (2024-1-8)
### Bug Fixes
- avoid pushing to history when clicking on the current link ([#3405](https://github.com/vuejs/vitepress/issues/3405)) ([d279e63](https://github.com/vuejs/vitepress/commit/d279e63cb4d417420cdc3fb3e6e03c96b777289f))
- **theme/regression:** external link icon not working ([c236570](https://github.com/vuejs/vitepress/commit/c236570f2806fe76bbc6a69568cf64ed5a3fc2ce)), closes [#3424](https://github.com/vuejs/vitepress/issues/3424)
- **theme/regression:** inter getting bundled even importing without-fonts entry ([#3412](https://github.com/vuejs/vitepress/issues/3412)) ([b03fb83](https://github.com/vuejs/vitepress/commit/b03fb83a4e67d92a865d90908ccbde3dd0f97373))
# [1.0.0-rc.35](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.34...v1.0.0-rc.35) (2024-1-3)
### Bug Fixes
- **client:** add computed dir and lang to html root ([c2b4c66](https://github.com/vuejs/vitepress/commit/c2b4c66e79fde7479f5f43841e1921a5c220c9a5)), closes [#3353](https://github.com//github.com/vuejs/vitepress/pull/3353/issues/issuecomment-1874753809)
- fill all empty code lines ([563020b](https://github.com/vuejs/vitepress/commit/563020ba61abda254af9a124ddafd12de644cd4e)), closes [#3305](https://github.com/vuejs/vitepress/issues/3305)
- fix theme chunking logic causing out-of-order styles ([#3403](https://github.com/vuejs/vitepress/issues/3403)) ([a6cd891](https://github.com/vuejs/vitepress/commit/a6cd891d95454b3130aaf08f499659d2585acc63))
- invalidate module cache for subsequent builds ([#3398](https://github.com/vuejs/vitepress/issues/3398)) ([27f60e0](https://github.com/vuejs/vitepress/commit/27f60e0b7784603c6fb300bd8dce64515eb98962))
### Features
- allow passing options to emoji plugin ([09e48db](https://github.com/vuejs/vitepress/commit/09e48db355f530c7a138437004659b61239f4b75)), closes [#3174](https://github.com/vuejs/vitepress/issues/3174)
- **theme:** allow specifying rel and target in logoLink ([6c89943](https://github.com/vuejs/vitepress/commit/6c899437c15b126b488e73c99cdaad77fc7e5611)), closes [#3264](https://github.com/vuejs/vitepress/issues/3264) [#3271](https://github.com/vuejs/vitepress/issues/3271)
### Performance Improvements
- **localSearch:** add concurrency pooling, cleanup logic, improve performance ([#3374](https://github.com/vuejs/vitepress/issues/3374)) ([ac5881e](https://github.com/vuejs/vitepress/commit/ac5881eeac3f042a8fbf034edb99e5f2b45eaa2a))
# [1.0.0-rc.34](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.33...v1.0.0-rc.34) (2023-12-30)
### Bug Fixes
- **build:** clear cache after build ([9568fea](https://github.com/vuejs/vitepress/commit/9568fea8fc50e625c8ef27c588eca3dbe5a44e81)), closes [#3363](https://github.com/vuejs/vitepress/issues/3363)
- **default-theme:** remove use of reactify for search i18n ([8687b86](https://github.com/vuejs/vitepress/commit/8687b86e1e00ae39ff9c8173aef04eb8a9cda0a8))
- print errors when importing an invalid dynamic route ([#3201](https://github.com/vuejs/vitepress/issues/3201)) ([6d89a08](https://github.com/vuejs/vitepress/commit/6d89a08cb76674f4d92f54218f8af5624bcf4c47))
- remove double title from home pages ([9f1f04e](https://github.com/vuejs/vitepress/commit/9f1f04e00a9722ec7369941c40d3d8ad86f61d35)), closes [#3375](https://github.com/vuejs/vitepress/issues/3375)
- **theme/i18n:** support customizing dark mode switch titles ([#3311](https://github.com/vuejs/vitepress/issues/3311)) ([50c9758](https://github.com/vuejs/vitepress/commit/50c9758d3fa1b60aad5399a0db890644ac44a522))
### Features
- support custom image lazy loading ([#3346](https://github.com/vuejs/vitepress/issues/3346)) ([55be3f1](https://github.com/vuejs/vitepress/commit/55be3f14d79eb578c9aa2e3bc7a90205c910005d))
- support dir in frontmatter ([#3353](https://github.com/vuejs/vitepress/issues/3353)) ([203446d](https://github.com/vuejs/vitepress/commit/203446d69193483a46e1082bba5fbad0e35966fb))
- **theme/i18n:** allow customizing sponsor link's text ([#3276](https://github.com/vuejs/vitepress/issues/3276)) ([9c20e3b](https://github.com/vuejs/vitepress/commit/9c20e3b5f80e4197c14c20fa751ec3c8c8219e8e))
- **theme:** allow using VPBadge classes in sidebar ([#3391](https://github.com/vuejs/vitepress/issues/3391)) ([50a774e](https://github.com/vuejs/vitepress/commit/50a774ea7c70bb200e12c176d6691ab7144a73f9))
- **theme:** new design for local nav and global header ([#3359](https://github.com/vuejs/vitepress/issues/3359)) ([d10bf42](https://github.com/vuejs/vitepress/commit/d10bf42c2632f1aacb905bc01b36274e9004cbd9))
# [1.0.0-rc.33](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.32...v1.0.0-rc.33) (2023-12-26)
### Features
- allow explicitly mark code element as `.vp-copy-ignore` ([#3360](https://github.com/vuejs/vitepress/issues/3360)) ([93122ee](https://github.com/vuejs/vitepress/commit/93122eee20cb6586026c1ffac04d9787861cc2f3))
- **build:** enable VUE_PROD_HYDRATION_MISMATCH_DETAILS when DEBUG is truthy ([f4d4280](https://github.com/vuejs/vitepress/commit/f4d4280d7d1728a966bb04968a9bac10470c3d06)), closes [#422](https://github.com/vuejs/vitepress/issues/422)
### Performance Improvements
- implement concurrent promise pooling for render task ([#3366](https://github.com/vuejs/vitepress/issues/3366))
# [1.0.0-rc.32](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.31...v1.0.0-rc.32) (2023-12-16)
### Features
- allow ignoring node in header ([#3331](https://github.com/vuejs/vitepress/issues/3331)) ([e4bf1e4](https://github.com/vuejs/vitepress/commit/e4bf1e48e6a1592d583b218425c1fa7497955dc5))
- expose `shikijiSetup` hook ([#3344](https://github.com/vuejs/vitepress/issues/3344)) ([d12e23d](https://github.com/vuejs/vitepress/commit/d12e23ddf69480418078ff39846c99ecf2e1eb1b))
- update shikiji, support twoslash ([#3339](https://github.com/vuejs/vitepress/issues/3339)) ([8800195](https://github.com/vuejs/vitepress/commit/880019545795fd075be89d94794bfbd05af461b5))
# [1.0.0-rc.31](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.30...v1.0.0-rc.31) (2023-11-25)
### Bug Fixes
- **build:** make assets go through vite pipeline during dev too ([#3258](https://github.com/vuejs/vitepress/issues/3258)) ([c3d7f22](https://github.com/vuejs/vitepress/commit/c3d7f22bd313b09e6965ac3125ea662ce283ed2d))
- **theme:** use VPLink for links in VPDocFooter ([#3248](https://github.com/vuejs/vitepress/issues/3248)) ([479a320](https://github.com/vuejs/vitepress/commit/479a320731313b8e7e0bad3f8383ae6bc05ed8e2))
# [1.0.0-rc.30](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.29...v1.0.0-rc.30) (2023-11-23)
### Bug Fixes
- **client:** no onAfterRouteChanged called after popstate ([#3227](https://github.com/vuejs/vitepress/issues/3227)) ([60fc8fd](https://github.com/vuejs/vitepress/commit/60fc8fd24460eede1dc73768ad0aa53616da746f)), closes [#3226](https://github.com/vuejs/vitepress/issues/3226)
- **theme:** remove double padding from sidebar ([ef6d8d1](https://github.com/vuejs/vitepress/commit/ef6d8d1e4295c6ff967c17b5b9c20c04843da5a0)), closes [#3228](https://github.com/vuejs/vitepress/issues/3228)
### Features
- migrate to shikiji ([#3237](https://github.com/vuejs/vitepress/pull/3237)) ([75f18e4](https://github.com/vuejs/vitepress/commit/75f18e47334933b642d14b8b69b372cb1ebd4244))
### BREAKING CHANGES
- VitePress now uses shikiji instead of shiki for syntax highlighting. If you're using features like adding extra languages or custom aliases, please refer [shikiji docs](https://github.com/antfu/shikiji) for migration guide or comment on [#3237](https://github.com/vuejs/vitepress/pull/3237) if you need help.
# [1.0.0-rc.29](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.28...v1.0.0-rc.29) (2023-11-19)
### Bug Fixes
- **client:** regression - router not working without .html present ([d63cb86](https://github.com/vuejs/vitepress/commit/d63cb867b14ba49c8333ad0d69d33874e2ece6c6)), closes [#3225](https://github.com/vuejs/vitepress/issues/3225)
# [1.0.0-rc.28](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.27...v1.0.0-rc.28) (2023-11-18)
### Bug Fixes
- **ally:** clear up confusion with the title of theme switch ([#3215](https://github.com/vuejs/vitepress/issues/3215)) ([6761036](https://github.com/vuejs/vitepress/commit/67610363bcb354d33327e6b5c3c2d916ed025ffc))
- **build:** support nested assetsDir ([02161d0](https://github.com/vuejs/vitepress/commit/02161d0f797cfa36d715119e8c7618770b1a6761))
- wrong recognition of non-html extension leads to route error ([#3218](https://github.com/vuejs/vitepress/issues/3218)) ([c4abc95](https://github.com/vuejs/vitepress/commit/c4abc950af7061611e3b5eff93e767706bd12396))
### Features
- **build:** html head meta generator ([#3219](https://github.com/vuejs/vitepress/issues/3219)) ([672e494](https://github.com/vuejs/vitepress/commit/672e4946ac3c24f3fc79469534e66cfaf6f23e67))
- **client:** allow disabling link auto-prefetching ([#3220](https://github.com/vuejs/vitepress/issues/3220)) ([563dc89](https://github.com/vuejs/vitepress/commit/563dc899757e58d2261bcb31081283eb395fab0b))
# [1.0.0-rc.27](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.26...v1.0.0-rc.27) (2023-11-17)
### Bug Fixes
- CSS missing after build ([#3217](https://github.com/vuejs/vitepress/issues/3217)) ([da73b58](https://github.com/vuejs/vitepress/commit/da73b58c795a65a09d028e0ca6acefa1170d3d5b)), closes [#3216](https://github.com/vuejs/vitepress/issues/3216)
# [1.0.0-rc.26](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.25...v1.0.0-rc.26) (2023-11-16)
### Bug Fixes
- "VPNavScreenMenuGroup" component HTML not supported ([#3148](https://github.com/vuejs/vitepress/issues/3148)) ([237ad85](https://github.com/vuejs/vitepress/commit/237ad859a982f3fa55f7bba0f98ca94707108618))
- **build:** remove frontmatter in md file inclusion ([dbbffa2](https://github.com/vuejs/vitepress/commit/dbbffa2487cd1f9899916baa166591248fb24334)), closes [#3195](https://github.com/vuejs/vitepress/issues/3195)
- style links in footer ([#3178](https://github.com/vuejs/vitepress/issues/3178)) ([a482611](https://github.com/vuejs/vitepress/commit/a482611d17197a0b7afc403891cd95f344e7a55f))
### Features
- switch to vite 5 and bump deps ([#3200](https://github.com/vuejs/vitepress/issues/3200)) ([d2238ee](https://github.com/vuejs/vitepress/commit/d2238eedb7c0c81b2d9f425e6f70f7019ad6a482))
### BREAKING CHANGES
- VitePress now runs on Vite 5. Please refer https://vitejs.dev/guide/migration for breaking changes and migration guide if you're relying on some Vite-specific things.
# [1.0.0-rc.25](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.24...v1.0.0-rc.25) (2023-11-05)
### Bug Fixes
- double-slash format url should be external link ([#3165](https://github.com/vuejs/vitepress/issues/3165)) ([7dbeac6](https://github.com/vuejs/vitepress/commit/7dbeac6df0dfc0da74dffc79998a85a3afa86874))
- missing export types in localSearch ([#3157](https://github.com/vuejs/vitepress/issues/3157)) ([0761062](https://github.com/vuejs/vitepress/commit/0761062790b441eccd0d57d51903271f30e713af))
- **theme:** table row background-color in custom containers ([#3179](https://github.com/vuejs/vitepress/issues/3179)) ([beecec1](https://github.com/vuejs/vitepress/commit/beecec16a8d62c18f46522d461db353c97199415))
- **theme:** theme switch is not hidden on force-dark ([#3155](https://github.com/vuejs/vitepress/issues/3155)) ([2276c1d](https://github.com/vuejs/vitepress/commit/2276c1d4dac547bb09015fcd0df73825b32c5fad))
### Features
- export `mergeConfig()` ([#3143](https://github.com/vuejs/vitepress/issues/3143)) ([a850786](https://github.com/vuejs/vitepress/commit/a850786a566606fda20cc4ed71b79e975307b52a))
### Performance Improvements
- reduce duplicate rendering in localSearch ([#3170](https://github.com/vuejs/vitepress/issues/3170)) ([878f437](https://github.com/vuejs/vitepress/commit/878f4378cdee3c41f7643d9c7693bb607344d0c2))
# [1.0.0-rc.24](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.23...v1.0.0-rc.24) (2023-10-24)
### Bug Fixes
- lock plugin-vue version ([aa75fd6](https://github.com/vuejs/vitepress/commit/aa75fd62643d51be647f6e5937c97b7c47bf9739))
- **styles:** large blur radius is causing color issues with safari ([a31e143](https://github.com/vuejs/vitepress/commit/a31e143afac597034a8d77f516961b0d2857ac8d))
### Features
- **template:** add types for theme config ([#3122](https://github.com/vuejs/vitepress/issues/3122)) ([56b3ce5](https://github.com/vuejs/vitepress/commit/56b3ce5032b1d3bcfd66a1a397d87172a6f113d7))
# [1.0.0-rc.23](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.22...v1.0.0-rc.23) (2023-10-22)
### Bug Fixes
- don't normalize non-html/non-http links ([#3114](https://github.com/vuejs/vitepress/issues/3114)) ([da3d781](https://github.com/vuejs/vitepress/commit/da3d7812a143e3aa360845b89f573d4e1ec637dd))
- **mpa:** properly emit assets in mpa mode ([#3115](https://github.com/vuejs/vitepress/issues/3115)) ([6cf1de5](https://github.com/vuejs/vitepress/commit/6cf1de5e9e15d4507054744b665ac15d5f9a05f1))
- **theme/search:** prevent reactivity loss with i18n ([#3121](https://github.com/vuejs/vitepress/issues/3121)) ([50d61fa](https://github.com/vuejs/vitepress/commit/50d61faefacc3885efe99fe5477a3b815354a0c4))
# [1.0.0-rc.22](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.21...v1.0.0-rc.22) (2023-10-15)
### Bug Fixes
- fixes a regression related with nanoid v5 ([#3090](https://github.com/vuejs/vitepress/issues/3090))
# [1.0.0-rc.21](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.20...v1.0.0-rc.21) (2023-10-12)
### Bug Fixes
- **build:** handle .mjs/.mts files as data / path loaders ([#3058](https://github.com/vuejs/vitepress/issues/3058)) ([7991180](https://github.com/vuejs/vitepress/commit/7991180080366f9eb0d43fe95d25b53cf7af652c))
- **client:** only update head if needed ([#3017](https://github.com/vuejs/vitepress/issues/3017)) ([f2fc3dc](https://github.com/vuejs/vitepress/commit/f2fc3dc51b8019c18d5ab70a6b55b8333c91045a))
- **theme:** search's configuration about buttonAriaLabel doesn't work ([#3070](https://github.com/vuejs/vitepress/issues/3070)) ([c08bd46](https://github.com/vuejs/vitepress/commit/c08bd46aa757e7a0bc28b2318fb38037d583b27d))
### Features
- **md:** allow customizing container titles globally ([#3044](https://github.com/vuejs/vitepress/issues/3044)) ([bdb0800](https://github.com/vuejs/vitepress/commit/bdb080093f95ec43d013ea2ad537e567bdbb5a44))
# [1.0.0-rc.20](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.15...v1.0.0-rc.20) (2023-09-24)
### Bug Fixes
- **build:** consistent route.path across dev and ssr ([#2997](https://github.com/vuejs/vitepress/issues/2997)) ([0d56855](https://github.com/vuejs/vitepress/commit/0d56855b54a97d4350485ee76c07a040fdc5738c))
- **build:** don't show missing lang warnings with text specifiers in fences ([aa40cec](https://github.com/vuejs/vitepress/commit/aa40cecd48942506ffb063863c9b054e66f1d79e))
- handle references in container titles ([7fbfe71](https://github.com/vuejs/vitepress/commit/7fbfe71b6cab2f091ba3d0c47a401fdc612b88b6)), closes [#3004](https://github.com/vuejs/vitepress/issues/3004)
- **hmr:** handle hmr in imported code snippets ([#3005](https://github.com/vuejs/vitepress/issues/3005)) ([e84f313](https://github.com/vuejs/vitepress/commit/e84f31371e9e5219d46ae58151667d24e12b77bb))
- snippet hmr not working with rewrites ([a275049](https://github.com/vuejs/vitepress/commit/a2750492be7869ed48a5bde1ffbc177093356758))
- selectively pass env for container titles ([1a9c32d](https://github.com/vuejs/vitepress/commit/1a9c32df12388386877c50daf9fc7924888eac07)), closes [#3007](https://github.com/vuejs/vitepress/issues/3007)
- **types:** add RegExp to markdown's allowed attributes ([#3008](https://github.com/vuejs/vitepress/issues/3008)) ([bc96b2b](https://github.com/vuejs/vitepress/commit/bc96b2bb5bc5361e55c46f270e3759c513db65d3))
# [1.0.0-rc.15](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.14...v1.0.0-rc.15) (2023-09-20)
### Bug Fixes
- **build:** allow using symlinks with code snippets ([f186901](https://github.com/vuejs/vitepress/commit/f186901a5157c904b3593089d72f2bad3530e7a3)), closes [#1617](https://github.com/vuejs/vitepress/issues/1617)
- **build:** handle importing code snippets not having an extension ([#2978](https://github.com/vuejs/vitepress/issues/2978)) ([e99aaad](https://github.com/vuejs/vitepress/commit/e99aaad9cf8ab3661e609cd2cf6ac7da57cb7eb5))
- **build:** indentation being lost in code blocks ([5bb6bb0](https://github.com/vuejs/vitepress/commit/5bb6bb0a147ad43ca2d7069aad50fb9c6c2c11d6)), closes [#2988](https://github.com/vuejs/vitepress/issues/2988)
- **compat:** reset setRawMode on process exit ([#2994](https://github.com/vuejs/vitepress/issues/2994)) ([70fe47c](https://github.com/vuejs/vitepress/commit/70fe47c1dd69d39a40c83e919324d2b71f19bdaa))
### Features
- allow passing fast glob options to `createContentLoader` ([4f9a60b](https://github.com/vuejs/vitepress/commit/4f9a60b0cfa2fa841465f6e8cc5f77ed3e023817)), closes [#2985](https://github.com/vuejs/vitepress/issues/2985)
# [1.0.0-rc.14](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.13...v1.0.0-rc.14) (2023-09-16)
### Bug Fixes
- **client:** router in invalid state after 404 ([#2972](https://github.com/vuejs/vitepress/issues/2972)) ([28ef0ea](https://github.com/vuejs/vitepress/commit/28ef0ea6f60ab33e9cf34ecef10e1515d84f7168))
- **client:** scripts loading out of order when added through head ([#2970](https://github.com/vuejs/vitepress/issues/2970)) ([98679c9](https://github.com/vuejs/vitepress/commit/98679c9e82fcd3bbe3829640d0386cbd730e61ba))
- customizing the starting line number even if globally set ([#2941](https://github.com/vuejs/vitepress/issues/2941)) ([0cd87b1](https://github.com/vuejs/vitepress/commit/0cd87b1bafa6158ded0bf741553816f3d9b43a89))
- make algolia search work with indices that don't return absolute urls ([#2956](https://github.com/vuejs/vitepress/issues/2956)) ([2a34c6b](https://github.com/vuejs/vitepress/commit/2a34c6b3076bf418b3abbbca984fcb033743a611)), closes [#336](https://github.com/vuejs/vitepress/issues/336) [#805](https://github.com/vuejs/vitepress/issues/805)
- **theme:** remove extra padding from top when navbar is hidden ([#2575](https://github.com/vuejs/vitepress/issues/2575)) ([fd46dc9](https://github.com/vuejs/vitepress/commit/fd46dc9b8f8951b3196e4208d958d1ca0e1dc6e8))
### Features
- mathjax support ([#2977](https://github.com/vuejs/vitepress/issues/2977)) ([7271a95](https://github.com/vuejs/vitepress/commit/7271a959480261d60c01146d2e520d0f662e0380))
- **theme:** allow forcing dark mode ([#2974](https://github.com/vuejs/vitepress/issues/2974)) ([1fb5d22](https://github.com/vuejs/vitepress/commit/1fb5d228a269e913163246e988806056b3f1b9d9))
- **theme:** allow forcing site locale in last updated format ([#2973](https://github.com/vuejs/vitepress/issues/2973)) ([a18e5e4](https://github.com/vuejs/vitepress/commit/a18e5e48a442b09487cda8ab14e3b103ce270641))
# [1.0.0-rc.13](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.12...v1.0.0-rc.13) (2023-09-13)
### Bug Fixes
- **theme:** allow wrapping feature icons ([a1e1267](https://github.com/vuejs/vitepress/commit/a1e1267549e198b35455d055536cd0c6d1ad79ce)), closes [#2923](https://github.com/vuejs/vitepress/issues/2923)
- **theme:** local search enter key with the search result ([#2937](https://github.com/vuejs/vitepress/issues/2937)) ([00ef2f1](https://github.com/vuejs/vitepress/commit/00ef2f1db0369f50b3b634508e798b19b9525b34))
### Features
- **theme:** add search insights boolean to algolia search ([#2940](https://github.com/vuejs/vitepress/issues/2940)) ([32aa2a7](https://github.com/vuejs/vitepress/commit/32aa2a7d179049e5a1ed809018c32418bf69e8d5))
### Reverts
- Revert "feat(theme): use inert to avoid traverse menus and content with keyboard" (#2953) ([54891df](https://github.com/vuejs/vitepress/commit/54891df6149f4d0a871b16edf5f9a8a6fec639f9)), closes [#2953](https://github.com/vuejs/vitepress/issues/2953) [#2932](https://github.com/vuejs/vitepress/issues/2932)
# [1.0.0-rc.12](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.11...v1.0.0-rc.12) (2023-09-10)
### Bug Fixes
- **theme:** prevent closing local search box on key enter ([#2933](https://github.com/vuejs/vitepress/issues/2933)) ([e544b41](https://github.com/vuejs/vitepress/commit/e544b411d91eba54154243b0af4cea3226c192c4))
- **theme:** use brand color on search highlight ([dfc0fbf](https://github.com/vuejs/vitepress/commit/dfc0fbfcb4f255461bd90aef23a3dda1422b8335)), closes [#2902](https://github.com/vuejs/vitepress/issues/2902)
### Features
- highlight nav by default when one of the items is matched ([#2893](https://github.com/vuejs/vitepress/issues/2893)) ([b1fbece](https://github.com/vuejs/vitepress/commit/b1fbece047ca503f2c59553f9e37a0aac4be52c9))
- process md includes before building local search index ([#2906](https://github.com/vuejs/vitepress/issues/2906)) ([c6ff5c7](https://github.com/vuejs/vitepress/commit/c6ff5c76867dc59d5548cb33fd8447e23712bef5))
- support for customizing the starting line number in a code block ([#2917](https://github.com/vuejs/vitepress/issues/2917)) ([c0ce7f7](https://github.com/vuejs/vitepress/commit/c0ce7f723e52682d9ca107e4ce4e0e5c82710e02))
- **theme:** allow setting target in home features ([#2897](https://github.com/vuejs/vitepress/issues/2897)) ([cb49673](https://github.com/vuejs/vitepress/commit/cb4967313e5edcfd4bfc12aa10e75fec7b32e0c8))
- **theme:** use inert to avoid traverse menus and content with keyboard ([#2932](https://github.com/vuejs/vitepress/issues/2932)) ([070fc0a](https://github.com/vuejs/vitepress/commit/070fc0a56ddb941e26a098ba7207b5d1e91b7b51))
# [1.0.0-rc.11](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.10...v1.0.0-rc.11) (2023-09-10)
### Bug Fixes
- **init:** missing mts extension on windows ([195ebe9](https://github.com/vuejs/vitepress/commit/195ebe9464e2cc9b208e7d6c8bc5fa9f92025fdc)), closes [#2886](https://github.com/vuejs/vitepress/issues/2886)
- respect attrs on custom containers ([8b76167](https://github.com/vuejs/vitepress/commit/8b76167ccfbe5bf21295db6905451e1c50ca4407))
- temp workaround for broken navigation from 404 to home ([a18d544](https://github.com/vuejs/vitepress/commit/a18d5447f29f05d75bf0e20ff839e5c3bcdac390)), closes [#2891](https://github.com/vuejs/vitepress/issues/2891)
- **theme:** dropdown menu partially hidden by the homepage footer when it is too long ([#2904](https://github.com/vuejs/vitepress/issues/2904)) ([a60f079](https://github.com/vuejs/vitepress/commit/a60f079f996cc8ce9aeb189a25187fdbce2217ab))
- **theme:** improve contrast of search highlight text ([#2887](https://github.com/vuejs/vitepress/issues/2887)) ([20f9770](https://github.com/vuejs/vitepress/commit/20f97702680b47eb9675770df4db94a3e3b94ef1))
- **theme:** link hover color inside a custom block ([#2876](https://github.com/vuejs/vitepress/issues/2876)) ([39784ca](https://github.com/vuejs/vitepress/commit/39784ca55fdbefa97b7e9f892609ef8bdaeadf50))
- **theme:** prevent layout shift in search button key ([#2889](https://github.com/vuejs/vitepress/issues/2889)) ([0088434](https://github.com/vuejs/vitepress/commit/0088434895e5df9afea5bb8e81c515a41e824c44))
- **theme:** search button key misplaced on safari ([18adc07](https://github.com/vuejs/vitepress/commit/18adc07117cbf151b51aa205419496938a322a2e))
- **types:** NavItem can only have either link or items ([#2880](https://github.com/vuejs/vitepress/issues/2880)) ([12ef12d](https://github.com/vuejs/vitepress/commit/12ef12d6330f61a29102e7a0d537e742ff20367f))
### Features
- detect bun package manager ([#2874](https://github.com/vuejs/vitepress/issues/2874)) ([83270fe](https://github.com/vuejs/vitepress/commit/83270fe65767016a98cd59b6256f1361439cc7c8))
- skip rendering if env.BUNDLE_ONLY is truthy ([#2890](https://github.com/vuejs/vitepress/issues/2890)) ([d40eb19](https://github.com/vuejs/vitepress/commit/d40eb1903be022c9dfe10136122f5dc5aacb71d3))
# [1.0.0-rc.10](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.9...v1.0.0-rc.10) (2023-08-28)
### Bug Fixes

@ -1,14 +1,12 @@
# VitePress (RC: release candidate) 📝💨
# VitePress 📝💨
[![Test](https://github.com/vuejs/vitepress/workflows/Test/badge.svg)](https://github.com/vuejs/vitepress/actions)
[![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)
[![chat](https://img.shields.io/badge/chat-discord-blue?logo=discord)](https://chat.vuejs.org)
---
VitePress is [VuePress](https://vuepress.vuejs.org)' spiritual successor, built on top of [vite](https://github.com/vitejs/vite).
Currently, it is in the `release candidate` stage. It is already suitable for out-of-the-box documentation use. We do not plan to introduce any breaking changes from here on until the stable release.
VitePress is a Vue-powered static site generator and a spiritual successor to [VuePress](https://vuepress.vuejs.org), built on top of [Vite](https://github.com/vitejs/vite).
## Documentation

@ -86,6 +86,11 @@ const sidebar: DefaultTheme.Config['sidebar'] = {
export default defineConfig({
title: 'Example',
description: 'An example app using VitePress.',
markdown: {
image: {
lazyLoading: true
}
},
themeConfig: {
sidebar,
search: {

@ -4,8 +4,8 @@ exports[`render correct content > main content 1`] = `
[
"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.",
"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.",
"Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of \\"de Finibus Bonorum et Malorum\\" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, \\"Lorem ipsum dolor sit amet..\\", comes from a line in section 1.10.32.",
"The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for those interested. Sections 1.10.32 and 1.10.33 from \\"de Finibus Bonorum et Malorum\\" by Cicero are also reproduced in their exact original form, accompanied by English versions from the 1914 translation by H. Rackham.",
"Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit amet..", comes from a line in section 1.10.32.",
"The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for those interested. Sections 1.10.32 and 1.10.33 from "de Finibus Bonorum et Malorum" by Cicero are also reproduced in their exact original form, accompanied by English versions from the 1914 translation by H. Rackham.",
"It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like).",
"There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet. It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which looks reasonable. The generated Lorem Ipsum is therefore always free from repetition, injected humour, or non-characteristic words etc.",
]

@ -1,7 +1,7 @@
# Static Data
<script setup lang="ts">
import { data } from './basic.data.js'
import { data } from './basic.data.mjs'
import { data as contentData } from './contentLoader.data.js'
</script>

@ -7,34 +7,34 @@ describe('static data file support in vite 3', () => {
expect(await page.textContent('pre#basic')).toMatchInlineSnapshot(`
"[
{
\\"foo\\": true
"foo": true
},
{
\\"bar\\": true
"bar": true
}
]"
`)
expect(await page.textContent('pre#content')).toMatchInlineSnapshot(`
"[
{
\\"src\\": \\"---\\\\ntitle: bar\\\\n---\\\\n\\\\nHello\\\\n\\\\n---\\\\n\\\\nworld\\\\n\\",
\\"html\\": \\"<p>Hello</p>\\\\n<hr>\\\\n<p>world</p>\\\\n\\",
\\"frontmatter\\": {
\\"title\\": \\"bar\\"
"src": "---\\ntitle: bar\\n---\\n\\nHello\\n\\n---\\n\\nworld\\n",
"html": "<p>Hello</p>\\n<hr>\\n<p>world</p>\\n",
"frontmatter": {
"title": "bar"
},
\\"excerpt\\": \\"<p>Hello</p>\\\\n\\",
\\"url\\": \\"/data-loading/content/bar.html\\",
\\"transformed\\": true
"excerpt": "<p>Hello</p>\\n",
"url": "/data-loading/content/bar.html",
"transformed": true
},
{
\\"src\\": \\"---\\\\ntitle: foo\\\\n---\\\\n\\\\nHello\\\\n\\\\n---\\\\n\\\\nworld\\\\n\\",
\\"html\\": \\"<p>Hello</p>\\\\n<hr>\\\\n<p>world</p>\\\\n\\",
\\"frontmatter\\": {
\\"title\\": \\"foo\\"
"src": "---\\ntitle: foo\\n---\\n\\nHello\\n\\n---\\n\\nworld\\n",
"html": "<p>Hello</p>\\n<hr>\\n<p>world</p>\\n",
"frontmatter": {
"title": "foo"
},
\\"excerpt\\": \\"<p>Hello</p>\\\\n\\",
\\"url\\": \\"/data-loading/content/foo.html\\",
\\"transformed\\": true
"excerpt": "<p>Hello</p>\\n",
"url": "/data-loading/content/foo.html",
"transformed": true
}
]"
`)

@ -196,3 +196,7 @@ export default config
## Markdown File Inclusion with Range without End
<!--@include: ./foo.md{6,}-->
## Image Lazy Loading
![vitepress logo](/vitepress.png)

@ -65,7 +65,7 @@ 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(35)
expect(count).toBe(36)
})
})
@ -163,19 +163,19 @@ describe('Line Numbers', () => {
describe('Import Code Snippets', () => {
test('basic', async () => {
const lines = page.locator('#basic-code-snippet + div code > span')
expect(await lines.count()).toBe(22)
expect(await lines.count()).toBe(11)
})
test('specify region', async () => {
const lines = page.locator('#specify-region + div code > span')
expect(await lines.count()).toBe(6)
expect(await lines.count()).toBe(3)
})
test('with other features', async () => {
const div = page.locator('#with-other-features + div')
expect(await getClassList(div)).toContain('line-numbers-mode')
const lines = div.locator('code > span')
expect(await lines.count()).toBe(6)
expect(await lines.count()).toBe(3)
expect(await getClassList(lines.nth(0))).toContain('highlighted')
})
})
@ -216,10 +216,10 @@ describe('Code Groups', () => {
// blocks
const blocks = div.locator('.blocks > div')
expect(await blocks.nth(0).locator('code > span').count()).toBe(22)
expect(await blocks.nth(0).locator('code > span').count()).toBe(11)
expect(await getClassList(blocks.nth(1))).toContain('line-numbers-mode')
expect(await getClassList(blocks.nth(1))).toContain('language-ts')
expect(await blocks.nth(1).locator('code > span').count()).toBe(6)
expect(await blocks.nth(1).locator('code > span').count()).toBe(3)
expect(
await getClassList(blocks.nth(1).locator('code > span').nth(0))
).toContain('highlighted')
@ -274,4 +274,16 @@ describe('Markdown File Inclusion', () => {
expect(trim(await p.nth(0).textContent())).toBe('This is a region')
expect(trim(await p.nth(1).textContent())).toBe('This is after region')
})
test('ignore frontmatter if range is not specified', async () => {
const p = page.locator('.vp-doc')
expect(await p.textContent()).not.toContain('title')
})
})
describe('Image Lazy Loading', () => {
test('render loading="lazy" in the <img> tag', async () => {
const img = page.locator('#image-lazy-loading + p img')
expect(await img.getAttribute('loading')).toBe('lazy')
})
})

@ -1,3 +1,7 @@
---
title: Nested Include
---
<!--@include: ./foo.md-->
### After Foo

@ -1,10 +1,13 @@
import fs from 'fs-extra'
import getPort from 'get-port'
import { nanoid } from 'nanoid'
import path from 'path'
import { chromium } from 'playwright-chromium'
import { fileURLToPath, URL } from 'url'
import { createServer, scaffold, ScaffoldThemeType } from 'vitepress'
const root = fileURLToPath(new URL('./.temp', import.meta.url))
const tempDir = fileURLToPath(new URL('./.temp', import.meta.url))
const getTempRoot = () => path.join(tempDir, nanoid())
const browser = await chromium.launch({
headless: !process.env.DEBUG,
@ -30,9 +33,11 @@ const variations = themes.flatMap((theme) =>
afterAll(async () => {
await page.close()
await browser.close()
await fs.remove(tempDir)
})
test.each(variations)('init %s', async (_, { theme, useTs }) => {
const root = getTempRoot()
await fs.remove(root)
scaffold({ root, theme, useTs, injectNpmScripts: false })
@ -62,7 +67,6 @@ test.each(variations)('init %s', async (_, { theme, useTs }) => {
// teardown
} finally {
await fs.remove(root)
await server.close()
}
})

@ -1,4 +1,40 @@
import { dedent } from 'node/markdown/plugins/snippet'
import { dedent, rawPathToToken } from 'node/markdown/plugins/snippet'
const removeEmptyKeys = <T extends Record<string, unknown>>(obj: T) => {
return Object.fromEntries(
Object.entries(obj).filter(([, value]) => value !== '')
) as T
}
/* prettier-ignore */
const rawPathTokenMap: [string, Partial<{ filepath: string, extension: string, title: string, region: string, lines: string, lang: string }>][] = [
['/path/to/file.extension', { filepath: '/path/to/file.extension', extension: 'extension', title: 'file.extension' }],
['./path/to/file.extension', { filepath: './path/to/file.extension', extension: 'extension', title: 'file.extension' }],
['/path to/file.extension', { filepath: '/path to/file.extension', extension: 'extension', title: 'file.extension' }],
['./path to/file.extension', { filepath: './path to/file.extension', extension: 'extension', title: 'file.extension' }],
['/path.to/file.extension', { filepath: '/path.to/file.extension', extension: 'extension', title: 'file.extension' }],
['./path.to/file.extension', { filepath: './path.to/file.extension', extension: 'extension', title: 'file.extension' }],
['/path .to/file.extension', { filepath: '/path .to/file.extension', extension: 'extension', title: 'file.extension' }],
['./path .to/file.extension', { filepath: './path .to/file.extension', extension: 'extension', title: 'file.extension' }],
['/path/to/file', { filepath: '/path/to/file', title: 'file' }],
['./path/to/file', { filepath: './path/to/file', title: 'file' }],
['/path to/file', { filepath: '/path to/file', title: 'file' }],
['./path to/file', { filepath: './path to/file', title: 'file' }],
['/path.to/file', { filepath: '/path.to/file', title: 'file' }],
['./path.to/file', { filepath: './path.to/file', title: 'file' }],
['/path .to/file', { filepath: '/path .to/file', title: 'file' }],
['./path .to/file', { filepath: './path .to/file', title: 'file' }],
['/path/to/file.extension#region', { filepath: '/path/to/file.extension', extension: 'extension', title: 'file.extension', region: '#region' }],
['./path/to/file.extension {c#}', { filepath: './path/to/file.extension', extension: 'extension', title: 'file.extension', lang: 'c#' }],
['/path to/file.extension {1,2,4-6}', { filepath: '/path to/file.extension', extension: 'extension', title: 'file.extension', lines: '1,2,4-6' }],
['/path to/file.extension {1,2,4-6 c#}', { filepath: '/path to/file.extension', extension: 'extension', title: 'file.extension', lines: '1,2,4-6', lang: 'c#' }],
['/path.to/file.extension [title]', { filepath: '/path.to/file.extension', extension: 'extension', title: 'title' }],
['./path.to/file.extension#region {c#}', { filepath: './path.to/file.extension', extension: 'extension', title: 'file.extension', region: '#region', lang: 'c#' }],
['/path/to/file#region {1,2,4-6}', { filepath: '/path/to/file', title: 'file', region: '#region', lines: '1,2,4-6' }],
['./path/to/file#region {1,2,4-6 c#}', { filepath: './path/to/file', title: 'file', region: '#region', lines: '1,2,4-6', lang: 'c#' }],
['/path to/file {1,2,4-6 c#} [title]', { filepath: '/path to/file', title: 'title', lines: '1,2,4-6', lang: 'c#' }],
['./path to/file#region {1,2,4-6 c#} [title]', { filepath: './path to/file', title: 'title', region: '#region', lines: '1,2,4-6', lang: 'c#' }],
]
describe('node/markdown/plugins/snippet', () => {
describe('dedent', () => {
@ -14,7 +50,7 @@ describe('node/markdown/plugins/snippet', () => {
)
).toMatchInlineSnapshot(`
"fn main() {
println!(\\"Hello\\");
println!("Hello");
}"
`)
})
@ -57,4 +93,10 @@ describe('node/markdown/plugins/snippet', () => {
`)
})
})
test('rawPathToToken', () => {
rawPathTokenMap.forEach(([rawPath, token]) => {
expect(removeEmptyKeys(rawPathToToken(rawPath))).toEqual(token)
})
})
})

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

@ -0,0 +1,17 @@
import { defineConfig } from 'vitepress'
import { shared } from './shared'
import { en } from './en'
import { zh } from './zh'
import { pt } from './pt'
import { ru } from './ru'
export default defineConfig({
...shared,
locales: {
root: { label: 'English', ...en },
zh: { label: '简体中文', ...zh },
pt: { label: 'Português', ...pt },
ru: { label: 'Русский', ...ru },
ko: { label: '한국어', lang: 'ko-KR', link: 'https://vitepress.vuejs.kr/' }
}
})

@ -0,0 +1,212 @@
import { createRequire } from 'module'
import { defineConfig, type DefaultTheme } from 'vitepress'
const require = createRequire(import.meta.url)
const pkg = require('vitepress/package.json')
export const pt = defineConfig({
lang: 'pt-BR',
description: 'Gerador de Site Estático desenvolvido com Vite e Vue.',
themeConfig: {
nav: nav(),
sidebar: {
'/pt/guide/': { base: '/pt/guide/', items: sidebarGuide() },
'/pt/reference/': { base: '/pt/reference/', items: sidebarReference() }
},
editLink: {
pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',
text: 'Edite esta página no GitHub'
},
footer: {
message: 'Lançado sob licença MIT',
copyright: `Direitos reservados © 2019-${new Date().getFullYear()} Evan You`
},
docFooter: {
prev: 'Anterior',
next: 'Próximo'
},
outline: {
label: 'Nesta página'
},
lastUpdated: {
text: 'Atualizado em',
formatOptions: {
dateStyle: 'short',
timeStyle: 'medium'
}
},
langMenuLabel: 'Alterar Idioma',
returnToTopLabel: 'Voltar ao Topo',
sidebarMenuLabel: 'Menu Lateral',
darkModeSwitchLabel: 'Tema Escuro',
lightModeSwitchTitle: 'Mudar para Modo Claro',
darkModeSwitchTitle: 'Mudar para Modo Escuro'
}
})
function nav(): DefaultTheme.NavItem[] {
return [
{
text: 'Guia',
link: '/pt/guide/what-is-vitepress',
activeMatch: '/pt/guide/'
},
{
text: 'Referência',
link: '/pt/reference/site-config',
activeMatch: '/pt/reference/'
},
{
text: pkg.version,
items: [
{
text: 'Registro de Mudanças',
link: 'https://github.com/vuejs/vitepress/blob/main/CHANGELOG.md'
},
{
text: 'Contribuindo',
link: 'https://github.com/vuejs/vitepress/blob/main/.github/contributing.md'
}
]
}
]
}
function sidebarGuide(): DefaultTheme.SidebarItem[] {
return [
{
text: 'Introdução',
collapsed: false,
items: [
{ text: 'O que é VitePress', link: 'what-is-vitepress' },
{ text: 'Iniciando', link: 'getting-started' },
{ text: 'Roteamento', link: 'routing' },
{ text: 'Implantação', link: 'deploy' }
]
},
{
text: 'Escrevendo',
collapsed: false,
items: [
{ text: 'Extensões Markdown', link: 'markdown' },
{ text: 'Manipulando Ativos', link: 'asset-handling' },
{ text: 'Frontmatter', link: 'frontmatter' },
{ text: 'Usando Vue em Markdown', link: 'using-vue' },
{ text: 'Internacionalização', link: 'i18n' }
]
},
{
text: 'Personalização',
collapsed: false,
items: [
{ text: 'Usando um tema personalizado', link: 'custom-theme' },
{ text: 'Estendendo o tema padrão', link: 'extending-default-theme' },
{
text: 'Carregamento de dados no momento da compilação',
link: 'data-loading'
},
{ text: 'Compatibilidade SSR', link: 'ssr-compat' },
{ text: 'Conectando a um CMS', link: 'cms' }
]
},
{
text: 'Experimental',
collapsed: false,
items: [
{ text: 'Modo MPA', link: 'mpa-mode' },
{ text: 'Geração de Sitemap', link: 'sitemap-generation' }
]
},
{
text: 'Configuração e Referência da API',
base: '/pt/reference/',
link: 'site-config'
}
]
}
function sidebarReference(): DefaultTheme.SidebarItem[] {
return [
{
text: 'Referência',
items: [
{ text: 'Configuração do Site', link: 'site-config' },
{ text: 'Configuração Frontmatter', link: 'frontmatter-config' },
{ text: 'API do tempo de execução', link: 'runtime-api' },
{ text: 'CLI', link: 'cli' },
{
text: 'Tema padrão',
base: '/pt/reference/default-theme-',
items: [
{ text: 'Visão Geral', link: 'config' },
{ text: 'Navegação', link: 'nav' },
{ text: 'Barra Lateral', link: 'sidebar' },
{ text: 'Página Inicial', link: 'home-page' },
{ text: 'Rodapé', link: 'footer' },
{ text: 'Layout', link: 'layout' },
{ text: 'Distintivo', link: 'badge' },
{ text: 'Página da Equipe', link: 'team-page' },
{ text: 'Links Anterior / Próximo', link: 'prev-next-links' },
{ text: 'Editar Link', link: 'edit-link' },
{ text: 'Selo Temporal de Atualização', link: 'last-updated' },
{ text: 'Busca', link: 'search' },
{ text: 'Carbon Ads', link: 'carbon-ads' }
]
}
]
}
]
}
export const search: DefaultTheme.AlgoliaSearchOptions['locales'] = {
pt: {
placeholder: 'Pesquisar documentos',
translations: {
button: {
buttonText: 'Pesquisar',
buttonAriaLabel: 'Pesquisar'
},
modal: {
searchBox: {
resetButtonTitle: 'Limpar pesquisa',
resetButtonAriaLabel: 'Limpar pesquisa',
cancelButtonText: 'Cancelar',
cancelButtonAriaLabel: 'Cancelar'
},
startScreen: {
recentSearchesTitle: 'Histórico de Pesquisa',
noRecentSearchesText: 'Nenhuma pesquisa recente',
saveRecentSearchButtonTitle: 'Salvar no histórico de pesquisas',
removeRecentSearchButtonTitle: 'Remover do histórico de pesquisas',
favoriteSearchesTitle: 'Favoritos',
removeFavoriteSearchButtonTitle: 'Remover dos favoritos'
},
errorScreen: {
titleText: 'Não foi possível obter resultados',
helpText: 'Verifique a sua conexão de rede'
},
footer: {
selectText: 'Selecionar',
navigateText: 'Navegar',
closeText: 'Fechar',
searchByText: 'Pesquisa por'
},
noResultsScreen: {
noResultsText: 'Não foi possível encontrar resultados',
suggestedQueryText: 'Você pode tentar uma nova consulta',
reportMissingResultsText:
'Deveriam haver resultados para essa consulta?',
reportMissingResultsLinkText: 'Clique para enviar feedback'
}
}
}
}
}

@ -0,0 +1,208 @@
import { createRequire } from 'module'
import { defineConfig, type DefaultTheme } from 'vitepress'
const require = createRequire(import.meta.url)
const pkg = require('vitepress/package.json')
export const ru = defineConfig({
lang: 'ru-RU',
description: 'Генератор статических сайтов на основе Vite и Vue.',
themeConfig: {
nav: nav(),
sidebar: {
'/ru/guide/': { base: '/ru/guide/', items: sidebarGuide() },
'/ru/reference/': { base: '/ru/reference/', items: sidebarReference() }
},
editLink: {
pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',
text: 'Редактировать страницу'
},
footer: {
message: 'Опубликовано под лицензией MIT.',
copyright: '© 2019 настоящее время, Эван Ю'
},
outline: { label: 'Содержание страницы' },
docFooter: {
prev: 'Предыдущая страница',
next: 'Следующая страница'
},
lastUpdated: {
text: 'Обновлено'
},
darkModeSwitchLabel: 'Оформление',
lightModeSwitchTitle: 'Переключить на светлую тему',
darkModeSwitchTitle: 'Переключить на тёмную тему',
sidebarMenuLabel: 'Меню',
returnToTopLabel: 'Вернуться к началу',
langMenuLabel: 'Изменить язык'
}
})
function nav(): DefaultTheme.NavItem[] {
return [
{
text: 'Руководство',
link: '/ru/guide/what-is-vitepress',
activeMatch: '/ru/guide/'
},
{
text: 'Справочник',
link: '/ru/reference/site-config',
activeMatch: '/ru/reference/'
},
{
text: pkg.version,
items: [
{
text: 'Изменения',
link: 'https://github.com/vuejs/vitepress/blob/main/CHANGELOG.md'
},
{
text: 'Вклад',
link: 'https://github.com/vuejs/vitepress/blob/main/.github/contributing.md'
}
]
}
]
}
function sidebarGuide(): DefaultTheme.SidebarItem[] {
return [
{
text: 'Введение',
collapsed: false,
items: [
{ text: 'Что такое VitePress?', link: 'what-is-vitepress' },
{ text: 'Первые шаги', link: 'getting-started' },
{ text: 'Маршрутизация', link: 'routing' },
{ text: 'Развёртывание', link: 'deploy' }
]
},
{
text: 'Написание',
collapsed: false,
items: [
{ text: 'Расширения Markdown', link: 'markdown' },
{ text: 'Обработка ресурсов', link: 'asset-handling' },
{ text: 'Метаданные', 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: 'Загрузка данных в режиме реального времени',
link: 'data-loading'
},
{ text: 'Совместимость с SSR', link: 'ssr-compat' },
{ text: 'Подключение к CMS', link: 'cms' }
]
},
{
text: 'Экспериментально',
collapsed: false,
items: [
{ text: 'Режим MPA', link: 'mpa-mode' },
{ text: 'Генерация карты сайта', link: 'sitemap-generation' }
]
},
{ text: 'Конфигурация и API', base: '/ru/reference/', link: 'site-config' }
]
}
function sidebarReference(): DefaultTheme.SidebarItem[] {
return [
{
text: 'Справочник',
items: [
{ text: 'Конфигурация сайта', link: 'site-config' },
{ text: 'Конфигурация метаданных', link: 'frontmatter-config' },
{ text: 'Runtime API', link: 'runtime-api' },
{ text: 'Командная строка', link: 'cli' },
{
text: 'Тема по умолчанию',
base: '/ru/reference/default-theme-',
items: [
{ text: 'Обзор', link: 'config' },
{ text: 'Навигация', link: 'nav' },
{ text: 'Сайдбар', link: 'sidebar' },
{ text: 'Главная страница', link: 'home-page' },
{ text: 'Подвал', link: 'footer' },
{ text: 'Макет', link: 'layout' },
{ text: 'Значки', link: 'badge' },
{ text: 'Страница команды', link: 'team-page' },
{
text: 'Предыдущая и следующая страницы',
link: 'prev-next-links'
},
{ text: 'Ссылка для редактирования', link: 'edit-link' },
{ text: 'Последнее обновление', link: 'last-updated' },
{ text: 'Поиск', link: 'search' },
{ text: 'Carbon Ads (реклама)', link: 'carbon-ads' }
]
}
]
}
]
}
export const search: DefaultTheme.AlgoliaSearchOptions['locales'] = {
ru: {
placeholder: 'Поиск в документации',
translations: {
button: {
buttonText: 'Поиск',
buttonAriaLabel: 'Поиск'
},
modal: {
searchBox: {
resetButtonTitle: 'Сбросить поиск',
resetButtonAriaLabel: 'Сбросить поиск',
cancelButtonText: 'Отменить поиск',
cancelButtonAriaLabel: 'Отменить поиск'
},
startScreen: {
recentSearchesTitle: 'История поиска',
noRecentSearchesText: 'Нет истории поиска',
saveRecentSearchButtonTitle: 'Сохранить в истории поиска',
removeRecentSearchButtonTitle: 'Удалить из истории поиска',
favoriteSearchesTitle: 'Избранное',
removeFavoriteSearchButtonTitle: 'Удалить из избранного'
},
errorScreen: {
titleText: 'Невозможно получить результаты',
helpText: 'Вам может потребоваться проверить подключение к Интернету'
},
footer: {
selectText: 'выбрать',
navigateText: 'перейти',
closeText: 'закрыть',
searchByText: 'поставщик поиска'
},
noResultsScreen: {
noResultsText: 'Нет результатов для',
suggestedQueryText: 'Вы можете попытаться узнать',
reportMissingResultsText:
'Считаете, что поиск даёт ложные результаты?',
reportMissingResultsLinkText: 'Нажмите на кнопку «Обратная связь»'
}
}
}
}
}

@ -0,0 +1,65 @@
import { defineConfig } from 'vitepress'
import { search as zhSearch } from './zh'
import { search as ptSearch } from './pt'
import { search as ruSearch } from './ru'
export const shared = defineConfig({
title: 'VitePress',
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: 'a18e2f4cc5665f6602c5631fd868adfd',
indexName: 'vitepress',
locales: { ...zhSearch, ...ptSearch, ...ruSearch }
}
},
carbonAds: { code: 'CEBDT27Y', placement: 'vuejsorg' }
}
})

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

@ -12,6 +12,10 @@ You can reference static assets in your markdown files, your `*.vue` components
Common image, media, and font filetypes are detected and included as assets automatically.
::: tip Linked files are not treated as assets
PDFs or other documents referenced by links within markdown files are not automatically treated as assets. To make linked files accessible, you must manually place them within the [`public`](#the-public-directory) directory of your project.
:::
All referenced assets, including those using absolute paths, will be copied to the output directory with a hashed file name in the production build. Never-referenced assets will not be copied. Image assets smaller than 4kb will be base64 inlined - this can be configured via the [`vite`](../reference/site-config#vite) config option.
All **static** path references, including absolute paths, should be based on your working directory structure.

@ -196,7 +196,7 @@ export default {
If the theme requires special VitePress config, you will need to also extend it in your own config:
```ts
// .vitepress/theme/config.ts
// .vitepress/config.ts
import baseConfig from 'awesome-vitepress-theme/config'
export default {
@ -208,7 +208,7 @@ export default {
Finally, if the theme provides types for its theme config:
```ts
// .vitepress/theme/config.ts
// .vitepress/config.ts
import baseConfig from 'awesome-vitepress-theme/config'
import { defineConfigWithTheme } from 'vitepress'
import type { ThemeConfig } from 'awesome-vitepress-theme'

@ -13,7 +13,7 @@ A data loader file must end with either `.data.js` or `.data.ts`. The file shoul
export default {
load() {
return {
data: 'hello'
hello: 'world'
}
}
}
@ -35,7 +35,7 @@ Output:
```json
{
"data": "hello"
"hello": "world"
}
```
@ -230,7 +230,7 @@ export { data }
export default defineLoader({
// type checked loader options
glob: ['...'],
watch: ['...'],
async load(): Promise<Data> {
// ...
}

@ -153,26 +153,24 @@ 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@v3
uses: actions/checkout@v4
with:
fetch-depth: 0 # Not needed if lastUpdated is not enabled
# - uses: pnpm/action-setup@v2 # Uncomment this if you're using pnpm
# - uses: pnpm/action-setup@v3 # Uncomment this if you're using pnpm
# - uses: oven-sh/setup-bun@v1 # Uncomment this if you're using Bun
- name: Setup Node
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: 18
node-version: 20
cache: npm # or pnpm / yarn
- name: Setup Pages
uses: actions/configure-pages@v3
uses: actions/configure-pages@v4
- name: Install dependencies
run: npm ci # or pnpm install / yarn install / bun install
- name: Build with VitePress
run: |
npm run docs:build # or pnpm docs:build / yarn docs:build / bun run docs:build
touch docs/.vitepress/dist/.nojekyll
run: npm run docs:build # or pnpm docs:build / yarn docs:build / bun run docs:build
- name: Upload artifact
uses: actions/upload-pages-artifact@v2
uses: actions/upload-pages-artifact@v3
with:
path: docs/.vitepress/dist
@ -187,7 +185,7 @@ Don't enable options like _Auto Minify_ for HTML code. It will remove comments f
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v2
uses: actions/deploy-pages@v4
```
::: warning
@ -285,3 +283,55 @@ Don't enable options like _Auto Minify_ for HTML code. It will remove comments f
### Edgio
Refer [Creating and Deploying a VitePress App To Edgio](https://docs.edg.io/guides/vitepress).
### Kinsta Static Site Hosting
You can deploy your Vitepress website on [Kinsta](https://kinsta.com/static-site-hosting/) by following these [instructions](https://kinsta.com/docs/vitepress-static-site-example/).
### Stormkit
You can deploy your VitePress project to [Stormkit](https://www.stormkit.io) by following these [instructions](https://stormkit.io/blog/how-to-deploy-vitepress).
### 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`.
```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";
}
}
}
```
This configuration assumes that your built VitePress site is located in the `/app` directory on your server. Adjust the `root` directive accordingly if your site's files are located elsewhere.
::: warning Do not default to index.html
The try_files resolution must not default to index.html like in other Vue applications. This would result in an invalid page state.
:::
Further information can be found in the [official nginx documentation](https://nginx.org/en/docs/), in these issues [#2837](https://github.com/vuejs/vitepress/discussions/2837), [#3235](https://github.com/vuejs/vitepress/issues/3235) as well as in this [blog post](https://blog.mehdi.cc/articles/vitepress-cleanurls-on-nginx-environment#readings) by Mehdi Merah.

@ -98,15 +98,31 @@ export default {
// .vitepress/theme/index.js
import DefaultTheme from 'vitepress/theme'
/** @type {import('vitepress').Theme} */
export default {
extends: DefaultTheme,
enhanceApp(ctx) {
enhanceApp({ app }) {
// register your custom global components
ctx.app.component('MyGlobalComponent' /* ... */)
app.component('MyGlobalComponent' /* ... */)
}
}
```
If you're using TypeScript:
```ts
// .vitepress/theme/index.ts
import type { Theme } from 'vitepress'
import DefaultTheme from 'vitepress/theme'
export default {
extends: DefaultTheme,
enhanceApp({ app }) {
// register your custom global components
app.component('MyGlobalComponent' /* ... */)
}
} satisfies Theme
```
Since we are using Vite, you can also leverage Vite's [glob import feature](https://vitejs.dev/guide/features.html#glob-import) to auto register a directory of components.
## Layout Slots
@ -119,7 +135,7 @@ import DefaultTheme from 'vitepress/theme'
import MyLayout from './MyLayout.vue'
export default {
...DefaultTheme,
extends: DefaultTheme,
// override the Layout with a wrapper component that
// injects the slots
Layout: MyLayout
@ -152,7 +168,7 @@ import DefaultTheme from 'vitepress/theme'
import MyComponent from './MyComponent.vue'
export default {
...DefaultTheme,
extends: DefaultTheme,
Layout() {
return h(DefaultTheme.Layout, null, {
'aside-outline-before': () => h(MyComponent)
@ -179,7 +195,10 @@ Full list of slots available in the default theme layout:
- `aside-ads-after`
- When `layout: 'home'` is enabled via 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`

@ -68,11 +68,15 @@ $ npx vitepress init
```
```sh [pnpm]
$ pnpm dlx vitepress init
$ pnpm vitepress init
```
```sh [yarn]
$ yarn vitepress init
```
```sh [bun]
$ bunx vitepress init
$ bun vitepress init
```
:::
@ -82,7 +86,7 @@ You will be greeted with a few simple questions:
<<< @/snippets/init.ansi
::: tip Vue as Peer Dependency
If you intend to perform customization that uses Vue components or APIs, you should also explicitly install `vue` as a peer dependency.
If you intend to perform customization that uses Vue components or APIs, you should also explicitly install `vue` as a dependency.
:::
## File Structure
@ -182,11 +186,15 @@ $ npx vitepress dev docs
```
```sh [pnpm]
$ pnpm exec vitepress dev docs
$ pnpm vitepress dev docs
```
```sh [yarn]
$ yarn vitepress dev docs
```
```sh [bun]
$ bunx vitepress dev docs
$ bun vitepress dev docs
```
:::
@ -199,7 +207,7 @@ The dev server should be running at `http://localhost:5173`. Visit the URL in yo
- To better understand how markdown files are mapped to generated HTML, proceed to the [Routing Guide](./routing).
- To discover more about what you can do on the page, such as writing markdown content or using Vue Component, refer to the "Writing" section of the guide. A great place to start would be to learn about [Markdown Extensions](./markdown).
- To discover more about what you can do on the page, such as writing markdown content or using Vue Components, refer to the "Writing" section of the guide. A great place to start would be to learn about [Markdown Extensions](./markdown).
- To explore the features provided by the default documentation theme, check out the [Default Theme Config Reference](../reference/default-theme-config).

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

@ -18,7 +18,7 @@ This allows you to link to the heading as `#my-anchor` instead of the default `#
## Links
Both internal and external links gets special treatments.
Both internal and external links get special treatment.
### Internal Links
@ -80,7 +80,7 @@ For more details, see [Frontmatter](../reference/frontmatter-config).
**Input**
```
```md
| Tables | Are | Cool |
| ------------- | :-----------: | ----: |
| col 3 is | right-aligned | $1600 |
@ -108,7 +108,7 @@ For more details, see [Frontmatter](../reference/frontmatter-config).
:tada: :100:
A [list of all emojis](https://github.com/markdown-it/markdown-it-emoji/blob/master/lib/data/full.json) is available.
A [list of all emojis](https://github.com/markdown-it/markdown-it-emoji/blob/master/lib/data/full.mjs) is available.
## Table of Contents
@ -206,6 +206,25 @@ console.log('Hello, VitePress!')
```
:::
Also, you may set custom titles globally by adding the following content in site config, helpful if not writing in English:
```ts
// config.ts
export default defineConfig({
// ...
markdown: {
container: {
tipLabel: '提示',
warningLabel: '警告',
dangerLabel: '危险',
infoLabel: '信息',
detailsLabel: '详细信息'
}
}
// ...
})
```
### `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.
@ -220,8 +239,6 @@ Wraps in a <div class="vp-raw">
`vp-raw` class can be directly used on elements too. Style isolation is currently opt-in:
::: details
- Install `postcss` with your preferred package manager:
```sh
@ -232,11 +249,9 @@ Wraps in a <div class="vp-raw">
```js
import { postcssIsolateStyles } from 'vitepress'
export default {
plugins: {
postcssIsolateStyles()
}
plugins: [postcssIsolateStyles()]
}
```
@ -248,11 +263,45 @@ Wraps in a <div class="vp-raw">
})
```
:::
## GitHub-flavored Alerts
VitePress also supports [GitHub-flavored alerts](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts) to render as callouts. They will be rendered the same as the [custom containers](#custom-containers).
```md
> [!NOTE]
> Highlights information that users should take into account, even when skimming.
> [!TIP]
> Optional information to help a user be more successful.
> [!IMPORTANT]
> Crucial information necessary for users to succeed.
> [!WARNING]
> Critical content demanding immediate user attention due to potential risks.
> [!CAUTION]
> Negative potential consequences of an action.
```
> [!NOTE]
> Highlights information that users should take into account, even when skimming.
> [!TIP]
> Optional information to help a user be more successful.
> [!IMPORTANT]
> Crucial information necessary for users to succeed.
> [!WARNING]
> Critical content demanding immediate user attention due to potential risks.
> [!CAUTION]
> Negative potential consequences of an action.
## Syntax Highlighting in Code Blocks
VitePress uses [Shiki](https://shiki.matsu.io/) to highlight language syntax in Markdown code blocks, using coloured text. Shiki supports a wide variety of programming languages. All you need to do is append a valid language alias to the beginning backticks for the code block:
VitePress uses [Shiki](https://github.com/shikijs/shiki) to highlight language syntax in Markdown code blocks, using coloured text. Shiki supports a wide variety of programming languages. All you need to do is append a valid language alias to the beginning backticks for the code block:
**Input**
@ -292,7 +341,7 @@ export default {
</ul>
```
A [list of valid languages](https://github.com/shikijs/shiki/blob/main/docs/languages.md) is available on Shiki's repository.
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.
@ -364,7 +413,7 @@ export default { // Highlighted
}
```
Alternatively, it's possible to highlight directly in the line by using the `// [!code hl]` comment.
Alternatively, it's possible to highlight directly in the line by using the `// [!code highlight]` comment.
**Input**
@ -373,7 +422,7 @@ Alternatively, it's possible to highlight directly in the line by using the `//
export default {
data () {
return {
msg: 'Highlighted!' // [!code hl]
msg: 'Highlighted!' // [!!code highlight]
}
}
}
@ -386,7 +435,7 @@ export default {
export default {
data() {
return {
msg: 'Highlighted!' // [!code hl]
msg: 'Highlighted!' // [!code highlight]
}
}
}
@ -400,14 +449,12 @@ Additionally, you can define a number of lines to focus using `// [!code focus:<
**Input**
Note that only one space is required after `!code`, here are two to prevent processing.
````
```js
export default {
data () {
return {
msg: 'Focused!' // [!code focus]
msg: 'Focused!' // [!!code focus]
}
}
}
@ -432,15 +479,13 @@ Adding the `// [!code --]` or `// [!code ++]` comments on a line will create a d
**Input**
Note that only one space is required after `!code`, here are two to prevent processing.
````
```js
export default {
data () {
return {
msg: 'Removed' // [!code --]
msg: 'Added' // [!code ++]
msg: 'Removed' // [!!code --]
msg: 'Added' // [!!code ++]
}
}
}
@ -466,15 +511,13 @@ Adding the `// [!code warning]` or `// [!code error]` comments on a line will co
**Input**
Note that only one space is required after `!code`, here are two to prevent processing.
````
```js
export default {
data () {
return {
msg: 'Error', // [!code error]
msg: 'Warning' // [!code warning]
msg: 'Error', // [!!code error]
msg: 'Warning' // [!!code warning]
}
}
}
@ -510,6 +553,8 @@ Please see [`markdown` options](../reference/site-config#markdown) for more deta
You can add `:line-numbers` / `:no-line-numbers` mark in your fenced code blocks to override the value set in config.
You can also customize the starting line number by adding `=` after `:line-numbers`. For example, `:line-numbers=2` means the line numbers in code blocks will start from `2`.
**Input**
````md
@ -524,6 +569,12 @@ const line3 = 'This is line 3'
const line2 = 'This is line 2'
const line3 = 'This is line 3'
```
```ts:line-numbers=2 {1}
// line-numbers is enabled and start from 2
const line3 = 'This is line 3'
const line4 = 'This is line 4'
```
````
**Output**
@ -540,6 +591,12 @@ const line2 = 'This is line 2'
const line3 = 'This is line 3'
```
```ts:line-numbers=2 {1}
// line-numbers is enabled and start from 2
const line3 = 'This is line 3'
const line4 = 'This is line 4'
```
## Import Code Snippets
You can import code snippets from existing files via following syntax:
@ -781,15 +838,76 @@ The format of the selected line range can be: `{3,}`, `{,10}`, `{1,10}`
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.
:::
## 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:
```sh
npm add -D markdown-it-mathjax3
```
```ts
// .vitepress/config.ts
export default {
markdown: {
math: true
}
}
```
**Input**
```md
When $a \ne 0$, there are two solutions to $(ax^2 + bx + c = 0)$ and they are
$$ x = {-b \pm \sqrt{b^2-4ac} \over 2a} $$
**Maxwell's equations:**
| equation | description |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| $\nabla \cdot \vec{\mathbf{B}} = 0$ | divergence of $\vec{\mathbf{B}}$ is zero |
| $\nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} = \vec{\mathbf{0}}$ | curl of $\vec{\mathbf{E}}$ is proportional to the rate of change of $\vec{\mathbf{B}}$ |
| $\nabla \times \vec{\mathbf{B}} -\, \frac1c\, \frac{\partial\vec{\mathbf{E}}}{\partial t} = \frac{4\pi}{c}\vec{\mathbf{j}} \nabla \cdot \vec{\mathbf{E}} = 4 \pi \rho$ | _wha?_ |
```
**Output**
When $a \ne 0$, there are two solutions to $(ax^2 + bx + c = 0)$ and they are
$$ x = {-b \pm \sqrt{b^2-4ac} \over 2a} $$
**Maxwell's equations:**
| equation | description |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| $\nabla \cdot \vec{\mathbf{B}} = 0$ | divergence of $\vec{\mathbf{B}}$ is zero |
| $\nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} = \vec{\mathbf{0}}$ | curl of $\vec{\mathbf{E}}$ is proportional to the rate of change of $\vec{\mathbf{B}}$ |
| $\nabla \times \vec{\mathbf{B}} -\, \frac1c\, \frac{\partial\vec{\mathbf{E}}}{\partial t} = \frac{4\pi}{c}\vec{\mathbf{j}} \nabla \cdot \vec{\mathbf{E}} = 4 \pi \rho$ | _wha?_ |
## Image Lazy Loading
You can enable lazy loading for each image added via markdown by setting `lazyLoading` to `true` in your config file:
```js
export default {
markdown: {
image: {
// image lazy loading is disabled by default
lazyLoading: true
}
}
}
```
## Advanced Configuration
VitePress uses [markdown-it](https://github.com/markdown-it/markdown-it) as the Markdown renderer. A lot of the extensions above are implemented via custom plugins. You can further customize the `markdown-it` instance using the `markdown` option in `.vitepress/config.js`:
```js
import { defineConfig } from 'vitepress'
import markdownItAnchor from 'markdown-it-anchor'
import markdownItFoo from 'markdown-it-foo'
module.exports = {
export default defineConfig({
markdown: {
// options for markdown-it-anchor
// https://github.com/valeriangalliat/markdown-it-anchor#usage
@ -806,7 +924,7 @@ module.exports = {
md.use(markdownItFoo)
}
}
}
})
```
See full list of configurable properties in [Config Reference: App Config](../reference/site-config#markdown).

@ -129,9 +129,9 @@ To serve clean URLs with VitePress, server-side support is required.
By default, VitePress resolves inbound links to URLs ending with `.html`. However, some users may prefer "Clean URLs" without the `.html` extension - for example, `example.com/path` instead of `example.com/path.html`.
Some servers or hosting platforms (for example Netlify or Vercel) provide the ability to map a URL like `/foo` to `/foo.html` if it exists, without a redirect:
Some servers or hosting platforms (for example Netlify, Vercel, GitHub Pages) provide the ability to map a URL like `/foo` to `/foo.html` if it exists, without a redirect:
- Netlify supports this by default.
- Netlify and GitHub Pages support this by default.
- Vercel requires enabling the [`cleanUrls` option in `vercel.json`](https://vercel.com/docs/concepts/projects/project-configuration#cleanurls).
If this feature is available to you, you can then also enable VitePress' own [`cleanUrls`](../reference/site-config#cleanurls) config option so that:
@ -139,7 +139,7 @@ If this feature is available to you, you can then also enable VitePress' own [`c
- Inbound links between pages are generated without the `.html` extension.
- If current path ends with `.html`, the router will perform a client-side redirect to the extension-less path.
If, however, you cannot configure your server with such support (e.g. GitHub pages), you will have to manually resort to the following directory structure:
If, however, you cannot configure your server with such support, you will have to manually resort to the following directory structure:
```
.

@ -6,7 +6,7 @@ outline: deep
VitePress pre-renders the app in Node.js during the production build, using Vue's Server-Side Rendering (SSR) capabilities. This means all custom code in theme components are subject to SSR Compatibility.
The [SSR section in official Vue docs](https://vuejs.org/guide/scaling-up/ssr.html) provides more context on what is SSR, the relationship between SSR / SSG, and common notes on writing SSR-friendly code. The rule of thumb is to only access browser / DOM APIs in `beforeMount` or `mounted` hooks of Vue components.
The [SSR section in official Vue docs](https://vuejs.org/guide/scaling-up/ssr.html) provides more context on what SSR is, the relationship between SSR / SSG, and common notes on writing SSR-friendly code. The rule of thumb is to only access browser / DOM APIs in `beforeMount` or `mounted` hooks of Vue components.
## `<ClientOnly>`
@ -52,17 +52,34 @@ Since [`Theme.enhanceApp`](./custom-theme#theme-interface) can be async, you can
```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)
app.use(plugin.default)
}
}
}
```
If you're using TypeScript:
```ts
// .vitepress/theme/index.ts
import type { Theme } from 'vitepress'
export default {
// ...
async enhanceApp({ app }) {
if (!import.meta.env.SSR) {
const plugin = await import('plugin-that-access-window-on-import')
app.use(plugin.default)
}
}
} satisfies Theme
```
### `defineClientComponent`
VitePress provides a convenience helper for importing Vue components that access browser APIs on import.

@ -34,11 +34,11 @@ VitePress aims to provide a great Developer Experience (DX) when working with Ma
## Performance
Unlike many traditional SSGs, a website generated by VitePress is in fact a [Single Page Application](https://en.wikipedia.org/wiki/Single-page_application) (SPA).
Unlike many traditional SSGs where each navigation results in a full page reload, a website generated by VitePress serves static HTML on the initial visit, but becomes a [Single Page Application](https://en.wikipedia.org/wiki/Single-page_application) (SPA) for subsequent navigation within the site. This model, in our opinion, provides an optimal balance for performance:
- **Fast Initial Load**
The initial visit to any page will be served the static, pre-rendered HTML for blazing fast loading speed and optimal SEO. The page then loads a JavaScript bundle that turns the page into a Vue SPA ("hydration"). The hydration process is extremely fast: on [PageSpeed Insights](https://pagespeed.web.dev/report?url=https%3A%2F%2Fvitepress.dev%2F), typical VitePress sites achieve near-perfect performance scores even on low-end mobile devices with a slow network.
The initial visit to any page will be served the static, pre-rendered HTML for fast loading speed and optimal SEO. The page then loads a JavaScript bundle that turns the page into a Vue SPA ("hydration"). Contrary to common assumptions of SPA hydration being slow, this process is actually extremely fast thanks to Vue 3's raw performance and compiler optimizations. On [PageSpeed Insights](https://pagespeed.web.dev/report?url=https%3A%2F%2Fvitepress.dev%2F), typical VitePress sites achieve near-perfect performance scores even on low-end mobile devices with a slow network.
- **Fast Post-load Navigation**

@ -7,13 +7,16 @@ titleTemplate: Vite & Vue Powered Static Site Generator
hero:
name: VitePress
text: Vite & Vue Powered Static Site Generator
tagline: Simple, powerful, and fast. Meet the modern SSG framework you've always wanted.
tagline: Markdown to Beautiful Docs in Minutes
actions:
- theme: brand
text: Get Started
text: What is VitePress?
link: /guide/what-is-vitepress
- theme: alt
text: Quickstart
link: /guide/getting-started
- theme: alt
text: View on GitHub
text: GitHub
link: https://github.com/vuejs/vitepress
image:
src: /vitepress-logo-large.webp
@ -33,13 +36,14 @@ 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(40px);
--vp-home-hero-image-filter: blur(44px);
}
@media (min-width: 640px) {
@ -50,7 +54,7 @@ features:
@media (min-width: 960px) {
:root {
--vp-home-hero-image-filter: blur(72px);
--vp-home-hero-image-filter: blur(68px);
}
}
</style>

@ -0,0 +1,39 @@
{
"$schema": "./node_modules/@lunariajs/core/config.schema.json",
"repository": {
"name": "vuejs/vitepress",
"rootDir": "docs"
},
"files": [
{
"location": ".vitepress/config/{en,zh,pt,ru}.ts",
"pattern": ".vitepress/config/@lang.ts",
"type": "universal"
},
{
"location": "**/*.md",
"pattern": "@lang/@path",
"type": "universal"
}
],
"defaultLocale": {
"label": "English",
"lang": "en"
},
"locales": [
{
"label": "简体中文",
"lang": "zh"
},
{
"label": "Português",
"lang": "pt"
},
{
"label": "Русский",
"lang": "ru"
}
],
"outDir": ".vitepress/dist/_translations",
"ignoreKeywords": ["lunaria-ignore"]
}

@ -3,11 +3,16 @@
"private": true,
"type": "module",
"scripts": {
"dev": "vitepress dev",
"build": "vitepress build",
"dev": "vitepress dev",
"lunaria:build": "lunaria build",
"lunaria:open": "open-cli .vitepress/dist/_translations/index.html",
"preview": "vitepress preview"
},
"devDependencies": {
"@lunariajs/core": "^0.0.32",
"markdown-it-mathjax3": "^4.3.2",
"open-cli": "^8.0.0",
"vitepress": "workspace:*"
}
}

@ -0,0 +1,59 @@
# Manipulação de Ativos {#asset-handling}
## Referenciando Ativos Estáticos {#referencing-static-assets}
Todos os arquivos Markdown são compilados em componentes Vue e processados por [Vite](https://vitejs.dev/guide/assets.html). Você pode **e deve** referenciar quaisquer ativos usando URLs relativas:
```md
![Uma imagem](./imagem.png)
```
Você pode referenciar ativos estáticos em seus arquivos markdown, seus componentes `*.vue` no tema, estilos e simples arquivos `.css`, usando caminhos públicos absolutos (com base na raiz do projeto) ou caminhos relativos (com base em seu sistema de arquivos). Este último é semelhante ao comportamento que você está acostumado se já usou Vite, Vue CLI ou o `file-loader` do webpack.
Tipos comuns de arquivos de imagem, mídia e fonte são detectados e incluídos automaticamente como ativos.
Todos os ativos referenciados, incluindo aqueles usando caminhos absolutos, serão copiados para o diretório de saída com um nome de arquivo hash na compilação de produção. Ativos nunca referenciados não serão copiados. Ativos de imagem menores que 4KB serão incorporados em base64 - isso pode ser configurado pela opção [`vite`](../reference/site-config#vite) da configuração.
Todas as referências de caminho **estáticas**, incluindo caminhos absolutos, devem ser baseadas na estrutura do seu diretório de trabalho.
## O Diretório Público {#the-public-directory}
Às vezes, pode ser necessário fornecer ativos estáticos que não são referenciados diretamente em nenhum de seus componentes do tema ou Markdown, ou você pode querer servir certos arquivos com o nome de arquivo original. Exemplos de tais arquivos incluem `robots.txt`, favicons e ícones PWA.
Você pode colocar esses arquivos no diretório `public` sob o [diretório fonte](./routing#source-directory). Por exemplo, se a raiz do seu projeto for `./docs` e estiver usando a localização padrão do diretório fonte, então o diretório público será `./docs/public`.
Os ativos colocados em `public` serão copiados para a raiz do diretório de saída como são.
Observe que você deve referenciar arquivos colocados em `public` usando o caminho absoluto da raiz - por exemplo, `public/icon.png` deve sempre ser referenciado no código fonte como `/icon.png`.
## URL Base {#base-url}
Se seu site for implantado em uma URL que não seja a raiz, será necessário definir a opção `base` em `.vitepress/config.js`. Por exemplo, se você planeja implantar seu site em `https://foo.github.io/bar/`, então `base` deve ser definido como `'/bar/'` (sempre deve começar e terminar com uma barra).
Todos os caminhos dos seus ativos estáticos são processados automaticamente para se ajustar aos diferentes valores de configuração `base`. Por exemplo, se você tiver uma referência absoluta a um ativo sob `public` no seu markdown:
```md
![Uma imagem](/imagem-dentro-de-public.png)
```
Você **não** precisa atualizá-lo quando alterar o valor de configuração `base` nesse caso.
No entanto, se você estiver criando um componente de tema que vincula ativos dinamicamente, por exemplo, uma imagem cujo `src` é baseado em um valor de configuração do tema:
```vue
<img :src="theme.logoPath" />
```
Nesse caso, é recomendável envolver o caminho com o [`auxiliar withBase`](../reference/runtime-api#withbase) fornecido por VitePress:
```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
---
# Conectando a um CMS {#connecting-to-a-cms}
## Fluxo de Trabalho Geral {#general-workflow}
Conectar VitePress a um CMS orbitará majoritariamente sobre [Rotas Dinâmicas](./routing#dynamic-routes). Certifique-se de entender como funcionam antes de proceder.
Como cada CMS funcionará de forma diferente, aqui podemos fornecer apenas um fluxo de trabalho genérico que precisará ser adaptado para cada cenário específico.
1. Se seu CMS exige autenticação, crie um arquivo `.env` para armazenar os tokens da API e carregá-los como:
```js
// posts/[id].paths.js
import { loadEnv } from 'vitepress'
const env = loadEnv('', process.cwd())
```
2. Obtenha os dados necessários do CMS e formate-os em caminhos de dados apropriados:
```js
export default {
async paths() {
// use a biblitoca do cliente CMS respectiva se preciso
const data = await (await fetch('https://my-cms-api', {
headers: {
// token se necessário
}
})).json()
return data.map(entry => {
return {
params: { id: entry.id, /* título, autores, data, etc. */ },
content: entry.content
}
})
}
}
```
3. Apresente o conteúdo na página:
```md
# {{ $params.title }}
- por {{ $params.author }} em {{ $params.date }}
<!-- @content -->
```
## Guias de Integração {#integration-guides}
Se você tiver escrito um guia sobre como integrar VitePress com um CMS específico, por favor use o link "Edite esta página" abaixo para enviá-lo para cá!

@ -0,0 +1,222 @@
# Usando um Tema Personalizado {#using-a-custom-theme}
## Resolução de Tema {#theme-resolving}
Você pode habilitar um tema personalizado criando um arquivo `.vitepress/theme/index.js` ou `.vitepress/theme/index.ts` (o "arquivo de entrada do tema"):
```
.
├─ docs # raiz do projeto
│ ├─ .vitepress
│ │ ├─ theme
│ │ │ └─ index.js # entrada do tema
│ │ └─ config.js # arquivo de configuração
│ └─ index.md
└─ package.json
```
VitePress sempre usará o tema personalizado em vez do tema padrão quando detectar a presença de um arquivo de entrada do tema. No entanto, você pode [estender o tema padrão](./extending-default-theme) para realizar personalizações avançadas sobre ele.
## Interface do Tema {#theme-interface}
Um tema personalizado do VitePress é definido como um objeto com a seguinte interface:
```ts
interface Theme {
/**
* Componente raiz de layout para toda página
* @required
*/
Layout: Component
/**
* Aprimora a instância da aplicação Vue
* @optional
*/
enhanceApp?: (ctx: EnhanceAppContext) => Awaitable<void>
/**
* Estende outro tema, chamando seu `enhanceApp` antes do nosso
* @optional
*/
extends?: Theme
}
interface EnhanceAppContext {
app: App // instância da aplicação Vue
router: Router // instância do roteador VitePress
siteData: Ref<SiteData> // Metadados do nível do site
}
```
O arquivo de entrada do tema deve exportar o tema como sua exportação padrão:
```js
// .vitepress/theme/index.js
// Você pode importar arquivos Vue diretamente no arquivo de entrada do tema
// VitePress já está pré-configurado com @vitejs/plugin-vue.
import Layout from './Layout.vue'
export default {
Layout,
enhanceApp({ app, router, siteData }) {
// ...
}
}
```
A exportação padrão é o único contrato para um tema personalizado, e apenas a propriedade `Layout` é exigida. Tecnicamente, um tema do VitePress pode ser tão simples quanto um único componente Vue.
Dentro do seu componente de layout, ele funciona como uma aplicação Vite + Vue 3 normal. Note que o tema também precisa ser [compatível com SSR](./ssr-compat).
## Construindo um Layout {#building-a-layout}
O componente de layout mais básico precisa conter um componente [`<Content />`](../reference/runtime-api#content):
```vue
<!-- .vitepress/theme/Layout.vue -->
<template>
<h1>Layout Personalizado!</h1>
<!-- aqui é onde o conteúdo markdown será apresentado -->
<Content />
</template>
```
O layout acima simplesmente renderiza o markdown de toda página como HTML. A primeira melhoria que podemos adicionar é lidar com erros 404:
```vue{1-4,9-12}
<script setup>
import { useData } from 'vitepress'
const { page } = useData()
</script>
<template>
<h1>Layout Personalizado!</h1>
<div v-if="page.isNotFound">
Página 404 personalizada!
</div>
<Content v-else />
</template>
```
O auxiliar [`useData()`](../reference/runtime-api#usedata) fornece todos os dados em tempo de execução que precisamos para mostrar layouts diferentes. Um dos outros dados que podemos acessar é o frontmatter da página atual. Podemos aproveitar isso para permitir que o usuário final controle o layout em cada página. Por exemplo, o usuário pode indicar que a página deve usar um layout especial de página inicial com:
```md
---
layout: home
---
```
E podemos ajustar nosso tema para lidar com isso:
```vue{3,12-14}
<script setup>
import { useData } from 'vitepress'
const { page, frontmatter } = useData()
</script>
<template>
<h1>Layout Personalizado!</h1>
<div v-if="page.isNotFound">
Página 404 personalizada!
</div>
<div v-if="frontmatter.layout === 'home'">
Página inicial personalizada!
</div>
<Content v-else />
</template>
```
Você pode, é claro, dividir o layout em mais componentes:
```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>Layout Personalizado!</h1>
<NotFound v-if="page.isNotFound" />
<Home v-if="frontmatter.layout === 'home'" />
<Page v-else /> <!-- <Page /> renders <Content /> -->
</template>
```
Consulte a [Referência da API em Tempo de Execução](../reference/runtime-api) para tudo que está disponível em componentes de tema. Além disso, você pode aproveitar [Carregamento de Dados em Tempo de Compilação](./data-loading) para gerar layouts orientados por dados - por exemplo, uma página que lista todas as postagens do blog no projeto atual.
## Distribuindo um Tema Personalizado {#distributing-a-custom-theme}
A maneira mais fácil de distribuir um tema personalizado é fornecê-lo como um [repositório de modelo no GitHub](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-template-repository).
Se você deseja distribuir seu tema como um pacote npm, siga estas etapas:
1. Exporte o objeto do tema como a exportação padrão no seu arquivo de pacote.
2. Se aplicável, exporte a definição de configuração de tipo do tema como `ThemeConfig`.
3. Se seu tema exigir ajustes na configuração VitePress, exporte essa configuração em um subdiretório do pacote (por exemplo, `meu-tema/config`) para que o usuário possa estendê-la.
4. Documente as opções de configuração do tema (tanto via arquivo de configuração quanto em frontmatter).
5. Forneça instruções claras sobre como consumir seu tema (veja abaixo).
## Consumindo um Tema Personalizado {#consuming-a-custom-theme}
Para consumir um tema externo, importe-o e reexporte-o a partir do arquivo de entrada do tema personalizado:
```js
// .vitepress/theme/index.js
import Theme from 'awesome-vitepress-theme'
export default Theme
```
Se o tema precisar ser estendido:
```js
// .vitepress/theme/index.js
import Theme from 'awesome-vitepress-theme'
export default {
extends: Theme,
enhanceApp(ctx) {
// ...
}
}
```
Se o tema exigir uma configuração especial do VitePress, você também precisará estendê-lo em sua própria configuração:
```ts
// .vitepress/theme/config.ts
import baseConfig from 'awesome-vitepress-theme/config'
export default {
// estenda a configuração base do tema (se preciso)
extends: baseConfig
}
```
Finalmente, se o tema fornecer tipos para a configuração do tema:
```ts
// .vitepress/theme/config.ts
import baseConfig from 'awesome-vitepress-theme/config'
import { defineConfigWithTheme } from 'vitepress'
import type { ThemeConfig } from 'awesome-vitepress-theme'
export default defineConfigWithTheme<ThemeConfig>({
extends: baseConfig,
themeConfig: {
// O tipo é `ThemeConfig`
}
})
```

@ -0,0 +1,248 @@
# Carregamento de Dados em Tempo de Compilação {#build-time-data-loading}
VitePress fornece um recurso chamado **carregadores de dado** que permite carregar dados arbitrários e importá-los de páginas ou de componentes. O carregamento de dados é executado **apenas no tempo da construção**: os dados resultantes serão serializados como JSON no pacote JavaScript final.
Os carregadores de dados podem ser usados para buscar dados remotos ou gerar metadados com base em arquivos locais. Por exemplo, você pode usar carregadores de dados para processar todas as suas páginas API locais e gerar automaticamente um índice de todas as entradas da API.
## Uso Básico {#basic-usage}
Um arquivo de carregador de dados deve terminar com `.data.js` ou `.data.ts`. O arquivo deve fornecer uma exportação padrão de um objeto com o método `load()`:
```js
// example.data.js
export default {
load() {
return {
hello: 'world'
}
}
}
```
O módulo do carregador é avaliado apenas no Node.js, então você pode importar APIs Node e dependências npm conforme necessário.
Você pode então importar dados deste arquivo em páginas `.md` e componentes `.vue` usando a exportação nomeada `data`:
```vue
<script setup>
import { data } from './example.data.js'
</script>
<pre>{{ data }}</pre>
```
Saída:
```json
{
"hello": "world"
}
```
Você notará que o próprio carregador de dados não exporta o `data`. É o VitePress chamando o método `load()` nos bastidores e expondo implicitamente o resultado por meio da exportação nomeada `data`.
Isso funciona mesmo se o carregador for assíncrono:
```js
export default {
async load() {
// buscar dados remotos
return (await fetch('...')).json()
}
}
```
## Dados de Arquivos Locais {#data-from-local-files}
Quando você precisa gerar dados com base em arquivos locais, você deve usar a opção `watch` no carregador de dados para que as alterações feitas nesses arquivos possam acionar atualizações rápidas.
A opção `watch` também é conveniente porque você pode usar [padrões glob](https://github.com/mrmlnc/fast-glob#pattern-syntax) para corresponder a vários arquivos. Os padrões podem ser relativos ao próprio arquivo do carregador, e a função `load()` receberá os arquivos correspondentes como caminhos absolutos.
O exemplo a seguir mostra o carregamento de arquivos CSV e a transformação deles em JSON usando [csv-parse](https://github.com/adaltas/node-csv/tree/master/packages/csv-parse/). Como este arquivo só é executado no tempo da construção, você não enviará o procesador CSV para o cliente!
```js
import fs from 'node:fs'
import { parse } from 'csv-parse/sync'
export default {
watch: ['./data/*.csv'],
load(watchedFiles) {
// watchedFiles será um array de caminhos absolutos dos arquivos correspondidos.
// gerar um array de metadados de post que pode ser usada para mostrar
// uma lista no layout do tema
return watchedFiles.map((file) => {
return parse(fs.readFileSync(file, 'utf-8'), {
columns: true,
skip_empty_lines: true
})
})
}
}
```
## `createContentLoader`
Ao construir um site focado em conteúdo, frequentemente precisamos criar uma página de "arquivo" ou "índice": uma página onde listamos todas as entradas disponíveis em nossa coleção de conteúdo, por exemplo, artigos de blog ou páginas de API. Nós **podemos** implementar isso diretamente com a API de carregador de dados, mas como este é um caso de uso tão comum, VitePress também fornece um auxiliar `createContentLoader` para simplificar isso:
```js
// posts.data.js
import { createContentLoader } from 'vitepress'
export default createContentLoader('posts/*.md', /* opções */)
```
O auxiliar aceita um padrão glob relativo ao [diretório fonte](./routing#source-directory) e retorna um objeto de carregador de dados `{ watch, load }` que pode ser usado como exportação padrão em um arquivo de carregador de dados. Ele também implementa cache com base nos selos de data do arquivo para melhorar o desempenho no desenvolvimento.
Note que o carregador só funciona com arquivos Markdown - arquivos não-Markdown correspondidos serão ignorados.
Os dados carregados serão um _array_ com o tipo `ContentData[]`:
```ts
interface ContentData {
// URL mapeada para a página. Ex: /posts/hello.html (não inclui a base)
// itere manualmente ou use `transform` personalizado para normalizar os caminhos
url: string
// dados frontmatter da página
frontmatter: Record<string, any>
// os seguintes estão presentes apenas se as opções relevantes estiverem habilitadas
// discutiremos sobre eles abaixo
src: string | undefined
html: string | undefined
excerpt: string | undefined
}
```
Por padrão, apenas `url` e `frontmatter` são fornecidos. Isso ocorre porque os dados carregados serão incorporados como JSON no pacote do cliente, então precisamos ser cautelosos com seu tamanho. Aqui está um exemplo de como usar os dados para construir uma página de índice de blog mínima:
```vue
<script setup>
import { data as posts } from './posts.data.js'
</script>
<template>
<h1>Todos os posts do blog</h1>
<ul>
<li v-for="post of posts">
<a :href="post.url">{{ post.frontmatter.title }}</a>
<span>por {{ post.frontmatter.author }}</span>
</li>
</ul>
</template>
```
### Opções {#options}
Os dados padrão podem não atender a todas as necessidades - você pode optar por transformar os dados usando opções:
```js
// posts.data.js
import { createContentLoader } from 'vitepress'
export default createContentLoader('posts/*.md', {
includeSrc: true, // incluir fonte markdown crua?
render: true, // incluir HTML completo da página apresentada?
excerpt: true, // incluir excerto?
transform(rawData) {
// mapeie, ordene ou filtre os dados crus conforme quiser.
// o resultado final é o que será enviado ao cliente.
return rawData.sort((a, b) => {
return +new Date(b.frontmatter.date) - +new Date(a.frontmatter.date)
}).map((page) => {
page.src // fonte markdown crua
page.html // HTML completo da página apresentada
page.excerpt // HTML do excerto apresentado (conteúdo acima do primeiro `---`)
return {/* ... */}
})
}
})
```
Veja como é usado no [blog Vue.js](https://github.com/vuejs/blog/blob/main/.vitepress/theme/posts.data.ts).
A API `createContentLoader` também pode ser usada dentro dos [ganchos de construção](../reference/site-config#build-hooks):
```js
// .vitepress/config.js
export default {
async buildEnd() {
const posts = await createContentLoader('posts/*.md').load()
// gerar arquivos com base nos metadados dos posts, por exemplo, feed RSS
}
}
```
**Tipos**
```ts
interface ContentOptions<T = ContentData[]> {
/**
* Incluir src?
* @default false
*/
includeSrc?: boolean
/**
* Renderizar src para HTML e incluir nos dados?
* @default false
*/
render?: boolean
/**
* Se `boolean`, deve-se processar e incluir o resumo? (apresentado como HTML)
*
* Se `function`, controla como o excerto é extraído do conteúdo.
*
* Se `string`, define um separador personalizado a ser usado para extrair o
* excerto. O separador padrão é `---` se `excerpt` for `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
/**
* Transforma os dados. Observe que os dados serão incorporados como JSON no pacote do cliente
* se importados de componentes ou arquivos markdown.
*/
transform?: (data: ContentData[]) => T | Promise<T>
}
```
## Carregadores de Dados com Tipos {#typed-data-loaders}
Ao usar TypeScript, você pode tipar seu carregador e exportar `data` da seguinte forma:
```ts
import { defineLoader } from 'vitepress'
export interface Data {
// tipo de dado
}
declare const data: Data
export { data }
export default defineLoader({
// opções do carregador verificadas pelo tipo
watch: ['...'],
async load(): Promise<Data> {
// ...
}
})
```
## Configuração {#configuration}
Para obter as informações de configuração dentro de um carregador, você pode usar um código como este:
```ts
import type { SiteConfig } from 'vitepress'
const config: SiteConfig = (globalThis as any).VITEPRESS_CONFIG
```

@ -0,0 +1,291 @@
---
outline: deep
---
# Implante seu Site VitePress {#deploy-your-vitepress-site}
Os guias a seguir são baseados em alguns pressupostos:
- O site VitePress está dentro do diretório `docs` do seu projeto.
- Você está usando o diretório de saída de compilação padrão (`.vitepress/dist`).
- VitePress está instalado como uma dependência local em seu projeto, e você configurou os seguintes scripts em seu `package.json`:
```json
{
"scripts": {
"docs:build": "vitepress build docs",
"docs:preview": "vitepress preview docs"
}
}
```
## Compilar e Testar Localmente {#build-and-test-locally}
1. Execute este comando para compilar a documentação:
```sh
$ npm run docs:build
```
2. Após a compilação, veja a prévia local executando:
```sh
$ npm run docs:preview
```
O comando `preview` inicializará um servidor web estático local que servirá o diretório de saída `.vitepress/dist` em `http://localhost:4173`. Você pode usar isso para garantir que tudo esteja correto antes de enviar para produção.
3. Você pode configurar a porta do servidor passando `--port` como argumento.
```json
{
"scripts": {
"docs:preview": "vitepress preview docs --port 8080"
}
}
```
Agora o método `docs:preview` implantará o servidor em `http://localhost:8080`.
## Configurando um Caminho Base Público {#setting-a-public-base-path}
Por padrão, assumimos que o site será implantado no caminho raiz de um domínio (`/`). Se seu site for servido em um subcaminho, por exemplo, `https://meusite.com/blog/`, você precisa então configurar a opção [`base`](../reference/site-config#base) para `'/blog/'` na configuração VitePress.
**Exemplo:** Ao usar GitHub Pages (ou GitLab Pages) e implantar em `user.github.io/repo/`, defina seu `base` como `/repo/`.
## Cabeçalhos de Cache HTTP {#http-cache-headers}
Se você tiver controle sobre os cabeçalhos HTTP de seu servidor em produção, pode-se configurar cabeçalhos `cache-control` para obter melhor desempenho em visitas repetidas.
A compilação de produção usa nomes de arquivos com hash para ativos estáticos (JavaScript, CSS e outros ativos importados que não estão em `public`). Se você inspecionar a prévia de produção usando as ferramentas de desenvolvedor do seu nevegador na aba rede, verá arquivos como `app.4f283b18.js`.
Este hash `4f283b18` é gerado a partir do conteúdo deste arquivo. A mesma URL com hash é garantida para servir o mesmo conteúdo do arquivo - se o conteúdo mudar, as URLs também mudam. Isso significa que você pode usar com segurança os cabeçalhos de cache mais fortes para esses arquivos. Todos esses arquivos serão colocados em `assets/` no diretório de saída, então você pode configurar o seguinte cabeçalho para eles:
```
Cache-Control: max-age=31536000,immutable
```
::: details Exemplo de arquivo `_headers` do Netlify
```
/assets/*
cache-control: max-age=31536000
cache-control: immutable
```
Nota: o arquivo `_headers` deve ser colocado no [diretório public](./asset-handling#the-public-directory) - em nosso caso, `docs/public/_headers` - para que ele seja copiado exatamente para o diretório de saída.
[Documentação de cabeçalhos personalizados do Netlify](https://docs.netlify.com/routing/headers/)
:::
::: details Exemplo de configuração Vercel em `vercel.json`
```json
{
"headers": [
{
"source": "/assets/(.*)",
"headers": [
{
"key": "Cache-Control",
"value": "max-age=31536000, immutable"
}
]
}
]
}
```
Nota: o arquivo `vercel.json` deve ser colocado na raiz do seu **repositório**.
[Documentação Vercel sobre configuração de cabeçalhos](https://vercel.com/docs/concepts/projects/project-configuration#headers)
:::
## Guias de Plataforma {#platform-guides}
### Netlify / Vercel / Cloudflare Pages / AWS Amplify / Render
Configure um novo projeto e altere estas configurações usando seu painel:
- **Comando de Compilação:** `npm run docs:build`
- **Diretório de Saída:** `docs/.vitepress/dist`
- **Versão do Node:** `18` (ou superior)
::: warning
Não ative opções como _Auto Minify_ para código HTML. Isso removerá comentários da saída que têm significado para Vue. Haverão erros de incompatibilidade de hidratação se forem removidos.
:::
### GitHub Pages
1. Crie um arquivo chamado `deploy.yml` dentro do diretório `.github/workflows` do seu projeto com algum conteúdo como este:
```yaml
# Exemplo de fluxo de trabalho para compilar e implantar um site VitePress no GitHub Pages
#
name: Implante o site VitePress no Pages
on:
# Executa em pushes direcionados à branch `main`.
# Altere para `master` se estiver usando a branch `master` como padrão.
push:
branches: [main]
# Permite executar manualmente este fluxo de trabalho na guia Actions
workflow_dispatch:
# Define permissões GITHUB_TOKEN para a implantação no GitHub Pages
permissions:
contents: read
pages: write
id-token: write
# Permite apenas uma implantação simultânea, pulando execuções em fila entre a execução em andamento e a última da fila.
# No entanto, NÃO cancela execuções em andamento, pois queremos permitir que essas implantações de produção sejam concluídas.
concurrency:
group: pages
cancel-in-progress: false
jobs:
# Trabalho de compilação
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0 # Não necessário se lastUpdated não estiver habilitado
# - uses: pnpm/action-setup@v3 # Descomente isso se estiver usando pnpm
# - uses: oven-sh/setup-bun@v1 # Descomente isso se estiver usando Bun
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm # ou pnpm / yarn
- name: Setup Pages
uses: actions/configure-pages@v4
- name: Install dependencies
run: npm ci # ou pnpm install / yarn install / bun install
- name: Build with VitePress
run: |
npm run docs:build # ou pnpm docs:build / yarn docs:build / bun run docs:build
touch docs/.vitepress/dist/.nojekyll
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: docs/.vitepress/dist
# Trabalho de implantação
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
Certifique-se de que a opção `base` em seu VitePress esteja configurada corretamente. Veja [Configurando um Caminho Base Público](#setting-a-public-base-path) para mais detalhes.
:::
2. Nas configurações do seu repositório sob o item do menu "Pages", selecione "GitHub Actions" em "Build and deployment > Source".
3. Envie suas alterações para a branch `main` e aguarde a conclusão do fluxo de trabalho do GitHub Actions. Você verá seu site implantado em `https://<username>.github.io/[repository]/` ou `https://<custom-domain>/` dependendo das suas configurações. Seu site será implantado automaticamente em cada push para a branch `main`.
### GitLab Pages
1. Defina `outDir` na configuração VitePress como `../public`. Configure a opção `base` para `'/<repository>/'` se você deseja implantar em `https://<username>.gitlab.io/<repository>/`.
2. Crie um arquivo chamado `.gitlab-ci.yml` na raiz do seu projeto com o conteúdo abaixo. Isso construirá e implantará seu site sempre que você fizer alterações no conteúdo:
```yaml
image: node:18
pages:
cache:
paths:
- node_modules/
script:
# - apk add git # Descomente isso se estiver usando imagens pequenas do Docker como o Alpine e tiver lastUpdated habilitado
- npm install
- npm run docs:build
artifacts:
paths:
- public
only:
- main
```
### Azure Static Web Apps {#azure-static-web-apps}
1. Siga a [documentação oficial](https://docs.microsoft.com/en-us/azure/static-web-apps/build-configuration).
2. Configure esses valores em seu arquivo de configuração (e remova aqueles que você não precisa, como `api_location`):
- **`app_location`**: `/`
- **`output_location`**: `docs/.vitepress/dist`
- **`app_build_command`**: `npm run docs:build`
### Firebase {#firebase}
1. Crie `firebase.json` e `.firebaserc` na raiz do seu projeto:
`firebase.json`:
```json
{
"hosting": {
"public": "docs/.vitepress/dist",
"ignore": []
}
}
```
`.firebaserc`:
```json
{
"projects": {
"default": "<SEU_ID_FIREBASE>"
}
}
```
2. Após executar `npm run docs:build`, execute este comando para implantar:
```sh
firebase deploy
```
### Surge
1. Após executar `npm run docs:build`, execute este comando para implantar:
```sh
npx surge docs/.vitepress/dist
```
### Heroku
1. Siga a documentação e o guia fornecidos em [`heroku-buildpack-static`](https://elements.heroku.com/buildpacks/heroku/heroku-buildpack-static).
2. Crie um arquivo chamado `static.json` na raiz do seu projeto com o conteúdo abaixo:
```json
{
"root": "docs/.vitepress/dist"
}
```
### Edgio
Consulte [Criar e Implantar um Aplicativo VitePress no Edgio](https://docs.edg.io/guides/vitepress).
### Kinsta Static Site Hosting {#kinsta-static-site-hosting}
Você pode implantar seu site Vitepress em [Kinsta](https://kinsta.com/static-site-hosting/) seguindo estas [instruções](https://kinsta.com/docs/vitepress-static-site-example/).

@ -0,0 +1,340 @@
---
outline: deep
---
# Estendendo o Tema Padrão {#extending-the-default-theme}
O tema padrão do VitePress é otimizado para documentação e pode ser personalizado. Consulte a [Visão Geral de Configuração do Tema Padrão](../reference/default-theme-config) para uma lista abrangente de opções.
No entanto, há casos em que apenas a configuração não será suficiente. Por exemplo:
1. É necessário ajustar a estilização CSS;
2. É necessário modificar a instância da aplicação Vue, por exemplo para registrar componentes globais;
3. É necessário injetar conteúdo personalizado no tema por meio de _slots_ no layout.
Essas personalizações avançadas exigirão o uso de um tema personalizado que "estende" o tema padrão.
::: tip
Antes de prosseguir, certifique-se de ler primeiro [Usando um Tema Personalizado](./custom-theme) para entender como temas personalizados funcionam.
:::
## Personalizando o CSS {#customizing-css}
O CSS do tema padrão pode ser personalizado substituindo as variáveis CSS no nível raiz:
```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;
}
```
Veja as [variáveis CSS do tema padrão](https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css) que podem ser substituídas.
## Usando Fontes Diferentes {#using-different-fonts}
VitePress usa [Inter](https://rsms.me/inter/) como fonte padrão e incluirá as fontes na saída de compilação. A fonte também é pré-carregada automaticamente em produção. No entanto, isso pode não ser desejável se você quiser usar uma fonte principal diferente.
Para evitar a inclusão de Inter na saída de compilação, importe o tema de `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: /* fonte de texto normal */
--vp-font-family-mono: /* fonte de código */
}
```
::: warning
Se estiver usando componentes opcionais como os componentes da [Página da Equipe](../reference/default-theme-team-page), certifique-se de também importá-los de `vitepress/theme-without-fonts`!
:::
Se a sua fonte é um arquivo local referenciado via `@font-face`, ela será processada como um ativo e incluída em `.vitepress/dist/assets` com um nome de arquivo hash. Para pré-carregar esse arquivo, use o gancho de construção [transformHead](../reference/site-config#transformhead):
```js
// .vitepress/config.js
export default {
transformHead({ assets }) {
// ajuste o regex para corresponder à sua fonte
const myFontFile = assets.find(file => /font-name\.\w+\.woff2/)
if (myFontFile) {
return [
[
'link',
{
rel: 'preload',
href: myFontFile,
as: 'font',
type: 'font/woff2',
crossorigin: ''
}
]
]
}
}
}
```
## Registrando Componentes Globais {#registering-global-components}
```js
// .vitepress/theme/index.js
import DefaultTheme from 'vitepress/theme'
/** @type {import('vitepress').Theme} */
export default {
extends: DefaultTheme,
enhanceApp({ app }) {
// registre seus componentes globais personalizados
app.component('MyGlobalComponent' /* ... */)
}
}
```
Se estiver usando TypeScript:
```ts
// .vitepress/theme/index.ts
import type { Theme } from 'vitepress'
import DefaultTheme from 'vitepress/theme'
export default {
extends: DefaultTheme,
enhanceApp({ app }) {
// registre seus componentes globais personalizados
app.component('MyGlobalComponent' /* ... */)
}
} satisfies Theme
```
Como estamos usando Vite, você também pode aproveitar a [funcionalidade de importação glob](https://vitejs.dev/guide/features.html#glob-import) do Vite para registrar automaticamente um diretório de componentes.
## _Slots_ no Layout {#layout-slots}
O componente `<Layout/>` do tema padrão possui alguns _slots_ que podem ser usados para injetar conteúdo em locais específicos da página. Aqui está um exemplo de como injetar um componente antes do esquema :
```js
// .vitepress/theme/index.js
import DefaultTheme from 'vitepress/theme'
import MyLayout from './MyLayout.vue'
export default {
extends: DefaultTheme,
// substitua o Layout por um componente envolvente que
// injeta os slots
Layout: MyLayout
}
```
```vue
<!--.vitepress/theme/MyLayout.vue-->
<script setup>
import DefaultTheme from 'vitepress/theme'
const { Layout } = DefaultTheme
</script>
<template>
<Layout>
<template #aside-outline-before>
Meu conteúdo personalizado superior da barra lateral
</template>
</Layout>
</template>
```
Ou você também pode usar a função _render_.
```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)
})
}
}
```
Lista completa de _slots_ disponíveis no layout do tema padrão:
- Quando `layout: 'doc'` (padrão) está habilitado via 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`
- Quando `layout: 'home'` está habilitado via frontmatter:
- `home-hero-before`
- `home-hero-info-before`
- `home-hero-info`
- `home-hero-actions-after`
- `home-hero-image`
- `home-hero-after`
- `home-features-before`
- `home-features-after`
- Quando `layout: 'page'` está habilitado via frontmatter:
- `page-top`
- `page-bottom`
- Na página não encontrada (404):
- `not-found`
- Sempre:
- `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`
## Usando a API View Transitions
### Na Alternância de Aparência {#on-appearance-toggle}
Você pode estender o tema padrão para fornecer uma transição personalizada quando o modo de cor é alternado. Um exemplo:
```vue
<!-- .vitepress/theme/Layout.vue -->
<script setup lang="ts">
import { useData } from 'vitepress'
import DefaultTheme from 'vitepress/theme'
import { nextTick, provide } from 'vue'
const { isDark } = useData()
const enableTransitions = () =>
'startViewTransition' in document &&
window.matchMedia('(prefers-reduced-motion: no-preference)').matches
provide('toggle-appearance', async ({ clientX: x, clientY: y }: MouseEvent) => {
if (!enableTransitions()) {
isDark.value = !isDark.value
return
}
const clipPath = [
`circle(0px at ${x}px ${y}px)`,
`circle(${Math.hypot(
Math.max(x, innerWidth - x),
Math.max(y, innerHeight - y)
)}px at ${x}px ${y}px)`
]
await document.startViewTransition(async () => {
isDark.value = !isDark.value
await nextTick()
}).ready
document.documentElement.animate(
{ clipPath: isDark.value ? clipPath.reverse() : clipPath },
{
duration: 300,
easing: 'ease-in',
pseudoElement: `::view-transition-${isDark.value ? 'old' : 'new'}(root)`
}
)
})
</script>
<template>
<DefaultTheme.Layout />
</template>
<style>
::view-transition-old(root),
::view-transition-new(root) {
animation: none;
mix-blend-mode: normal;
}
::view-transition-old(root),
.dark::view-transition-new(root) {
z-index: 1;
}
::view-transition-new(root),
.dark::view-transition-old(root) {
z-index: 9999;
}
.VPSwitchAppearance {
width: 22px !important;
}
.VPSwitchAppearance .check {
transform: none !important;
}
</style>
```
Resultado (**atenção!**: cores piscantes, movimentos súbitos, luzes brilhantes):
<details>
<summary>Demo</summary>
![Demo de Transição de Alternância de Aparência](/appearance-toggle-transition.webp)
</details>
Consulte [Chrome Docs](https://developer.chrome.com/docs/web-platform/view-transitions/) para mais detalhes sobre _view transitions_.
### Na Mudança de Rota {#on-route-change}
Em breve.
## Substituindo Componentes Internos {#overriding-internal-components}
Você pode usar os [aliases](https://vitejs.dev/config/shared-options.html#resolve-alias) Vite para substituir os componentes do tema padrão pelos seus personalizados:
```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)
)
}
]
}
}
})
```
Para saber o nome exato do componente consulte [nosso código fonte](https://github.com/vuejs/vitepress/tree/main/src/client/theme-default/components). Como os componentes são internos, há uma pequena chance de que o nome deles seja atualizado entre lançamentos secundários.

@ -0,0 +1,48 @@
# Frontmatter
## Utilização {#usage}
VitePress suporta frontmatter YAML em todos os arquivos Markdown, processando-os com [gray-matter](https://github.com/jonschlinkert/gray-matter). O frontmatter deve estar no topo do arquivo Markdown (antes de qualquer elemento, incluindo tags `<script>`), e deve ter a forma de um YAML válido entre linhas com traços triplos. Exemplo:
```md
---
title: Documentação com VitePress
editLink: true
---
```
Muitas opções de configuração do site ou do tema padrão têm opções correspondentes no frontmatter. Você pode usar o frontmatter para sobrepor um comportamento específico apenas para a página atual. Para mais detalhes, veja [Referência de Configuração do Frontmatter](../reference/frontmatter-config).
Você também pode definir dados próprios frontmatter personalizados, para serem usados em expressões Vue dinâmicas na página.
## Acesso aos Dados do Frontmatter {#accessing-frontmatter-data}
Os dados do frontmatter podem ser acessados por meio da variável global especial `$frontmatter`:
Aqui está um exemplo de como você poderia usá-lo em seu arquivo Markdown:
```md
---
title: Documentação com VitePress
editLink: true
---
# {{ $frontmatter.title }}
Conteúdo do guia
```
Você também pode acessar os dados do frontmatter da página atual em `<script setup>` com o auxiliar [`useData()`](../reference/runtime-api#usedata).
## Formatos Alternativos do Frontmatter {#alternative-frontmatter-formats}
VitePress também suporta a sintaxe frontmatter JSON, começando e terminando com chaves:
```json
---
{
"title": "Criando blog como um hacker",
"editLink": true
}
---
```

@ -0,0 +1,216 @@
# Iniciando {#getting-started}
## Experimente Online {#try-it-online}
Você pode experimentar VitePress diretamente no seu navegador em [StackBlitz](https://vitepress.new).
## Instalação {#installation}
### Pré-requisitos {#prerequisites}
- [Node.js](https://nodejs.org/) na versão 18 ou superior.
- Terminal para acessar VitePress através da sua interface de linha de comando (CLI).
- Editor de texto com suporte a sintaxe [Markdown](https://en.wikipedia.org/wiki/Markdown).
- [VSCode](https://code.visualstudio.com/) é recomendado, junto com a [extensão oficial Vue](https://marketplace.visualstudio.com/items?itemName=Vue.volar).
VitePress pode ser usado sozinho, ou ser instalado em um projeto já existente. Em ambos os casos, você pode instalá-lo com:
::: code-group
```sh [npm]
$ npm add -D vitepress
```
```sh [pnpm]
$ pnpm add -D vitepress
```
```sh [yarn]
$ yarn add -D vitepress
```
```sh [bun]
$ bun add -D vitepress
```
:::
::: details Está recebendo avisos sobre dependências correspondentes ausentes?
Se usar PNPM, você perceberá um aviso de ausência de `@docsearch/js`. Isso não evita que o VitePress funcione. Se você deseja suprimir este aviso, adicione o seguinte no seu `package.json`:
```json
"pnpm": {
"peerDependencyRules": {
"ignoreMissing": [
"@algolia/client-search",
"search-insights"
]
}
}
```
:::
::: tip NOTA
VitePress é um pacote apenas para ESM. Não use `require()` para importá-lo, e certifique de que o `package.json` mais próximo contém `"type": "module"`, ou mude a extensão do arquivo de seus arquivos releavantes como `.vitepress/config.js` para `.mjs`/`.mts`. Refira-se ao [Guia de resolução de problemas Vite](http://vitejs.dev/guide/troubleshooting.html#this-package-is-esm-only) para mais detalhes. Além disso, dentro de contextos de JavaScript comum assíncronos, você pode usar `await import('vitepress')`.
:::
### Assistente de Instalação {#setup-wizard}
VitePress tem embutido um assistente de instalação pela linha de comando que irá ajudar a construir um projeto básico. Depois da instalação, inicie o assistente rodando:
::: code-group
```sh [npm]
$ npx vitepress init
```
```sh [pnpm]
$ pnpm vitepress init
```
```sh [yarn]
$ yarn vitepress init
```
```sh [bun]
$ bun vitepress init
```
:::
Você será cumprimentado com algumas perguntas simples:
<<< @/snippets/init.ansi
::: tip Vue como Dependência Correspondente
Se você tem a intenção de realizar personalização que usa componentes Vue ou APIs, você deve instalar explicitamente `vue` como uma dependência correspondente.
:::
## Estrutura de Arquivos {#file-structure}
Se você estiver construindo um site VitePress individual, você pode desenvolver seu site no diretório atual (`./`). Entretanto, se você está instalando VitePress em um projeto existente juntamente com outro código fonte, é recomendado construir o site em um diretório aninhado (e.g. `./docs`) para que esteja separado do resto do seu projeto.
Assumindo qa escolha de desenvolver o projeto VitePress em `./docs`, a estrutura de arquivos gerada deve parecer com a seguinte:
```
.
├─ docs
│ ├─ .vitepress
│ │ └─ config.js
│ ├─ api-examples.md
│ ├─ markdown-examples.md
│ └─ index.md
└─ package.json
```
O diretório `docs` é considerado a **raiz do projeto** do seu site VitePress. O diretório `.vitepress` é um local reservado para arquivos de configuração VitePress, cache do servidor de desenvolvimento, resultados da build, e código de personalização de tema opcional.
::: tip
Por padrão, VitePress armazena o cache do servidor de desenvolvimento em `.vitepress/cache`, e o resultado da build de produção em `.vitepress/dist`. Se usar Git, você deve adicioná-los ao seu arquivo `.gitignore`. Estes locais também podem ser [configurados](../reference/site-config#outdir).
:::
### O arquivo de configuração {#the-config-file}
O arquivo de configuração (`.vitepress/config.js`) permite que você personalize vários aspectos do seu site VitePress, com as opções mais básicas sendo o título e a descrição do site:
```js
// .vitepress/config.js
export default {
// opções a nível do site
title: 'VitePress',
description: 'Só uma brincadeira.',
themeConfig: {
// opções a nível do tema
}
}
```
Você também pode configurar o comportamento do tema através da opção `themeConfig`. Consulte a [Referência de Configuração](../reference/site-config) para detalhes completos sobre todas as opções de configuração.
### Arquivos Fonte {#source-files}
Arquivos Markdown fora do diretório `.vitepress` são considerados **arquivos fonte**.
VitePress usa **roteamento baseado em arquivos**: cada arquivo `.md` é compilado em um arquivo correspondente `.html` com o mesmo caminho. Por exemplo, `index.md` será compilado em `index.html`, e pode ser visitado no caminho raiz `/` do site VitePress resultante.
VitePress também fornece a habilidade de gerar URLs limpas, reescrever caminhos, e gerar páginas dinamicamente. Estes serão tratados no [Guia de Roteamento](./routing).
## Instalado e Funcionando {#up-and-running}
A ferramenta deve ter também injetado os seguintes scripts npm no seu `package.json` se você permitiu isso durante o processo de instalação:
```json
{
...
"scripts": {
"docs:dev": "vitepress dev docs",
"docs:build": "vitepress build docs",
"docs:preview": "vitepress preview docs"
},
...
}
```
O script `docs:dev` iniciará um servidor de desenvolvimento local com atualizações instantâneas. Rode-o com o seguinte comando:
::: 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
```
:::
Em vez de scripts npm, você também pode invocar VitePress diretamente com:
::: 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
```
:::
Mais usos da linha de comando estão documentados na [Referência CLI](../reference/cli).
O servidor de desenvolvimento deve estar rodando em `http://localhost:5173`. Visite a URL no seu navegador para ver o seu novo site em ação!
## O que vem depois? {#what-s-next}
- Para melhor entender como arquivos markdown são mapeados no HTML gerado, prossiga para o [Guia de Roteamento](./routing).
- Para descobrir mais sobre o que você pode fazer em uma página, como escrever conteúdo markdown ou usar um componente Vue, refira-se a seção "Escrevendo" do guia. Um ótimo lugar para começar seria aprendendo mais sobre [Extensões Markdown](./markdown).
- Para explorar as funcionalidades fornecidas pelo tema padrão da documentação, confira a [Referência de Configuração do Tema Padrão](../reference/default-theme-config).
- Se você quer aprofundar a personalização da aparência do seu site, explore tanto em [Estenda o Tema Padrão](./extending-default-theme) como [Construa um Tema Personalizado](./custom-theme).
- Uma vez que sua documentação tomar forma, certifique-se de ler o [Guia de Lançamento](./deploy).

@ -0,0 +1,113 @@
# Internacionalização {#internationalization}
Para usar recursos de i18n integrados, é necessário criar uma estrutura de diretórios da seguinte forma:
```
docs/
├─ es/
│ ├─ foo.md
├─ fr/
│ ├─ foo.md
├─ foo.md
```
Em seguida, no arquivo `docs/.vitepress/config.ts`:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
// propriedades compartilhadas e outras coisas de nível superior...
locales: {
root: {
label: 'English',
lang: 'en'
},
fr: {
label: 'French',
lang: 'fr', // opcional, será adicionado como atributo `lang` na tag `html`
link: '/fr/guide' // padrão /fr/ -- aparece no menu de traduções da barra de navegação, pode ser externo
// outras propriedades específicas de cada idioma...
}
}
})
```
As seguintes propriedades podem ser substituídas para cada idioma (incluindo a raiz):
```ts
interface LocaleSpecificConfig<ThemeConfig = any> {
lang?: string
dir?: string
title?: string
titleTemplate?: string | boolean
description?: string
head?: HeadConfig[] // será mesclado com as entradas head existentes, as metatags duplicadas são removidas automaticamente
themeConfig?: ThemeConfig // será mesclado superficialmente, coisas comuns podem ser colocadas na entrada de n[ivel superior de themeConfig
}
```
Consulte a interface [`DefaultTheme.Config`](https://github.com/vuejs/vitepress/blob/main/types/default-theme.d.ts) para obter detalhes sobre a personalização dos textos marcadores do tema padrão. Não substitua `themeConfig.algolia` ou `themeConfig.carbonAds` no nível do idioma. Consulte a [documentação Algolia](../reference/default-theme-search#i18n) para usar a pesquisa multilínguas.
**Dica profissional:** O arquivo de configuração pode ser armazenado em `docs/.vitepress/config/index.ts` também. Isso pode ajudar a organizar as coisas criando um arquivo de configuração por idioma e então mesclá-los e exportá-los a partir de `index.ts`.
## Diretório separado para cada localização {#separate-directory-for-each-locale}
A seguinte estrutura é totalmente válida:
```
docs/
├─ en/
│ ├─ foo.md
├─ es/
│ ├─ foo.md
├─ fr/
├─ foo.md
```
No entanto, VitePress não redirecionará `/` para `/en/` por padrão. Você precisará configurar seu servidor para isso. Por exemplo, no Netlify, você pode adicionar um arquivo `docs/public/_redirects` assim:
```
/* /es/:splat 302 Language=es
/* /fr/:splat 302 Language=fr
/* /en/:splat 302
```
**Dica profissional:** Se estiver usando a abordagem acima, você pode usar o cookie `nf_lang` para persistir a escolha de idioma do usuário:
```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>
```
## Suporte a RTL (Experimental) {#rtl-support-experimental}
Para suporte a RTL (Right to Left), especifique `dir: 'rtl'` na configuração e use algum plugin RTLCSS PostCSS como <https://github.com/MohammadYounes/rtlcss>, <https://github.com/vkalinichev/postcss-rtl> ou <https://github.com/elchininet/postcss-rtlcss>. Você precisará configurar seu plugin PostCSS para usar `:where([dir="ltr"])` e `:where([dir="rtl"])` como prefixos para evitar problemas de especificidade CSS.

@ -0,0 +1,929 @@
# Extensões Markdown {#markdown-extensions}
VitePress vem com Extensões Markdown embutidas.
## Âncoras de Cabeçalho {#header-anchors}
Cabeçalhos recebem a aplicação automaticamente de links âncora. A apresentação das âncoras pode ser configurada usando a opção `markdown.anchor`.
### Âncoras personalizadas {#custom-anchors}
Para especificar uma _tag_ âncora personalizada para um cabeçalho em vez de usar aquela gerada automaticamente, adicione um sufixo ao cabeçalho:
```
# Usando âncoras personalizadas {#minha-ancora}
```
Isso permite que você tenha um link do cabeçalho como `#minha-ancora` em vez do padrão `#usando-ancoras-personalizadas`.
## Links {#links}
Ambos os links internos e externos recebem tratamento especial.
### Links Internos {#internal-links}
Os links internos são convertidos em links de roteador para navegação SPA. Além disso, todo arquivo `index.md` contido em cada subdiretório será automaticamente convertido para `index.html`, com a URL correspondente `/`.
Por exemplo, dada a seguinte estrutura de diretórios:
```
.
├─ index.md
├─ foo
│ ├─ index.md
│ ├─ one.md
│ └─ two.md
└─ bar
├─ index.md
├─ three.md
└─ four.md
```
E supondo que você esteja em `foo/one.md`:
```md
[Página Inicial](/) <!-- leva o usuário ao index.md raiz -->
[foo](/foo/) <!-- leva o usuário ao index.html do diretório foo -->
[foo heading](./#heading) <!-- ancora o usuário a um cabeçalho do arquivo índice foo -->
[bar - three](../bar/three) <!-- você pode omitir a extensão -->
[bar - three](../bar/three.md) <!-- você pode adicionar .md -->
[bar - four](../bar/four.html) <!-- ou você pode adicionar .html -->
```
### Sufixo de Página {#page-suffix}
Páginas e links internos são gerados com o sufixo `.html` por padrão.
### Links Externos {#external-links}
Links externos recebem automaticamente `target="_blank" rel="noreferrer"`:
- [vuejs.org](https://vuejs.org)
- [VitePress no GitHub](https://github.com/vuejs/vitepress)
## Frontmatter {#frontmatter}
[YAML frontmatter](https://jekyllrb.com/docs/front-matter/) é suportado por padrão:
```yaml
---
título: Escrevendo como um Hacker
idioma: pt-BR
---
```
Esses dados estarão disponíveis para o restante da página, junto com todos os componentes personalizados e de temas.
Para mais detalhes, veja [Frontmatter](../reference/frontmatter-config).
## Tabelas ao Estilo GitHub {#github-style-tables}
**Entrada**
```md
| Tabelas | São | Legais |
| ------------- | :-----------: | ----: |
| col 3 está | à direita | $1600 |
| col 2 está | centralizada | $12 |
| listras | são legais | $1 |
```
**Saída**
| Tabelas | São | Legais |
| ------------- | :-----------: | -----: |
| col 3 está | à direita | \$1600 |
| col 2 está | centralizada | \$12 |
| listras | são legais | \$1 |
## Emoji :tada:
**Entrada**
```
:tada: :100:
```
**Saída**
:tada: :100:
Uma [lista de todos os emojis](https://github.com/markdown-it/markdown-it-emoji/blob/master/lib/data/full.mjs) está disponível.
## Tabela de Conteúdo (TOC)
**Entrada**
```
[[toc]]
```
**Saída**
[[toc]]
A apresentação de TOC (Table of Contents) pode ser configurada usando a opção `markdown.toc`.
## Recipientes Personalizados {#custom-containers}
Recipientes personalizados podem ser definidos por seus tipos, títulos e conteúdos.
### Título Padrão {#default-title}
**Entrada**
```md
::: info
Este é um bloco de informações.
:::
::: tip
Este é um aviso.
:::
::: warning
Este é um aviso.
:::
::: danger
Este é um aviso de perigo.
:::
::: details
Este é um bloco de detalhes.
:::
```
**Saída**
::: info
Este é um bloco de informações.
:::
::: tip
Este é um aviso.
:::
::: warning
Este é um aviso.
:::
::: danger
Este é um aviso de perigo.
:::
::: details
Este é um bloco de detalhes.
:::
### Título Personalizado {#custom-title}
Você pode definir um título personalizado adicionando o texto imediatamente após o "tipo" do recipiente.
**Entrada**
```md
::: danger STOP
Zona de perigo, não prossiga
:::
::: details Clique para ver o código
```js
console.log('Olá, VitePress!')
```
:::
```
**Saída**
::: danger STOP
Zona de perigo, não prossiga
:::
::: details Clique para ver o código
```js
console.log('Olá, VitePress!')
```
:::
Além disso, você pode definir títulos personalizados globalmente adicionando o seguinte conteúdo no arquivo de configuração do site, útil se não estiver escrevendo em inglês:
```ts
// config.ts
export default defineConfig({
// ...
markdown: {
container: {
tipLabel: '提示',
warningLabel: '警告',
dangerLabel: '危险',
infoLabel: '信息',
detailsLabel: '详细信息'
}
}
// ...
})
```
### `raw`
Este é um recipiente especial que pode ser usado para evitar conflitos de estilo e roteador com VitePress. Isso é especialmente útil ao documentar bibliotecas de componentes. Você também pode verificar [whyframe](https://whyframe.dev/docs/integrations/vitepress) para melhor isolamento.
**Sintaxe**
```md
::: raw
Envolve em um <div class="vp-raw">
:::
```
A classe `vp-raw` também pode ser usada diretamente em elementos. O isolamento de estilo é atualmente opcional:
- Instale o `postcss` com seu gerenciador de pacotes preferido:
```sh
$ npm add -D postcss
```
- Crie um arquivo chamado `docs/postcss.config.mjs` e adicione o seguinte:
```js
import { postcssIsolateStyles } from 'vitepress'
export default {
plugins: [postcssIsolateStyles()]
}
```
Ele utiliza [`postcss-prefix-selector`](https://github.com/postcss/postcss-load-config) internamente. Você pode passar opções assim:
```js
postcssIsolateStyles({
includeFiles: [/vp-doc\.css/] // o padrão é /base\.css/
})
```
## Alertas no estilo GitHub {#github-flavored-alerts}
VitePress também suporta [alertas no estilo 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) para apresentar como um bloco de chamada. Eles serão apresentados da mesma forma que [elementos personalizados](#custom-containers).
```md
> [!NOTE]
> Destaca informações que os usuários devem levar em consideração, mesmo ao ler rapidamente.
> [!TIP]
> Informações opcionais para ajudar o usuário a ter mais sucesso.
> [!IMPORTANT]
> Informações cruciais necessárias para que os usuários tenham sucesso.
> [!WARNING]
> Conteúdo crítico exigindo atenção imediata do usuário devido a riscos potenciais.
> [!CAUTION]
> Potenciais consequências negativas de uma ação.
```
> [!NOTE]
> Destaca informações que os usuários devem levar em consideração, mesmo ao ler rapidamente.
> [!TIP]
> Informações opcionais para ajudar o usuário a ter mais sucesso.
> [!IMPORTANT]
> Informações cruciais necessárias para que os usuários tenham sucesso.
> [!WARNING]
> Conteúdo crítico exigindo atenção imediata do usuário devido a riscos potenciais.
> [!CAUTION]
> Potenciais consequências negativas de uma ação.
## Destaque de Sintaxe em Blocos de Código {#syntax-highlighting-in-code-blocks}
VitePress utiliza [Shiki](https://github.com/shikijs/shiki) para destacar a sintaxe da linguagem em blocos de código Markdown, usando texto colorido. Shiki suporta uma ampla variedade de linguagens de programação. Tudo o que você precisa fazer é adicionar um _alias_ de linguagem válido após os crases iniciais do bloco de código:
**Entrada**
````
```js
export default {
name: 'MyComponent',
// ...
}
```
````
````
```html
<ul>
<li v-for="todo in todos" :key="todo.id">
{{ todo.text }}
</li>
</ul>
```
````
**Saída**
```js
export default {
name: 'MyComponent'
// ...
}
```
```html
<ul>
<li v-for="todo in todos" :key="todo.id">
{{ todo.text }}
</li>
</ul>
```
Uma [lista de linguagens válidas](https://shiki.style/languages) está disponível no repositório Shiki.
Você também pode personalizar o tema de destaque de sintaxe na configuração do aplicativo. Consulte as [opções `markdown`](../reference/site-config#markdown) para mais detalhes.
## Destaque de Linha em Blocos de Código {#line-highlighting-in-code-blocks}
**Entrada**
````
```js{4}
export default {
data () {
return {
msg: 'Destacado!'
}
}
}
```
````
**Saída**
```js{4}
export default {
data () {
return {
msg: 'Destacado!'
}
}
}
```
Além de uma única linha, você também pode especificar múltiplas linhas únicas, intervalos, ou ambos:
- Intervalos de linha: por exemplo, `{5-8}`, `{3-10}`, `{10-17}`
- Múltiplas linhas únicas: por exemplo, `{4,7,9}`
- Intervalos de linha e linhas únicas: por exemplo, `{4,7-13,16,23-27,40}`
**Entrada**
````
```js{1,4,6-8}
export default { // Destacado
data () {
return {
msg: `Destacado!
Esta linha não está destacada,
mas esta e as próximas 2 estão.`,
motd: 'VitePress é incrível',
lorem: 'ipsum'
}
}
}
```
````
**Saída**
```js{1,4,6-8}
export default { // Destacado
data () {
return {
msg: `Destacado!
Esta linha não está destacada,
mas esta e as próximas 2 estão.`,
motd: 'VitePress é incrível',
lorem: 'ipsum',
}
}
}
```
Alternativamente, é possível destacar diretamente na linha usando o comentário `// [!code highlight]`.
**Entrada**
````
```js
export default {
data () {
return {
msg: 'Destacado!' // [!!code highlight]
}
}
}
```
````
**Saída**
```js
export default {
data() {
return {
msg: 'Destacado!' // [!code destaque]
}
}
}
```
## Foco em Blocos de Código {#focus-in-code-blocks}
Adicionando o comentário `// [!code focus]` em uma linha irá destacá-la e desfocar as outras partes do código.
Além disso, você pode definir o número de linhas para focar usando `// [!code focus:<linhas>]`.
**Entrada**
````
```js
export default {
data () {
return {
msg: 'Focado!' // [!!code focus]
}
}
}
```
````
**Saída**
```js
export default {
data() {
return {
msg: 'Focado!' // [!code focus]
}
}
}
```
## Diferenças Coloridas em Blocos de Código {#colored-diffs-in-code-blocks}
Adicionar os comentários `// [!code --]` ou `// [!code ++]` em uma linha criará uma diferença nessa linha, mantendo as cores do bloco de código.
**Entrada**
````
```js
export default {
data () {
return {
msg: 'Removido' // [!!code --]
msg: 'Adicionado' // [!!code ++]
}
}
}
```
````
**Saída**
```js
export default {
data () {
return {
msg: 'Removido' // [!code --]
msg: 'Adicionado' // [!code ++]
}
}
}
```
## Erros e Avisos em Blocos de Código {#errors-and-warnings-in-code-blocks}
Adicionar os comentários `// [!code warning]` ou `// [!code error]` em uma linha colorirá os blocos conforme apropriado.
**Entrada**
````
```js
export default {
data () {
return {
msg: 'Erro', // [!!code error]
msg: 'Aviso' // [!!code warning]
}
}
}
```
````
**Saída**
```js
export default {
data() {
return {
msg: 'Erro', // [!code error]
msg: 'Aviso' // [!code warning]
}
}
}
```
## Números de Linha {#line-numbers}
Você pode habilitar números de linha para cada bloco de código através do arquivo de configuração:
```js
export default {
markdown: {
lineNumbers: true
}
}
```
Consulte as [opções markdown](../reference/site-config#markdown) para mais detalhes.
Você pode adicionar a marca `:line-numbers` / `:no-line-numbers` em seus blocos de código para substituir o valor definido na configuração.
Você também pode personalizar o número inicial da linha adicionando `=` após `:line-numbers`. Por exemplo, `:line-numbers=2` significa que os números das linhas nos blocos de código começarão a partir de `2`.
**Entrada**
````md
```ts {1}
// números de linha desativados por padrão
const line2 = 'Esta é a linha 2'
const line3 = 'Esta é a linha 3'
```
```ts:line-numbers {1}
// números de linha ativados
const line2 = 'Esta é a linha 2'
const line3 = 'Esta é a linha 3'
```
```ts:line-numbers=2 {1}
// números de linha ativados e começam do 2
const line3 = 'Esta é a linha 3'
const line4 = 'Esta é a linha 4'
```
````
**Saída**
```ts {1}
// números de linha desativados por padrão
const line2 = 'Esta é a linha 2'
const line3 = 'Esta é a linha 3'
```
```ts:line-numbers {1}
// números de linha ativados
const line2 = 'Esta é a linha 2'
const line3 = 'Esta é a linha 3'
```
```ts:line-numbers=2 {1}
// números de linha ativados e começam do 2
const line3 = 'Esta é a linha 3'
const line4 = 'Esta é a linha 4'
```
## Importar _Snippets_ de Código {#import-code-snippets}
Você pode importar trechos de código de arquivos existentes usando a seguinte sintaxe:
```md
<<< @/filepath
```
Também suporta [destaque de linha](#line-highlighting-in-code-blocks):
```md
<<< @/filepath{highlightLines}
```
**Entrada**
```md
<<< @/snippets/snippet.js{2}
```
**Arquivo de Código**
<<< @/snippets/snippet.js
**Saída**
<<< @/snippets/snippet.js{2}
::: dica
O valor de `@` corresponde à raiz do código fonte. Por padrão, é a raiz do projeto VitePress, a menos que `srcDir` seja configurado. Alternativamente, você também pode importar de caminhos relativos:
```md
<<< ../snippets/snippet.js
```
:::
Você também pode usar uma [região VS Code](https://code.visualstudio.com/docs/editor/codebasics#_folding) para incluir apenas a parte correspondente do arquivo de código. Você pode fornecer um nome de região personalizado após um `#` seguindo o caminho do arquivo:
**Entrada**
```md
<<< @/snippets/snippet-with-region.js#snippet{1}
```
**Arquivo de Código**
<<< @/snippets/snippet-with-region.js
**Saída**
<<< @/snippets/snippet-with-region.js#snippet{1}
Você também pode especificar o idioma dentro das chaves (`{}`), assim:
```md
<<< @/snippets/snippet.cs{c#}
<!-- com destaque de linha: -->
<<< @/snippets/snippet.cs{1,2,4-6 c#}
<!-- com números de linha: -->
<<< @/snippets/snippet.cs{1,2,4-6 c#:line-numbers}
```
Isso é útil se a linguagem original não puder ser inferida pela extensão do arquivo.
## Grupos de Código {#code-groups}
Você pode agrupar vários blocos de código assim:
**Entrada**
````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
```
:::
````
**Saída**
::: 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
```
:::
Você também pode [importar _snippets_ de código](#import-code-snippets) em grupos de código:
**Entrada**
```md
::: code-group
<!-- nome de arquivo usado como título por padrão -->
<<< @/snippets/snippet.js
<!-- você pode fornecer um personalizado também -->
<<< @/snippets/snippet-with-region.js#snippet{1,2 ts:line-numbers} [snippet with region]
:::
```
**Output**
::: code-group
<<< @/snippets/snippet.js
<<< @/snippets/snippet-with-region.js#snippet{1,2 ts:line-numbers} [snippet with region]
:::
## Inclusão de Arquivo Markdown {#markdown-file-inclusion}
Você pode incluir um arquivo markdown em outro arquivo markdown, mesmo aninhado.
::: dica
Você também pode prefixar o caminho do markdown com `@`, ele atuará como a raiz de origem. Por padrão, é a raiz do projeto VitePress, a menos que `srcDir` seja configurado.
:::
Por exemplo, você pode incluir um arquivo markdown relativo usando isto:
**Entrada**
```md
# Documentação
## Conceitos Básicos
<!--@include: ./parts/basics.md-->
```
**Arquivo da Parte** (`parts/basics.md`)
```md
Algumas coisas básicas.
### Configuração
Pode ser criada usando `.foorc.json`.
```
**Código Equivalente**
```md
# Documentação
## Conceitos Básicos
Algumas coisas básicas.
### Configuração
Pode ser criada usando `.foorc.json`.
```
Também suporta a seleção de um intervalo de linhas:
**Entrada**
```md
# Documentação
## Conceitos Básicos
<!--@include: ./parts/basics.md{3,}-->
```
**Arquivo da Parte** (`parts/basics.md`)
```md
Algumas coisas básicas.
### Configuração
Pode ser criada usando `.foorc.json`.
```
**Código Equivalente**
```md
# Documentação
## Conceitos Básicos
### Configuração
Pode ser criada usando `.foorc.json`.
```
O formato do intervalo de linhas selecionado pode ser: `{3,}`, `{,10}`, `{1,10}`
::: aviso
Observe que isso não gera erros se o arquivo não estiver presente. Portanto, ao usar esse recurso, certifique-se de que o conteúdo está sendo mostrado como esperado.
:::
## Equações Matemáticas {#math-equations}
Isso é atualmente opcional. Para ativá-lo, você precisa instalar `markdown-it-mathjax3` e definir `markdown.math` como `true` no seu arquivo de configuração:
```sh
npm add -D markdown-it-mathjax3
```
```ts
// .vitepress/config.ts
export default {
markdown: {
math: true
}
}
```
**Entrada**
```md
Quando $a \ne 0$, existem duas soluções para $(ax^2 + bx + c = 0)$ e elas são
$$ x = {-b \pm \sqrt{b^2-4ac} \over 2a} $$
**Equações de Maxwell:**
| equação | descrição |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| $\nabla \cdot \vec{\mathbf{B}} = 0$ | a divergência de $\vec{\mathbf{B}}$ é zero |
| $\nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} = \vec{\mathbf{0}}$ | a rotacional de $\vec{\mathbf{E}}$ é proporcional à taxa de variação de $\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$ | _hã?_ |
**Saída**
Quando $a \ne 0$, existem duas soluções para $(ax^2 + bx + c = 0)$ e são
$$ x = {-b \pm \sqrt{b^2-4ac} \over 2a} $$
**Equações de Maxwell:**
| equação | descrição |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| $\nabla \cdot \vec{\mathbf{B}} = 0$ | a divergência de $\vec{\mathbf{B}}$ é zero |
| $\nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} = \vec{\mathbf{0}}$ | a rotacional de $\vec{\mathbf{E}}$ é proporcional à taxa de variação de $\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$ | _hã?_ |
## _Lazy Loading_ de Imagens {#image-lazy-loading}
Você pode ativar o "carregamento folgado" para cada imagem adicionada via markdown definindo `lazyLoading` como `true` no seu arquivo de configuração:
```js
export default {
markdown: {
image: {
// o carregamento folgado de imagens está desativado por padrão
lazyLoading: true
}
}
}
```
## Configuração Avançada {#advanced-configuration}
VitePress usa [markdown-it](https://github.com/markdown-it/markdown-it) como interpretador Markdown. Muitas das extensões acima são implementadas por meio de _plugins_ personalizados. Você pode personalizar ainda mais a instância `markdown-it` usando a opção `markdown` em `.vitepress/config.js`:
```js
import { defineConfig } from 'vitepress'
import markdownItAnchor from 'markdown-it-anchor'
import markdownItFoo from 'markdown-it-foo'
export default defineConfig({
markdown: {
// opções para markdown-it-anchor
// https://github.com/valeriangalliat/markdown-it-anchor#usage
anchor: {
permalink: markdownItAnchor.permalink.headerLink()
},
// opções para @mdit-vue/plugin-toc
// https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-toc#options
toc: { level: [1, 2] },
config: (md) => {
// use mais plugins markdown-it!
md.use(markdownItFoo)
}
}
})
```
Consulte a lista completa de propriedades configuráveis em [Referência de Configuração: Configuração da Aplicação](../reference/site-config#markdown).

@ -0,0 +1,23 @@
# Modo MPA <Badge type="warning" text="experimental" /> {#mpa-mode}
O modo MPA (Aplicação Multipáginas) pode ser habilitado pela linha de comando com `vitepress build --mpa`, ou através da configuração pela opção `mpa: true`.
No modo MPA, todas as páginas são apresentadas por padrão sem qualquer JavaScript incluído. Como resultado, o site em produção provavelmente terá uma nota de desempenho de visita inicial superior com ferramentas de auditoria.
Entretanto, devido a ausência de navegação SPA, links entre páginas acarretarão em recarregamentos de página completos. Navegações pós-carregamento no modo MPA não parecerão tão instantâneas quanto no modo SPA.
Também note que não ter JavaScript por padrão significa que você está essencialmente utilizando Vue como modelo de linguagem no lado do servidor. Nenhum manipulador de evento será embutido no navegador, então não haverá interatividade. Para carregar JavaScript no lado do cliente, você precisará usar a tag especial `<script client>`:
```html
<script client>
document.querySelector('h1').addEventListener('click', () => {
console.log('JavaScript no lado do cliente!')
})
</script>
# Olá
```
`<script client>` é uma funcionalidade exclusiva VitePress, não uma funcionalidade Vue. Funciona tanto em arquivos `.md` quanto em arquivos `.vue`, mas apenas no modo MPA. Scripts de cliente em todos os componentes do tema serão empacotados juntos, enquanto o script do cliente para uma página específica será dividido apenas para aquela página.
Note que `<script client>` **não é avaliado como código de componente Vue**: é processado como um simples módulo JavaScript. Por esta razão, o modo MPA deve ser usado apenas se seu site exige o mínimo absoluto de interatividade no lado do cliente.

@ -0,0 +1,372 @@
---
outline: deep
---
# Roteamento {#routing}
## Roteamento baseado em Arquivos {#file-based-routing}
VitePress utiliza roteamento baseado em arquivos, isso significa que as páginas HTML geradas são mapeadas da estrutura de diretórios dos arquivos fonte Markdown. Por exemplo, dada a seguinte estrutura de diretório:
```
.
├─ guide
│ ├─ getting-started.md
│ └─ index.md
├─ index.md
└─ prologue.md
```
As páginas HTML geradas serão:
```
index.md --> /index.html (acessível por /)
prologue.md --> /prologue.html
guide/index.md --> /guide/index.html (acessível por /guide/)
guide/getting-started.md --> /guide/getting-started.html
```
O HTML resultante pode ser hospedado em qualquer servidor web que possa servir arquivos estáticos.
## Diretório Raiz e Fonte {#root-and-source-directory}
Existem dois conceitos importantes na estrutura de arquivos de um projeto VitePress: o **diretório raiz** e o **diretório fonte**.
### Diretório Raiz {#project-root}
O diretório raiz é onde o VitePress procura pelo diretório especial `.vitepress`. O diretório `.vitepress` é um local reservado para o arquivo de configuração do VitePress, o cache do servidor de desenvolvimento, o resultado da compilação e o código de personalização de tema opcional.
Ao executar `vitepress dev` ou `vitepress build` no terminal, VitePress usará o diretório atual como diretório raiz do projeto. Para especificar um subdiretório como raiz, é necessário passar o caminho relativo para o comando. Por exemplo, se o projeto VitePress estiver localizado em `./docs`, deve-se executar `vitepress dev docs`:
```
.
├─ docs # diretório raiz
│ ├─ .vitepress # diretório de configuração
│ ├─ getting-started.md
│ └─ index.md
└─ ...
```
```sh
vitepress dev docs
```
Isso resultará no seguinte mapeamento da fonte para HTML:
```
docs/index.md --> /index.html (acessível como /)
docs/getting-started.md --> /getting-started.html
```
### Diretório Fonte {#source-directory}
O diretório fonte é onde seus arquivos fonte em Markdown estão. Por padrão, é o mesmo que o diretório raiz. No entanto, você pode configurá-lo por meio da opção de configuração [`srcDir`](../reference/site-config#srcdir).
A opção `srcDir` é resolvida em relação ao diretório raiz do projeto. Por exemplo, com `srcDir: 'src'`, sua estrutura de arquivos ficará assim:
```
. # diretório raiz
├─ .vitepress # diretório de configuração
└─ src # diretório fonte
├─ getting-started.md
└─ index.md
```
O mapeamento resultante da fonte para HTML:
```
src/index.md --> /index.html (acessível como /)
src/getting-started.md --> /getting-started.html
```
## Links Entre Páginas {#linking-between-pages}
Você pode usar tanto caminhos absolutos quanto relativos ao vincular páginas. Note que, embora ambas as extensões `.md` e `.html` funcionem, a prática recomendada é omitir as extensões de arquivo para que o VitePress possa gerar as URLs finais com base na sua configuração.
```md
<!-- Fazer -->
[Getting Started](./getting-started)
[Getting Started](../guide/getting-started)
<!-- Não Fazer -->
[Getting Started](./getting-started.md)
[Getting Started](./getting-started.html)
```
Saiba mais sobre a vinculação de ativos, como imagens, em [Manipulação de Ativos](./asset-handling).
### Vinculação a Páginas Não VitePress {#linking-to-non-vitepress-pages}
Se você deseja vincular a uma página em seu site que não é gerada pelo VitePress, será necessário usar a URL completa (abre em uma nova guia) ou especificar explicitamente o destino:
**Entrada**
```md
[Link para pure.html](/pure.html){target="_self"}
```
**Saída**
[Link para pure.html](/pure.html){target="_self"}
::: dica Nota
Nos links Markdown, a `base` é automaticamente adicionada à URL. Isso significa que, se você deseja vincular a uma página fora da sua base, será necessário algo como `../../pure.html` no link (resolvido em relação à página atual pelo navegador).
Alternativamente, pode-se usar diretamente a sintaxe da tag âncora:
```md
<a href="/pure.html" target="_self">Link para pure.html</a>
```
:::
## Geração de URL Limpa {#generating-clean-url}
::: aviso Suporte do Servidor Necessário
Para servir URLs limpas com VitePress, é necessário suporte no lado do servidor.
:::
Por padrão, VitePress resolve links de entrada para URLs que terminam com `.html`. No entanto, alguns usuários podem preferir "URLs limpas" sem a extensão `.html`, por exemplo, `example.com/caminho` em vez de `example.com/caminho.html`.
Alguns servidores ou plataformas de hospedagem (por exemplo, Netlify, Vercel, GitHub Pages) fornecem a habilidade de mapear uma URL como `/foo` para `/foo.html` se ela existir, sem redirecionamento:
- Netlify e GitHub Pages suportam isso por padrão.
- Vercel requer a ativação da opção [`cleanUrls` no `vercel.json`](https://vercel.com/docs/concepts/projects/project-configuration#cleanurls).
Se essa funcionalidade estiver disponível para você, também se pode ativar a própria opção de configuração [`cleanUrls`](../reference/site-config#cleanurls) de VitePress para que:
- Links de entrada entre páginas sejam gerados sem a extensão `.html`.
- Se o caminho atual terminar com `.html`, o roteador realizará um redirecionamento no lado do cliente para o caminho sem extensão.
No entanto, se você não puder configurar o servidor com esse suporte, será necessário recorrer manualmente à seguinte estrutura de diretório:
```
.
├─ getting-started
│ └─ index.md
├─ installation
│ └─ index.md
└─ index.md
```
# Reescrita de Rota {#route-rewrites}
Você pode personalizar o mapeamento entre a estrutura de diretórios fonte e as páginas geradas. Isso é útil quando você tem uma estrutura de projeto complexa. Por exemplo, digamos que você tenha um monorepo com vários pacotes e gostaria de colocar as documentações junto com os arquivos fonte desta forma:
```
.
├─ packages
│ ├─ pkg-a
│ │ └─ src
│ │ ├─ pkg-a-code.ts
│ │ └─ pkg-a-docs.md
│ └─ pkg-b
│ └─ src
│ ├─ pkg-b-code.ts
│ └─ pkg-b-docs.md
```
E você deseja que as páginas VitePress sejam geradas assim:
```
packages/pkg-a/src/pkg-a-docs.md --> /pkg-a/index.html
packages/pkg-b/src/pkg-b-docs.md --> /pkg-b/index.html
```
Você pode realizar isso configurando a opção [`rewrites`](../reference/site-config#rewrites) assim:
```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'
}
}
```
A opção `rewrites` também suporta parâmetros de rota dinâmicos. No exemplo acima, seria verboso listar todos os caminhos se você tiver muitos pacotes. Dado que todos eles têm a mesma estrutura de arquivo, você pode simplificar a configuração assim:
```ts
export default {
rewrites: {
'packages/:pkg/src/(.*)': ':pkg/index.md'
}
}
```
Os caminhos de reescrita são compilados usando o pacote `path-to-regexp` - consulte [sua documentação](https://github.com/pillarjs/path-to-regexp#parameters) para uma sintaxe mais avançada.
::: warning Links Relativos com Reescritas
Quando as reescritas estão habilitadas, **links relativos devem ser baseados nos caminhos reescritos**. Por exemplo, para criar um link relativo de `packages/pkg-a/src/pkg-a-code.md` para `packages/pkg-b/src/pkg-b-code.md`, deve-se usar:
```md
[Link para PKG B](../pkg-b/pkg-b-code)
```
:::
## Rotas Dinâmicas {#dynamic-routes}
Você pode gerar muitas páginas usando um único arquivo Markdown e dados dinâmicos. Por exemplo, você pode criar um arquivo `packages/[pkg].md` que gera uma página correspondente para cada pacote em um projeto. Aqui, o segmento `[pkg]` é um **parâmetro** de rota que diferencia cada página das outras.
### Arquivo de Carregamento de Caminhos {#paths-loader-file}
Como VitePress é um gerador de site estático, os caminhos possíveis das páginas devem ser determinados no momento da compilação. Portanto, uma página de rota dinâmica **deve** ser acompanhada por um **arquivo de carregamento de caminhos**. Para `packages/[pkg].md`, precisaremos de `packages/[pkg].paths.js` (`.ts` também é suportado):
```
.
└─ packages
├─ [pkg].md # modelo de rota
└─ [pkg].paths.js # carregador de caminhos da rota
```
O carregador de caminhos deve fornecer um objeto com um método `paths` como sua exportação padrão. O método `paths` deve retornar um _array_ de objetos com uma propriedade `params`. Cada um desses objetos gerará uma página correspondente.
Dado o seguinte _array_ `paths`:
```js
// packages/[pkg].paths.js
export default {
paths() {
return [
{ params: { pkg: 'foo' }},
{ params: { pkg: 'bar' }}
]
}
}
```
As páginas HTML geradas serão:
```
.
└─ packages
├─ foo.html
└─ bar.html
```
### Múltiplos Parâmetros {#multiple-params}
Uma rota dinâmica pode conter múltiplos parâmetros:
**Estrutura de Arquivo**
```
.
└─ packages
├─ [pkg]-[version].md
└─ [pkg]-[version].paths.js
```
**Carregador de Caminhos**
```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' }}
]
}
```
**Saída**
```
.
└─ packages
├─ foo-1.0.0.html
├─ foo-2.0.0.html
├─ bar-1.0.0.html
└─ bar-2.0.0.html
```
### Gerando Caminhos Dinamicamente {#dynamically-generating-paths}
O módulo de carregamento de caminhos é executado no Node.js e apenas durante o momento de compilação. Você pode gerar dinamicamente o _array_ de caminhos usando qualquer dado, seja local ou remoto.
Gerando caminhos a partir de arquivos locais:
```js
import fs from 'fs'
export default {
paths() {
return fs
.readdirSync('packages')
.map((pkg) => {
return { params: { pkg }}
})
}
}
```
Gerando caminhos a partir de dados remotos:
```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
}
}
})
}
}
```
### Acessando Parâmetros na Página {#accessing-params-in-page}
Você pode usar os parâmetros para passar dados adicionais para cada página. O arquivo de rota Markdown pode acessar os parâmetros da página atual em expressões Vue através da propriedade global `$params`:
```md
- nome do pacote: {{ $params.pkg }}
- versão: {{ $params.version }}
```
Você também pode acessar os parâmetros da página atual através da API de tempo de execução [`useData`](../reference/runtime-api#usedata). Isso está disponível tanto em arquivos Markdown quanto em componentes Vue:
```vue
<script setup>
import { useData } from 'vitepress'
// params é uma ref Vue
const { params } = useData()
console.log(params.value)
</script>
```
### Apresentando Conteúdo Cru {#rendering-raw-content}
Parâmetros passados para a página serão serializados na carga JavaScript do cliente, portanto, evite passar dados pesados nos parâmetros, como Markdown cru ou conteúdo HTML obtido de um CMS remoto.
Em vez disso, você pode passar tal conteúdo para cada página usando a propriedade `content` em cada objeto de caminho:
```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 ou HTML cru
}
})
}
}
```
Em seguida, use a seguinte sintaxe especial para apresentar o conteúdo como parte do próprio arquivo Markdown:
```md
<!-- @content -->
```

@ -0,0 +1,53 @@
# Geração de Sitemap {#sitemap-generation}
VitePress vem com suporte embutido para gerar um arquivo `sitemap.xml` para seu site. Para habilitar, adicione o seguinte ao seu `.vitepress/config.js`:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
sitemap: {
hostname: 'https://example.com'
}
})
```
Para ter tags `<lastmod>` em seu `sitemap.xml`, você pode habilitar a opção [`lastUpdated`](../reference/default-theme-last-updated).
## Opções {#options}
O suporte de Sietmap é alimentado pelo módulo [`sitemap`](https://www.npmjs.com/package/sitemap). Você pode passar qualquer uma das opções suportadas por ele na opção `sitemap` do seu arquivo de configuração. Esses serão passados diretamente ao construtor `SitemapStream`. Refira-se a [documentação `sitemap`](https://www.npmjs.com/package/sitemap#options-you-can-pass) para mais detalhes. Exemplo:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
sitemap: {
hostname: 'https://example.com',
lastmodDateOnly: false
}
})
```
## Gancho `transformItems`
Você pode usar o gancho `sitemap.transformItems` para modificar os itens do sitemap antes de eles serem escritos no arquivo `sitemap.xml`. Este gancho é chamado com um _array_ de itens sitemap e espera um _array_ de itens sitemap como retorno. Exemplo:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
sitemap: {
hostname: 'https://example.com',
transformItems: (items) => {
// adiciona novos itens ou modifica/filtra itens existentes
items.push({
url: '/extra-page',
changefreq: 'monthly',
priority: 0.8
})
return items
}
}
})
```

@ -0,0 +1,136 @@
---
outline: deep
---
# Compatibilidade SSR {#ssr-compatibility}
VitePress pré-interpreta a aplicação no Node.js durante a compilação de produção, utilizando as capacidades de Interpretação do Lado do Servidor (SSR) do Vue. Isso significa que todo o código personalizado nos componentes do tema está sujeito à Compatibilidade SSR.
A [seção SSR na documentação Vue oficial](https://vuejs.org/guide/scaling-up/ssr.html) fornece mais contexto sobre o que é SSR, a relação entre SSR / SSG e notas comuns sobre escrever código amigável a SSR. A regra geral é acessar apenas APIs do navegador / DOM nos gatilhos `beforeMount` ou `mounted` dos componentes Vue.
## `<ClientOnly>`
Se você estiver usando ou demonstrando componentes que não são compatíveis com SSR (por exemplo, contêm diretivas personalizadas), você pode envolvê-los no componente embutido `<ClientOnly>`:
```md
<ClientOnly>
<ComponenteNaoCompativelComSSR />
</ClientOnly>
```
## Bibliotecas que Acessam a API do Navegador na Importação {#libraries-that-access-browser-api-on-import}
Alguns componentes ou bibliotecas acessam APIs do navegador **na importação**. Para usar código que assume um ambiente de navegador na importação, você precisa importá-los dinamicamente.
### Importando no Gatilho `mounted` {#importing-in-mounted-hook}
```vue
<script setup>
import { onMounted } from 'vue'
onMounted(() => {
import('./lib-que-acessa-window-na-importacao').then((module) => {
// usar código
})
})
</script>
```
### Importação Condicional {#conditional-import}
Você também pode importar condicionalmente uma dependência usando o sinalizador `import.meta.env.SSR` (parte das [variáveis de ambiente Vite](https://vitejs.dev/guide/env-and-mode.html#env-variables)):
```js
if (!import.meta.env.SSR) {
import('./lib-que-acessa-window-na-importacao').then((module) => {
// usar código
})
}
```
Como [`Theme.enhanceApp`](./custom-theme#theme-interface) pode ser assíncrono, você pode importar condicionalmente e registrar plugins Vue que acessam APIs do navegador na importação:
```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-acessa-window-na-importacao')
app.use(plugin.default)
}
}
}
```
Se estiver usando 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-que-acessa-window-na-importacao')
app.use(plugin.default)
}
}
} satisfies Theme
```
### `defineClientComponent`
VitePress fornece um auxiliar de conveniência para importar componentes Vue que acessam APIs do navegador na importação.
```vue
<script setup>
import { defineClientComponent } from 'vitepress'
const ClientComp = defineClientComponent(() => {
return import('componente-que-acessa-window-na-importacao')
})
</script>
<template>
<ClientComp />
</template>
```
Você também pode passar propriedades/filhos/_slots_ para o componente alvo:
```vue
<script setup>
import { ref } from 'vue'
import { defineClientComponent } from 'vitepress'
const clientCompRef = ref(null)
const ClientComp = defineClientComponent(
() => import('componente-que-acessa-window-na-importacao'),
// os argumentos são passados para h() - https://vuejs.org/api/render-function.html#h
[
{
ref: clientCompRef
},
{
default: () => 'slot padrão',
foo: () => h('div', 'foo'),
bar: () => [h('span', 'um'), h('span', 'dois')]
}
],
// retorno de chamada depois que o componente é carregado, pode ser assíncrono
() => {
console.log(clientCompRef.value)
}
)
</script>
<template>
<ClientComp />
</template>
```
O componente alvo só será importado no gatilho `mounted` do componente que o envolve.

@ -0,0 +1,255 @@
# Usando Vue em Markdown {#using-vue-in-markdown}
Em VitePress, cada arquivo Markdown é compilado para HTML e então processado como um [Componente de Arquivo Único Vue](https://vuejs.org/guide/scaling-up/sfc.html). Isso significa que você pode usar qualquer funcionalidade Vue dentro do Markdown, incluindo a interpolação dinâmica, usar componentes Vue ou lógica arbitrária de componentes Vue dentro da página adicionando uma tag `<script>`.
Vale ressaltar que VitePress aproveita o compilador Vue para detectar e otimizar automaticamente as partes puramente estáticas do conteúdo Markdown. Os conteúdos estáticos são otimizados em nós de espaço reservado únicos e eliminados da carga JavaScript da página para visitas iniciais. Eles também são ignorados durante a hidratação no lado do cliente. Em resumo, você só paga pelas partes dinâmicas em qualquer página específica.
::: tip Compatibilidade SSR
Todo uso do Vue precisa ser compatível com SSR. Consulte [Compatibilidade SSR](./ssr-compat) para detalhes e soluções comuns.
:::
## Criação de _Templates_ {#templating}
### Interpolação {#interpolation}
Cada arquivo Markdown é primeiro compilado para HTML e depois passado como um componente Vue para a canalização de processos Vite. Isso significa que você pode usar interpolação no estilo Vue no texto:
**Entrada**
```md
{{ 1 + 1 }}
```
**Saída**
<div class="language-text"><pre><code>{{ 1 + 1 }}</code></pre></div>
### Diretivas {#directives}
Diretivas também funcionam (observe que, por definiçào, HTML cru também é válido em Markdown):
**Entrada**
```html
<span v-for="i in 3">{{ i }}</span>
```
**Saída**
<div class="language-text"><pre><code><span v-for="i in 3">{{ i }} </span></code></pre></div>
## `<script>` e `<style>`
As tags `<script>` e `<style>` em nível raiz nos arquivos Markdown funcionam igualmente como nos Componentes de Arquivo Único Vue, incluindo `<script setup>`, `<style module>`, e etc. A principal diferença aqui é que não há uma tag `<template>`: todo outro conteúdo em nível raiz é Markdown. Além disso, observe que todas as tags devem ser colocadas **após** o frontmatter:
```html
---
hello: world
---
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
## Conteúdo Markdown
A contagem é: {{ count }}
<button :class="$style.button" @click="count++">Incrementar</button>
<style module>
.button {
color: red;
font-weight: bold;
}
</style>
```
::: warning Evite `<style scoped>` no Markdown
Quando usado no Markdown, `<style scoped>` exige a adição de atributos especiais a cada elemento na página atual, o que aumentará significativamente o tamanho da página. `<style module>` é preferido quando é necessária uma estilização localizada em uma página.
:::
Você também tem acesso às APIs de tempo de execução VitePress, como o [auxiliar `useData`](../reference/runtime-api#usedata), que fornece acesso aos metadados da página atual:
**Entrada**
```html
<script setup>
import { useData } from 'vitepress'
const { page } = useData()
</script>
<pre>{{ page }}</pre>
```
**Saída**
```json
{
"path": "/usando-vue.html",
"title": "Usando Vue em Markdown",
"frontmatter": {},
...
}
```
## Usando Componentes {#using-components}
Você pode importar e usar componentes Vue diretamente nos arquivos Markdown.
### Importando no Markdown {#importing-in-markdown}
Se um componente é usado apenas por algumas páginas, é recomendável importá-los explicitamente onde são usados. Isso permite que eles sejam divididos adequadamente e carregados apenas quando as páginas relevantes são mostradas:
```md
<script setup>
import CustomComponent from '../components/CustomComponent.vue'
</script>
# Documentação
Este é um arquivo .md usando um componente personalizado
<CustomComponent />
## Mais documentação
...
```
### Registrando Componentes Globalmente {#registering-components-globally}
Se um componente for usado na maioria das páginas, eles podem ser registrados globalmente personalizando a instância do aplicativo Vue. Consulte a seção relevante em [Estendendo o Tema Padrão](./extending-default-theme#registering-global-components) para um exemplo.
::: warning IMPORTANT
Certifique-se de que o nome de um componente personalizado contenha um hífen ou esteja em PascalCase. Caso contrário, ele será tratado como um elemento alinhado e envolvido dentro de uma tag `<p>`, o que levará a uma incompatibilidade de hidratação pois `<p>` não permite que elementos de bloco sejam colocados dentro dele.
:::
### Usando Componentes Em Cabeçalhos <ComponenteNoCabeçalho /> {#using-components-in-headers}
Você pode usar componentes Vue nos cabeçalhos, mas observe a diferença entre as seguintes sintaxes:
| Markdown | HTML de Saída | Cabeçalho Processado |
| ------------------------------------------------------- | ----------------------------------------- | ------------- |
| <pre v-pre><code> # texto &lt;Tag/&gt; </code></pre> | `<h1>texto <Tag/></h1>` | `texto` |
| <pre v-pre><code> # texto \`&lt;Tag/&gt;\` </code></pre> | `<h1>texto <code>&lt;Tag/&gt;</code></h1>` | `texto <Tag/>` |
O HTML envolvido por `<code>` será exibido como é; somente o HTML que **não** estiver envolvido será analisado pelo Vue.
::: tip
O HTML de saída é realizado por [Markdown-it](https://github.com/Markdown-it/Markdown-it), enquanto os cabeçalhos processados são manipulados pelo VitePress (e usados tanto na barra lateral quanto no título do documento).
:::
## Escapes {#escaping}
Você pode escapar de interpolações Vue envolvendo-as em um `<span>` ou outros elementos com a diretiva `v-pre`:
**Entrada**
```md
Isto <span v-pre>{{ será exibido como é }}</span>
```
**Saída**
<div class="escape-demo">
<p>Isto <span v-pre>{{ será exibido como é }}</span></p>
</div>
Alternativamente, você pode envolver todo o parágrafo em um container personalizado `v-pre`:
```md
::: v-pre
{{ Isto será exibido como é }}
:::
```
**Output**
<div class="escape-demo">
::: v-pre
{{ Isto será exibido como é }}
:::
</div>
## "Des-escape" em Blocos de Código {#unescape-in-code-blocks}
Por padrão, todos os blocos de código cercados são automaticamente envolvidos com `v-pre`, então nenhuma sintaxe Vue será processada dentro deles. Para permitir a interpolação no estilo Vue dentro do cercado, você pode adicionar a linguagem com o sufixo `-vue` , por exemplo, `js-vue`:
**Entrada**
````md
```js-vue
Olá {{ 1 + 1 }}
```
````
**Saída**
```js-vue
Olá {{ 1 + 1 }}
```
Observe que isso pode impedir que certos tokens sejam realçados corretamente.
## Usando Pré-processadores CSS {#using-css-pre-processors}
O VitePress possui [suporte embutido](https://vitejs.dev/guide/features.html#css-pre-processors) para pré-processadores CSS: arquivos `.scss`, `.sass`, `.less`, `.styl` e `.stylus`. Não é necessário instalar plugins específicos do Vite para eles, mas o próprio pré-processador correspondente deve ser instalado:
```
# .scss e .sass
npm install -D sass
# .less
npm install -D less
# .styl e .stylus
npm install -D stylus
```
Então você pode usar o seguinte em Markdown e nos componentes do tema:
```vue
<style lang="sass">
.title
font-size: 20px
</style>
```
## Usando _Teleports_ {#using-teleports}
Vitepress atualmente oferece suporte a SSG para _teleports_ apenas para o corpo. Para outros alvos, você pode envolvê-los dentro do componente embutido `<ClientOnly>` ou injetar a marcação de _teleport_ na localização correta em sua página final HTML por meio do [gancho `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 @@
# O que é VitePress? {#what-is-vitepress}
O VitePress é um [Gerador de Site Estático](https://en.wikipedia.org/wiki/Static_site_generator) (SSG) projetado para criar sites rápidos e centrados em conteúdo. Em suma, VitePress utiliza seu conteúdo-fonte escrito em [Markdown](https://en.wikipedia.org/wiki/Markdown), aplica um tema a ele e gera páginas HTML estáticas que podem ser facilmente implantadas em qualquer lugar.
<div class="tip custom-block" style="padding-top: 8px">
Quer apenas experimentar? Pule para o [Início Rápido](./getting-started).
</div>
## Casos de Uso {#use-cases}
- **Documentação**
VitePress vem com um tema padrão projetado para documentação técnica. Ele alimenta esta página que você está lendo agora, juntamente com a documentação [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 [muitos outros](https://www.vuetelescope.com/explore?framework.slug=vitepress).
A [documentação oficial Vue.js](https://vuejs.org/) também é baseada em VitePress, mas usa um tema personalizado compartilhado entre várias traduções.
- **Blogs, Portfólios e Sites de Marketing**
VitePress suporta [temas totalmente personalizáveis](./custom-theme), com a experiência de desenvolvedor padrão de uma aplicação Vite + Vue. A construção com Vite significa que você pode aproveitar diretamente plugins Vite de seu rico ecossistema. Adicionalmente, VitePress fornece APIs flexíveis para [carregar dados](./data-loading) (locais ou remotos) e [gerar rotas dinamicamente](./routing#dynamic-routes). Você pode usá-lo para construir praticamente qualquer coisa desde que os dados possam ser determinados no momento da construção.
O [blog oficial Vue.js](https://blog.vuejs.org/) é um blog simples que gera sua página inicial baseada em conteúdo local.
## Experiência de Desenvolvedor {#developer-experience}
VitePress visa proporcionar excelente Experiência de Desenvolvedor (DX) ao trabalhar com conteúdo em Markdown.
- **[Alimentado por Vite:](https://vitejs.dev/)** inicialização instantânea do servidor, com edições sempre refletidas instantaneamente (<100ms) sem recarregamento de página.
- **[Extensões Markdown Integradas:](./markdown)** Frontmatter, tabelas, destaque de sintaxe... você escolhe. Especificamente, VitePress fornece muitos recursos avançados para trabalhar com blocos de código, tornando-o ideal para documentação altamente técnica.
- **[Markdown Aprimorado por Vue:](./using-vue)** cada página Markdown é também um [Componente de Arquivo Único Vue](https://pt.vuejs.org/guide/scaling-up/sfc.html), graças à compatibilidade de sintaxe de 100% do template Vue com HTML. Você pode incorporar interatividade em seu conteúdo estático usando recursos de template Vue ou componentes Vue importados.
## Desempenho {#performance}
Ao contrário de muitos SSGs tradicionais, um site gerado pelo VitePress é na verdade uma [Aplicação de Página Única](https://en.wikipedia.org/wiki/Single-page_application) (SPA).
- **Carregamento Inicial Rápido**
A visita inicial a qualquer página será servida com o HTML estático pré-renderizado para velocidade de carregamento rápida e SEO otimizado. A página então carrega um pacote JavaScript que transforma a página em uma SPA Vue ("hidratação"). O processo de hidratação é extremamente rápido: no [PageSpeed Insights](https://pagespeed.web.dev/report?url=https%3A%2F%2Fvitepress.dev%2F), sites típicos VitePress alcançam pontuações de desempenho quase perfeitas, mesmo em dispositivos móveis de baixo desempenho com uma rede lenta.
- **Navegação Rápida pós-carregamento**
Mais importante ainda, o modelo SPA leva a uma melhor experiência do usuário **após** o carregamento inicial. A navegação subsequente dentro do site não causará mais uma recarga completa da página. Em vez disso, o conteúdo da página de entrada será buscado e atualizado dinamicamente. VitePress também pré-carrega automaticamente pedaços de página para links que estão dentro do viewport. Na maioria dos casos, a navegação pós-carregamento parecerá instantânea.
- **Interatividade Sem Penalidades**
Para ser capaz de hidratar as partes dinâmicas Vue incorporadas dentro do Markdown estático, cada página Markdown é processada como um componente Vue e compilada em JavaScript. Isso pode parecer ineficiente, mas o compilador Vue é inteligente o suficiente para separar as partes estáticas e dinâmicas, minimizando tanto o custo de hidratação quanto o tamanho da carga. Para o carregamento inicial da página, as partes estáticas são automaticamente eliminadas da carga JavaScript e puladas durante a hidratação.
## E o VuePress? {#what-about-vuepress}
VitePress é o sucessor espiritual de VuePress. VuePress era orginalmente baseado em Vue 2 e webpack. Com Vue 3 e Vite, VitePress oferece uma experiência de desenvolvedor significativamente melhor, melhor desempenho em produção, um tema padrão mais polido e uma API de personalização mais flexível.
A diferença da API entre VitePress e VuePress reside principalmente em temas e personalização. Se você estiver usando VuePress 1 com o tema padrão, a migração para VitePress deve ser relativamente simples.
Também houve esforço investido em VuePress 2, que também suporta Vue 3 e Vite com melhor compatibilidade do que VuePress 1. No entanto, manter dois SSGs em paralelo não é sustentável, então a equipe Vue decidiu focar em VitePress como o principal SSG recomendado a longo prazo.

@ -0,0 +1,60 @@
---
layout: home
title: VitePress
titleTemplate: Gerador de Site Estático desenvolvido com Vite & Vue
hero:
name: VitePress
text: Gerador de Site Estático Vite & Vue
tagline: Markdown para Lindos Documentos em Minutos
actions:
- theme: brand
text: O que é VitePress?
link: /pt/guide/what-is-vitepress
- theme: alt
text: Iniciar
link: /pt/guide/getting-started
- theme: alt
text: GitHub
link: https://github.com/vuejs/vitepress
image:
src: /vitepress-logo-large.webp
alt: VitePress
features:
- icon: 📝
title: Foco no seu conteúdo
details: Cria sites de documentação belos e sem esforço apenas com 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: Aproveite a experiência Vite
details: Início de servidor instantâneo, atualizações ultrarrápidas, e plugins do ecossistema 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: Personalize com Vue
details: Use sintaxe e componentes Vue diretamente em markdown, ou construa temas personalizados com Vue.
- icon: 🚀
title: Entregue Sites Rápidos
details: Carregamento inicial rápido com HTML estático, navegação rápida com roteamento no lado do 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>

@ -0,0 +1,74 @@
# Interface de Linha de Comando {#command-line-interface}
## `vitepress dev`
Inicia o servidor de desenvolvimento VitePress com o diretório designado como raiz. Por padrão usa o diretório atual. O comando `dev` pode também ser omitido ao rodar no diretório atual.
### Uso
```sh
# inicia no diretório atual, omitindo `dev`
vitepress
# inicia em um subdiretório
vitepress dev [root]
```
### Opções {#options}
| Opção | Descrição |
| --------------- | ----------------------------------------------------------------- |
| `--open [path]` | Abre o navegador na inicialização (`boolean \| string`) |
| `--port <port>` | Especifica porta (`number`) |
| `--base <path>` | Caminho base público (padrão: `/`) (`string`) |
| `--cors` | Habilita CORS |
| `--strictPort` | Interrompe se a porta especificada já está em uso (`boolean`) |
| `--force` | Força o otimizador a ignorar o cache e reempacotar (`boolean`) |
## `vitepress build`
Compila o site VitePress para produção.
### Uso
```sh
vitepress build [root]
```
### Opções
| Opção | Descrição |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------- |
| `--mpa` (experimental) | Compila no [Modo MPA](../guide/mpa-mode) sem hidratação no lado do cliente (`boolean`) |
| `--base <path>` | Caminho base público (padrão: `/`) (`string`) |
| `--target <target>` | Transpila o alvo (padrão: `"modules"`) (`string`) |
| `--outDir <dir>` | Diretório de saída relativo ao **cwd** (padrão: `<root>/.vitepress/dist`) (`string`) |
| `--minify [minifier]` | Habilita/desabilita minificação, ou especifica um minificador para usar (padrão: `"esbuild"`) (`boolean \| "terser" \| "esbuild"`) |
| `--assetsInlineLimit <number>` | Limite em bytes para alinhar ativos em base64 (padrão: `4096`) (`number`) |
## `vitepress preview`
Prevê localmente a compilação de produção.
### Uso
```sh
vitepress preview [root]
```
### Opções
| Opção | Descrição |
| --------------- | ------------------------------------------ |
| `--base <path>` | Caminho base público (padrão: `/`) (`string`) |
| `--port <port>` | Especifica porta (`number`) |
## `vitepress init`
Inicia o [Assistente de Instalação](../guide/getting-started#setup-wizard) no diretório atual.
### Uso
```sh
vitepress init
```

@ -0,0 +1,69 @@
# Emblema {#badge}
O emblema permite adicionar status aos seus cabeçalhos. Por exemplo, pode ser útil especificar o tipo da seção ou a versão suportada.
## Uso {#usage}
Você pode usar o componente `Badge` que está disponível globalmente.
```html
### Title <Badge type="info" text="default" />
### Title <Badge type="tip" text="^1.9.0" />
### Title <Badge type="warning" text="beta" />
### Title <Badge type="danger" text="caution" />
```
O código acima é apresentado como:
### Title <Badge type="info" text="default" />
### Title <Badge type="tip" text="^1.9.0" />
### Title <Badge type="warning" text="beta" />
### Title <Badge type="danger" text="caution" />
## Filiação Personalizada {#custom-children}
`<Badge>` aceita `children` (filhos), que serão exibidos no emblema.
```html
### Title <Badge type="info">custom element</Badge>
```
### Title <Badge type="info">custom element</Badge>
## Personalize o Tipo de Cor {#customize-type-color}
Você pode personalizar o estilo dos emblemas sobrepondo variáveis CSS. Os seguintes são os valores padrão:
```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>`
O componente `<Badge>` aceita as seguintes propriedades:
```ts
interface Props {
// Quando `<slot>` é passado, esse valor é ignorado.
text?: string
// O padrão é `tip`.
type?: 'info' | 'tip' | 'warning' | 'danger'
}
```

@ -0,0 +1,22 @@
# Carbon Ads {#carbon-ads}
VitePress tem suporte embutido para [Carbon Ads](https://www.carbonads.net/). Ao definir as credenciais Carbon Ads na configuração, VitePress mostrará anúncios na página.
```js
export default {
themeConfig: {
carbonAds: {
code: 'seu-código-carbon',
placement: 'sua-veiculação-carbon'
}
}
}
```
Esses valores são usados para chamar o sript em CDN do carbon como mostrado abaixo.
```js
`//cdn.carbonads.com/carbon.js?serve=${code}&placement=${placement}`
```
Para aprender mais sobre a configuração Carbon Ads, por favor visite [Site Carbon Ads](https://www.carbonads.net/).

@ -0,0 +1,452 @@
# Configuração do Tema Padrão {#default-theme-config}
A configuração do tema permite que você personalize seu tema. Você pode definir a configuração do tema através da opção `themeConfig` no arquivo de configuração:
```ts
export default {
lang: 'pt-BR',
title: 'VitePress',
description: 'Gerador de site estático Vite & Vue.',
// Configurações relacionadas ao tema.
themeConfig: {
logo: '/logo.svg',
nav: [...],
sidebar: { ... }
}
}
```
**As opções documentadas nesta página se aplicam apenas ao tema padrão.** Temas diferentes esperam configurações de tema diferentes. Ao usar um tema personalizado, o objeto de configuração do tema será passado para o tema para que se possam definir comportamentos condicionais.
## i18nRouting
- Tipo: `boolean`
Alterar o local para, por exemplo, `zh` alterará a URL de `/foo` (ou `/en/foo/`) para `/zh/foo`. Você pode desativar esse comportamento definindo `themeConfig.i18nRouting` como `false`.
## logo
- Tipo: `ThemeableImage`
Arquivo de logo a ser exibido na barra de navegação, logo antes do título do site. Aceita um caminho em string, ou um objeto para definir um logo diferente para os modos claro/escuro.
```ts
export default {
themeConfig: {
logo: '/logo.svg'
}
}
```
```ts
type ThemeableImage =
| string
| { src: string; alt?: string }
| { light: string; dark: string; alt?: string }
```
## siteTitle
- Tipo: `string | false`
Você pode personalizar este item para substituir o título padrão do site (`title` na configuração da aplicação) na navegação. Quando definido como `false`, o título na navegação será desativado. Útil quando você tem um `logo` que já contém o título do site.
```ts
export default {
themeConfig: {
siteTitle: 'Olá Mundo'
}
}
```
## nav
- Tipo: `NavItem`
A configuração para o item do menu de navegação. Mais detalhes em [Tema Padrão: Navegação](./default-theme-nav#navigation-links).
```ts
export default {
themeConfig: {
nav: [
{ text: 'Guia', link: '/guide' },
{
text: 'Menu Dropdown',
items: [
{ text: 'Item A', link: '/item-1' },
{ text: 'Item B', link: '/item-2' },
{ text: 'Item C', link: '/item-3' }
]
}
]
}
}
```
```ts
type NavItem = NavItemWithLink | NavItemWithChildren
interface NavItemWithLink {
text: string
link: string
activeMatch?: string
target?: string
rel?: string
noIcon?: boolean
}
interface NavItemChildren {
text?: string
items: NavItemWithLink[]
}
interface NavItemWithChildren {
text?: string
items: (NavItemChildren | NavItemWithLink)[]
activeMatch?: string
}
```
## sidebar
- Tipo: `Sidebar`
A configuração para o item do menu da barra lateral. Mais detalhes em [Tema Padrão: Barra Lateral](./default-theme-sidebar).
```ts
export default {
themeConfig: {
sidebar: [
{
text: 'Guia',
items: [
{ text: 'Introdução', link: '/introduction' },
{ text: 'Começando', link: '/getting-started' },
...
]
}
]
}
}
```
```ts
export type Sidebar = SidebarItem[] | SidebarMulti
export interface SidebarMulti {
[path: string]: SidebarItem[]
}
export type SidebarItem = {
/**
* O rótulo de texto do item.
*/
text?: string
/**
* O link do item.
*/
link?: string
/**
* Os filhos do item.
*/
items?: SidebarItem[]
/**
* Se não especificado, o grupo não é retrátil.
*
* Se `true`, o grupo é retrátil e é colapsado por padrão.
*
* Se `false`, o grupo é retrátil, mas expandido por padrão.
*/
collapsed?: boolean
}
```
## aside
- Tipo: `boolean | 'left'`
- Padrão: `true`
- Pode ser anulado por página via [frontmatter](./frontmatter-config#aside)
Definir este valor como `false` impede a apresentação do elemento aside.\
Definir este valor como `true` apresenta o aside à direita.\
Definir este valor como `left` apresenta o aside à esquerda.
Se você quiser desativá-lo para todas as visualizações, você deve usar `outline: false` em vez disso.
## outline
- Tipo: `Outline | Outline['level'] | false`
- O nível pode ser sobreposto por página via [frontmatter](./frontmatter-config#outline)
Definir este valor como `false` impede a apresentação do elemento _outline_. Consulte a interface para obter mais detalhes:
```ts
interface Outline {
/**
* Os níveis de títulos a serem exibidos na outline.
* Um único número significa que apenas os títulos desse nível serão exibidos.
* Se uma tupla for passada, o primeiro número é o nível mínimo e o segundo número é o nível máximo.
* `'deep'` é o mesmo que `[2, 6]`, o que significa que todos os títulos de `<h2>` a `<h6>` serão exibidos.
*
* @default 2
*/
level?: number | [number, number] | 'deep'
/**
* O título a ser exibido na outline.
*
* @default 'On this page'
*/
label?: string
}
```
## socialLinks
- Tipo: `SocialLink[]`
Você pode definir esta opção para mostrar os links de redes sociais com ícones na navegação.
```ts
export default {
themeConfig: {
socialLinks: [
{ icon: 'github', link: 'https://github.com/vuejs/vitepress' },
{ icon: 'twitter', link: '...' },
// Você também pode adicionar ícones personalizados passando SVG como string:
{
icon: {
svg: '<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Dribbble</title><path d="M12...6.38z"/></svg>'
},
link: '...',
// Você também pode incluir um rótulo personalizado para acessibilidade (opcional mas recomendado):
ariaLabel: 'cool link'
}
]
}
}
```
```ts
interface SocialLink {
icon: SocialLinkIcon
link: string
ariaLabel?: string
}
type SocialLinkIcon =
| 'discord'
| 'facebook'
| 'github'
| 'instagram'
| 'linkedin'
| 'mastodon'
| 'npm'
| 'slack'
| 'twitter'
| 'x'
| 'youtube'
| { svg: string }
```
## footer
- Tipo: `Footer`
- Pode ser sobreposto por página via [frontmatter](./frontmatter-config#footer)
Configuração do rodapé. Você pode adicionar uma mensagem ou texto de direitos autorais no rodapé, no entanto, ela só será exibida quando a página não contiver uma barra lateral. Isso se deve a preocupações de design.
```ts
export default {
themeConfig: {
footer: {
message: 'Lançado sob a Licença MIT.',
copyright: 'Direitos autorais © 2019-presente Evan You'
}
}
}
```
```ts
export interface Footer {
message?: string
copyright?: string
}
```
## editLink
- Tipo: `EditLink`
- Pode ser sobreposto por página via [frontmatter](./frontmatter-config#editlink)
O _EditLink_ permite exibir um link para editar a página em serviços de gerenciamento Git, como GitHub ou GitLab. Consulte [Tema Padrão: Editar Link](./default-theme-edit-link) para mais detalhes.
```ts
export default {
themeConfig: {
editLink: {
pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',
text: 'Editar esta página no GitHub'
}
}
}
```
```ts
export interface EditLink {
pattern: string
text?: string
}
```
## lastUpdated
- Tipo: `LastUpdatedOptions`
Permite personalização para o texto de última atualização e o formato de data.
```ts
export default {
themeConfig: {
lastUpdated: {
text: 'Atualizado em',
formatOptions: {
dateStyle: 'full',
timeStyle: 'medium'
}
}
}
}
```
```ts
export interface LastUpdatedOptions {
/**
* @default 'Last updated'
*/
text?: string
/**
* @default
* { dateStyle: 'short', timeStyle: 'short' }
*/
formatOptions?: Intl.DateTimeFormatOptions & { forceLocale?: boolean }
}
```
## algolia
- Tipo: `AlgoliaSearch`
Uma opção para dar suporte à pesquisa em seu site de documentação usando [Algolia DocSearch](https://docsearch.algolia.com/docs/what-is-docsearch). Saiba mais em [Tema Padrão: Pesquisa](./default-theme-search).
```ts
export interface AlgoliaSearchOptions extends DocSearchProps {
locales?: Record<string, Partial<DocSearchProps>>
}
```
Veja todas as opções [aqui](https://github.com/vuejs/vitepress/blob/main/types/docsearch.d.ts).
## carbonAds {#carbon-ads}
- Tipo: `CarbonAdsOptions`
Uma opção para mostrar [Carbon Ads](https://www.carbonads.net/).
```ts
export default {
themeConfig: {
carbonAds: {
code: 'seu-código-carbon',
placement: 'sua-veiculação-carbon'
}
}
}
```
```ts
export interface CarbonAdsOptions {
code: string
placement: string
}
```
Saiba mais em [Tema Padrão: Carbon Ads](./default-theme-carbon-ads).
## docFooter
- Tipo: `DocFooter`
Pode ser usado para personalizar o texto que aparece acima dos links anterior e próximo. Útil se não estiver escrevendo documentação em inglês. Também pode ser usado para desabilitar globalmente os links anterior/próximo. Se você quiser ativar/desativar seletivamente os links anterior/próximo, pode usar [frontmatter](./default-theme-prev-next-links).
```ts
export default {
themeConfig: {
docFooter: {
prev: 'Página anterior',
next: 'Próxima página'
}
}
}
```
```ts
export interface DocFooter {
prev?: string | false
next?: string | false
}
```
## darkModeSwitchLabel
- Tipo: `string`
- Padrão: `Appearance`
Pode ser usado para personalizar o rótulo do botão de modo escuro. Esse rótulo é exibido apenas na visualização móvel.
## lightModeSwitchTitle
- Tipo: `string`
- Padrão: `Switch to light theme`
Pode ser usado para personalizar o título do botão de modo claro que aparece ao passar o mouse.
## darkModeSwitchTitle
- Tipo: `string`
- Padrão: `Switch to dark theme`
Pode ser usado para personalizar o título do botão de modo escuro que aparece ao passar o mouse.
## sidebarMenuLabel
- Tipo: `string`
- Padrão: `Menu`
Pode ser usado para personalizar o rótulo do menu da barra lateral. Esse rótulo é exibido apenas na visualização móvel.
## returnToTopLabel
- Tipo: `string`
- Padrão: `Return to top`
Pode ser usado para personalizar o rótulo do botão de retorno ao topo. Esse rótulo é exibido apenas na visualização móvel.
## langMenuLabel
- Tipo: `string`
- Padrão: `Change language`
Pode ser usado para personalizar o aria-label do botão de idioma na barra de navegação. Isso é usado apenas se você estiver usando [i18n](../guide/i18n).
## externalLinkIcon
- Tipo: `boolean`
- Padrão: `false`
Se deve mostrar um ícone de link externo ao lado de links externos no markdown.

@ -0,0 +1,60 @@
# Editar Link {#edit-link}
## Configuração a nível de Site {#site-level-config}
Editar Link permite que você mostre um link para editar a página com serviços de gerenciamento Git, como GitHub ou GitLab. Para habilitar, adicione a opção `themeConfig.editLink` na sua configuração.
```js
export default {
themeConfig: {
editLink: {
pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path'
}
}
}
```
A opção `pattern` define a estrutura da URL para o link, e `:path` será substituído com o mesmo caminho de página.
Você também pode colocar uma função pura que aceita [`PageData`](./runtime-api#usedata) como argumento e retorna uma URL em string.
```js
export default {
themeConfig: {
editLink: {
pattern: ({ filePath }) => {
if (filePath.startsWith('packages/')) {
return `https://github.com/acme/monorepo/edit/main/${filePath}`
} else {
return `https://github.com/acme/monorepo/edit/main/docs/${filePath}`
}
}
}
}
}
```
Isso não deve gerar efeitos colaterais ou acessar qualquer coisa fora do seu escopo, uma vez que será serializado e executado no navegador.
Por padrão, isso irá adicionar o link com texto "Edite essa página" no final da página de documentação. Você pode personalizar esse texto ao definir a opção `text`.
```js
export default {
themeConfig: {
editLink: {
pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',
text: 'Edite essa página no GitHub'
}
}
}
```
## Configuração Frontmatter {#frontmatter-config}
A funcionalidade pode ser desabilitada por página usando a opção `editLink` no frontmatter:
```yaml
---
editLink: false
---
```

@ -0,0 +1,53 @@
# Rodapé {#footer}
VitePress irá mostrar o rodapé global na parte inferior da página quando `themeConfig.footer` está presente.
```ts
export default {
themeConfig: {
footer: {
message: 'Lançado sob Licença MIT.',
copyright: 'Direitos Reservados © 2019-present Evan You'
}
}
}
```
```ts
export interface Footer {
// A mensagem mostrada logo antes do copyright.
message?: string
// O próprio texto de copyright.
copyright?: string
}
```
A configuração acima também suporta strings HTML. Então, por exemplo, se você quiser configurar o texto de rodapé para ter alguns links, você pode ajustar a configuração como o seguinte:
```ts
export default {
themeConfig: {
footer: {
message: 'Lançado sob <a href="https://github.com/vuejs/vitepress/blob/main/LICENSE">Licença MIT</a>.',
copyright: 'Direitos Reservados © 2019-present <a href="https://github.com/yyx990803">Evan You</a>'
}
}
}
```
::: warning
Apenas elementos _inline_ serão usados em `message` e `copyright` conforme eles são apresentados dentro do elemento `<p>`. Se você quiser adicionar elementos de tipo _block_, considere usar o _slot_ [`layout-bottom`](../guide/extending-default-theme#layout-slots).
:::
Note que o rodapé não será mostrado quando a [Barra Lateral](./default-theme-sidebar) estiver visível.
## Configuração Frontmatter {#frontmatter-config}
Isso pode ser desabilitado por página usando a opção `footer` em frontmatter:
```yaml
---
footer: false
---
```

@ -0,0 +1,168 @@
# Página Inicial {#home-page}
O tema padrão VitePress fornece um layout de página inicial, que você também pode ver em uso [na página inicial deste site](../). Você pode usá-lo em qualquer uma de suas páginas especificando `layout: home` em [frontmatter](./frontmatter-config).
```yaml
---
layout: home
---
```
No entanto, essa opção sozinha não faz muito. Você pode adicionar várias "seções" diferentes pré-modeladas à página inicial definindo opções adicionais como `hero` e `features`.
## Seção Hero {#hero-section}
A seção _Hero_ fica no topo da página inicial. Aqui segue como você pode configurar a seção _Hero_.
```yaml
---
layout: home
hero:
name: VitePress
text: Gerador de site estático com Vite & Vue.
tagline: Lorem ipsum...
image:
src: /logo.png
alt: VitePress
actions:
- theme: brand
text: Iniciar
link: /guide/what-is-vitepress
- theme: alt
text: Ver no GitHub
link: https://github.com/vuejs/vitepress
---
```
```ts
interface Hero {
// A string mostrada acima de `text`. Vem com a cor da marca
// e espera-se que seja curta, como o nome do produto.
name?: string
// O texto principal para a seção hero.
// Isso será definido como uma tag `h1`.
text: string
// Slogan exibido abaixo de `text`.
tagline?: string
// A imagem é exibida ao lado da área de texto e slogan.
image?: ThemeableImage
// Botões acionáveis para exibir na seção hero da página inicial.
actions?: HeroAction[]
}
type ThemeableImage =
| string
| { src: string; alt?: string }
| { light: string; dark: string; alt?: string }
interface HeroAction {
// Tema de cor do botão. Padrão: `brand`.
theme?: 'brand' | 'alt'
// Rótulo do botão.
text: string
// Destino do link do botão.
link: string
// Atributo target do link.
target?: string
// Atributo rel do link.
rel?: string
}
```
### Personalizando a cor do nome {#customizing-the-name-color}
VitePress usa a cor da marca (`--vp-c-brand-1`) para `name`. No entanto, você pode personalizar essa cor sobrescrevendo a variável `--vp-home-hero-name-color`.
```css
:root {
--vp-home-hero-name-color: blue;
}
```
Você também pode personalizá-la ainda mais combinando `--vp-home-hero-name-background` para dar ao `name` uma cor degradê.
```css
:root {
--vp-home-hero-name-color: transparent;
--vp-home-hero-name-background: -webkit-linear-gradient(120deg, #bd34fe, #41d1ff);
}
```
## Seção de Funcionalidades {#features-section}
Na seção de funcionalidades, você pode listar qualquer número de funcionalidades que deseja mostrar imediatamente após a seção _Hero_. Para configurá-la, passe a opção `features` para o frontmatter.
Você pode fornecer um ícone para cada funcionalidade, que pode ser um emoji ou qualquer tipo de imagem. Quando o ícone configurado é uma imagem (svg, png, jpeg...), você deve fornecer o ícone com a largura e altura apropriadas; você também pode fornecer a descrição, seu tamanho intrínseco, bem como suas variantes para temas escuros e claros quando necessário.
```yaml
---
layout: home
features:
- icon: 🛠️
title: Simples e minimalista, sempre
details: Lorem ipsum...
- icon:
src: /cool-feature-icon.svg
title: Outro recurso legal
details: Lorem ipsum...
- icon:
dark: /dark-feature-icon.svg
light: /light-feature-icon.svg
title: Outro recurso legal
details: Lorem ipsum...
---
```
```ts
interface Feature {
// Mostra ícone em cada bloco de funcionalide.
icon?: FeatureIcon
// Título da funcionalidade.
title: string
// Detalhes da funcionalidade.
details: string
// Link quando clicado no componente de funcionalidade.
// O link pode ser interno ou externo.
//
// ex. `guide/reference/default-theme-home-page` ou `https://example.com`
link?: string
// Texto do link a ser exibido dentro do componente de funcionalidade.
// Melhor usado com a opção `link`.
//
// ex. `Saiba mais`, `Visitar página`, etc.
linkText?: string
// Atributo rel do link para a opção `link`.
//
// ex. `external`
rel?: string
// Atributo target do link para a opção `link`.
target?: string
}
type FeatureIcon =
| string
| { src: string; alt?: string; width?: string; height: string }
| {
light: string
dark: string
alt?: string
width?: string
height: string
}
```

@ -0,0 +1,27 @@
# Última Atualização {#last-updated}
O tempo em que o conteúdo foi atualizado pela última vez será mostrado no canto inferior direito da página. Para habilitar, adicione a opção `lastUpdated` na sua configuração.
::: tip
Você precisa fazer _commit_ no arquivo markdown para ver o tempo atualizado.
:::
## Configuração a nível de Site {#site-level-config}
```js
export default {
lastUpdated: true
}
```
## Configuração Frontmatter {#frontmatter-config}
Isso pode ser desabilitado por página usando a opção `lastUpdated` no frontmatter:
```yaml
---
lastUpdated: false
---
```
Refira-se ao [Tema Padrão: Última Atualização](./default-theme-config#lastupdated) para mais detalhes. Qualquer valor positivo a nível de tema também habilitará a funcionalidade a não ser que esteja explicitamente desabilitada a nível de página ou de site.

@ -0,0 +1,62 @@
# Layout {#layout}
Você pode escolher o layout da página definindo a opção de `layout` para o [frontmatter](./frontmatter-config) da página. Há três opções de layout: `doc`, `page` e `home`. Se nada for especificado, a página será tratada como página `doc`.
```yaml
---
layout: doc
---
```
## Layout do documento {#doc-layout}
A opção `doc` é o layout padrão e estiliza todo o conteúdo Markdown com o visual de "documentação". Ela funciona agrupando todo o conteúdo na classe CSS `vp-doc`, e aplicando os estilos aos elementos abaixo dela.
Quase todos os elementos genéricos, como `p` ou `h2`, recebem um estilo especial. Portanto, lembre-se de que se você adicionar qualquer HTML personalizado dentro de um conteúdo Markdown, ele também será afetado por esses estilos.
Ele também fornece recursos específicos de documentação listados abaixo. Esses recursos estão habilitados apenas neste layout.
- Editar link
- Links Anterior e Próximo
- _Outline_
- [Carbon Ads](./default-theme-carbon-ads)
## Layout da Página {#page-layout}
A opção `page` é tratada como "página em branco". O Markdown ainda será processado e todas as [Extensões Markdown](../guide/markdown) funcionarão da mesma forma que o layout `doc`, mas este não receberá nenhum estilo padrão.
O layout da página permitirá que você estilize tudo sem que o tema VitePress afete a marcação. Isso é útil quando você deseja criar sua própria página personalizada.
Observe que mesmo neste layout, a barra lateral ainda aparecerá se a página tiver uma configuração de barra lateral correspondente.
## Layout da Home {#home-layout}
A opção `home` gerará um modelo de _"Homepage"_. Nesse layout você pode definir opções extras, como `hero` e `features`, para personalizar ainda mais o conteúdo. Visite [Tema padrão: Página Inicial](./default-theme-home-page) para obter mais detalhes.
## Sem Layout {#no-layout}
Se você não quiser nenhum layout, pode passar `layout: false` pelo frontmatter. Esta opção é útil se você deseja uma página de destino totalmente personalizável (sem barra lateral, barra de navegação ou rodapé por padrão).
## Layout Personalizado {#custom-layout}
Você também pode usar um layout personalizado:
```md
---
layout: foo
---
```
Isto irá procurar um componente chamado `foo` registrado no contexto. Por exemplo, você pode registrar seu componente globalmente em `.vitepress/theme/index.ts`:
```ts
import DefaultTheme from 'vitepress/theme'
import Foo from './Foo.vue'
export default {
extends: DefaultTheme,
enhanceApp({ app }) {
app.component('foo', Foo)
}
}
```

@ -0,0 +1,162 @@
# Navegação {#nav}
Referente a barra de navegação exibida no topo da página. Ela contém o título do site, links do menu global, e etc.
## Título do Site e Logo {#site-title-and-logo}
Por padrão, a navegação mostra o título do site referenciando o valor de [`config.title`](./site-config#title). Se desejar alterar o que é exibido na navegação, você pode definir um texto personalizado na opção `themeConfig.siteTitle`.
```js
export default {
themeConfig: {
siteTitle: 'Meu Título Personalizado'
}
}
```
Se você tiver um logo para seu site, pode mostrá-lo passando o caminho para a imagem. Você deve colocar o logo diretamente dentro da pasta `public`, e definir o caminho absoluto para ele.
```js
export default {
themeConfig: {
logo: '/my-logo.svg'
}
}
```
Ao adicionar um logo, ele é mostrado juntamente com o título do site. Se seu logo tem tudo o que você precisa e se você desejar ocultar o texto do título, defina `false` na opção `siteTitle`.
```js
export default {
themeConfig: {
logo: '/my-logo.svg',
siteTitle: false
}
}
```
Você também pode passar um objeto como logo se quiser adicionar um atributo `alt` ou personalizá-lo com base no modo claro/escuro. Consulte [`themeConfig.logo`](./default-theme-config#logo) para obter detalhes.
## Links de Navegação {#navigation-links}
Você pode definir a opção `themeConfig.nav` para adicionar links à sua navegação.
```js
export default {
themeConfig: {
nav: [
{ text: 'Guia', link: '/guide' },
{ text: 'Configuração', link: '/config' },
{ text: 'Registro de Alterações', link: 'https://github.com/...' }
]
}
}
```
`text` é o próprio texto mostrado na navegação, e o `link` é o link para o qual será navegado quando o texto for clicado. Para o link, defina o caminho para o próprio arquivo sem o prefixo `.md` e sempre comece com `/`.
Links de navegação também podem ser menus _dropdown_. Para fazer isso, defina a chave `items` na opção do link.
```js
export default {
themeConfig: {
nav: [
{ text: 'Guia', link: '/guide' },
{
text: 'Menu Dropdown',
items: [
{ text: 'Item A', link: '/item-1' },
{ text: 'Item B', link: '/item-2' },
{ text: 'Item C', link: '/item-3' }
]
}
]
}
}
```
Note que o título do menu _dropdown_ (`Menu Dropdown` no exemplo acima) não pode ter a propriedade `link`, pois ele se torna um botão para abrir o diálogo dropdown.
Você também pode adicionar "seções" aos itens do menu _dropdown_ passando mais itens aninhados.
```js
export default {
themeConfig: {
nav: [
{ text: 'Guia', link: '/guia' },
{
text: 'Menu Dropdown',
items: [
{
// Título da seção.
text: 'Título da Seção A',
items: [
{ text: 'Item A da Seção A', link: '...' },
{ text: 'Item B da Seção B', link: '...' }
]
}
]
},
{
text: 'Menu Dropdown',
items: [
{
// Você também pode omitir o título.
items: [
{ text: 'Item A da Seção A', link: '...' },
{ text: 'Item B da Seção B', link: '...' }
]
}
]
}
]
}
}
```
### Personalizar o estado "ativo" do link {#customize-link-s-active-state}
Os itens do menu de navegação serão destacados quando a página atual estiver no caminho correspondente. Se desejar personalizar o caminho a ser correspondido, defina a propriedade `activeMatch` e regex como um valor em string.
```js
export default {
themeConfig: {
nav: [
// Este link fica no estado ativo quando
// o usuário está no caminho `/config/`.
{
text: 'Guia',
link: '/guide',
activeMatch: '/config/'
}
]
}
}
```
::: warning
`activeMatch` deve ser uma string regex, mas você deve defini-la como uma string. Não podemos usar um objeto RegExp real aqui porque ele não é serializável durante o momento de construção.
:::
### Personalizar os atributos "target" e "rel" de links {#customize-link-s-target-and-rel-attributes}
Por padrão, VitePress determina automaticamente os atributos `target` e `rel` baseado em um link externo ou não. Mas se você quiser, também pode personalizá-los.
```js
export default {
themeConfig: {
nav: [
{
text: 'Merchandise',
link: 'https://www.thegithubshop.com/',
target: '_self',
rel: 'sponsored'
}
]
}
}
```
## Links Sociais {#social-links}
Consulte [`socialLinks`](./default-theme-config#sociallinks).

@ -0,0 +1,43 @@
# Links Anterior e Próximo {#prev-next-links}
Você pode personalizar o texto e o link para os botões de Anterior e Próximo mostrados ao fim da página. Isso é útil quando você quer mostrar um texto diferente daquele que você tem na barra lateral. Além disso, você pode achar útil desabilitar o rodapé ou link para a página para ela não ser incluída na sua barra lateral.
## prev
- Tipo: `string | false | { text?: string; link?: string }`
- Detalhes:
Especifica o texto/link para mostrar no link para a página anterior. Se você não ver isso no frontmatter, o texto/link será inferido da configuração da barra lateral.
- Exemplos:
- Para personalizar apenas o texto:
```yaml
---
prev: 'Iniciar | Markdown'
---
```
- Para personalizar ambos texto e link:
```yaml
---
prev:
text: 'Markdown'
link: '/guide/markdown'
---
```
- Para esconder a página anterior:
```yaml
---
prev: false
---
```
## next
O mesmo que `prev` mas para a próxima página.

@ -0,0 +1,379 @@
---
outline: deep
---
# Pesquisa {#search}
## Pesquisa Local {#local-search}
VitePress oferece suporte à pesquisa de texto completa usando um índice no navegador graças ao [minisearch](https://github.com/lucaong/minisearch/). Para habilitar esse recurso, basta definir a opção `themeConfig.search.provider` como `'local'` no arquivo `.vitepress/config.ts`:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
themeConfig: {
search: {
provider: 'local'
}
}
})
```
Exemplo de resultado:
![captura de tela do modal de pesquisa](/search.png)
Alternativamente, você pode usar [Algolia DocSearch](#algolia-search) ou alguns plugins da comunidade como <https://www.npmjs.com/package/vitepress-plugin-search> ou <https://www.npmjs.com/package/vitepress-plugin-pagefind>.
### i18n {#local-search-i18n}
Você pode usar uma configuração como esta para usar a pesquisa multilínguas:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
themeConfig: {
search: {
provider: 'local',
options: {
locales: {
zh: {
translations: {
button: {
buttonText: '搜索文档',
buttonAriaLabel: '搜索文档'
},
modal: {
noResultsText: '无法找到相关结果',
resetButtonTitle: '清除查询条件',
footer: {
selectText: '选择',
navigateText: '切换'
}
}
}
}
}
}
}
}
})
```
### Opções MiniSearch {#mini-search-options}
Você pode configurar o MiniSearch assim:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
themeConfig: {
search: {
provider: 'local',
options: {
miniSearch: {
/**
* @type {Pick<import('minisearch').Options, 'extractField' | 'tokenize' | 'processTerm'>}
*/
options: {
/* ... */
},
/**
* @type {import('minisearch').SearchOptions}
* @default
* { fuzzy: 0.2, prefix: true, boost: { title: 4, text: 2, titles: 1 } }
*/
searchOptions: {
/* ... */
}
}
}
}
}
})
```
Saiba mais na [documentação do MiniSearch](https://lucaong.github.io/minisearch/classes/MiniSearch.MiniSearch.html).
### Apresentador de Conteúdo Personalizado {#custom-content-renderer}
Você pode personalizar a função usada para apresentar o conteúdo markdown antes de indexá-lo:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
themeConfig: {
search: {
provider: 'local',
options: {
/**
* @param {string} src
* @param {import('vitepress').MarkdownEnv} env
* @param {import('markdown-it')} md
*/
_render(src, env, md) {
// retorne a string HTML
}
}
}
}
})
```
Essa função será removida dos dados do site no lado do cliente, então você pode usar APIs do Node.js nela.
#### Exemplo: Excluindo páginas da pesquisa {#example-excluding-pages-from-search}
Você pode excluir páginas da pesquisa adicionando `search: false` ao frontmatter da página. Alternativamente:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
themeConfig: {
search: {
provider: 'local',
options: {
_render(src, env, md) {
const html = md.render(src, env)
if (env.frontmatter?.search === false) return ''
if (env.relativePath.startsWith('algum/caminho')) return ''
return html
}
}
}
}
})
```
::: warning Nota
No caso uma função `_render` personalizada ser fornecida, você precisa manipular o `search: false` do frontmatter por conta própria. Além disso, o objeto `env` não estará completamente populado antes que `md.render` seja chamado, então verificações em propriedades opcionais `env`, como `frontmatter`, devem ser feitas após isso.
:::
#### Exemplo: Transformando conteúdo - adicionando âncoras {#example-transforming-content-adding-anchors}
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
themeConfig: {
search: {
provider: 'local',
options: {
_render(src, env, md) {
const html = md.render(src, env)
if (env.frontmatter?.title)
return md.render(`# ${env.frontmatter.title}`) + html
return html
}
}
}
}
})
```
## Pesquisa Algolia {#algolia-search}
VitePress oferece suporte à pesquisa em seu site de documentação usando [Algolia DocSearch](https://docsearch.algolia.com/docs/what-is-docsearch). Consulte o guia de início deles. Em seu arquivo `.vitepress/config.ts`, você precisará fornecer pelo menos o seguinte para que funcione:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
themeConfig: {
search: {
provider: 'algolia',
options: {
appId: '...',
apiKey: '...',
indexName: '...'
}
}
}
})
```
### i18n {#algolia-search-i18n} {#algolia-search-i18n}
Você pode usar uma configuração como esta para usar a pesquisa multilínguas:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
themeConfig: {
search: {
provider: 'algolia',
options: {
appId: '...',
apiKey: '...',
indexName: '...',
locales: {
zh: {
placeholder: '搜索文档',
translations: {
button: {
buttonText: '搜索文档',
buttonAriaLabel: '搜索文档'
},
modal: {
searchBox: {
resetButtonTitle: '清除查询条件',
resetButtonAriaLabel: '清除查询条件',
cancelButtonText: '取消',
cancelButtonAriaLabel: '取消'
},
startScreen: {
recentSearchesTitle: '搜索历史',
noRecentSearchesText: '没有搜索历史',
saveRecentSearchButtonTitle: '保存至搜索历史',
removeRecentSearchButtonTitle: '从搜索历史中移除',
favoriteSearchesTitle: '收藏',
removeFavoriteSearchButtonTitle: '从收藏中移除'
},
errorScreen: {
titleText: '无法获取结果',
helpText: '你可能需要检查你的网络连接'
},
footer: {
selectText: '选择',
navigateText: '切换',
closeText: '关闭',
searchByText: '搜索提供者'
},
noResultsScreen: {
noResultsText: '无法找到相关结果',
suggestedQueryText: '你可以尝试查询',
reportMissingResultsText: '你认为该查询应该有结果?',
reportMissingResultsLinkText: '点击反馈'
}
}
}
}
}
}
}
}
})
```
[Essas opções](https://github.com/vuejs/vitepress/blob/main/types/docsearch.d.ts) podem ser sobrepostas. Consulte a documentação oficial Algolia para obter mais informações sobre elas.
### Configuração _Crawler_ {#crawler-config}
Aqui está um exemplo de configuração baseado na qual este site usa:
```ts
new Crawler({
appId: '...',
apiKey: '...',
rateLimit: 8,
startUrls: ['https://vitepress.dev/'],
renderJavaScript: false,
sitemaps: [],
exclusionPatterns: [],
ignoreCanonicalTo: false,
discoveryPatterns: ['https://vitepress.dev/**'],
schedule: 'at 05:10 on Saturday',
actions: [
{
indexName: 'vitepress',
pathsToMatch: ['https://vitepress.dev/**'],
recordExtractor: ({ $, helpers }) => {
return helpers.docsearch({
recordProps: {
lvl1: '.content h1',
content: '.content p, .content li',
lvl0: {
selectors: '',
defaultValue: 'Documentation'
},
lvl2: '.content h2',
lvl3: '.content h3',
lvl4: '.content h4',
lvl5: '.content h5'
},
indexHeadings: true
})
}
}
],
initialIndexSettings: {
vitepress: {
attributesForFaceting: ['type', 'lang'],
attributesToRetrieve: ['hierarchy', 'content', 'anchor', 'url'],
attributesToHighlight: ['hierarchy', 'hierarchy_camel', 'content'],
attributesToSnippet: ['content:10'],
camelCaseAttributes: ['hierarchy', 'hierarchy_radio', 'content'],
searchableAttributes: [
'unordered(hierarchy_radio_camel.lvl0)',
'unordered(hierarchy_radio.lvl0)',
'unordered(hierarchy_radio_camel.lvl1)',
'unordered(hierarchy_radio.lvl1)',
'unordered(hierarchy_radio_camel.lvl2)',
'unordered(hierarchy_radio.lvl2)',
'unordered(hierarchy_radio_camel.lvl3)',
'unordered(hierarchy_radio.lvl3)',
'unordered(hierarchy_radio_camel.lvl4)',
'unordered(hierarchy_radio.lvl4)',
'unordered(hierarchy_radio_camel.lvl5)',
'unordered(hierarchy_radio.lvl5)',
'unordered(hierarchy_radio_camel.lvl6)',
'unordered(hierarchy_radio.lvl6)',
'unordered(hierarchy_camel.lvl0)',
'unordered(hierarchy.lvl0)',
'unordered(hierarchy_camel.lvl1)',
'unordered(hierarchy.lvl1)',
'unordered(hierarchy_camel.lvl2)',
'unordered(hierarchy.lvl2)',
'unordered(hierarchy_camel.lvl3)',
'unordered(hierarchy.lvl3)',
'unordered(hierarchy_camel.lvl4)',
'unordered(hierarchy.lvl4)',
'unordered(hierarchy_camel.lvl5)',
'unordered(hierarchy.lvl5)',
'unordered(hierarchy_camel.lvl6)',
'unordered(hierarchy.lvl6)',
'content'
],
distinct: true,
attributeForDistinct: 'url',
customRanking: [
'desc(weight.pageRank)',
'desc(weight.level)',
'asc(weight.position)'
],
ranking: [
'words',
'filters',
'typo',
'attribute',
'proximity',
'exact',
'custom'
],
highlightPreTag: '<span class="algolia-docsearch-suggestion--highlight">',
highlightPostTag: '</span>',
minWordSizefor1Typo: 3,
minWordSizefor2Typos: 7,
allowTyposOnNumericTokens: false,
minProximity: 1,
ignorePlurals: true,
advancedSyntax: true,
attributeCriteriaComputedByMinProximity: true,
removeWordsIfNoResults: 'allOptional'
}
}
})
```
<style>
img[src="/search.png"] {
width: 100%;
aspect-ratio: 1 / 1;
}
</style>

@ -0,0 +1,215 @@
# Barra Lateral {#sidebar}
A barra lateral é o bloco principal de navegação da sua documentação. Você pode configurar o menu da barra lateral em [`themeConfig.sidebar`](./default-theme-config#sidebar).
```js
export default {
themeConfig: {
sidebar: [
{
text: 'Guia',
items: [
{ text: 'Introdução', link: '/introduction' },
{ text: 'Iniciando', link: '/getting-started' },
...
]
}
]
}
}
```
## O Básico {#the-basics}
A forma mais simples do menu da barra lateral é passar um único _array_ de links. O item do primeiro nível define a "seção" da barra lateral. Ele deve conter `text`, que é o título da seção, e `items` que são os próprios links de navegação.
```js
export default {
themeConfig: {
sidebar: [
{
text: 'Título da Seção A',
items: [
{ text: 'Item A', link: '/item-a' },
{ text: 'Item B', link: '/item-b' },
...
]
},
{
text: 'Título da Seção B',
items: [
{ text: 'Item C', link: '/item-c' },
{ text: 'Item D', link: '/item-d' },
...
]
}
]
}
}
```
Cada `link` deve especificar o caminho para o próprio arquivo começando com `/`. Se você adicionar uma barra no final do link, será mostrado o `index.md` do diretório correspondente.
```js
export default {
themeConfig: {
sidebar: [
{
text: 'Guia',
items: [
// Isso mostra a página `/guide/index.md`.
{ text: 'Introdução', link: '/guide/' }
]
}
]
}
}
```
Você pode aninhar ainda mais os itens da barra lateral até 6 níveis de profundidade contando a partir do nível raiz. Note que níveis mais profundos que 6 serão ignorados e não serão exibidos na barra lateral.
```js
export default {
themeConfig: {
sidebar: [
{
text: 'Nível 1',
items: [
{
text: 'Nível 2',
items: [
{
text: 'Nível 3',
items: [
...
]
}
]
}
]
}
]
}
}
```
## Múltiplas Barras Laterais {#multiple-sidebars}
Você pode mostrar uma barra lateral diferente dependendo do caminho da página. Por exemplo, como mostrado neste site, você pode querer criar seções separadas de conteúdo em sua documentação, como a página "Guia" e a página "Configuração".
Para fazer isso, primeiro organize suas páginas em diretórios para cada seção desejada:
```
.
├─ guide/
│ ├─ index.md
│ ├─ one.md
│ └─ two.md
└─ config/
├─ index.md
├─ three.md
└─ four.md
```
Em seguida, atualize sua configuração para definir sua barra lateral para cada seção. Desta vez, você deve passar um objeto em vez de um array.
```js
export default {
themeConfig: {
sidebar: {
// Esta barra lateral é exibida quando um usuário
// está no diretório `guide`.
'/guide/': [
{
text: 'Guia',
items: [
{ text: 'Índice', link: '/guide/' },
{ text: 'Um', link: '/guide/one' },
{ text: 'Dois', link: '/guide/two' }
]
}
],
// Esta barra lateral é exibida quando um usuário
// está no diretório `config`.
'/config/': [
{
text: 'Configuração',
items: [
{ text: 'Índice', link: '/config/' },
{ text: 'Três', link: '/config/three' },
{ text: 'Quatro', link: '/config/four' }
]
}
]
}
}
}
```
## Grupos Retráteis na Barra Lateral {#collapsible-sidebar-groups}
Adicionando a opção `collapsed` ao grupo da barra lateral, ela mostra um botão para ocultar/mostrar cada seção.
```js
export default {
themeConfig: {
sidebar: [
{
text: 'Título da Seção A',
collapsed: false,
items: [...]
}
]
}
}
```
Todas as seções são "abertas" por padrão. Se você deseja que elas estejam "fechadas" na carga inicial da página, defina a opção `collapsed` como `true`.
```js
export default {
themeConfig: {
sidebar: [
{
text: 'Título da Seção A',
collapsed: true,
items: [...]
}
]
}
}
```
## `useSidebar` <Badge type="info" text="composable" />
Retorna dados relacionados à barra lateral. O objeto retornado tem o seguinte 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">Visível apenas quando a barra lateral existe</div>
</template>
```

@ -0,0 +1,258 @@
<script setup>
import { VPTeamMembers } from 'vitepress/theme'
const members = [
{
avatar: 'https://github.com/yyx990803.png',
name: 'Evan You',
title: 'Criador',
links: [
{ icon: 'github', link: 'https://github.com/yyx990803' },
{ icon: 'twitter', link: 'https://twitter.com/youyuxi' }
]
},
{
avatar: 'https://github.com/kiaking.png',
name: 'Kia King Ishii',
title: 'Desenvolvedor',
links: [
{ icon: 'github', link: 'https://github.com/kiaking' },
{ icon: 'twitter', link: 'https://twitter.com/KiaKing85' }
]
}
]
</script>
# Página da Equipe {#team-page}
Se você quiser apresentar sua equipe, você pode usar componentes de equipe para construir a Página da Equipe. Existem duas maneiras de usar esses componentes. Uma é incorporá-lo na página de documento, e outra é criar uma Página de Equipe completa.
## Mostrar membros da equipe em uma página {#show-team-members-in-a-page}
Você pode usar o componente `<VPTeamMembers>` exposto em `vitepress/theme` para exibir uma lista de membros da equipe em qualquer página.
```html
<script setup>
import { VPTeamMembers } from 'vitepress/theme'
const members = [
{
avatar: 'https://www.github.com/yyx990803.png',
name: 'Evan You',
title: 'Criador',
links: [
{ icon: 'github', link: 'https://github.com/yyx990803' },
{ icon: 'twitter', link: 'https://twitter.com/youyuxi' }
]
},
...
]
</script>
# Nosso time
Diga olá à nossa equipe incrível.
<VPTeamMembers size="small" :members="members" />
```
O código acima exibirá um membro da equipe em um elemento tipo cartão. Ele deve exibir algo semelhante ao abaixo.
<VPTeamMembers size="small" :members="members" />
O componente `<VPTeamMembers>` vem em 2 tamanhos diferentes, pequeno `small` e médio `medium`. Enquanto é uma questão de preferência, geralmente o tamanho `small` deve encaixar melhor quando usado na página de documento. Além disso, você pode adicionar mais propriedades a cada membro, como adicionar o botão "descrição" ou "patrocinador". Saiba mais sobre em [`<VPTeamMembers>`](#vpteammembers).
Incorporar membros da equipe na página de documento é bom para equipes de pequeno porte, onde ter uma página de equipe inteira dedicada pode ser demais, ou introduzir membros parciais como uma referência ao contexto da documentação.
Se você tiver um grande número de membros, ou simplesmente quiser ter mais espaço para mostrar os membros da equipe, considere [criar uma página de equipe completa.](#create-a-full-team-page)
## Criando uma página de equipe completa {#create-a-full-team-page}
Em vez de adicionar membros da equipe à página de documento, você também pode criar uma Página de Equipe completa, da mesma forma que pode criar uma [Página Inicial](./default-theme-home-page) personalizada.
Para criar uma página de equipe, primeiro crie um novo arquivo md. O nome do arquivo não importa, mas aqui vamos chamá-lo de `team.md`. Neste arquivo, defina a opção `layout: page` do frontmatter, e então você poderá compor a estrutura da sua página usando componentes `TeamPage`.
```html
---
layout: page
---
<script setup>
import {
VPTeamPage,
VPTeamPageTitle,
VPTeamMembers
} from 'vitepress/theme'
const members = [
{
avatar: 'https://www.github.com/yyx990803.png',
name: 'Evan You',
title: 'Criador',
links: [
{ icon: 'github', link: 'https://github.com/yyx990803' },
{ icon: 'twitter', link: 'https://twitter.com/youyuxi' }
]
},
...
]
</script>
<VPTeamPage>
<VPTeamPageTitle>
<template #title>
Nosso time
</template>
<template #lead>
O desenvolvimento do VitePress é orientado por uma equipe internacional,
alguns dos membros escolheram ser apresentados abaixo.
</template>
</VPTeamPageTitle>
<VPTeamMembers
:members="members"
/>
</VPTeamPage>
```
Ao criar uma página de equipe completa, lembre-se de agrupar todos os componentes com o componente `<VPTeamPage>`. Este componente garantirá que todos os componentes aninhados relacionados à equipe obtenham a estrutura de layout adequada, como espaçamentos.
O componente `<VPPageTitle>` adiciona a seção de título da página. O título é `<h1>`. Use os _slots_ `#title` e `#lead`para documentar sobre sua equipe.
`<VPMembers>` funciona da mesma forma que quando usado em uma página de documento. Ele exibirá a lista de membros.
### Adicione seções para dividir os membros da equipe {#add-sections-to-divide-team-members}
Você pode adicionar "seções" à página da equipe. Por exemplo, você pode ter diferentes tipos de membros da equipe, como membros da Equipe Principal e Parceiros da Comunidade. Você pode dividir esses membros em seções para explicar melhor os papéis de cada grupo.
Para fazer isso, adicione o componente `<VPTeamPageSection>` ao arquivo `team.md` que criamos anteriormente.
```html
---
layout: page
---
<script setup>
import {
VPTeamPage,
VPTeamPageTitle,
VPTeamMembers,
VPTeamPageSection
} from 'vitepress/theme'
const coreMembers = [...]
const partners = [...]
</script>
<VPTeamPage>
<VPTeamPageTitle>
<template #title>Nosso time</template>
<template #lead>...</template>
</VPTeamPageTitle>
<VPTeamMembers size="medium" :members="coreMembers" />
<VPTeamPageSection>
<template #title>Parceiros</template>
<template #lead>...</template>
<template #members>
<VPTeamMembers size="small" :members="partners" />
</template>
</VPTeamPageSection>
</VPTeamPage>
```
O componente `<VPTeamPageSection>` pode ter os _slots_ `#title` e `#lead` similar ao componente `VPTeamPageTitle`, e também o _slot_ `#members` para exibir os membros da equipe.
Lembre-se de colocar o componente `<VPTeamMembers>` dentro do _slot_ `#members`.
## `<VPTeamMembers>`
O componente `<VPTeamMembers>` exibe uma determinada lista de membros.
```html
<VPTeamMembers
size="medium"
:members="[
{ avatar: '...', name: '...' },
{ avatar: '...', name: '...' },
...
]"
/>
```
```ts
interface Props {
// Tamanho de cada membro. O padrão é `medium`.
size?: 'small' | 'medium'
// Lista de membros a serem exibidos.
members: TeamMember[]
}
interface TeamMember {
// Imagem avatar do membro
avatar: string
// Nome do membro.
name: string
// Título a ser mostrado abaixo do nome do membro.
// Ex.: Desenvolvedor, Engenheiro de Software, etc.
title?: string
// Organização a qual o membro pertence.
org?: string
// URL da organização.
orgLink?: string
// Descrição do membro.
desc?: string
// Links sociais, por exemplo, GitHub, Twitter, etc.
// Você pode passar o objeto de Links Sociais aqui.
// Veja: https://vitepress.dev/reference/default-theme-config.html#sociallinks
links?: SocialLink[]
// URL da página de patrocinador do membro.
sponsor?: string
// Texto para o link do patrocinador. O padrão é 'Sponsor'.
actionText?: string
}
```
## `<VPTeamPage>`
O componente raiz ao criar uma página de equipe completa. Ele aceita apenas um único _slot_. Ele estilizará todos os componentes relacionados à equipe passados.
## `<VPTeamPageTitle>`
Adiciona a seção "título" da página. Melhor usar logo no início sob `<VPTeamPage>`. Aceita os _slots_ `#title` e `#lead`.
```html
<VPTeamPage>
<VPTeamPageTitle>
<template #title>
Nosso time
</template>
<template #lead>
O desenvolvimento do VitePress é orientado por uma equipe internacional,
alguns dos membros escolheram ser apresentados abaixo.
</template>
</VPTeamPageTitle>
</VPTeamPage>
```
## `<VPTeamPageSection>`
Cria uma "seção" na página da equipe. Aceita os _slots_ `#title`, `#lead` e `#members`. Você pode adicionar quantas seções quiser dentro de `<VPTeamPage>`.
```html
<VPTeamPage>
...
<VPTeamPageSection>
<template #title>Parceiros</template>
<template #lead>Lorem ipsum...</template>
<template #members>
<VPTeamMembers :members="data" />
</template>
</VPTeamPageSection>
</VPTeamPage>
```

@ -0,0 +1,221 @@
---
outline: deep
---
# Configuração Frontmatter {#frontmatter-config}
Frontmatter permite a configuração baseada em páginas. Em cada arquivo markdown, você pode usar a configuração frontmatter para sobrepor opções de configuração a nível de site ou de tema. Além disso, existem opções de configuração que só podem ser definidas em frontmatter.
Exemplo de uso:
```md
---
title: Documentação com VitePress
editLink: true
---
```
Você pode acessar os dados do frontmatter através da variável global `$frontmatter` em expressões Vue:
```md
{{ $frontmatter.title }}
```
## title
- Tipo: `string`
Título para a página. É o mesmo que [config.title](./site-config#title), e sobrepõe a configuração a nível de site.
```yaml
---
title: VitePress
---
```
## titleTemplate
- Tipo: `string | boolean`
O sufixo para o título. É o mesmo que [config.titleTemplate](./site-config#titletemplate), e sobrepõe a configuração a nível de site.
```yaml
---
title: VitePress
titleTemplate: Gerador de site estático com Vite & Vue
---
```
## description
- Tipo: `string`
Descrição para a página. É o mesmo que [config.description](./site-config#description), e sobrepõe a configuração a nível de site.
```yaml
---
description: VitePress
---
```
## head
- Tipo: `HeadConfig[]`
Especifica tags head adicionais a serem injetadas na página atual. Elas serão acrescentadas após as tags head injetadas pela configuração a nível de site.
```yaml
---
head:
- - meta
- name: description
content: hello
- - meta
- name: keywords
content: super duper SEO
---
```
```ts
type HeadConfig =
| [string, Record<string, string>]
| [string, Record<string, string>, string]
```
## Somente no Tema Padrão {#default-theme-only}
As seguintes opções frontmatter são aplicáveis apenas ao usar o tema padrão.
### layout
- Tipo: `doc | home | page`
- Padrão: `doc`
Determina o layout da página.
- `doc` - Aplica estilos de documentação padrão ao conteúdo markdown.
- `home` - Layout especial para a "Página Inicial". Você pode adicionar opções extras como `hero` e `features` para criar rapidamente uma bela página inicial.
- `page` - Comporta-se de maneira semelhante a `doc`, mas não aplica estilos ao conteúdo. Útil quando você deseja criar uma página totalmente personalizada.
```yaml
---
layout: doc
---
```
### hero <Badge type="info" text="apenas para página inicial" />
Define o conteúdo da seção _hero_ na página inicial quando `layout` está definido como `home`. Mais detalhes em [Tema Padrão: Página Inicial](./default-theme-home-page).
### features <Badge type="info" text="apenas para página inicial" />
Define os itens a serem exibidos na seção de funcionalidades quando `layout` está definido como `home`. Mais detalhes em [Tema Padrão: Página Inicial](./default-theme-home-page).
### navbar
- Tipo: `boolean`
- Padrão: `true`
Se deve exibir a [barra de navegação](./default-theme-nav).
```yaml
---
navbar: false
---
```
### sidebar
- Tipo: `boolean`
- Padrão: `true`
Se deve exibir a [barra lateral](./default-theme-sidebar).
```yaml
---
sidebar: false
---
```
### aside
- Tipo: `boolean | 'left'`
- Padrão: `true`
Define a localização do componente aside no layout `doc`.
Configurar este valor como `false` impede a apresentação do elemento aside.\
Configurar este valor como `true` apresenta o aside à direita.\
Configurar este valor como `'left'` apresenta o aside à esquerda.
```yaml
---
aside: false
---
```
### outline
- Tipo: `number | [number, number] | 'deep' | false`
- Padrão: `2`
Os níveis do cabeçalho no _outline_ a serem exibidos para a página. É o mesmo que [config.themeConfig.outline.level](./default-theme-config#outline), e sobrepõe o valor definido na configuração no nível do site.
### lastUpdated
- Tipo: `boolean | Date`
- Padrão: `true`
Se deve mostrar o texto de [última atualização](./default-theme-last-updated) no rodapé da página atual. Se uma data e hora específica forem especificadas, ela será exibida em vez do último horário de modificação do git.
```yaml
---
lastUpdated: false
---
```
### editLink
- Tipo: `boolean`
- Padrão: `true`
Se deve exibir o [link de edição](./default-theme-edit-link) no rodapé da página atual.
```yaml
---
editLink: false
---
```
### footer
- Tipo: `boolean`
- Padrão: `true`
Se deve exibir o [rodapé](./default-theme-footer).
```yaml
---
footer: false
---
```
### pageClass
- Tipo: `string`
Adiciona um nome de classe extra a uma página específica.
```yaml
---
pageClass: custom-page-class
---
```
Em seguida, você pode personalizar os estilos desta página específica no arquivo `.vitepress/theme/custom.css`:
```css
.custom-page-class {
  /* estilos específicos da página */
}
```

@ -0,0 +1,165 @@
# API em Tempo de Execução {#runtime-api}
VitePress oferece várias APIs embutidas para permitir o acesso aos dados da aplicação. VitePress vem também com alguns componentes embutidos que podem ser usados globalmente.
Os métodos auxiliares são importáveis globais de `vitepress` e geralmente são usados em componentes Vue de temas personalizados. No entanto, eles também podem ser usados dentro de páginas `.md` porque os arquivos markdown são compilados em [Componentes de Arquivo Único Vue (SFC)](https://vuejs.org/guide/scaling-up/sfc.html).
Métodos que começam com `use*` indicam que é uma função da [API de Composição Vue 3](https://vuejs.org/guide/introduction.html#composition-api) ("Composable") que só pode ser usada dentro de `setup()` ou `<script setup>`.
## `useData` <Badge type="info" text="composable" />
Retorna dados específicos da página. O objeto retornado possui o seguinte tipo:
```ts
interface VitePressData<T = any> {
/**
* Metadados do nível do site
*/
site: Ref<SiteData<T>>
/**
* themeConfig de .vitepress/config.js
*/
theme: Ref<T>
/**
* Metadados do nível da página
*/
page: Ref<PageData>
/**
* Frontmatter da página
*/
frontmatter: Ref<PageData['frontmatter']>
/**
* Parâmetros dinâmicos da rota
*/
params: Ref<PageData['params']>
title: Ref<string>
description: Ref<string>
lang: Ref<string>
isDark: Ref<boolean>
dir: Ref<string>
localeIndex: Ref<string>
}
interface PageData {
title: string
titleTemplate?: string | boolean
description: string
relativePath: string
filePath: string,
headers: Header[]
frontmatter: Record<string, any>
params?: Record<string, any>
isNotFound?: boolean
lastUpdated?: number
}
```
**Exemplo:**
```vue
<script setup>
import { useData } from 'vitepress'
const { theme } = useData()
</script>
<template>
<h1>{{ theme.footer.copyright }}</h1>
</template>
```
## `useRoute` <Badge type="info" text="composable" />
Retorna o objeto de rota atual com o seguinte tipo:
```ts
interface Route {
path: string
data: PageData
component: Component | null
}
```
## `useRouter` <Badge type="info" text="composable" />
Retorna a instância do roteador VitePress para que você possa navegar programaticamente para outra página.
```ts
interface Router {
/**
* Rota atual.
*/
route: Route
/**
* Navegar para uma nova URL.
*/
go: (to?: string) => Promise<void>
/**
* Chamado antes da mudança de rota. Retorne `false` para cancelar a navegação.
*/
onBeforeRouteChange?: (to: string) => Awaitable<void | boolean>
/**
* Chamado antes do carregamento do componente da página (depois que o estado do histórico é
* atualizado). Retorne `false` para cancelar a navegação.
*/
onBeforePageLoad?: (to: string) => Awaitable<void | boolean>
/**
* Chamado após a mudança de rota.
*/
onAfterRouteChanged?: (to: string) => Awaitable<void>
}
```
## `withBase` <Badge type="info" text="helper" />
- **Tipo**: `(path: string) => string`
Anexa o [`base`](./site-config#base) configurado a um caminho de URL fornecido. Veja também [Base URL](../guide/asset-handling#base-url).
## `<Content />` <Badge type="info" text="component" />
O componente `<Content />` exibe o conteúdo markdown renderizado. Útil [ao criar seu próprio tema](../guide/custom-theme).
```vue
<template>
<h1>Layout Personalizado!</h1>
<Content />
</template>
```
## `<ClientOnly />` <Badge type="info" text="component" />
O componente `<ClientOnly />` revela seu _slot_ apenas no lado do cliente.
Como as aplicações VitePress são interpretadas no lado do servidor em Node.js ao gerar builds estáticos, qualquer uso do Vue deve seguir os requisitos de código universal. Em resumo, certifique-se de acessar apenas APIs do Navegador / DOM em ganchos `beforeMount` ou `mounted`.
Se você estiver usando ou demonstrando componentes que não são compatíveis com SSR (por exemplo, contêm diretivas personalizadas), você pode envolvê-los dentro do componente `ClientOnly`.
```vue-html
<ClientOnly>
<NonSSRFriendlyComponent />
</ClientOnly>
```
- Relacionado: [Compatibilidade SSR](../guide/ssr-compat)
## `$frontmatter` <Badge type="info" text="template global" />
Acesse diretamente os dados [frontmatter](../guide/frontmatter) da página atual em expressões Vue.
```md
---
title: Olá
---
# {{ $frontmatter.title }}
```
## `$params` <Badge type="info" text="template global" />
Acesse diretamente os [parâmetros de rota dinâmica](../guide/routing#dynamic-routes) da página atual em expressões Vue.
```md
- nome do pacote: {{ $params.pkg }}
- versão: {{ $params.version }}
```

@ -0,0 +1,705 @@
---
outline: deep
---
# Configuração do Site {#site-config}
A configuração do site é onde você pode definir as configurações globais do site. As opções de configuração do aplicativo definem configurações que se aplicam a todos os sites VitePress, independentemente do tema que estão usando. Por exemplo, o diretório base ou o título do site.
## Visão geral {#overview}
### Resolução de Configuração {#config-resolution}
O arquivo de configuração é sempre resolvido a partir de `<root>/.vitepress/config.[ext]`, onde `<root>` é a [raiz do projeto](../guide/routing#root-and-source-directory) VitePress e `[ext]` é uma das extensões de arquivo suportadas. O TypeScript é suportado de fábrica. As extensões suportadas incluem `.js`, `.ts`, `.mjs` e `.mts`.
Recomenda-se usar a sintaxe de módulos ES nos arquivos de configuração. O arquivo de configuração deve exportar por padrão um objeto:
```ts
export default {
// opções de configuração de nível da aplicação
lang: 'pt-BR',
title: 'VitePress',
description: 'Gerador de site estático Vite & Vue.',
...
}
```
:::details Configuração Dinâmica (Assíncrona)
Se você precisar gerar dinamicamente a configuração, também pode exportar por padrão uma função. Por exemplo:
```ts
import { defineConfig } from 'vitepress'
export default async () => {
const posts = await (await fetch('https://my-cms.com/blog-posts')).json()
return defineConfig({
// opções de configuração de nível da aplicação
lang: 'pt-BR',
title: 'VitePress',
description: 'Gerador de site estático Vite & Vue.',
// opções de configuração de nível do tema
themeConfig: {
sidebar: [
...posts.map((post) => ({
text: post.name,
link: `/posts/${post.name}`
}))
]
}
})
}
```
Você também pode usar o `await` no nível superior. Como:
```ts
import { defineConfig } from 'vitepress'
const posts = await (await fetch('https://my-cms.com/blog-posts')).json()
export default defineConfig({
// opções de configuração de nível da aplicação
lang: 'pt-BR',
title: 'VitePress',
description: 'Gerador de site estático Vite & Vue.',
// opções de configuração de nível do tema
themeConfig: {
sidebar: [
...posts.map((post) => ({
text: post.name,
link: `/posts/${post.name}`
}))
]
}
})
```
:::
### Configuração Intellisense {#config-intellisense}
Usar o auxiliar `defineConfig` fornecerá Intellisense alimentado por TypeScript para as opções de configuração. Supondo que seu IDE o suporte, isso deve funcionar tanto em JavaScript quanto em TypeScript.
```js
import { defineConfig } from 'vitepress'
export default defineConfig({
// ...
})
```
### Configuração de Tema Tipada {#typed-theme-config}
Por padrão, o auxiliar `defineConfig` espera o tipo de configuração de tema do tema padrão:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
themeConfig: {
// O tipo é `DefaultTheme.Config`
}
})
```
Se você estiver usando um tema personalizado e desejar verificações de tipo para a configuração do tema, será necessário usar `defineConfigWithTheme` em vez disso, e passar o tipo de configuração para o seu tema personalizado por meio de um argumento genérico:
```ts
import { defineConfigWithTheme } from 'vitepress'
import type { ThemeConfig } from 'your-theme'
export default defineConfigWithTheme<ThemeConfig>({
themeConfig: {
// O tipo é `ThemeConfig`
}
})
```
### Configuração Vite, Vue & Markdown
- **Vite**
Você pode configurar a instância subjacente do Vite usando a opção [vite](#vite) em sua configuração VitePress. Não é necessário criar um arquivo de configuração Vite separado.
- **Vue**
VitePress já inclui o plugin Vue oficial para Vite ([@vitejs/plugin-vue](https://github.com/vitejs/vite-plugin-vue)). Você pode configurar suas opções usando a opção [vue](#vue) em sua configuração VitePress.
- **Markdown**
Você pode configurar a instância subjacente de [Markdown-It](https://github.com/markdown-it/markdown-it) usando a opção [markdown](#markdown) em sua configuração VitePress.
## Metadados do Site {#site-metadata}
### title
- Tipo: `string`
- Padrão: `VitePress`
- Pode ser substituído por página via [frontmatter](./frontmatter-config#title)
Título do site. Ao usar o tema padrão, isso será exibido na barra de navegação.
Ele também será usado como o sufixo padrão para todos os títulos individuais das páginas, a menos que [`titleTemplate`](#titletemplate) seja definido. O título final de uma página individual será o conteúdo textual do seu primeiro cabeçalho `<h1>`, combinado com o título global como sufixo. Por exemplo, com a seguinte configuração e conteúdo da página:
```ts
export default {
title: 'Meu Site Incrível'
}
```
```md
# Olá
```
O título da página será `Olá | Meu Site Incrível`.
### titleTemplate
- Tipo: `string | boolean`
- Pode ser substituído por página via [frontmatter](./frontmatter-config#titletemplate)
Permite personalizar o sufixo do título de cada página ou o título inteiro. Por exemplo:
```ts
export default {
title: 'Meu Site Incrível',
titleTemplate: 'Sufixo Personalizado'
}
```
```md
# Olá
```
O título da página será `Olá | Sufixo Personalizado`.
Para personalizar completamente como o título deve ser renderizado, você pode usar o símbolo `:title` em `titleTemplate`:
```ts
export default {
titleTemplate: ':title - Sufixo Personalizado'
}
```
Aqui, `:title` será substituído pelo texto inferido do primeiro cabeçalho `<h1>` da página. O título do exemplo anterior da página será `Olá - Sufixo Personalizado`.
A opção pode ser definida como `false` para desativar sufixos de título.
### description
- Tipo: `string`
- Padrão: `Um site VitePress`
- Pode ser substituído por página via [frontmatter](./frontmatter-config#descrição)
Descrição para o site. Isso será apresentado como uma tag `<meta>` na página HTML.
```ts
export default {
descrição: 'Um site VitePress'
}
```
### head
- Tipo: `HeadConfig[]`
- Padrão: `[]`
- Pode ser acrescentado por página via [frontmatter](./frontmatter-config#head)
Elementos adicionais para adicionar na tag `<head>` da página HTML. As tags adicionadas pelo usuário são mostradas antes da tag `head` de fechamento, após as tags VitePress.
```ts
type HeadConfig =
| [string, Record<string, string>]
| [string, Record<string, string>, string]
```
#### Exemplo: Adicionando um favicon {#example-adding-a-favicon}
```ts
export default {
cabeça: [['link', { rel: 'icon', href: '/favicon.ico' }]]
} // coloque o favicon.ico no diretório public, se a base estiver definida, use /base/favicon.ico
/* Mostraria:
<link rel="icon" href="/favicon.ico">
*/
```
#### Exemplo: Adicionando Fontes do Google {#example-adding-google-fonts}
```ts
export default {
head: [
[
'link',
{ rel: 'preconnect', href: 'https://fonts.googleapis.com' }
],
[
'link',
{ rel: 'preconnect', href: 'https://fonts.gstatic.com', crossorigin: '' }
],
[
'link',
{ href: 'https://fonts.googleapis.com/css2?family=Roboto&display=swap', rel: 'stylesheet' }
]
]
}
/* Mostraria:
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto&display=swap" rel="stylesheet">
*/
```
#### Exemplo: Registrando um _service worker_ {#example-registering-a-service-worker}
```ts
export default {
head: [
[
'script',
{ id: 'register-sw' },
`;(() => {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
}
})()`
]
]
}
/* Mostraria:
<script id="register-sw">
;(() => {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
}
})()
</script>
*/
```
#### Exemplo: Usando o Google Analytics {#example-using-google-analytics}
```ts
export default {
head: [
[
'script',
{ async: '', src: 'https://www.googletagmanager.com/gtag/js?id=TAG_ID' }
],
[
'script',
{},
`window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'TAG_ID');`
]
]
}
/* Mostraria:
<script async src="https://www.googletagmanager.com/gtag/js?id=TAG_ID"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'TAG_ID');
</script>
*/
```
### lang
- Tipo: `string`
- Padrão: `en-US`
O atributo de idioma para o site. Isso será mostrado como uma tag `<html lang="en-US">` na página HTML.
```ts
export default {
lang: 'en-US'
}
```
### base
- Tipo: `string`
- Padrão: `/`
A URL base em que o site será implantado. Você precisará definir isso se planeja implantar seu site em um subdiretório, por exemplo, no GitHub pages. Se você planeja implantar seu site em `https://foo.github.io/bar/` então você deve definir a base como `'/bar/'`. Deve sempre começar e terminar com uma barra.
A base é automaticamente adicionada a todos as URLs que começam com / em outras opções, então você só precisa especificá-la uma vez.
```ts
export default {
base: '/base/'
}
```
## Roteamento {#routing}
### cleanUrls
- Tipo: `boolean`
- Padrão: `false`
Quando definido como `true`, VitePress removerá o `.html` no final dos URLs. Veja também [Gerando URL Limpa](../guide/routing#generating-clean-url).
::: alerta Suporte do Servidor Necessário
Ativar isso pode exigir configurações adicionais em sua plataforma de hospedagem. Para funcionar, seu servidor deve ser capaz de servir `/foo.html` ao visitar `/foo` **sem redirecionamento**.
:::
### rewrites
- Tipo: `Record<string, string>`
Define mapeamentos personalizados de diretório &lt;-&gt; URL. Veja [Roteamento: Reescrever Rotas](../guide/routing#route-rewrites) para mais detalhes.
```ts
export default {
rewrites: {
'source/:page': 'destination/:page'
}
}
```
## Construção {#build}
### srcDir
- Tipo: `string`
- Padrão: `.`
O diretório onde suas páginas de markdown são armazenadas, relativo à raiz do projeto. Veja também [Diretório Raiz e Fonte](../guide/routing#root-and-source-directory).
```ts
export default {
srcDir: './src'
}
```
### srcExclude
- Tipo: `string`
- Padrão: `undefined`
Um [padrão glob](https://github.com/mrmlnc/fast-glob#pattern-syntax) para corresponder a arquivos markdown que devem ser excluídos como conteúdo fonte.
```ts
export default {
srcExclude: ['**/README.md', '**/TODO.md']
}
```
### outDir
- Tipo: `string`
- Padrão: `./.vitepress/dist`
A localização da saída da compilação para o site, relativa à [raiz do projeto](../guide/routing#root-and-source-directory).
```ts
export default {
outDir: '../public'
}
```
### assetsDir
- Tipo: `string`
- Padrão: `assets`
Especifica o diretório para aninhar ativos gerados. O caminho deve estar dentro de [`outDir`](#outdir) e é resolvido em relação a ele.
```ts
export default {
assetsDir: 'static'
}
```
### cacheDir
- Tipo: `string`
- Padrão: `./.vitepress/cache`
O diretório para arquivos de cache, relativo à [raiz do projeto](../guide/routing#root-and-source-directory). Veja também: [cacheDir](https://vitejs.dev/config/shared-options.html#cachedir).
```ts
export default {
cacheDir: './.vitepress/.vite'
}
```
### ignoreDeadLinks
- Tipo: `boolean | 'localhostLinks' | (string | RegExp | ((link: string) => boolean))[]`
- Padrão: `false`
Quando definido como `true`, VitePress não falhará na compilação devido a links quebrados.
Quando definido como `'localhostLinks'`, a compilação falhará em links quebrados, mas não verificará links `localhost`.
```ts
export default {
ignoreDeadLinks: true
}
```
Também pode ser um _array_ de uma exata URL em string, padrões regex, ou funções de filtro personalizadas.
```ts
export default {
ignoreDeadLinks: [
// ignora URL exata "/playground"
'/playground',
// ignora todos os links localhost
/^https?:\/\/localhost/,
// ignora todos os links incluindo "/repl/""
/\/repl\//,
// função personalizada, ignora todos os links incluindo "ignore"
(url) => {
return url.toLowerCase().includes('ignore')
}
]
}
```
### mpa <Badge type="warning" text="experimental" />
- Tipo: `boolean`
- Padrão: `false`
Quando definido como `true`, a aplicação em produção será compilada no [Modo MPA](../guide/mpa-mode). O modo MPA envia 0kb de JavaScript por padrão, às custas de desabilitar a navegação no lado do cliente e exigir permissão explícita para interatividade.
## Tematização {#theming}
### appearance
- Tipo: `boolean | 'dark' | 'force-dark' | import('@vueuse/core').UseDarkOptions`
- Padrão: `true`
Se habilitar o modo escuro (adicionando a classe `.dark` ao elemento `<html>`).
- Se a opção estiver definida como `true` o tema padrão é determinado pelo esquema de cores preferido do usuário.
- Se a opção estiver definida como `dark` o tema é escuro por padrão, a menos que o usuário mude manualmente.
- Se a opção estiver definida como `false` os usuários não poderão mudar o tema.
Esta opção injeta um script em linha que restaura as configurações dos usuários do armazenamento local (_local storage_) usando a chave `vitepress-theme-appearance`. Isso garante que a classe `.dark` seja aplicada antes de a página ser mostrada para evitar oscilações.
`appearance.initialValue` só pode ser `'dark' | undefined`. Refs ou getters não são suportados.
### lastUpdated
- Tipo: `boolean`
- Padrão: `false`
Para obter o selo de tempo da última atualização para cada página usando o Git. O selo de data será incluído nos dados de cada página, acessíveis via [`useData`](./runtime-api#usedata).
Ao usar o tema padrão, habilitar esta opção exibirá o horário da última atualização de cada página. Você pode personalizar o texto via opção [`themeConfig.lastUpdatedText`](./default-theme-config#lastupdatedtext).
## Personalização {#customization}
### markdown
- Tipo: `MarkdownOption`
Configure as opções do processador Markdown. VitePress usa [Markdown-it](https://github.com/markdown-it/markdown-it) como processador e [Shiki](https://github.com/shikijs/shiki) para destacar sintaxe de linguagem. Dentro desta opção, você pode passar várias opções Markdown relacionadas para atender às suas necessidades.
```js
export default {
markdown: {...}
}
```
Verifique a [declaração de tipo e jsdocs](https://github.com/vuejs/vitepress/blob/main/src/node/markdown/markdown.ts) para todas as opções disponíveis.
### vite
- Tipo: `import('vite').UserConfig`
Passe a [Configuração Vite](https://vitejs.dev/config/) crua para o servidor interno / empacotador Vite.
```js
export default {
vite: {
// Opções de configuração Vite
}
}
```
### vue
- Tipo: `import('@vitejs/plugin-vue').Options`
Passe as opções [`@vitejs/plugin-vue`](https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue#options) cruas para a instância interna do plugin.
```js
export default {
vue: {
// Opções @vitejs/plugin-vue
}
}
```
## Ganchos de Compilação {#build-hooks}
Os ganchos de compilação VitePress permitem adicionar novas funcionalidades ao seu site:
- Sitemap
- Indexação de Pesquisa
- PWA
- _Teleports_
## buildEnd
- Tipo: `(siteConfig: SiteConfig) => Awaitable<void>`
`buildEnd` é um gancho de compilação CLI (Interface de Linha de Comando), ele será executado após a conclusão da compilação (SSG), mas antes que o processo VitePress CLI termine.
```ts
export default {
async buildEnd(siteConfig) {
// ...
}
}
```
## postRender
- Tipo: `(context: SSGContext) => Awaitable<SSGContext | void>`
- `postRender` é um gancho de compilação, chamado quando a interpretação SSG é concluída. Ele permitirá que você manipule o conteúdo de _teleports_ durante a geração de site estático.
```ts
export default {
async postRender(context) {
// ...
}
}
```
```ts
interface SSGContext {
content: string
teleports?: Record<string, string>
[key: string]: any
}
```
## transformHead
- Tipo: `(context: TransformContext) => Awaitable<HeadConfig[]>`
`transformHead` é um gancho de compilação para transformar o cabeçalho antes de gerar cada página. Isso permite adicionar entradas no cabeçalho que não podem ser adicionadas estaticamente à configuração VitePress. Você só precisa retornar entradas extras, que serão mescladas automaticamente com as existentes.
:::warning
Não faça mutações em qualquer item dentro de `context`.
:::
```ts
export default {
async transformHead(context) {
// ...
}
}
```
```ts
interface TransformContext {
page: string // e.g. index.md (relativo a srcDir)
assets: string[] // todos os ativos não-js/css com URL pública completamente resolvida
siteConfig: SiteConfig
siteData: SiteData
pageData: PageData
title: string
description: string
head: HeadConfig[]
content: string
}
```
Note que este gancho só é chamado ao gerar o site estaticamente. Não é chamado durante o desenvolvimento. Se você precisar adicionar entradas de cabeçalho dinâmicas durante o desenvolvimento, pode usar o gancho [`transformPageData`](#transformpagedata) em seu lugar.
```ts
export default {
transformPageData(pageData) {
pageData.frontmatter.head ??= []
pageData.frontmatter.head.push([
'meta',
{
name: 'og:title',
content:
pageData.frontmatter.layout === 'home'
? `VitePress`
: `${pageData.title} | VitePress`
}
])
}
}
```
#### Exemplo: Adicionar URL canônica `<link>` {#example-adding-a-canonical-url-link}
```ts
export default {
transformPageData(pageData) {
const canonicalUrl = `https://example.com/${pageData.relativePath}`
.replace(/index\.md$/, '')
.replace(/\.md$/, '.html')
pageData.frontmatter.head ??= []
pageData.frontmatter.head.push([
'link',
{ rel: 'canonical', href: canonicalUrl }
])
}
}
```
### transformHtml
- Tipo: `(code: string, id: string, context: TransformContext) => Awaitable<string | void>`
`transformHtml` é um gancho de compilação para transformar o conteúdo de cada página antes de salvá-lo no disco.
:::warning
Não faça mutações em qualquer item dentro de `context`. Além disso, modificar o conteúdo HTML pode causar problemas de hidratação em tempo de execução.
:::
```ts
export default {
async transformHtml(code, id, context) {
// ...
}
}
```
### transformPageData
- Tipo: `(pageData: PageData, context: TransformPageContext) => Awaitable<Partial<PageData> | { [key: string]: any } | void>`
`transformPageData` é um gancho para transformar os dados de cada página. Você pode fazer mutações diretamente em `pageData` ou retornar valores alterados que serão mesclados nos dados da página.
:::warning
Não faça mutações em qualquer item dentro de `context` e tenha cuidado pois isso pode impactar no desempenho do servidor de desenvolvimento, especialmente se você tiver algumas solicitações de rede ou computações pesadas (como gerar imagens) no gancho. Você pode verificar `process.env.NODE_ENV === 'production'` para lógica condicional.
:::
```ts
export default {
async transformPageData(pageData, { siteConfig }) {
pageData.contributors = await getPageContributors(pageData.relativePath)
}
// ou retorne dados a serem mesclados
async transformPageData(pageData, { siteConfig }) {
return {
contributors: await getPageContributors(pageData.relativePath)
}
}
}
```
```ts
interface TransformPageContext {
siteConfig: SiteConfig
}
```

@ -1,3 +1,6 @@
/assets/*
cache-control: max-age=31536000
cache-control: immutable
cache-control: immutable
/_translations/*
x-robots-tag: noindex

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

@ -93,6 +93,7 @@ interface NavItemWithLink {
activeMatch?: string
target?: string
rel?: string
noIcon?: boolean
}
interface NavItemChildren {
@ -134,7 +135,7 @@ export default {
export type Sidebar = SidebarItem[] | SidebarMulti
export interface SidebarMulti {
[path: string]: SidebarItem[]
[path: string]: SidebarItem[] | { items: SidebarItem[]; base: string }
}
export type SidebarItem = {
@ -161,6 +162,19 @@ export type SidebarItem = {
* If `false`, group is collapsible but expanded by default
*/
collapsed?: boolean
/**
* Base path for the children items.
*/
base?: string
/**
* Customize text that appears on the footer of previous/next page.
*/
docFooterText?: string
rel?: string
target?: string
}
```
@ -244,8 +258,10 @@ type SocialLinkIcon =
| 'instagram'
| 'linkedin'
| 'mastodon'
| 'npm'
| 'slack'
| 'twitter'
| 'x'
| 'youtube'
| { svg: string }
```
@ -331,7 +347,7 @@ export interface LastUpdatedOptions {
* @default
* { dateStyle: 'short', timeStyle: 'short' }
*/
formatOptions?: Intl.DateTimeFormatOptions
formatOptions?: Intl.DateTimeFormatOptions & { forceLocale?: boolean }
}
```
@ -406,6 +422,20 @@ export interface DocFooter {
Can be used to customize the dark mode switch label. This label is only displayed in the mobile view.
## lightModeSwitchTitle
- Type: `string`
- Default: `Switch to light theme`
Can be used to customize the light mode switch title that appears on hovering.
## darkModeSwitchTitle
- Type: `string`
- Default: `Switch to dark theme`
Can be used to customize the dark mode switch title that appears on hovering.
## sidebarMenuLabel
- Type: `string`

@ -69,6 +69,12 @@ interface HeroAction {
// Destination link of the button.
link: string
// Link target attribute.
target?: string
// Link rel attribute.
rel?: string
}
```
@ -131,7 +137,7 @@ interface Feature {
// Link when clicked on feature component. The link can
// be both internal or external.
//
// e.g. `guid/reference/default-theme-home-page` or `htttps://example.com`
// e.g. `guide/reference/default-theme-home-page` or `https://example.com`
link?: string
// Link text to be shown inside feature component. Best
@ -144,6 +150,9 @@ interface Feature {
//
// e.g. `external`
rel?: string
// Link target attribute for the `link` option.
target?: string
}
type FeatureIcon =
@ -157,3 +166,30 @@ type FeatureIcon =
height: string
}
```
## Markdown Content
You can add additional content to your site's homepage just by adding Markdown below the `---` frontmatter divider.
````md
---
layout: home
hero:
name: VitePress
text: Vite & Vue powered static site generator.
---
## Getting Started
You can get started using VitePress right away using `npx`!
```sh
npm init
npx vitepress init
```
````
::: info
VitePress didn't always auto-style the extra content of the `layout: home` page. To revert to older behavior, you can add `markdownStyles: false` to the frontmatter.
:::

@ -96,7 +96,7 @@ export default defineConfig({
})
```
Learn more in [MiniSearch docs](https://lucaong.github.io/minisearch/classes/_minisearch_.minisearch.html).
Learn more in [MiniSearch docs](https://lucaong.github.io/minisearch/classes/MiniSearch.MiniSearch.html).
### Custom content renderer

@ -212,6 +212,9 @@ interface TeamMember {
// URL for the sponsor page for the member.
sponsor?: string
// Text for the sponsor link. Defaults to 'Sponsor'.
actionText?: string
}
```

@ -38,6 +38,10 @@ interface VitePressData<T = any> {
isDark: Ref<boolean>
dir: Ref<string>
localeIndex: Ref<string>
/**
* Current location hash
*/
hash: Ref<string>
}
interface PageData {

@ -24,6 +24,62 @@ export default {
}
```
:::details Dynamic (Async) Config
If you need to dynamically generate the config, you can also default export a function. For example:
```ts
import { defineConfig } from 'vitepress'
export default async () => {
const posts = await (await fetch('https://my-cms.com/blog-posts')).json()
return defineConfig({
// app level config options
lang: 'en-US',
title: 'VitePress',
description: 'Vite & Vue powered static site generator.',
// theme level config options
themeConfig: {
sidebar: [
...posts.map((post) => ({
text: post.name,
link: `/posts/${post.name}`
}))
]
}
})
}
```
You can also use top-level `await`. For example:
```ts
import { defineConfig } from 'vitepress'
const posts = await (await fetch('https://my-cms.com/blog-posts')).json()
export default defineConfig({
// app level config options
lang: 'en-US',
title: 'VitePress',
description: 'Vite & Vue powered static site generator.',
// theme level config options
themeConfig: {
sidebar: [
...posts.map((post) => ({
text: post.name,
link: `/posts/${post.name}`
}))
]
}
})
```
:::
### Config Intellisense
Using the `defineConfig` helper will provide TypeScript-powered intellisense for config options. Assuming your IDE supports it, this should work in both JavaScript and TypeScript.
@ -360,7 +416,7 @@ export default {
- Type: `string`
- Default: `assets`
The directory for assets files. See also: [assetsDir](https://vitejs.dev/config/build-options.html#build-assetsdir).
Specify the directory to nest generated assets under. The path should be inside [`outDir`](#outdir) and is resolved relative to it.
```ts
export default {
@ -415,6 +471,13 @@ export default {
}
```
### metaChunk <Badge type="warning" text="experimental" />
- Type: `boolean`
- Default: `false`
When set to `true`, extract pages metadata to a separate JavaScript chunk instead of inlining it in the initial HTML. This makes each page's HTML payload smaller and makes the pages metadata cacheable, thus reducing server bandwidth when you have many pages in the site.
### mpa <Badge type="warning" text="experimental" />
- Type: `boolean`
@ -426,7 +489,7 @@ When set to `true`, the production app will be built in [MPA Mode](../guide/mpa-
### appearance
- Type: `boolean | 'dark' | import('@vueuse/core').UseDarkOptions`
- Type: `boolean | 'dark' | 'force-dark' | import('@vueuse/core').UseDarkOptions`
- Default: `true`
Whether to enable dark mode (by adding the `.dark` class to the `<html>` element).
@ -454,81 +517,15 @@ When using the default theme, enabling this option will display each page's last
- Type: `MarkdownOption`
Configure Markdown parser options. VitePress uses [Markdown-it](https://github.com/markdown-it/markdown-it) as the parser, and [Shiki](https://shiki.matsu.io/) to highlight language syntax. Inside this option, you may pass various Markdown related options to fit your needs.
Configure Markdown parser options. VitePress uses [Markdown-it](https://github.com/markdown-it/markdown-it) as the parser, and [Shiki](https://github.com/shikijs/shiki) to highlight language syntax. Inside this option, you may pass various Markdown related options to fit your needs.
```js
export default {
markdown: {
theme: 'material-theme-palenight',
lineNumbers: true,
// adjust how header anchors are generated,
// useful for integrating with tools that use different conventions
anchor: {
slugify(str) {
return encodeURIComponent(str)
}
}
}
markdown: {...}
}
```
Below are all the options that you can have in this object:
```ts
interface MarkdownOptions extends MarkdownIt.Options {
// Custom theme for syntax highlighting.
// You can use an existing theme.
// See: https://github.com/shikijs/shiki/blob/main/docs/themes.md#all-themes
// Or add your own theme.
// See: https://github.com/shikijs/shiki/blob/main/docs/themes.md#loading-theme
theme?:
| Shiki.IThemeRegistration
| { light: Shiki.IThemeRegistration; dark: Shiki.IThemeRegistration }
// Enable line numbers in code block.
lineNumbers?: boolean
// Add support for your own languages.
// https://github.com/shikijs/shiki/blob/main/docs/languages.md#supporting-your-own-languages-with-shiki
languages?: Shiki.ILanguageRegistration
// markdown-it-anchor plugin options.
// See: https://github.com/valeriangalliat/markdown-it-anchor#usage
anchor?: anchorPlugin.AnchorOptions
// markdown-it-attrs plugin options.
// See: https://github.com/arve0/markdown-it-attrs
attrs?: {
leftDelimiter?: string
rightDelimiter?: string
allowedAttributes?: string[]
disable?: boolean
}
// specify default language for syntax highlighter
defaultHighlightLang?: string
// @mdit-vue/plugin-frontmatter plugin options.
// See: https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-frontmatter#options
frontmatter?: FrontmatterPluginOptions
// @mdit-vue/plugin-headers plugin options.
// See: https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-headers#options
headers?: HeadersPluginOptions
// @mdit-vue/plugin-sfc plugin options.
// See: https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-sfc#options
sfc?: SfcPluginOptions
// @mdit-vue/plugin-toc plugin options.
// See: https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-toc#options
toc?: TocPluginOptions
// Configure the Markdown-it instance.
config?: (md: MarkdownIt) => void
}
```
Check the [type declaration and jsdocs](https://github.com/vuejs/vitepress/blob/main/src/node/markdown/markdown.ts) for all the options available.
### vite
@ -655,6 +652,24 @@ export default {
}
```
#### Example: Adding a canonical URL `<link>`
```ts
export default {
transformPageData(pageData) {
const canonicalUrl = `https://example.com/${pageData.relativePath}`
.replace(/index\.md$/, '')
.replace(/\.md$/, '.html')
pageData.frontmatter.head ??= []
pageData.frontmatter.head.push([
'link',
{ rel: 'canonical', href: canonicalUrl }
])
}
}
```
### transformHtml
- Type: `(code: string, id: string, context: TransformContext) => Awaitable<string | void>`

@ -0,0 +1,80 @@
<script setup lang="ts">
import { ref } from 'vue'
const showModal = ref(false)
</script>
<template>
<button class="modal-button" @click="showModal = true">
Показать модальное окно
</button>
<Teleport to="body">
<Transition name="modal">
<div v-show="showModal" class="modal-mask">
<div class="modal-container">
<p>Привет из модального окна!</p>
<div class="model-footer">
<button class="modal-button" @click="showModal = false">
Закрыть
</button>
</div>
</div>
</div>
</Transition>
</Teleport>
</template>
<style scoped>
.modal-mask {
position: fixed;
z-index: 200;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
transition: opacity 0.3s ease;
}
.modal-container {
width: 300px;
margin: auto;
padding: 20px 30px;
background-color: var(--vp-c-bg);
border-radius: 2px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.33);
transition: all 0.3s ease;
}
.model-footer {
margin-top: 8px;
text-align: right;
}
.modal-button {
padding: 4px 8px;
border-radius: 4px;
border-color: var(--vp-button-alt-border);
color: var(--vp-button-alt-text);
background-color: var(--vp-button-alt-bg);
}
.modal-button:hover {
border-color: var(--vp-button-alt-hover-border);
color: var(--vp-button-alt-hover-text);
background-color: var(--vp-button-alt-hover-bg);
}
.modal-enter-from,
.modal-leave-to {
opacity: 0;
}
.modal-enter-from .modal-container,
.modal-leave-to .modal-container {
transform: scale(1.1);
}
</style>

@ -0,0 +1,63 @@
# Обработка ресурсов {#asset-handling}
## Ссылки на статические ресурсы {#referencing-static-assets}
Все файлы Markdown компилируются в компоненты Vue и обрабатываются [Vite](https://vitejs.dev/guide/assets.html). Вы можете, **и должны**, ссылаться на любые ресурсы, используя относительные URL:
```md
![Изображение](./image.png)
```
Вы можете ссылаться на статические ресурсы в ваших файлах разметки, компоненты `*.vue` в теме, стили и обычные файлы `.css`, используя абсолютные пути (основанные на корне проекта) или относительные пути (основанные на вашей файловой системе). Последнее похоже на поведение, к которому вы привыкли, если использовали Vite, Vue CLI или `file-loader` в webpack.
Распространенные типы файлов изображений, мультимедиа и шрифтов определяются и включаются в качестве ресурсов автоматически.
::: tip Связанные файлы не рассматриваются как ресурсы
PDF-файлы или другие документы, на которые есть ссылки в файлах с разметкой, не рассматриваются автоматически как ресурсы. Чтобы сделать связанные файлы доступными, вы должны вручную поместить их в каталог [`public`](#the-public-directory) вашего проекта.
:::
Все ссылающиеся ресурсы, включая те, которые используют абсолютные пути, будут скопированы в выходной каталог с хэшированным именем файла в производственной сборке. Ресурсы, на которые никогда не ссылались, не будут скопированы. Изображения размером менее 4 КБ будут вставляться в формате base64 — это можно настроить с помощью опции конфигурации [`vite`](../reference/site-config#vite).
Все **статические** ссылки на пути, включая абсолютные пути, должны быть основаны на структуре ваших рабочих каталогов.
## Директория `public` {#the-public-directory}
Иногда вам может понадобиться предоставить статические ресурсы, на которые нет прямых ссылок ни в одном из компонентов Markdown или темы, или вы можете захотеть предоставить определённые файлы с оригинальным именем. Примерами таких файлов являются `robots.txt`, `favicon.ico` и иконки 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`:
```md
![Изображение](/image-inside-public.png)
```
В этом случае вам **не** нужно обновлять его при изменении значения конфигурации `base`.
Однако если вы создаете компонент темы, который динамически ссылается на активы, например, изображение, атрибут `src` которого основан на значении конфигурации темы:
```vue
<img :src="theme.logoPath" />
```
В этом случае рекомендуется обернуть путь с помощью [хелпера `withBase`](../reference/runtime-api#withbase), предоставляемого VitePress:
```vue
<script setup>
import { withBase, useData } from 'vitepress'
const { theme } = useData()
</script>
<template>
<img :src="withBase(theme.logoPath)" />
</template>
```

@ -0,0 +1,58 @@
---
outline: deep
---
# Подключение к CMS {#connecting-to-a-cms}
## Общий рабочий процесс {#general-workflow}
Подключение VitePress к CMS в значительной степени зависит от [динамических маршрутов](./routing#dynamic-routes). Прежде чем приступить к работе, убедитесь, что вы понимаете, как это работает.
Поскольку каждая CMS работает по-своему, здесь мы можем предоставить лишь общую схему работы, которую вам нужно будет адаптировать под свой конкретный сценарий.
1. Если ваша CMS требует аутентификации, создайте файл `.env` для хранения токенов API и загрузите его таким образом:
```js
// posts/[id].paths.js
import { loadEnv } from 'vitepress'
const env = loadEnv('', process.cwd())
```
2. Получите необходимые данные из CMS и преобразуйте их в соответствующие пути:
```js
export default {
async paths() {
// при необходимости используйте соответствующую клиентскую библиотеку CMS
const data = await (
await fetch('https://my-cms-api', {
headers: {
// токен, если необходимо
}
})
).json()
return data.map((entry) => {
return {
params: { id: entry.id /* заголовок, автор, дата и т. д. */ },
content: entry.content
}
})
}
}
```
3. Отрисуйте содержимое страницы:
```md
# {{ $params.title }}
- Автор: {{ $params.author }}, {{ $params.date }}
<!-- @content -->
```
## Руководства по интеграции {#integration-guides}
Если вы написали руководство по интеграции VitePress с конкретной CMS, воспользуйтесь ссылкой «Редактировать эту страницу», чтобы добавить его сюда!

@ -0,0 +1,222 @@
# Пользовательская тема {#using-a-custom-theme}
## Разрешение темы {#theme-resolving}
Вы можете включить пользовательскую тему, создав файл `.vitepress/theme/index.js` или `.vitepress/theme/index.ts` («файл входа темы»):
```
.
├─ docs # корень проекта
│ ├─ .vitepress
│ │ ├─ theme
│ │ │ └─ index.js # файл входа темы
│ │ └─ config.js # файл конфигурации
│ └─ index.md
└─ package.json
```
VitePress всегда будет использовать пользовательскую тему вместо темы по умолчанию, если обнаружит наличие входного файла темы. Однако вы можете [расширить тему по умолчанию](./extending-default-theme), чтобы выполнить расширенные настройки поверх нее.
## Интерфейс темы {#theme-interface}
Пользовательская тема VitePress определяется как объект со следующим интерфейсом:
```ts
interface Theme {
/**
* Корневой компонент макета для каждой страницы
* @required
*/
Layout: Component
/**
* Улучшение экземпляра приложения Vue
* @optional
*/
enhanceApp?: (ctx: EnhanceAppContext) => Awaitable<void>
/**
* Расширяем другую тему, вызывая её `enhanceApp` перед нашей
* @optional
*/
extends?: Theme
}
interface EnhanceAppContext {
app: App // Экземпляр приложения Vue
router: Router // Экземпляр маршрутизатора VitePress
siteData: Ref<SiteData> // Метаданные на уровне сайта
}
```
Файл входа темы должен экспортировать тему по умолчанию:
```js
// .vitepress/theme/index.js
// Вы можете напрямую импортировать файлы Vue в файле входа темы.
// VitePress предварительно настроен с помощью @vitejs/plugin-vue.
import Layout from './Layout.vue'
export default {
Layout,
enhanceApp({ app, router, siteData }) {
// ...
}
}
```
Экспорт по умолчанию является единственным контрактом для пользовательской темы, и только свойство `Layout` является обязательным. Таким образом, технически тема VitePress может быть простой, как один компонент Vue.
Внутри компонент макета работает так же, как и обычное приложение Vite + Vue 3. Обратите внимание, что тема также должна быть [SSR-совместимой](./ssr-compat).
## Создание макета {#building-a-layout}
Самый базовый компонент макета должен содержать компонент [`<Content />`](../reference/runtime-api#content):
```vue
<!-- .vitepress/theme/Layout.vue -->
<template>
<h1>Пользовательский макет!</h1>
<!-- здесь будет отображаться содержимое в формате Markdown -->
<Content />
</template>
```
Приведённая выше схема просто отображает разметку каждой страницы в виде 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>
```
Обратитесь к [Справочнику Runtime API](../reference/runtime-api), чтобы узнать обо всём, что доступно в компонентах темы. Кроме того, вы можете использовать [загрузку данных в режиме реального времени](./data-loading) для создания макета, управляемого данными — например, страницы со списком всех записей в блоге текущего проекта.
## Распространение пользовательской темы {#distributing-a-custom-theme}
Самый простой способ распространить пользовательскую тему — предоставить её в виде [репозитория шаблонов на GitHub](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-template-repository).
Если вы хотите распространить тему в виде пакета npm, выполните следующие действия:
1. Экспортируйте объект темы в качестве экспорта по умолчанию в записи пакета.
2. Если есть возможность, экспортируйте определение типа конфигурации темы как `ThemeConfig`.
3. Если ваша тема требует настройки конфигурации VitePress, экспортируйте эту конфигурацию в подпапку пакета (например. `my-theme/config`), чтобы пользователь мог расширить её.
4. Документируйте параметры конфигурации темы (как через файл конфигурации, так и через метаданные).
5. Предоставьте чёткие инструкции по использованию вашей темы (см. ниже).
## Использование пользовательской темы {#consuming-a-custom-theme}
Чтобы использовать внешнюю тему, импортируйте и реэкспортируйте её из элемента пользовательской темы:
```js
// .vitepress/theme/index.js
import Theme from 'awesome-vitepress-theme'
export default Theme
```
Если тема требует расширения:
```js
// .vitepress/theme/index.js
import Theme from 'awesome-vitepress-theme'
export default {
extends: Theme,
enhanceApp(ctx) {
// ...
}
}
```
Если тема требует специальных настроек VitePress, вам нужно будет также расширить их в своем собственном конфиге:
```ts
// .vitepress/config.ts
import baseConfig from 'awesome-vitepress-theme/config'
export default {
// расширить базовый конфиг темы (если необходимо)
extends: baseConfig
}
```
Наконец, если тема предоставляет типы для своего конфига темы:
```ts
// .vitepress/config.ts
import baseConfig from 'awesome-vitepress-theme/config'
import { defineConfigWithTheme } from 'vitepress'
import type { ThemeConfig } from 'awesome-vitepress-theme'
export default defineConfigWithTheme<ThemeConfig>({
extends: baseConfig,
themeConfig: {
// Тип `ThemeConfig`
}
})
```

@ -0,0 +1,258 @@
# Загрузка данных в режиме реального времени {#build-time-data-loading}
VitePress предоставляет функцию **загрузчиков данных**, которая позволяет загружать произвольные данные и импортировать их со страниц или компонентов. Загрузка данных выполняется **только во время сборки**: Полученные данные будут сериализованы в виде JSON в финальной сборке JavaScript.
Загрузчики данных могут использоваться для получения удалённых данных или генерирования метаданных на основе локальных файлов. Например, вы можете использовать загрузчики данных для анализа всех локальных страниц API и автоматического создания индекса всех записей API.
## Пример использования {#basic-usage}
Файл загрузчика данных должен заканчиваться либо `.data.js`, либо `.data.ts`. Файл должен предоставлять экспорт объекта по умолчанию с помощью метода `load()`:
```js
// example.data.js
export default {
load() {
return {
hello: 'мир'
}
}
}
```
Модуль загрузчика выполняется только в Node.js, поэтому вы можете импортировать любые API Node и зависимости npm по мере необходимости.
Затем вы можете импортировать данные из этого файла в страницы `.md` и компоненты `.vue` с помощью экспорта с именем `data`:
```vue
<script setup>
import { data } from './example.data.js'
</script>
<pre>{{ data }}</pre>
```
Результат:
```json
{
"hello": "мир"
}
```
Вы заметите, что сам загрузчик данных не экспортирует `data`. Это VitePress вызывает метод `load()` за кулисами и неявно раскрывает результат через именованный экспорт `data`.
Это работает, даже если загрузчик асинхронный:
```js
export default {
async load() {
// получение удалённых данных
return (await fetch('...')).json()
}
}
```
## Данные из локальных файлов {#data-from-local-files}
Если вам нужно генерировать данные на основе локальных файлов, используйте опцию `watch` в загрузчике данных, чтобы изменения, внесённые в эти файлы, вызывали горячие обновления.
Опция `watch` удобна ещё и тем, что вы можете использовать [шаблоны glob](https://github.com/mrmlnc/fast-glob#pattern-syntax) для соответствия нескольким файлам. Шаблоны могут быть относительными к самому файлу загрузчика, а функция `load()` будет получать совпадающие файлы в виде абсолютных путей.
В следующем примере показана загрузка CSV-файлов и их преобразование в JSON с помощью [csv-parse](https://github.com/adaltas/node-csv/tree/master/packages/csv-parse/). Поскольку этот файл выполняется только во время сборки, вы не будете передавать 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 загрузчика данных, но поскольку это очень распространённый случай использования, VitePress также предоставляет функцию `createContentLoader`, чтобы упростить эту задачу:
```js
// posts.data.js
import { createContentLoader } from 'vitepress'
export default createContentLoader('posts/*.md' /* параметры */)
```
Эта функция принимает шаблон glob относительно [исходного каталога](./routing#source-directory) и возвращает объект `{ watch, load }` загрузчика данных, который может быть использован в качестве экспорта по умолчанию в файле загрузчика данных. В нем также реализовано кэширование на основе временных меток изменения файлов для повышения производительности dev.
Обратите внимание, что загрузчик работает только с файлами Markdown — совпадающие файлы, не относящиеся к Markdown, будут пропущены.
Загруженные данные будут представлять собой массив с типом `ContentData[]`:
```ts
interface ContentData {
// отображаемый URL-адрес страницы, например: /posts/hello.html (не включает `base`)
// выполните итерацию вручную или используйте пользовательскую `трансформацию` для нормализации путей
url: string
// метаданные страницы
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>by {{ post.frontmatter.author }}</span>
</li>
</ul>
</template>
```
### Параметры {#options}
Данные по умолчанию могут не соответствовать всем требованиям — вы можете изменить данные с помощью параметров:
```js
// posts.data.js
import { createContentLoader } from 'vitepress'
export default createContentLoader('posts/*.md', {
includeSrc: true, // включить исходный текст в формате Markdown?
render: true, // включать в себя полный HTML страницы?
excerpt: true, // включить отрывок?
transform(rawData) {
// составляйте карты, сортируйте или фильтруйте исходные данные по своему усмотрению.
// конечный результат — это то, что будет отправлено клиенту.
return rawData
.sort((a, b) => {
return +new Date(b.frontmatter.date) - +new Date(a.frontmatter.date)
})
.map((page) => {
page.src // исходный текст в формате Markdown
page.html // отображение полной страницы HTML
page.excerpt // отображаемый отрывок HTML (содержимое выше первого `---`)
return {
/* ... */
}
})
}
})
```
Посмотрите, как он используется в [блоге Vue.js](https://github.com/vuejs/blog/blob/main/.vitepress/theme/posts.data.ts).
API `createContentLoader` также можно использовать внутри [хуков сборки](../reference/site-config#build-hooks):
```js
// .vitepress/config.js
export default {
async buildEnd() {
const posts = await createContentLoader('posts/*.md').load()
// генерируем файлы на основе метаданных сообщений, например, RSS-канал
}
}
```
**Types**
```ts
interface ContentOptions<T = ContentData[]> {
/**
* Включаем src?
* @default false
*/
includeSrc?: boolean
/**
* Преобразовываем src в 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
---
# Развёртывание вашего сайта VitePress {#deploy-your-vitepress-site}
Следующие руководства основаны на некоторых общих предположениях:
- Сайт VitePress находится в директории `docs` вашего проекта.
- Вы используете выходной каталог сборки по умолчанию (`.vitepress/dist`).
- VitePress установлен как локальная зависимость в вашем проекте, и вы установили следующие скрипты в вашем `package.json`:
```json
{
"scripts": {
"docs:build": "vitepress build docs",
"docs:preview": "vitepress preview docs"
}
}
```
## Создание и локальное тестирование {#build-and-test-locally}
1. Выполните эту команду, чтобы собрать документацию:
```sh
$ npm run docs:build
```
2. После сборки просмотрите её локально, запустив команду:
```sh
$ npm run docs:preview
```
Команда `preview` загрузит локальный статический веб-сервер, который будет обслуживать выходной каталог `.vitepress/dist` по адресу `http://localhost:4173`. Вы можете использовать это, чтобы убедиться, что всё выглядит хорошо, прежде чем отправлять в производство.
3. Вы можете настроить порт сервера, передав `--port` в качестве аргумента.
```json
{
"scripts": {
"docs:preview": "vitepress preview docs --port 8080"
}
}
```
Теперь метод `docs:preview` запустит сервер по адресу `http://localhost:8080`.
## Установка публичного базового пути {#setting-a-public-base-path}
По умолчанию предполагается, что сайт будет развёрнут по корневому пути домена (`/`). Если ваш сайт будет обслуживаться по подпути, например, `https://mywebsite.com/blog/`, то в конфигурации VitePress необходимо установить для опции [`base`](../reference/site-config#base) значение `'/blog/'`.
**Пример:** Если вы используете Github (или GitLab) Pages и развёртываете на `user.github.io/repo/`, то установите `base` на `/repo/`.
## Заголовки кэша HTTP {#http-cache-headers}
Если вы контролируете HTTP-заголовки на своем рабочем сервере, вы можете настроить заголовки `cache-control` для достижения лучшей производительности при повторных посещениях.
В производственной сборке используются хэшированные имена файлов для статических ресурсов (JavaScript, CSS и другие импортированные ресурсы, не находящиеся в `public`). Если вы просмотрите предварительную версию с помощью сетевой вкладки devtools вашего браузера, вы увидите файлы типа `app.4f283b18.js`.
Этот хэш `4f283b18` генерируется из содержимого этого файла. Один и тот же хэшированный URL гарантированно обслуживает одно и то же содержимое файла — если содержимое меняется, то и URL тоже. Это означает, что вы можете смело использовать самые сильные заголовки кэша для этих файлов. Все такие файлы будут помещены в каталог `assets/` в выходном каталоге, поэтому вы можете настроить для них следующий заголовок:
```
Cache-Control: max-age=31536000,immutable
```
::: details Пример файла Netlify `_headers`
```
/assets/*
cache-control: max-age=31536000
cache-control: immutable
```
Примечание: файл `_headers` должен быть помещён в [директорию `public`](./asset-handling#the-public-directory) — в нашем случае `docs/public/_headers` — так, чтобы он был скопирован в выходной каталог.
[Netlify custom headers documentation](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}
Создайте новый проект и измените эти настройки с помощью панели управления:
- **Build Command:** `npm run docs:build`
- **Output Directory:** `docs/.vitepress/dist`
- **Node Version:** `18` (или выше)
::: warning ПРЕДУПРЕЖДЕНИЕ
Не включайте такие опции, как _Auto Minify_ для HTML-кода. Он удалит из вывода комментарии, которые имеют значение для Vue. При их удалении могут возникать ошибки несоответствия гидратации.
:::
### GitHub Pages {#github-pages}
1. Создайте файл с именем `deploy.yml` в директории `.github/workflows` вашего проекта с примерно таким содержанием:
```yaml
# Пример рабочего процесса для создания и развёртывания сайта VitePress на GitHub Pages
#
name: Deploy VitePress site to Pages
on:
# Выполняется при пушах, направленных в ветку `main`. Измените это значение на `master`, если вы
# используете ветку `master` в качестве ветки по умолчанию.
push:
branches: [main]
# Позволяет запустить этот рабочий процесс вручную на вкладке «Actions».
workflow_dispatch:
# Устанавливает разрешения GITHUB_TOKEN, чтобы разрешить развёртывание на страницах GitHub.
permissions:
contents: read
pages: write
id-token: write
# Разрешите только одно одновременное развёртывание, пропуская запуски, стоящие в очереди.
# Однако НЕ отменяйте текущие запуски, поскольку мы хотим дать возможность завершить производственные развёртывания.
concurrency:
group: pages
cancel-in-progress: false
jobs:
# Сборка
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0 # Не требуется, если функция lastUpdated не включена
# - uses: pnpm/action-setup@v3 # Раскомментируйте, если вы используете pnpm
# - uses: oven-sh/setup-bun@v1 # Раскомментируйте, если вы используете Bun
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm # или pnpm / yarn
- name: Setup Pages
uses: actions/configure-pages@v4
- name: Install dependencies
run: npm ci # или pnpm install / yarn install / bun install
- name: Build with VitePress
run: npm run docs:build # или pnpm docs:build / yarn docs:build / bun run docs:build
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: docs/.vitepress/dist
# Развёртывание
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` в вашем VitePress настроена правильно. Дополнительные сведения см. в секции [Установка публичного базового пути](#setting-a-public-base-path).
:::
2. В настройках вашего репозитория в разделе «Pages» выберите пункт меню «GitHub Actions» в секции «Build and deployment > Source».
3. Внесите свои изменения в ветку `main` и дождитесь завершения процесса GitHub Actions. Вы должны увидеть, что ваш сайт развёрнут по адресу `https://<username>.github.io/[repository]/` или `https://<custom-domain>/` в зависимости от ваших настроек. Ваш сайт будет автоматически разворачиваться при каждом внесении изменений в ветке `main`.
### GitLab Pages {#gitlab-pages}
1. Установите `outDir` в конфигурации VitePress на `../public`. Настройте опцию `base` на `'/<репозиторий>/'`, если вы хотите развернуть ваш проект по адресу на `https://<имя пользователя>.gitlab.io/<репозиторий>/`.
2. Создайте файл с именем `.gitlab-ci.yml` в корне вашего проекта с приведённым ниже содержимым. Это позволит создавать и развёртывать ваш сайт каждый раз, когда вы вносите изменения в его содержимое:
```yaml
image: node:18
pages:
cache:
paths:
- node_modules/
script:
# - apk add git # Отметьте это, если вы используете небольшие докер-образы, такие как alpine, и у вас включен lastUpdated
- npm install
- npm run docs:build
artifacts:
paths:
- public
only:
- main
```
### Статические веб-приложения Azure {#azure-static-web-apps}
1. Следуйте [официальной документации](https://docs.microsoft.com/ru-ru/azure/static-web-apps/build-configuration).
2. Установите эти значения в вашем конфигурационном файле (и удалите те, которые вам не нужны, например, `api_location`):
- **`app_location`**: `/`
- **`output_location`**: `docs/.vitepress/dist`
- **`app_build_command`**: `npm run docs:build`
### Firebase {#firebase}
1. Создайте `firebase.json` и `.firebaserc` в корне вашего проекта:
`firebase.json`:
```json
{
"hosting": {
"public": "docs/.vitepress/dist",
"ignore": []
}
}
```
`.firebaserc`:
```json
{
"projects": {
"default": "<YOUR_FIREBASE_ID>"
}
}
```
2. После запуска `npm run docs:build` выполните эту команду для развёртывания:
```sh
firebase deploy
```
### Surge {#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
{
"root": "docs/.vitepress/dist"
}
```
### Edgio {#edgio}
См. [Создание и развёртывание приложения VitePress в Edgio](https://docs.edg.io/applications/v6/sites_frameworks/getting_started/vitepress).
### Хостинг статических файлов Kinsta {#kinsta-static-site-hosting}
Вы можете развернуть свой сайт Vitepress на [Kinsta](https://kinsta.com/static-site-hosting/), следуя этим [инструкциям](https://kinsta.com/docs/vitepress-static-site-example/).
### Stormkit
Вы можете развернуть свой проект VitePress на [Stormkit](https://www.stormkit.io), следуя следующим [инструкциям](https://stormkit.io/blog/how-to-deploy-vitepress).
### Nginx
Вот пример конфигурации блока сервера Nginx. Эта настройка включает сжатие gzip для общих текстовых ресурсов, правила обслуживания статических файлов вашего сайта VitePress с правильными заголовками кэширования и обработку параметра `cleanUrls: true`.
```nginx
server {
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
listen 80;
server_name _;
index index.html;
location / {
# расположение контента
root /app;
# точные совпадения -> обратные чистые URL-адреса -> папки -> не найдены
try_files $uri $uri.html $uri/ =404;
# несуществующие страницы
error_page 404 /404.html;
# папка без index.html вызывает ошибку 403 в этой настройке
error_page 403 /404.html;
# настройка заголовков кэширования
# файлы в папке с ресурсами имеют хэши имён файлов
location ~* ^/assets/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
}
```
Эта конфигурация предполагает, что ваш собранный сайт VitePress находится в директории `/app`. При необходимости измените директиву `root`, если файлы вашего сайта расположены в другом месте.
::: warning Не используйте index.html по умолчанию
Разрешение try_files не должно использовать index.html, как это делается в других приложениях Vue. Это может привести к недопустимому состоянию страницы.
:::
Дополнительную информацию можно найти в официальной документации [Nginx](https://nginx.org/ru/docs/), а также в следующих обсуждениях: [#2837](https://github.com/vuejs/vitepress/discussions/2837), [#3235](https://github.com/vuejs/vitepress/issues/3235), а также в [блоге Mehdi Merah](https://blog.mehdi.cc/articles/vitepress-cleanurls-on-nginx-environment#readings).

@ -0,0 +1,342 @@
---
outline: deep
---
# Расширение темы по умолчанию {#extending-the-default-theme}
Тема VitePress по умолчанию оптимизирована для документации и может быть настроена по своему усмотрению. Полный список опций можно найти в главе [Настройки темы по умолчанию](../reference/default-theme-config).
Однако есть ряд случаев, когда одной лишь конфигурации будет недостаточно. Например:
1. Вам нужно изменить стили CSS;
2. Вам нужно изменить экземпляр приложения Vue, например, чтобы зарегистрировать глобальные компоненты;
3. Вам нужно внедрить пользовательский контент в тему через слоты макета.
Эти расширенные настройки потребуют использования пользовательской темы, которая «расширяет» тема по умолчанию.
::: tip СОВЕТ
Прежде чем приступить к работе, обязательно прочитайте главу [Пользовательская тема](./custom-theme), чтобы понять, как работают пользовательские темы.
:::
## Настройка CSS {#customizing-css}
CSS темы по умолчанию можно настроить, переопределив переменные CSS корневого уровня:
```js
// .vitepress/theme/index.js
import DefaultTheme from 'vitepress/theme'
import './custom.css'
export default DefaultTheme
```
```css
/* .vitepress/theme/custom.css */
:root {
--vp-c-brand-1: #646cff;
--vp-c-brand-2: #747bff;
}
```
См. [переменные CSS темы по умолчанию](https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css), которые можно переопределить.
## Использование различных шрифтов {#using-different-fonts}
VitePress использует [Inter](https://rsms.me/inter/) в качестве шрифта по умолчанию, и будет включать шрифты в вывод сборки. Шрифт также автоматически загружается в производство. Однако это может быть нежелательно, если вы хотите использовать другой основной шрифт.
Чтобы не включать Inter в вывод сборки, импортируйте тему из `vitepress/theme-without-fonts`:
```js
// .vitepress/theme/index.js
import DefaultTheme from 'vitepress/theme-without-fonts'
import './my-fonts.css'
export default DefaultTheme
```
```css
/* .vitepress/theme/custom.css */
:root {
--vp-font-family-base: /* normal text font */ --vp-font-family-mono:
/* code font */;
}
```
::: warning ПРЕДУПРЕЖДЕНИЕ
Если вы используете дополнительные компоненты, такие как [Страница команды](../reference/default-theme-team-page), убедитесь, что они также импортированы из `vitepress/theme-without-fonts`!
:::
Если ваш шрифт — это локальный файл, на который ссылаются через `@font-face`, он будет обработан как ресурс и включён в каталог `.vitepress/dist/assets` с хэшированным именем файла. Чтобы предварительно загрузить этот файл, используйте хук сборки [transformHead](../reference/site-config#transformhead):
```js
// .vitepress/config.js
export default {
transformHead({ assets }) {
// настраиваем regex соответствующим образом, чтобы он соответствовал вашему шрифту
const myFontFile = assets.find((file) => /font-name\.\w+\.woff2/)
if (myFontFile) {
return [
[
'link',
{
rel: 'preload',
href: myFontFile,
as: 'font',
type: 'font/woff2',
crossorigin: ''
}
]
]
}
}
}
```
## Регистрация глобальных компонентов {#registering-global-components}
```js
// .vitepress/theme/index.js
import DefaultTheme from 'vitepress/theme'
/** @type {import('vitepress').Theme} */
export default {
extends: DefaultTheme,
enhanceApp({ app }) {
// регистрируем пользовательские глобальные компоненты
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, вы также можете использовать [глобальную функцию импорта](https://vitejs.dev/guide/features.html#glob-import) Vite для автоматической регистрации каталога компонентов.
## Слоты макета {#layout-slots}
Компонент `<Layout/>` темы по умолчанию имеет несколько слотов, которые можно использовать для вставки содержимого в определённые места страницы. Вот пример внедрения компонента в структуру before:
```js
// .vitepress/theme/index.js
import DefaultTheme from 'vitepress/theme'
import MyLayout from './MyLayout.vue'
export default {
extends: DefaultTheme,
// переопределяем макет с помощью компонента-обёртки, который
// вводит слоты
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)
})
}
}
```
Полный список слотов, доступных в макете темы по умолчанию:
- Когда `layout: 'doc'` (по умолчанию) включен через метаданные:
- `doc-top`
- `doc-bottom`
- `doc-footer-before`
- `doc-before`
- `doc-after`
- `sidebar-nav-before`
- `sidebar-nav-after`
- `aside-top`
- `aside-bottom`
- `aside-outline-before`
- `aside-outline-after`
- `aside-ads-before`
- `aside-ads-after`
- Когда `layout: 'home'` включен через метаданные:
- `home-hero-before`
- `home-hero-info-before`
- `home-hero-info`
- `home-hero-info-after`
- `home-hero-actions-after`
- `home-hero-image`
- `home-hero-after`
- `home-features-before`
- `home-features-after`
- Когда `layout: 'page'` включен через метаданные:
- `page-top`
- `page-bottom`
- На странице «Не найдено (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`
## Использование View Transitions 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',
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>
Более подробно о переходах между представлениями читайте в [документации Chrome](https://developer.chrome.com/docs/web-platform/view-transitions/).
### Изменение маршрута {#on-route-change}
Скоро будет.
## Переопределение внутренних компонентов {#overriding-internal-components}
Вы можете использовать [псевдонимы](https://vitejs.dev/config/shared-options.html#resolve-alias) Vite, чтобы заменить стандартные компоненты темы на свои собственные:
```ts
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vitepress'
export default defineConfig({
vite: {
resolve: {
alias: [
{
find: /^.*\/VPNavBar\.vue$/,
replacement: fileURLToPath(
new URL('./components/CustomNavBar.vue', import.meta.url)
)
}
]
}
}
})
```
Чтобы узнать точное название компонента, обратитесь к [нашему исходному коду](https://github.com/vuejs/vitepress/tree/main/src/client/theme-default/components). Поскольку компоненты являются внутренними, есть небольшая вероятность того, что их название будет обновлено между минорными выпусками.

@ -0,0 +1,48 @@
# Метаданные {#frontmatter}
## Использование {#usage}
VitePress поддерживает метаданные YAML во всех Markdown-файлах, разбирая их с помощью [gray-matter](https://github.com/jonschlinkert/gray-matter). Метаданные должны находиться в верхней части Markdown-файла (перед любыми элементами, включая теги `<script>`) и иметь вид корректного YAML, заданного между тройными пунктирными линиями. Пример:
```md
---
title: Документация с VitePress
editLink: true
---
```
Многие параметры конфигурации сайта или темы по умолчанию имеют соответствующие опции в блоке метаданных. Вы можете использовать метаданные, чтобы переопределить определённое поведение только для текущей страницы. Подробности см. в [Справочнике по настройке метаданных](../reference/frontmatter-config).
Вы также можете определить собственные метаданные, которые будут использоваться в динамических выражениях Vue на странице.
## Доступ к метаданным {#accessing-frontmatter-data}
Доступ к метаданным можно получить через специальную глобальную переменную `$frontmatter`:
Вот пример того, как можно использовать его в файле Markdown:
```md
---
title: Документация с VitePress
editLink: true
---
# {{ $frontmatter.title }}
Содержание руководства
```
Вы также можете получить доступ к метаданным текущей страницы в `<script setup>` с помощью [хелпера `useData()`](../reference/runtime-api#usedata).
## Альтернативные форматы метаданных {#alternative-frontmatter-formats}
VitePress также поддерживает синтаксис метаданных JSON, начинающийся и заканчивающийся фигурными скобками:
```json
---
{
"title": "Веду блог как хакер",
"editLink": true
}
---
```

@ -0,0 +1,216 @@
# Первые шаги {#getting-started}
## Попробуйте онлайн {#try-it-online}
Вы можете попробовать VitePress прямо в браузере на [StackBlitz](https://vitepress.new).
## Установка {#installation}
### Требования {#prerequisites}
- [Node.js](https://nodejs.org/) версии 18 или выше.
- Терминал для доступа к VitePress через интерфейс командной строки (CLI).
- Текстовый редактор с поддержкой синтаксиса [Markdown](https://ru.wikipedia.org/wiki/Markdown).
- Рекомендуется использовать [VSCode](https://code.visualstudio.com/), а также [официальное расширение Vue](https://marketplace.visualstudio.com/items?itemName=Vue.volar).
VitePress можно использовать самостоятельно или установить в существующий проект. В обоих случаях вы можете установить его с помощью:
::: code-group
```sh [npm]
$ npm add -D vitepress
```
```sh [pnpm]
$ pnpm add -D vitepress
```
```sh [yarn]
$ yarn add -D vitepress
```
```sh [bun]
$ bun add -D vitepress
```
:::
::: details Получаете предупреждения об отсутствующих зависимостях?
Если вы используете PNPM, вы заметите предупреждение об отсутствующем пакете `@docsearch/js`. Это не мешает работе VitePress. Если вы хотите подавить это предупреждение, добавьте следующее в ваш `package.json`:
```json
"pnpm": {
"peerDependencyRules": {
"ignoreMissing": [
"@algolia/client-search",
"search-insights"
]
}
}
```
:::
::: tip ПРИМЕЧАНИЕ
VitePress — это пакет, предназначенный только для ESM. Не используйте `require()` для импорта, и убедитесь, что ближайший `package.json` содержит `"type": "module"`, или измените расширение соответствующих файлов, например, `.vitepress/config.js` на `.mjs`/`.mts`. Более подробную информацию см. в [Руководстве по устранению неполадок Vite](https://vitejs.dev/guide/troubleshooting.html#this-package-is-esm-only). Кроме того, внутри асинхронных контекстов CJS можно использовать `await import('vitepress')` вместо этого.
:::
### Мастер настройки {#setup-wizard}
VitePress поставляется с мастером настройки командной строки, который поможет вам создать базовый проект. После установки запустите мастер, запустив его:
::: code-group
```sh [npm]
$ npx vitepress init
```
```sh [pnpm]
$ pnpm vitepress init
```
```sh [yarn]
$ yarn vitepress init
```
```sh [bun]
$ bun vitepress init
```
:::
Вас встретят несколькими простыми вопросами:
<<< @/snippets/init.ansi
::: tip Vue как зависимость
Если вы собираетесь выполнять кастомизацию с использованием компонентов или API Vue, вам также следует явно установить `vue` в качестве зависимости.
:::
## Структура файлов {#file-structure}
Если вы создаете отдельный сайт VitePress, вы можете разместить его в текущей директории (`./`). Однако если вы устанавливаете VitePress в существующий проект вместе с другим исходным кодом, рекомендуется поместить сайт во вложенную директорию (например, `./docs`), чтобы он был отделён от остальной части проекта.
Если предположить, что вы решили разместить проект VitePress в `./docs`, то сгенерированная структура файлов должна выглядеть следующим образом:
```
.
├─ docs
│ ├─ .vitepress
│ │ └─ config.js
│ ├─ api-examples.md
│ ├─ markdown-examples.md
│ └─ index.md
└─ package.json
```
Директория `docs` считается **корнем проекта** сайта VitePress. Директория `.vitepress` — это зарезервированное место для конфигурационного файла VitePress, кэша dev-сервера, результатов сборки и дополнительного кода настройки темы.
::: tip СОВЕТ
По умолчанию VitePress хранит кэш своего dev-сервера в файле `.vitepress/cache`, а выходные данные сборки — в файле `.vitepress/dist`. Если вы используете Git, вам следует добавить их в файл `.gitignore`. Эти места также могут быть [сконфигурированы](../reference/site-config#outdir).
:::
### Конфигурационный файл {#the-config-file}
Файл конфигурации (`.vitepress/config.js`) позволяет настраивать различные аспекты сайта VitePress, самыми основными из которых являются название и описание сайта:
```js
// .vitepress/config.js
export default {
// параметры сайта
title: 'Заголовок сайта',
description: 'Описание сайта.',
themeConfig: {
// параметры темы
}
}
```
Вы также можете настроить поведение темы с помощью опции `themeConfig`. Загляните в главу [Настройка сайта](../reference/site-config) для получения подробной информации обо всех параметрах конфигурации.
### Исходные файлы {#source-files}
Файлы Markdown за пределами директории `.vitepress` считаются **исходными файлами**.
VitePress использует **маршрутизацию на основе файлов**: Каждый файл `.md` компилируется в соответствующий файл `.html` с тем же путем. Например, `index.md` будет скомпилирован в `index.html`, и его можно будет посетить по корневому пути `/` результирующего сайта VitePress.
VitePress также предоставляет возможность генерировать чистые URL-адреса, переписывать пути и динамически генерировать страницы. Всё это будет рассмотрено в [Руководстве по маршрутизации](./routing).
## Скрипты запуска {#up-and-running}
Мастер настройки также должен был внедрить следующие скрипты npm в ваш `package.json`, если вы разрешили ему это сделать в процессе установки:
```json
{
...
"scripts": {
"docs:dev": "vitepress dev docs",
"docs:build": "vitepress build docs",
"docs:preview": "vitepress preview docs"
},
...
}
```
Скрипт `docs:dev` запустит локальный dev-сервер с мгновенными горячими обновлениями. Запустите его с помощью следующей команды:
::: code-group
```sh [npm]
$ npm run docs:dev
```
```sh [pnpm]
$ pnpm run docs:dev
```
```sh [yarn]
$ yarn docs:dev
```
```sh [bun]
$ bun run docs:dev
```
:::
Вместо npm-скриптов вы также можете вызывать VitePress напрямую с помощью:
::: code-group
```sh [npm]
$ npx vitepress dev docs
```
```sh [pnpm]
$ pnpm vitepress dev docs
```
```sh [yarn]
$ yarn vitepress dev docs
```
```sh [bun]
$ bun vitepress dev docs
```
:::
Более подробная информация об использовании командной строки описана в главе [Командная строка](../reference/cli).
Dev-сервер должен быть запущен по адресу `http://localhost:5173`. Перейдите по URL-адресу в браузере, чтобы увидеть новый сайт в действии!
## Что дальше? {#what-s-next}
- Чтобы лучше понять, как Markdown-файлы сопоставляются с генерируемым HTML, перейдите к [Руководству по маршрутизации](./routing).
- Чтобы узнать больше о том, что вы можете делать на странице, например, писать содержимое в формате Markdown или использовать компоненты Vue, обратитесь к разделу «Написание». Начать стоит с изучения главы [Расширения Markdown](./markdown).
- Чтобы изучить возможности, предоставляемые темой документации по умолчанию, ознакомьтесь с главой [Настройка темы по умолчанию](../reference/default-theme-config).
- Если вы хотите ещё больше изменить внешний вид своего сайта, изучите главы [Расширение темы по умолчанию](./extending-default-theme) или [Пользовательская тема](./custom-theme).
- Как только ваш сайт документации обретёт форму, обязательно прочитайте [Руководство по развёртыванию](./deploy).

@ -0,0 +1,113 @@
# Интернационализация {#internationalization}
Чтобы использовать встроенные функции i18n, необходимо создать следующую структуру каталогов:
```
docs/
├─ es/
│ ├─ foo.md
├─ ru/
│ ├─ foo.md
├─ foo.md
```
Затем в `docs/.vitepress/config.ts`:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
// общие свойства и другие вещи верхнего уровня...
locales: {
root: {
label: 'English',
lang: 'en'
},
ru: {
label: 'Русский',
lang: 'ru', // необязательный, будет добавлен как атрибут `lang` в тег `html`
link: '/ru/guide' // по умолчанию /ru/ -- отображается в меню переводов на панели навигации, может быть внешним
// другие свойства, специфичные для локали...
}
}
})
```
Следующие свойства могут быть переопределены для каждой локали (включая корневую):
```ts
interface LocaleSpecificConfig<ThemeConfig = any> {
lang?: string
dir?: string
title?: string
titleTemplate?: string | boolean
description?: string
head?: HeadConfig[] // будут объединены с существующими записями в заголовке, дублирующие метатеги будут автоматически удалены
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#algolia-search-i18n).
**Совет:** Конфигурационный файл можно хранить и в `docs/.vitepress/config/index.ts`. Это может помочь вам организовать работу, создав конфигурационный файл для каждой локали, а затем объединить и экспортировать их из `index.ts`.
## Отдельный каталог для каждой локали {#separate-directory-for-each-locale}
Пример многоязычной структуры:
```
docs/
├─ en/
│ ├─ foo.md
├─ es/
│ ├─ foo.md
├─ ru/
├─ foo.md
```
Однако по умолчанию VitePress не будет перенаправлять `/` на `/en/`. Для этого вам нужно будет настроить свой сервер. Например, в Netlify вы можете добавить файл `docs/public/_redirects` следующим образом:
```
/* /es/:splat 302 Language=es
/* /ru/:splat 302 Language=ru
/* /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}
Для поддержки языков с написанием справа налево укажите `dir: 'rtl'` в конфиге и используйте какой-нибудь плагин RTLCSS PostCSS, например <https://github.com/MohammadYounes/rtlcss>, <https://github.com/vkalinichev/postcss-rtl> или <https://github.com/elchininet/postcss-rtlcss>. Вам нужно настроить плагин PostCSS на использование `:where([dir="ltr"])` и `:where([dir="rtl"])` в качестве префиксов, чтобы избежать проблем со спецификой CSS.

@ -0,0 +1,933 @@
# Расширения Markdown {#markdown-extensions}
VitePress поставляется со встроенными расширениями Markdown.
## Якоря заголовков {#header-anchors}
К заголовкам автоматически применяются якорные ссылки. Отрисовку якорей можно настроить с помощью опции `markdown.anchor`.
### Пользовательские якоря {#custom-anchors}
Чтобы указать пользовательский тег якоря для заголовка, а не использовать автоматически сгенерированный, добавьте суффикс к заголовку:
```
# Использование пользовательских якорей {#мой-якорь}
```
Это позволит вам ссылаться на заголовок как `#мой-якорь` вместо стандартного `#использование-пользовательских-якорей`.
## Ссылки {#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](/) <!-- отправляет пользователя в корневой index.md -->
[foo](/foo/) <!-- отправляет пользователя на страницу index.html из каталога foo -->
[foo heading](./#heading) <!-- привязывает пользователя к заголовку в индексном файле foo -->
[bar - three](../bar/three) <!-- вы можете опустить расширение -->
[bar - three](../bar/three.md) <!-- вы можете добавить .md -->
[bar - four](../bar/four.html) <!-- или вы можете добавить .html -->
```
### Суффикс страницы {#page-suffix}
Страницы и внутренние ссылки по умолчанию генерируются с суффиксом `.html`.
### Внешние ссылки {#external-links}
Исходящие ссылки автоматически получают значение `target="_blank" rel="noreferrer"`:
- [vuejs.org](https://vuejs.org)
- [VitePress on GitHub](https://github.com/vuejs/vitepress)
## Метаданные {#frontmatter}
[Метаданные YAML](https://jekyllrb.com/docs/front-matter/) поддерживаются из коробки:
```yaml
---
title: Веду блог как хакер
lang: ru-RU
---
```
Эти данные будут доступны остальной части страницы, а также всем пользовательским и тематическим компонентам.
Более подробную информацию можно найти в главе [Метаданные](../reference/frontmatter-config).
## Таблицы в стиле GitHub {#github-style-tables}
**Разметка**
```md
| Таблицы | это | круто |
| ---------------- | :----------------------: | ----: |
| столбец 3 | выровнен по правому краю | $1600 |
| столбец 2 | отцентрован | $12 |
| полосатые строки | как полоски у зебры | $1 |
```
**Результат**
| Таблицы | это | круто |
| ---------------- | :----------------------: | -----: |
| столбец 3 | выровнен по правому краю | \$1600 |
| столбец 2 | отцентрован | \$12 |
| полосатые строки | как полоски у зебры | \$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]]
Отрисовка 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('Привет, VitePress!')
```
:::
````
**Результат**
::: danger СТОП
Опасная зона, остановитесь
:::
::: details Нажмите на меня, чтобы просмотреть код
```js
console.log('Привет, VitePress!')
```
:::
Кроме того, вы можете установить пользовательские заголовки глобально, добавив следующее содержимое в конфигурацию сайта, полезное, если вы пишете не на английском языке:
```ts
// config.ts
export default defineConfig({
// ...
markdown: {
container: {
tipLabel: 'СОВЕТ',
warningLabel: 'ПРЕДУПРЕЖДЕНИЕ',
dangerLabel: 'ОПАСНОСТЬ',
infoLabel: 'ИНФОРМАЦИЯ',
detailsLabel: 'Подробная информация'
}
}
// ...
})
```
### `raw` {#raw}
Это специальный контейнер, который можно использовать для предотвращения конфликтов стилей и маршрутизаторов с VitePress. Это особенно полезно при документировании библиотек компонентов. Вы также можете посмотреть [whyframe](https://whyframe.dev/docs/integrations/vitepress) для лучшей изоляции.
**Syntax**
```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()]
}
```
Он использует [`postcss-prefix-selector`](https://github.com/postcss/postcss-load-config) под капотом. Вы можете передать ему параметры следующим образом:
```js
postcssIsolateStyles({
includeFiles: [/vp-doc\.css/] // по умолчанию /base\.css/
})
```
## Оповещения в стиле GitHub {#github-flavored-alerts}
VitePress также поддерживает [Оповещения в стиле 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-in-code-blocks}
VitePress использует [Shiki](https://github.com/shikijs/shiki) для выделения синтаксиса языка в блоках кода 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).
Вы также можете настроить тему подсветки синтаксиса в конфигурации приложения. Более подробную информацию см. в секции [`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-8}
export default { // Подсвечено
data () {
return {
msg: `Подсвечено!
Эта строка не выделена,
но эта и две следующих - да.`,
motd: 'VitePress - это потрясающе',
lorem: 'ipsum'
}
}
}
```
````
**Результат**
```js{1,4,6-8}
export default { // Подсвечено
data () {
return {
msg: `Подсвечено!
Эта строка не выделена,
но эта и две следующих - да.`,
motd: 'VitePress - это потрясающе',
lorem: 'ipsum',
}
}
}
```
Кроме того, можно выделять непосредственно в строке, используя комментарий `// [!code highlight]`.
**Разметка**
````
```js
export default {
data () {
return {
msg: 'Подсвечено!' // [!!code highlight]
}
}
}
```
````
**Результат**
```js
export default {
data() {
return {
msg: 'Подсвечено!' // [!code highlight]
}
}
}
```
## Фокус в блоках кода {#focus-in-code-blocks}
Добавление комментария `// [!code focus]` к строке сфокусирует её и размоет остальные части кода.
Кроме того, вы можете задать количество строк для фокусировки с помощью `// [!code focus:<lines>]`.
**Разметка**
````
```js
export default {
data () {
return {
msg: 'Фокус!' // [!!code focus]
}
}
}
```
````
**Результат**
```js
export default {
data() {
return {
msg: 'Фокус!' // [!code focus]
}
}
}
```
## Подсветка различий в блоках кода {#colored-diffs-in-code-blocks}
Добавление в строку комментариев `// [!code --]` или `// [!code ++]` создаст diff этой строки, сохраняя цвета блока кода.
**Разметка**
````
```js
export default {
data () {
return {
msg: 'Удалено' // [!!code --]
msg: 'Добавлено' // [!!code ++]
}
}
}
```
````
**Результат**
```js
export default {
data () {
return {
msg: 'Удалено' // [!code --]
msg: 'Добавлено' // [!code ++]
}
}
}
```
## Ошибки и предупреждения в блоках кода {#errors-and-warnings-in-code-blocks}
Добавление в строку комментариев `// [!code warning]` или `// [!code error]` окрасит её соответствующим образом.
**Разметка**
````
```js
export default {
data () {
return {
msg: 'Ошибка', // [!!code error]
msg: 'Предупреждение' // [!!code warning]
}
}
}
```
````
**Результат**
```js
export default {
data() {
return {
msg: 'Ошибка', // [!code error]
msg: 'Предупреждение' // [!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}
// опция line-numbers по умолчанию отключена
const line2 = 'Строка 2'
const line3 = 'Строка 3'
```
```ts:line-numbers {1}
// опция line-numbers включена
const line2 = 'Строка 2'
const line3 = 'Строка 3'
```
```ts:line-numbers=2 {1}
// опция line-numbers включена, нумерация начинается с 2
const line3 = 'Строка 3'
const line4 = 'Строка 4'
```
````
**Результат**
```ts {1}
// опция line-numbers по умолчанию отключена
const line2 = 'Строка 2'
const line3 = 'Строка 3'
```
```ts:line-numbers {1}
// опция line-numbers включена
const line2 = 'Строка 2'
const line3 = 'Строка 3'
```
```ts:line-numbers=2 {1}
// опция line-numbers включена, нумерация начинается с 2
const line3 = 'Строка 3'
const line4 = 'Строка 4'
```
## Импорт фрагментов кода {#import-code-snippets}
Вы можете импортировать фрагменты кода из существующих файлов, используя следующий синтаксис:
```md
<<< @/filepath
```
[Выделение строк](#line-highlighting-in-code-blocks) тоже поддерживается:
```md
<<< @/filepath{highlightLines}
```
**Разметка**
```md
<<< @/snippets/snippet.js{2}
```
**Файл с кодом**
<<< @/snippets/snippet.js
**Результат**
<<< @/snippets/snippet.js{2}
::: tip СОВЕТ
Значение `@` соответствует корню источника. По умолчанию это корень проекта VitePress, если не настроен `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#}
<!-- с подсветкой строк: -->
<<< @/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 символ `@`, он будет выступать в качестве корня источника. По умолчанию это корень проекта VitePress, если не настроена опция `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}`
::: warning ПРЕДУПРЕЖДЕНИЕ
Обратите внимание, что это не приводит к ошибкам, если ваш файл отсутствует. Поэтому при использовании этой функции убедитесь, что содержимое отображается так, как ожидается.
:::
## Математические уравнения {#math-equations}
В настоящее время эта фича предоставляется по желанию. Чтобы включить её, вам нужно установить `markdown-it-mathjax3` и установить значение `true` для опции `markdown.math` в вашем файле конфигурации:
```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} $$
**Уравнения Максвелла:**
| уравнение | описание |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| $\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}}$ | искривление $\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} $$
**Уравнения Максвелла:**
| уравнение | описание |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| $\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}}$ | искривление $\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$ | _что?_ |
## Ленивая загрузка изображений {#image-lazy-loading}
Вы можете включить ленивую загрузку для каждого изображения, добавленного через markdown, установив значение `true` для опции `lazyLoading` в вашем файле конфигурации:
```js
export default {
markdown: {
image: {
// ленивая загрузка изображений отключена по умолчанию
lazyLoading: true
}
}
}
```
## Расширенная конфигурация {#advanced-configuration}
VitePress использует [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)
}
}
})
```
Полный список настраиваемых свойств см. в секции [`markdown`](../reference/site-config#markdown).

@ -0,0 +1,23 @@
# Переход с VitePress 0.x
Если вы переходите с версии VitePress 0.x, то в ней есть несколько изменений, связанных с новыми функциями и улучшениями. Следуйте этому руководству, чтобы узнать, как перенести ваше приложение на последнюю версию VitePress.
## Конфигурация приложения
- Функция интернационализации ещё не реализована.
## Конфигурация темы
- Опция `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`.
## Конфигурация метаданных
- Опция `home: true` заменена на `layout: home`. Кроме того, многие настройки, связанные с главной страницей, были изменены для обеспечения дополнительных возможностей. Подробности см. в разделе [Главная страница](../reference/default-theme-home-page).
- Опция `footer` перенесена в [`themeConfig.footer`](../reference/default-theme-config#footer).

@ -0,0 +1,30 @@
# Переход с VuePress
## Конфигурация
### Сайдбар
Боковая панель больше не заполняется автоматически из метаданных. Вы можете [самостоятельно прочитать вступление](https://github.com/vuejs/vitepress/issues/572#issuecomment-1170116225), чтобы научиться динамически заполнять боковую панель. [Дополнительные утилиты для этого](https://github.com/vuejs/vitepress/issues/96) могут быть предоставлены в будущем.
## Markdown
### Изображения
В отличие от VuePress, VitePress автоматически обрабатывает опцию [`base`](./asset-handling#base-url) вашего конфига, когда вы используете статическое изображение.
Таким образом, теперь вы можете выводить изображения без тега `img`.
```diff
- <img :src="$withBase('/foo.png')" alt="foo">
+ ![foo](/foo.png)
```
::: warning ПРЕДУПРЕЖДЕНИЕ
Для динамических изображений вам всё ещё нужно использовать `withBase`, как показано в [Руководстве по базовому URL](./asset-handling#base-url).
:::
Используйте регулярное выражение `<img.*withBase\('(.*)'\).*alt="([^"]*)".*>` для поиска всех изображений с синтаксисом `![](...)` и замены на `![$2]($1)`.
---
продолжение следует...

@ -0,0 +1,23 @@
# Режим MPA <Badge type="warning" text="экспериментально" /> {#mpa-mode}
Режим MPA (Multi-Page Application — «Многостраничное приложение») можно включить через командную строку с помощью команды `vitepress build --mpa`, или через конфигурацию с помощью опции `mpa: true`.
В режиме MPA все страницы по умолчанию отображаются без включенного JavaScript. В результате производственный сайт, скорее всего, получит более высокую оценку эффективности первых посещений с помощью инструментов аудита.
Однако из-за отсутствия навигации SPA межстраничные ссылки будут приводить к полной перезагрузке страницы. После загрузки навигация в режиме MPA будет не такой мгновенной, как в режиме SPA.
Также обратите внимание, что «no-JS-by-default» («без JS по умолчанию») означает, что вы используете Vue исключительно как серверный язык шаблонов. Никаких обработчиков событий в браузере не будет, поэтому интерактивности не будет. Чтобы загрузить JavaScript со стороны клиента, вам нужно использовать специальный тег `<script client>`:
```html
<script client>
document.querySelector('h1').addEventListener('click', () => {
console.log('JavaScript на стороне клиента!')
})
</script>
# Привет
```
`<script client>` — это функция только для VitePress, а не для Vue. Она работает как в файлах `.md`, так и в файлах `.vue`, но только в режиме MPA. Клиентские скрипты во всех компонентах темы будут объединены вместе, в то время как клиентский скрипт для конкретной страницы будет разделён только для этой страницы.
Обратите внимание, что `<script client>` **не оценивается как код компонента Vue**: он обрабатывается как обычный модуль JavaScript. По этой причине режим MPA следует использовать только в том случае, если ваш сайт требует абсолютно минимальной интерактивности на стороне клиента.

@ -0,0 +1,371 @@
---
outline: deep
---
# Маршрутизация {#routing}
## Маршрутизация на основе файлов {#file-based-routing}
VitePress использует маршрутизацию на основе файлов, что означает, что сгенерированные HTML-страницы отображаются на основе структуры папок исходных файлов Markdown. Например, при следующей структуре папок:
```
.
├─ guide
│ ├─ getting-started.md
│ └─ index.md
├─ index.md
└─ prologue.md
```
Сгенерированные HTML-страницы будут выглядеть так:
```
index.md --> /index.html (доступна по адресу /)
prologue.md --> /prologue.html
guide/index.md --> /guide/index.html (доступна по адресу /guide/)
guide/getting-started.md --> /guide/getting-started.html
```
Полученный HTML можно разместить на любом веб-сервере, который может обслуживать статические файлы.
## Корневая директория и директория с исходными файлами {#root-and-source-directory}
В файловой структуре проекта VitePress есть два важных понятия: **корень проекта** и **директория с исходными файлами**.
### Корень проекта {#project-root}
Корень проекта — это место, где VitePress будет пытаться искать специальный каталог `.vitepress`. Директория `.vitepress` — это зарезервированное место для конфигурационного файла VitePress, кэша dev-сервера, результатов сборки и дополнительного кода настройки темы.
Когда вы запускаете `vitepress dev` или `vitepress build` из командной строки, VitePress будет использовать текущий рабочий каталог в качестве корня проекта. Чтобы указать подкаталог в качестве корневого, нужно передать команде относительный путь. Например, если ваш проект VitePress находится в папке `./docs`, вам следует выполнить команду `vitepress dev docs`:
```
.
├─ docs # корень проекта
│ ├─ .vitepress # директория с настройками
│ ├─ getting-started.md
│ └─ index.md
└─ ...
```
```sh
vitepress dev docs
```
В результате получится следующее сопоставление источника с HTML:
```
docs/index.md --> /index.html (доступна по адресу /)
docs/getting-started.md --> /getting-started.html
```
### Директория с исходными файлами {#source-directory}
Директория с исходными файлами — это место, где хранятся ваши исходные файлы Markdown. По умолчанию она совпадает с корнем проекта. Однако вы можете настроить её с помощью параметра [`srcDir`](../reference/site-config#srcdir).
Опция `srcDir` разрешается относительно корня проекта. Например, с помощью `srcDir: 'src'`, ваша файловая структура будет выглядеть следующим образом:
```
. # корень проекта
├─ .vitepress # директория с настройками
└─ src # директория с исходными файлами
├─ getting-started.md
└─ index.md
```
Итоговое сопоставление исходного кода с HTML:
```
src/index.md --> /index.html (доступна по адресу /)
src/getting-started.md --> /getting-started.html
```
## Связи между страницами {#linking-between-pages}
При создании ссылок между страницами можно использовать как абсолютные, так и относительные пути. Обратите внимание, что хотя расширения `.md` и `.html` будут работать, лучше всего опускать расширения файлов, чтобы VitePress мог генерировать конечные URL на основе вашего конфига.
```md
<!-- Будут работать -->
[Первые шаги](./getting-started)
[Первые шаги](../guide/getting-started)
<!-- Не будут работать -->
[Первые шаги](./getting-started.md)
[Первые шаги](./getting-started.html)
```
Узнайте больше о ссылках на такие ресурсы, как изображения, в главе [Обработка ресурсов](./asset-handling).
### Ссылки на страницы, не принадлежащие VitePress {#linking-to-non-vitepress-pages}
Если вы хотите создать ссылку на страницу вашего сайта, которая не создана VitePress, вам нужно будет либо использовать полный URL-адрес (откроется в новой вкладке), либо явно указать цель:
**Разметка**
```md
[Ссылка на pure.html](/pure.html){target="_self"}
```
**Результат**
[Ссылка на pure.html](/pure.html){target="_self"}
::: tip Примечание
В ссылках Markdown к URL-адресу автоматически добавляется значение параметра `base`. Это означает, что если вы хотите создать ссылку на страницу за пределами `base`, вам понадобится что-то вроде `../../pure.html` в ссылке (разрешаемой браузером относительно текущей страницы).
Альтернативно можно напрямую использовать синтаксис тега ссылки:
```md
<a href="/pure.html" target="_self">Ссылка на pure.html</a>
```
:::
## Создание чистого URL-адреса {#generating-clean-url}
::: warning Требуется поддержка сервера
Для обслуживания чистых URL-адресов с помощью VitePress требуется поддержка на стороне сервера.
:::
По умолчанию VitePress разрешает входящие ссылки на URL-адреса, заканчивающиеся на `.html`. Однако некоторые пользователи могут предпочесть «Чистые URL-адреса» без расширения `.html` — например, `example.com/path` вместо `example.com/path.html`.
Некоторые серверы или хостинговые платформы (например, Netlify, Vercel, GitHub Pages) предоставляют возможность сопоставлять URL-адрес типа `/foo` с `/foo.html`, если он существует, без перенаправления:
- Страницы Netlify и GitHub поддерживают это по умолчанию.
- Vercel требует включить [опцию `cleanUrls` в `vercel.json`](https://vercel.com/docs/concepts/projects/project-configuration#cleanurls).
Если эта функция вам доступна, вы также можете включить собственную опцию конфигурации VitePress [`cleanUrls`](../reference/site-config#cleanurls), чтобы обеспечить следующее поведение:
- Входящие ссылки между страницами генерируются без расширения `.html`.
- Если текущий путь заканчивается на `.html`, маршрутизатор выполнит перенаправление на стороне клиента на путь без расширений.
Однако если вы не можете настроить свой сервер с такой поддержкой, вам придётся вручную прибегнуть к следующей структуре каталогов:
```
.
├─ getting-started
│ └─ index.md
├─ installation
│ └─ index.md
└─ index.md
```
## Перезапись маршрутов {#route-rewrites}
Вы можете настроить сопоставление между структурой исходного каталога и создаваемыми страницами. Это полезно, когда у вас сложная структура проекта. Допустим, у вас есть монорепо с несколькими пакетами, и вы хотите поместить документацию вместе с исходными файлами, как это сделано здесь:
```
.
├─ packages
│ ├─ pkg-a
│ │ └─ src
│ │ ├─ pkg-a-code.ts
│ │ └─ pkg-a-docs.md
│ └─ pkg-b
│ └─ src
│ ├─ pkg-b-code.ts
│ └─ pkg-b-docs.md
```
И вы хотите, чтобы страницы VitePress генерировались следующим образом:
```
packages/pkg-a/src/pkg-a-docs.md --> /pkg-a/index.html
packages/pkg-b/src/pkg-b-docs.md --> /pkg-b/index.html
```
Этого можно добиться, настроив опцию [`rewrites`](../reference/site-config#rewrites) следующим образом:
```ts
// .vitepress/config.js
export default {
rewrites: {
'packages/pkg-a/src/pkg-a-docs.md': 'pkg-a/index.md',
'packages/pkg-b/src/pkg-b-docs.md': 'pkg-b/index.md'
}
}
```
Опция `rewrites` также поддерживает динамические параметры маршрута. В приведенном выше примере, если у вас много пакетов, перечислять все пути было бы скучно. Учитывая, что все они имеют одинаковую структуру файлов, вы можете упростить конфигурацию следующим образом:
```ts
export default {
rewrites: {
'packages/:pkg/src/(.*)': ':pkg/index.md'
}
}
```
Пути перезаписи компилируются с помощью пакета `path-to-regexp` — обратитесь к [его документации](https://github.com/pillarjs/path-to-regexp#parameters) за более сложным синтаксисом.
::: warning Относительные ссылки с переписыванием
Когда переписывание включено, **относительные ссылки должны быть основаны на переписанных путях**. Например, чтобы создать относительную ссылку с `packages/pkg-a/src/pkg-a-code.md` на `packages/pkg-b/src/pkg-b-code.md`, нужно использовать:
```md
[Ссылка на PKG B](../pkg-b/pkg-b-code)
```
:::
## Динамические маршруты {#dynamic-routes}
Вы можете создать множество страниц, используя один файл Markdown и динамические данные. Например, вы можете создать файл `packages/[pkg].md`, который будет генерировать соответствующую страницу для каждого пакета в проекте. Здесь сегмент `[pkg]` является **параметром** маршрута, который отличает каждую страницу от других.
### Файл загрузчика путей {#paths-loader-file}
Поскольку VitePress — это генератор статических сайтов, возможные пути страниц должны быть определены во время сборки. Поэтому динамическая маршрутная страница **должна** сопровождаться **файлом загрузчика путей**. Для `packages/[pkg].md` нам понадобится `packages/[pkg].paths.js` (`.ts` также поддерживается):
```
.
└─ packages
├─ [pkg].md # шаблон маршрута
└─ [pkg].paths.js # загрузчик путей маршрута
```
Загрузчик путей должен предоставлять объект с методом `paths` в качестве экспорта по умолчанию. Метод `paths` должен возвращать массив объектов со свойством `params`. Для каждого из этих объектов будет создана соответствующая страница.
Дан следующий массив `paths`:
```js
// packages/[pkg].paths.js
export default {
paths() {
return [{ params: { pkg: 'foo' } }, { params: { pkg: 'bar' } }]
}
}
```
Сгенерированные HTML-страницы будут выглядеть так:
```
.
└─ packages
├─ foo.html
└─ bar.html
```
### Несколько параметров {#multiple-params}
Динамический маршрут может содержать несколько параметров:
**Структура файлов**
```
.
└─ packages
├─ [pkg]-[version].md
└─ [pkg]-[version].paths.js
```
**Загрузчик путей**
```js
export default {
paths: () => [
{ params: { pkg: 'foo', version: '1.0.0' } },
{ params: { pkg: 'foo', version: '2.0.0' } },
{ params: { pkg: 'bar', version: '1.0.0' } },
{ params: { pkg: 'bar', version: '2.0.0' } }
]
}
```
**Результат**
```
.
└─ packages
├─ foo-1.0.0.html
├─ foo-2.0.0.html
├─ bar-1.0.0.html
└─ bar-2.0.0.html
```
### Динамически генерируемые пути {#dynamically-generating-paths}
Модуль загрузчика путей запускается в Node.js и выполняется только во время сборки. Вы можете динамически генерировать массив путей, используя любые данные, как локальные, так и удалённые.
Генерация путей из локальных файлов:
```js
import fs from 'fs'
export default {
paths() {
return fs.readdirSync('packages').map((pkg) => {
return { params: { pkg } }
})
}
}
```
Генерация путей из удалённых данных:
```js
export default {
async paths() {
const pkgs = await (await fetch('https://my-api.com/packages')).json()
return pkgs.map((pkg) => {
return {
params: {
pkg: pkg.name,
version: pkg.version
}
}
})
}
}
```
### Доступ к параметрам на странице {#accessing-params-in-page}
Вы можете использовать параметры для передачи дополнительных данных на каждую страницу. Файл маршрута Markdown может получить доступ к параметрам текущей страницы в выражениях Vue через глобальное свойство `$params`:
```md
- package name: {{ $params.pkg }}
- version: {{ $params.version }}
```
Вы также можете получить доступ к параметрам текущей страницы через Runtime API [`useData`](../reference/runtime-api#usedata). Это доступно как в файлах Markdown, так и в компонентах Vue:
```vue
<script setup>
import { useData } from 'vitepress'
// params — это ref-ссылка Vue
const { params } = useData()
console.log(params.value)
</script>
```
### Рендеринг необработанного содержимого {#rendering-raw-content}
Параметры, передаваемые странице, будут сериализованы в полезной нагрузке клиентского JavaScript, поэтому вам следует избегать передачи в параметрах больших объемов данных, например, необработанного Markdown или HTML-контента, полученного из удаленной CMS.
Вместо этого вы можете передавать такое содержимое на каждую страницу с помощью свойства `content` каждого объекта path:
```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,53 @@
# Генерация карты сайта {#sitemap-generation}
VitePress поставляется с готовой поддержкой генерации файла `sitemap.xml` для вашего сайта. Чтобы включить её, добавьте следующее в файл `.vitepress/config.js`:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
sitemap: {
hostname: 'https://example.com'
}
})
```
Чтобы теги `<lastmod>` присутствовали в вашем файле `sitemap.xml`, вы можете включить опцию [`lastUpdated`](../reference/default-theme-last-updated).
## Параметры {#options}
Поддержка карты сайта осуществляется с помощью модуля [`sitemap`](https://www.npmjs.com/package/sitemap). Вы можете передать любые поддерживаемые им параметры в опцию `sitemap` в вашем конфигурационном файле. Они будут переданы непосредственно в конструктор `SitemapStream`. Более подробную информацию см. в документации [`sitemap`](https://www.npmjs.com/package/sitemap#options-you-can-pass). Пример:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
sitemap: {
hostname: 'https://example.com',
lastmodDateOnly: false
}
})
```
## Хук `transformItems` {#transformitems-hook}
Вы можете использовать хук `sitemap.transformItems` для изменения элементов карты сайта перед их записью в файл `sitemap.xml`. Этот хук вызывается с массивом элементов sitemap и ожидает возвращения массива элементов sitemap. Пример:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
sitemap: {
hostname: 'https://example.com',
transformItems: (items) => {
// добавляем новые элементы или изменяем/фильтруем существующие
items.push({
url: '/extra-page',
changefreq: 'monthly',
priority: 0.8
})
return items
}
}
})
```

@ -0,0 +1,137 @@
---
outline: deep
---
# Совместимость с SSR {#ssr-compatibility}
VitePress предварительно рендерит приложение в Node.js во время производственной сборки, используя возможности Vue по рендерингу на стороне сервера (SSR). Это означает, что весь пользовательский код в компонентах темы подлежит проверке на совместимость с SSR.
Глава [Рендеринг на стороне сервера](https://ru.vuejs.org/guide/scaling-up/ssr.html) в документации Vue содержит более подробную информацию о том, что такое SSR, взаимосвязь между SSR и SSG, а также общие указания по написанию кода, дружественного к SSR. Правило заключается в том, чтобы обращаться к API браузера / DOM только в хуках `beforeMount` или `mounted` компонентов Vue.
## `<ClientOnly>` {#clientonly}
Если вы используете или демонстрируете компоненты, которые не являются SSR-дружественными (например, содержат пользовательские директивы), вы можете обернуть их внутри встроенного компонента `<ClientOnly>`:
```md
<ClientOnly>
<NonSSRFriendlyComponent />
</ClientOnly>
```
## Библиотеки, обращающиеся к API браузера при импорте {#libraries-that-access-browser-api-on-import}
Некоторые компоненты или библиотеки получают доступ к API браузера **при импорте**. Чтобы использовать код, предполагающий наличие среды браузера при импорте, необходимо динамически импортировать их.
### Импорт в хуке `onMounted` {#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`](./custom-theme#theme-interface) может быть асинхронным, вы можете условно импортировать и регистрировать плагины 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}
VitePress предоставляет удобный помощник для импорта компонентов Vue, которые получают доступ к API браузера при импорте.
```vue
<script setup>
import { defineClientComponent } from 'vitepress'
const ClientComp = defineClientComponent(() => {
return import('component-that-access-window-on-import')
})
</script>
<template>
<ClientComp />
</template>
```
Вы также можете передавать параметры/дочерние элементы/слоты целевому компоненту:
```vue
<script setup>
import { ref } from 'vue'
import { defineClientComponent } from 'vitepress'
const clientCompRef = ref(null)
const ClientComp = defineClientComponent(
() => import('component-that-access-window-on-import'),
// args передаются в функцию h() - https://ru.vuejs.org/api/render-function.html#h
[
{
ref: clientCompRef
},
{
default: () => 'default slot',
foo: () => h('div', 'foo'),
bar: () => [h('span', 'one'), h('span', 'two')]
}
],
// обратный вызов после загрузки компонента, может быть асинхронным
() => {
console.log(clientCompRef.value)
}
)
</script>
<template>
<ClientComp />
</template>
```
Целевой компонент будет импортирован только в смонтированный хук компонента-обёртки.

@ -0,0 +1,253 @@
# Использование Vue в Markdown {#using-vue-in-markdown}
В VitePress каждый Markdown-файл компилируется в HTML, а затем обрабатывается как [однофайловый компонент Vue](https://ru.vuejs.org/guide/scaling-up/sfc.html). Это означает, что вы можете использовать любые возможности Vue внутри Markdown, включая динамический шаблонизатор, использование компонентов Vue или произвольную логику компонентов Vue на странице, добавив тег `<script>`.
Стоит отметить, что VitePress использует компилятор Vue для автоматического обнаружения и оптимизации чисто статических частей контента в формате Markdown. Статичное содержимое оптимизируется в отдельные узлы-заполнители и исключается из полезной нагрузки JavaScript страницы при первых посещениях. Они также пропускаются при гидратации на стороне клиента. Короче говоря, вы платите только за динамические части на каждой конкретной странице.
::: tip Совместимость с SSR
Всё, что используется в Vue, должно быть совместимо с SSR. Подробности и общие обходные пути см. в главе [Совместимость с SSR](./ssr-compat).
:::
## Шаблонизация {#templating}
### Интерполяция {#interpolation}
Каждый файл Markdown сначала компилируется в HTML, а затем передается в качестве компонента Vue в конвейер процесса Vite. Это означает, что вы можете использовать интерполяцию в стиле Vue в тексте:
**Разметка**
```md
{{ 1 + 1 }}
```
**Результат**
<div class="language-text"><pre><code>{{ 1 + 1 }}</code></pre></div>
### Директивы {#directives}
Директивы также работают (обратите внимание, что по замыслу необработанный HTML также допустим в Markdown):
**Разметка**
```html
<span v-for="i in 3">{{ i }}</span>
```
**Результат**
<div class="language-text"><pre><code><span v-for="i in 3">{{ i }} </span></code></pre></div>
## `<script>` и `<style>` {#script-and-style}
Теги корневого уровня `<script>` и `<style>` в Markdown-файлах работают так же, как и в Vue SFC, включая `<script setup>`, `<style module>` и т. д. Главное отличие заключается в отсутствии тега `<template>`: всё остальное содержимое корневого уровня — Markdown. Также обратите внимание, что все теги должны располагаться **после** метаданных:
```html
---
hello: world
---
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
## Содержание в формате Markdown. Счётчик: {{ count }}
<button :class="$style.button" @click="count++">Увеличить</button>
<style module>
.button {
color: red;
font-weight: bold;
}
</style>
```
::: warning Избегайте `<style scoped>` в Markdown
При использовании в Markdown `<style scoped>` требует добавления специальных атрибутов к каждому элементу на текущей странице, что значительно увеличивает размер страницы. `<style module>` предпочтительнее, когда на странице требуется локально копируемый стиль.
:::
У вас также есть доступ к runtime API VitePress, например, к [хелперу `useData`](../reference/runtime-api#usedata), который предоставляет доступ к метаданным текущей страницы:
**Разметка**
```html
<script setup>
import { useData } from 'vitepress'
const { page } = useData()
</script>
<pre>{{ page }}</pre>
```
**Результат**
```json
{
"path": "/using-vue.html",
"title": "Использование Vue в Markdown",
"frontmatter": {},
...
}
```
## Использование компонентов {#using-components}
Вы можете импортировать и использовать компоненты Vue непосредственно в файлах Markdown.
### Импорт в Markdown {#importing-in-markdown}
Если компонент используется только на нескольких страницах, рекомендуется явно импортировать его туда, где он используется. Это позволяет правильно разделить их по коду и загружать только при показе соответствующих страниц:
```md
<script setup>
import CustomComponent from '../components/CustomComponent.vue'
</script>
# Документация
Это .md с использованием пользовательского компонента
<CustomComponent />
## Другая документация
...
```
### Глобальная регистрация компонентов {#registering-components-globally}
Если компонент будет использоваться на большинстве страниц, его можно зарегистрировать глобально, настроив экземпляр приложения Vue. Пример смотрите в соответствующей главе [Расширение темы по умолчанию](./extending-default-theme#registering-global-components).
::: warning ВАЖНО
Убедитесь, что имя пользовательского компонента содержит дефис или написано в PascalCase. В противном случае он будет рассматриваться как встроенный элемент и заключен в тег `<p>`, что приведет к несоответствию гидратации, поскольку `<p>` не позволяет размещать внутри него блочные элементы.
:::
### Использование компонентов в заголовках <ComponentInHeader /> {#using-components-in-headers}
Вы можете использовать компоненты Vue в заголовках, но обратите внимание на разницу между следующими синтаксисами:
| Markdown | Итоговый HTML | Разобранный заголовок |
| -------------------------------------------------------- | ------------------------------------------ | --------------------- |
| <pre v-pre><code> # текст &lt;Tag/&gt; </code></pre> | `<h1>текст <Tag/></h1>` | `текст` |
| <pre v-pre><code> # текст \`&lt;Tag/&gt;\` </code></pre> | `<h1>текст <code>&lt;Tag/&gt;</code></h1>` | `текст <Tag/>` |
HTML, обёрнутый `<code>`, будет отображаться как есть; только тот HTML, который **не** обёрнут, будет разобран Vue.
::: tip ПРИМЕЧАНИЕ
Вывод HTML осуществляется с помощью [Markdown-it](https://github.com/Markdown-it/Markdown-it), а парсинг заголовков обрабатывается VitePress (и используется как для боковой панели, так и для заголовка документа).
:::
## Экранирование {#escaping}
Вы можете избежать интерполяций Vue, обернув их в `<span>` или другие элементы с помощью директивы `v-pre`:
**Разметка**
```md
Это <span v-pre>{{ будет отображаться как есть}}</span>.
```
**Результат**
<div class="escape-demo">
<p>Это <span v-pre>{{ будет отображаться как есть}}</span></p>
</div>
В качестве альтернативы вы можете обернуть весь абзац в пользовательский контейнер `v-pre`:
```md
::: v-pre
{{ Это будет отображаться как есть }}
:::
```
**Результат**
<div class="escape-demo">
::: v-pre
{{ Это будет отображаться как есть }}
:::
</div>
## Unescape в блоках кода {#unescape-in-code-blocks}
По умолчанию все изолированные блоки кода автоматически оборачиваются `v-pre`, поэтому внутри них не будет обрабатываться синтаксис Vue. Чтобы включить интерполяцию в стиле Vue внутри фигурных скобок, вы можете добавить к языку суффикс `-vue`, например `js-vue`:
**Разметка**
````md
```js-vue
Привет, {{ 1 + 1 }}
```
````
**Результат**
```js-vue
Привет, {{ 1 + 1 }}
```
Обратите внимание, что при этом некоторые лексемы могут не выделяться синтаксисом должным образом.
## Использование препроцессоров CSS {#using-css-pre-processors}
VitePress имеет [встроенную поддержку](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>
```
## Использование телепортов {#using-teleports}
В настоящее время Vitepress поддерживает SSG только для телепортов к элементу `body`. Для других целей вы можете обернуть их внутри встроенного компонента `<ClientOnly>` или внедрить разметку телепортации в нужное место HTML конечной страницы через [хук `postRender`](../reference/site-config#postrender).
<ModalDemo />
::: details Исходный код
<<< @/ru/components/ModalDemo.vue
:::
```md
<ClientOnly>
<Teleport to="#modal">
<div>
// ...
</div>
</Teleport>
</ClientOnly>
```
<script setup>
import ModalDemo from '../components/ModalDemo.vue'
import ComponentInHeader from '../../components/ComponentInHeader.vue'
</script>
<style>
.escape-demo {
border: 1px solid var(--vp-c-border);
border-radius: 8px;
padding: 0 20px;
}
</style>

@ -0,0 +1,57 @@
# Что такое VitePress? {#what-is-vitepress}
VitePress — это [Генератор статических сайтов](https://en.wikipedia.org/wiki/Static_site_generator) (ГСС), предназначенный для быстрого создания сайтов, ориентированных на контент. В двух словах, VitePress берёт ваш исходный контент, написанный в [Markdown](https://ru.wikipedia.org/wiki/Markdown), применяет к нему тему и генерирует статические HTML-страницы, которые можно легко развернуть в любом месте.
<div class="tip custom-block" style="padding-top: 8px">
Хотите попробовать прямо сейчас? Перейдите к главе [Первые шаги](./getting-started).
</div>
## Примеры использования {#use-cases}
- **Документация**
VitePress поставляется с темой по умолчанию, предназначенной для технической документации. Она содержит эту страницу, которую вы сейчас читаете, а также документацию по [Vite](https://vitejs.dev/), [Rollup](https://rollupjs.org/), [Pinia](https://pinia.vuejs.org/), [VueUse](https://vueuse.org/), [Vitest](https://vitest.dev/), [D3](https://d3js.org/), [UnoCSS](https://unocss.dev/), [Iconify](https://iconify.design/) и [многое другое](https://www.vuetelescope.com/explore?framework.slug=vitepress).
[Официальная документация Vue.js](https://vuejs.org/) также основана на VitePress, но использует пользовательскую тему, разделяемую между несколькими переводами.
- **Блоги, портфолио и маркетинговые сайты**
VitePress поддерживает [полностью кастомизированные темы](./custom-theme), при этом разработчики могут использовать стандартное приложение Vite + Vue. То, что он построен на базе Vite, также означает, что вы можете напрямую использовать плагины Vite из его богатой экосистемы. Кроме того, VitePress предоставляет гибкие API для [загрузки данных](./data-loading) (локальной или удаленной) и [динамической генерации маршрутов](./routing#dynamic-routes). С его помощью можно построить практически всё, что угодно, если данные могут быть определены во время сборки.
Официальный [блог Vue.js](https://blog.vuejs.org/) — это простой блог, который генерирует свою индексную страницу на основе локального контента.
## Опыт разработчика {#developer-experience}
VitePress стремится обеспечить отличные возможности для разработчиков при работе с содержимым в формате Markdown.
- **[На базе Vite:](https://vitejs.dev/)** мгновенный запуск сервера, правки всегда отражаются мгновенно (<100 мс) без перезагрузки страницы.
- **[Встроенные расширения Markdown:](./markdown)** Frontmatter, таблицы, подсветка синтаксиса... называйте как хотите. В частности, VitePress предоставляет множество расширенных возможностей для работы с блоками кода, что делает его идеальным для создания технической документации.
- **[Markdown с возможностями Vue:](./using-vue)** каждая Markdown-страница также является [однофайловым компонентом](https://ru.vuejs.org/guide/scaling-up/sfc.html) Vue, благодаря 100% синтаксической совместимости шаблона Vue с HTML. Вы можете внедрить интерактивность в статический контент, используя шаблонизаторы Vue или импортированные компоненты Vue.
## Производительность {#performance}
В отличие от многих традиционных ГСС, где каждая навигация приводит к полной перезагрузке страницы, сайт, созданный VitePress, обслуживает статический HTML при первом посещении, но становится [Одностраничным приложением](https://ru.wikipedia.org/wiki/%D0%9E%D0%B4%D0%BD%D0%BE%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%87%D0%BD%D0%BE%D0%B5_%D0%BF%D1%80%D0%B8%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5) (SPA) для последующей навигации по сайту. Эта модель, на наш взгляд, обеспечивает оптимальный баланс производительности:
- **Быстрая начальная загрузка**
При первом посещении любой страницы будет использоваться статичный, предварительно отрендеренный HTML для быстрой загрузки и оптимального SEO. Затем на страницу загружается пакет JavaScript, который превращает страницу в Vue SPA («гидратация»). Вопреки распространённому мнению о медленной гидратации SPA, этот процесс на самом деле чрезвычайно быстр благодаря высокой производительности Vue 3 и оптимизациям компилятора. По данным [PageSpeed Insights](https://pagespeed.web.dev/report?url=https%3A%2F%2Fvitepress.dev%2F), типичные сайты VitePress достигают почти идеальных показателей производительности даже на мобильных устройствах с низкой скоростью передачи данных.
- **Быстрая навигация после загрузки**
Что ещё более важно, модель SPA приводит к улучшению пользовательского опыта **после** первоначальной загрузки. Последующая навигация по сайту больше не будет приводить к полной перезагрузке страницы. Вместо этого содержимое входящей страницы будет получено и динамически обновлено. VitePress также автоматически выполняет предварительную выборку фрагментов страницы для ссылок, которые находятся в пределах области просмотра. В большинстве случаев навигация после загрузки будет ощущаться мгновенно.
- **Интерактивность без штрафов**
Для того чтобы динамические части Vue, встроенные в статический Markdown, могли работать в режиме гидратации, каждая страница Markdown обрабатывается как компонент Vue и компилируется в JavaScript. Это может показаться неэффективным, но компилятор Vue достаточно умён, чтобы разделить статическую и динамическую части, минимизируя как стоимость гидратации, так и размер полезной нагрузки. При первоначальной загрузке страницы статические части автоматически исключаются из полезной нагрузки JavaScript и пропускаются во время гидратации.
## Что насчёт VuePress? {#what-about-vuepress}
VitePress — это духовный наследник VuePress. Оригинальный VuePress был основан на Vue 2 и webpack. Благодаря Vue 3 и Vite под капотом, VitePress обеспечивает значительно лучший опыт разработки, лучшую производительность, более отточенную тему по умолчанию и более гибкий API для настройки.
Разница в API между VitePress и VuePress заключается в основном в тематическом оформлении и настройке. Если вы используете VuePress 1 с темой по умолчанию, то переход на VitePress будет относительно простым.
Также были приложены усилия для создания VuePress 2, который также поддерживает Vue 3 и Vite с большей совместимостью с VuePress 1. Однако поддерживать два генератора параллельно не представляется возможным, поэтому команда Vue решила сосредоточиться на VitePress как основном рекомендуемом генераторе статических сайтов в долгосрочной перспективе.

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

Loading…
Cancel
Save