diff --git a/docs/guide/data-loading.md b/docs/guide/data-loading.md
index d23e25d6..6d54b2ca 100644
--- a/docs/guide/data-loading.md
+++ b/docs/guide/data-loading.md
@@ -23,7 +23,7 @@ The loader module is evaluated only in Node.js, so you can import Node APIs and
You can then import data from this file in `.md` pages and `.vue` components using the `data` named export:
-```html
+```vue
@@ -70,7 +70,7 @@ export default {
// watchedFiles will be an array of absolute paths of the matched files.
// generate an array of blog post metadata that can be used to render
// a list in the theme layout
- return watchedFiles.map(file => {
+ return watchedFiles.map((file) => {
return parse(fs.readFileSync(file, 'utf-8'), {
columns: true,
skip_empty_lines: true
@@ -147,9 +147,9 @@ export default createContentLoader('posts/*.md', {
// the final result is what will be shipped to the client.
return rawData.sort((a, b) => {
return +new Date(b.frontmatter.date) - +new Date(a.frontmatter.date)
- }).map(page => {
- page.src // raw markdown source
- page.html // rendered full page HTML
+ }).map((page) => {
+ page.src // raw markdown source
+ page.html // rendered full page HTML
page.excerpt // rendered excerpt HTML (content above first `---`)
return {/* ... */}
})
@@ -159,7 +159,7 @@ export default createContentLoader('posts/*.md', {
Check out how it is used in the [Vue.js blog](https://github.com/vuejs/blog/blob/main/.vitepress/theme/posts.data.ts).
-The `createContentLoader` API can also be used inside [build hooks](/reference/site-config#build-hooks):
+The `createContentLoader` API can also be used inside [build hooks](../reference/site-config#build-hooks):
```js
// .vitepress/config.js
@@ -171,6 +171,48 @@ export default {
}
```
+**Types**
+
+```ts
+interface ContentOptions {
+ /**
+ * Include src?
+ * @default false
+ */
+ includeSrc?: boolean
+
+ /**
+ * Render src to HTML and include in data?
+ * @default false
+ */
+ render?: boolean
+
+ /**
+ * If `boolean`, whether to parse and include excerpt? (rendered as HTML)
+ *
+ * If `function`, control how the excerpt is extracted from the content.
+ *
+ * If `string`, define a custom separator to be used for extracting the
+ * excerpt. Default separator is `---` if `excerpt` is `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
+
+ /**
+ * Transform the data. Note the data will be inlined as JSON in the client
+ * bundle if imported from components or markdown files.
+ */
+ transform?: (data: ContentData[]) => T | Promise
+}
+```
+
## Typed Data Loaders
When using TypeScript, you can type your loader and `data` export like so:
diff --git a/docs/guide/deploy.md b/docs/guide/deploy.md
index 7ebbc314..679d9ff9 100644
--- a/docs/guide/deploy.md
+++ b/docs/guide/deploy.md
@@ -73,7 +73,7 @@ Cache-Control: max-age=31536000,immutable
cache-control: immutable
```
-Note: the `_headers` file should be placed in the [public directory](/guide/asset-handling#the-public-directory) - in our case, `docs/public/_headers` - so that it is copied verbatim to the output directory.
+Note: the `_headers` file should be placed in the [public directory](./asset-handling#the-public-directory) - in our case, `docs/public/_headers` - so that it is copied verbatim to the output directory.
[Netlify custom headers documentation](https://docs.netlify.com/routing/headers/)
diff --git a/docs/guide/extending-default-theme.md b/docs/guide/extending-default-theme.md
index a0ccfd9e..332fa971 100644
--- a/docs/guide/extending-default-theme.md
+++ b/docs/guide/extending-default-theme.md
@@ -59,10 +59,10 @@ export default DefaultTheme
```
::: warning
-If you are using optional components like the [Team Page](/reference/default-theme-team-page) components, make sure to also import them from `vitepress/theme-without-fonts`!
+If you are using optional components like the [Team Page](../reference/default-theme-team-page) components, make sure to also import them from `vitepress/theme-without-fonts`!
:::
-If your font is a local file referenced via `@font-face`, it will be processed as an asset and included under `.vitepress/dist/assets` with hashed filename. To preload this file, use the [transformHead](/reference/site-config#transformhead) build hook:
+If your font is a local file referenced via `@font-face`, it will be processed as an asset and included under `.vitepress/dist/assets` with hashed filename. To preload this file, use the [transformHead](../reference/site-config#transformhead) build hook:
```js
// .vitepress/config.js
diff --git a/docs/guide/ssr-compat.md b/docs/guide/ssr-compat.md
index 11c6a081..82eb58e5 100644
--- a/docs/guide/ssr-compat.md
+++ b/docs/guide/ssr-compat.md
@@ -48,7 +48,7 @@ if (!import.meta.env.SSR) {
}
```
-Since [`Theme.enhanceApp`](/guide/custom-theme#theme-interface) can be async, you can conditionally import and register Vue plugins that access browser APIs on import:
+Since [`Theme.enhanceApp`](./custom-theme#theme-interface) can be async, you can conditionally import and register Vue plugins that access browser APIs on import:
```js
// .vitepress/theme/index.js
diff --git a/docs/reference/runtime-api.md b/docs/reference/runtime-api.md
index e4839d0c..03bb6160 100644
--- a/docs/reference/runtime-api.md
+++ b/docs/reference/runtime-api.md
@@ -141,7 +141,7 @@ If you are using or demoing components that are not SSR-friendly (for example, c
```
-- Related: [SSR Compatibility](/guide/ssr-compat)
+- Related: [SSR Compatibility](../guide/ssr-compat)
## `$frontmatter`
diff --git a/src/node/contentLoader.ts b/src/node/contentLoader.ts
index 048fc216..98c5585d 100644
--- a/src/node/contentLoader.ts
+++ b/src/node/contentLoader.ts
@@ -9,19 +9,41 @@ import { createMarkdownRenderer, type MarkdownRenderer } from './markdown'
export interface ContentOptions {
/**
* Include src?
- * default: false
+ * @default false
*/
includeSrc?: boolean
+
/**
* Render src to HTML and include in data?
- * default: false
+ * @default false
*/
render?: boolean
+
/**
- * Whether to parse and include excerpt (rendered as HTML)
- * default: false
+ * If `boolean`, whether to parse and include excerpt? (rendered as HTML)
+ *
+ * If `function`, control how the excerpt is extracted from the content.
+ *
+ * If `string`, define a custom separator to be used for extracting the
+ * excerpt. Default separator is `---` if `excerpt` is `true`.
+ *
+ * @see https://github.com/jonschlinkert/gray-matter#optionsexcerpt
+ * @see https://github.com/jonschlinkert/gray-matter#optionsexcerpt_separator
+ *
+ * @default false
*/
- excerpt?: boolean
+ excerpt?:
+ | boolean
+ | ((
+ file: {
+ data: { [key: string]: any }
+ content: string
+ excerpt?: string
+ },
+ options?: any
+ ) => void)
+ | string
+
/**
* Transform the data. Note the data will be inlined as JSON in the client
* bundle if imported from components or markdown files.
@@ -110,9 +132,13 @@ export function createContentLoader(
raw.push(cached.data)
} else {
const src = fs.readFileSync(file, 'utf-8')
- const { data: frontmatter, excerpt } = matter(src, {
- excerpt: true
- })
+ const { data: frontmatter, excerpt } = matter(
+ src,
+ // @ts-expect-error gray-matter types are wrong
+ typeof renderExcerpt === 'string'
+ ? { excerpt_separator: renderExcerpt }
+ : { excerpt: renderExcerpt }
+ )
const url =
'/' +
normalizePath(path.relative(config.srcDir, file)).replace(