Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 48 additions & 6 deletions docs/guide/data-loading.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
<script setup>
import { data } from './example.data.js'
</script>
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 {/* ... */}
})
Expand All @@ -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
Expand All @@ -171,6 +171,48 @@ export default {
}
```

**Types**

```ts
interface ContentOptions<T = ContentData[]> {
/**
* 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<T>
}
```

## Typed Data Loaders

When using TypeScript, you can type your loader and `data` export like so:
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/deploy.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/)

Expand Down
4 changes: 2 additions & 2 deletions docs/guide/extending-default-theme.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/ssr-compat.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/runtime-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ If you are using or demoing components that are not SSR-friendly (for example, c
</ClientOnly>
```

- Related: [SSR Compatibility](/guide/ssr-compat)
- Related: [SSR Compatibility](../guide/ssr-compat)

## `$frontmatter` <Badge type="info" text="template global" />

Expand Down
42 changes: 34 additions & 8 deletions src/node/contentLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,41 @@ import { createMarkdownRenderer, type MarkdownRenderer } from './markdown'
export interface ContentOptions<T = ContentData[]> {
/**
* 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.
Expand Down Expand Up @@ -110,9 +132,13 @@ export function createContentLoader<T = ContentData[]>(
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(
Expand Down