Page renders in dev stamp block elements with data-v-inspector
attributes carrying the cwd-relative source file, line and column —
include-aware through the line map, so content pulled in via
`<!-- @include -->` points at the included file. The attribute is the
one vite-plugin-vue-inspector's overlay reads off arbitrary elements,
so the Vue DevTools component inspector jumps to the markdown source
out of the box; a ~50-line dev-only client handler additionally makes
alt+click open the editor through Vite's built-in /__open-in-editor
endpoint with no plugins installed (#4293). Fence wrappers, code
groups and GitHub alerts re-emit the attribute from their hand-built
markup; builds, the local search index and content loader output are
env-gated and stay byte-identical. Opt out with
`markdown.sourceAttrs: false`.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
env.links becomes an array of { url, raw, loc } objects: the normalized
href, the destination as authored (decoded), and the exact position it was
authored at — including inside `<!-- @include -->`-ed files, which
previously reported the including page with a line in the expanded text.
Reports print the URL as written plus the resolved page path
(`(resolves to /x) in file.md:12:5`), fixing #4992 and #3774's halves of
the same complaint, and table-cell links (which had no line at all) and
links past the first line of a paragraph now carry exact positions.
Carries over the raw-URL reporting and test matrix from #5316.
BREAKING CHANGE: `env.links` entries are objects instead of strings and
`env.linkLines` is gone; `ignoreDeadLinks` strings, regexes and filter
functions now match the link as authored instead of the normalized encoded
URL, and filter functions receive a `{ file, line, column, url }` context
object instead of the source path string; `MarkdownCompileResult.deadLinks`
entries gained `resolved`/`column` and their `url` is now the authored
form. The markdown-it rule names `github-alerts`, `snippet` and
`vitepress_link_lines` are renamed/replaced by `vp_`-prefixed rules.
Co-authored-by: Bjorn Lu <34116392+bluwy@users.noreply.github.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Include expansion now emits a line map alongside the expanded source
(env.lineMap): one segment per contiguous run of lines, composed through
nested includes, region/heading/range slices (with the included file's
stripped frontmatter height folded in) and the isolation blank lines. Every
resolved source position now names the physical file a construct was
authored in.
This replaces the rebase-marker mechanism outright: relative URLs in
included markdown are rebased by resolving the token's position instead of
maintaining a marker stack scrubbed out of html_block tokens, which also
extends rebasing to lines following an inline include and makes block
isolation of own-line markdown includes unconditional (previously both were
skipped when markers could not be emitted).
BREAKING CHANGE: the `<!-- @include-start/end -->` markers no longer exist
in the expanded source (`env.src`).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Every inline rule is wrapped (lazily on first parse, so user config rules
are covered) to record the source range it consumed onto the tokens it
emits; a terminal core rule converts ranges into {file, line, column} via
the parent inline map and env.lineMap, stamped as token.meta.vpLoc together
with the decoded as-authored destination (token.meta.vpRaw). Table-cell
inline tokens inherit their row's map, and links spliced in by the linkify
core rule recover at least their line. Ranges ride on token objects, so
plugins that splice children or mutate content don't disturb them.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Moves <!-- @include: --> expansion out of markdownToVue and the local
search plugin into an include plugin registered on the renderer, which
wraps renderAsync and expands includes whenever the env carries a file
path. createMarkdownRenderer users and createContentLoader with render
or excerpt enabled now get includes expanded too (previously the
directives silently came through unexpanded), and the expansion is
reachable from the public API without exporting the helper (#4838).
Region selection uses the region engine (all same-named regions
concatenate, matched across comment styles), frontmatter of markdown
files is stripped before locating regions and headings so both share
one coordinate space, and the region suffix is anchored to the end of
the include path, so paths containing # now work.
Files reached by a failed render are still reported, so that creating
a missing snippet or include recovers the page instead of requiring an
edit of the including file.
BREAKING CHANGES:
- a missing region or heading anchor now throws instead of silently
including the whole file, and out-of-bounds or inverted ranges throw
instead of clamping; markdown.include.silent logs a warning and
expands to nothing instead
- markdown.include is a new option; false disables include processing
- custom search _render functions receive the raw source (sync
md.render does not expand includes; use renderAsync)
- the include-expanded source is exposed as env.src
Co-authored-by: Miroma <its.miroma@proton.me>
Co-authored-by: Naloam <110604855+Naloam@users.noreply.github.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Discovered config files are keyed by their source directory, but the
lookup walked the rewrite-applied relativePath, so directories covered
by rewrites silently lost their additional config. Resolve against
pageData.filePath on both server and client, which also makes dynamic
route pages inherit configs from their route template's directory.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Standardizes the tone across the file and documents all previously
undocumented types and members.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
`markdown.codeCopyButton` now holds both the button tooltip
(`tooltipText`) and the text shown after copying (`copiedText`),
per-locale overridable via `locales.<index>.markdown.codeCopyButton`.
The copied text is emitted as a `data-copied` attribute on the button
and rendered by the theme with `content: attr(data-copied)`.
BREAKING CHANGE: `markdown.codeCopyButtonTitle` is now
`markdown.codeCopyButton.tooltipText`, and its default changed from
"Copy Code" to "Copy code". The `--vp-code-copy-copied-text-content`
CSS variable and its built-in per-language `:lang()` defaults are
removed - set `codeCopyButton.copiedText` (per locale) instead.
close#4431
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Strings baked into pages by the markdown renderer can now be overridden
per locale via `locales.<index>.markdown` in the site config: container
titles (including GitHub-flavored alerts and custom containers) and the
code copy button title. Values resolve against `env.localeIndex` at
render time and fall back to the root markdown options, so the single
shared renderer keeps working unchanged.
close#4431
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replace the standalone `useData().hash` ref (backed by its own
`hashchange` listener in `initData`) with the `hash` already tracked on
the route, so the current URL is observed in one place and behaves
consistently during SSR.
- `isActive()` no longer reads `location.hash` at call time; it takes
the current hash as an argument (plus an optional `skipHashCheck`)
and `matchPath` is now required, making it pure and SSR-safe
- nav bar menus, nav screen menus, and menu links now react to hash-only
navigation too
- sidebar active-state tracking is reworked on top of the route: items
without a link are handled, and collapsed groups reliably auto-expand
when a child link becomes active (including on hash changes)
- prev/next links now properly ignore query strings and hashes when
deduplicating sidebar candidates (via `normalize`) and when matching
the current page
- custom `i18nRouting` functions receive the whole current `Route`
instead of only the hash string; language menu links are resolved
from the route (en + ru docs updated)
- `useLangs()` / `resolveLocaleLink()` are refactored with
self-documenting, JSDoc'd options (`linkToCorrespondingPage`,
`targetLocaleLink`, `currentLocaleLink`), and `resolveLocaleLink`
gained focused unit tests covering locale-home links, corresponding
links, cleanUrls, index pages, root-locale switching, and custom
routing functions
- unavoidable hydration mismatches are silenced with
`data-allow-mismatch` (viewport-dependent inline styles, per-locale
alternate links that embed the current query/hash)
- the `Route` interface moved to the shared types so
`DefaultTheme.I18nRouting` can reference it; the `vitepress` type
export is unchanged
- misc cleanups: `uniqBy` moved to theme support utils, `smartComputed`
comparator now called as `(newValue, oldValue)`, import ordering
BREAKING CHANGE: `useData().hash` has been removed. Read the hash from
`useRoute()` instead.
BREAKING CHANGE: custom `themeConfig.i18nRouting` functions now receive
the current `Route` as their second argument instead of the hash
string: `(data, route, targetLocale) => string`. Use `route.hash` for
the previous value; `route.path`, `route.query`, and `route.data` are
available as well.
Replaces the JS-based scroll offset logic with native CSS `scroll-margin-top`. The default theme sets it on headings using `--vp-nav-height` and `--vp-layout-top-height`, and `scrollTo` now uses `scrollIntoView` which respects it natively.
BREAKING CHANGE: `scrollOffset` from config is removed. Users wanting to customize scroll offset should customize `scroll-margin-top` via CSS instead. `smoothScroll` support from `router.go` is also removed as it didn't work as expected for most users. Users wanting smooth scrolling should set `scroll-behavior: smooth` in CSS, ideally inside a `@media (prefers-reduced-motion: no-preference)` block.
BREAKING CHANGES: `search.options.exclude` for local search is removed in favor of more flexible `search.options._render`
Co-authored-by: Divyansh Singh <40380293+brc-dd@users.noreply.github.com>
- The main reason behind this change is because previously the FS-based
timestamp is inaccurate and will change on every remote deployment in
CI environments, resulting in cache invalidation on every build. Using
git timestamps makes them stable.
- This is now disabled by default for performance reasons, as getting
the git timestamp requires spawning a child process and is expensive.
To enable it, use the new `lastUpdated: true` config option.