建置時間資料載入
VitePress 提供一個名為資料載入器的功能,讓你可以載入任意資料並從頁面或元件匯入。資料載入僅在建置時執行:產生的資料將以 JSON 格式序列化在最終的 JavaScript 程式包中。
資料載入器可用於擷取遠端資料,或根據本機檔案產生元資料。例如,你可以使用資料載入器解析所有本機 API 頁面,並自動產生所有 API 條目的索引。
基本用法
資料載入器檔案必須以 .data.js
或 .data.ts
結尾。檔案應提供具有 load()
方法的物件的預設匯出
// example.data.js
export default {
load() {
return {
hello: 'world'
}
}
}
載入器模組僅在 Node.js 中評估,因此你可以根據需要匯入 Node API 和 npm 相依性。
然後,你可以使用 data
命名匯出,從 .md
頁面和 .vue
元件匯入此檔案中的資料
<script setup>
import { data } from './example.data.js'
</script>
<pre>{{ data }}</pre>
輸出
{
"hello": "world"
}
你會注意到資料載入器本身並未匯出 data
。VitePress 會在幕後呼叫 load()
方法,並透過 data
命名匯出隱含地公開結果。
即使載入器是非同步的,這仍然有效
export default {
async load() {
// fetch remote data
return (await fetch('...')).json()
}
}
來自本機檔案的資料
當你需要根據本機檔案產生資料時,你應該在資料載入器中使用 watch
選項,以便對這些檔案所做的變更可以觸發熱更新。
watch
選項的另一個好處是,你可以使用 glob 模式 來比對多個檔案。這些模式可以相對於 loader 檔案本身,而 load()
函式會接收到比對到的檔案作為絕對路徑。
以下範例展示如何載入 CSV 檔案,並使用 csv-parse 將它們轉換成 JSON。由於這個檔案只會在建置時執行,因此你不會將 CSV 解析器傳送給用戶端!
import fs from 'node:fs'
import { parse } from 'csv-parse/sync'
export default {
watch: ['./data/*.csv'],
load(watchedFiles) {
// 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 parse(fs.readFileSync(file, 'utf-8'), {
columns: true,
skip_empty_lines: true
})
})
}
}
createContentLoader
在建置以內容為主的網站時,我們經常需要建立「檔案」或「索引」頁面:一個我們列出內容集合中所有可用條目的頁面,例如部落格文章或 API 頁面。我們可以直接使用資料載入器 API 實作這個功能,但由於這是非常常見的用例,因此 VitePress 也提供了一個 createContentLoader
輔助函式來簡化這個過程
// posts.data.js
import { createContentLoader } from 'vitepress'
export default createContentLoader('posts/*.md', /* options */)
這個輔助函式會取得相對於 來源目錄 的 glob 模式,並傳回一個 { watch, load }
資料載入器物件,這個物件可以用作資料載入器檔案中的預設匯出。它還會根據檔案修改時間戳記實作快取,以提升開發效能。
請注意,這個載入器只適用於 Markdown 檔案,比對到的非 Markdown 檔案將會被略過。
載入的資料會是一個 ContentData[]
類型的陣列
interface ContentData {
// mapped URL for the page. e.g. /posts/hello.html (does not include base)
// manually iterate or use custom `transform` to normalize the paths
url: string
// frontmatter data of the page
frontmatter: Record<string, any>
// the following are only present if relevant options are enabled
// we will discuss them below
src: string | undefined
html: string | undefined
excerpt: string | undefined
}
預設情況下,只會提供 url
和 frontmatter
。這是因為載入的資料會以 JSON 形式內嵌在用戶端套件中,因此我們需要小心它的大小。以下是一個使用資料建置一個最小的部落格索引頁面的範例
<script setup>
import { data as posts } from './posts.data.js'
</script>
<template>
<h1>All Blog Posts</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>
選項
預設資料可能無法滿足所有需求,你可以選擇使用選項來轉換資料
// posts.data.js
import { createContentLoader } from 'vitepress'
export default createContentLoader('posts/*.md', {
includeSrc: true, // include raw markdown source?
render: true, // include rendered full page HTML?
excerpt: true, // include excerpt?
transform(rawData) {
// map, sort, or filter the raw data as you wish.
// 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
page.excerpt // rendered excerpt HTML (content above first `---`)
return {/* ... */}
})
}
})
查看 Vue.js 部落格 中如何使用它。
createContentLoader
API 也可以在 建置掛鉤 中使用
// .vitepress/config.js
export default {
async buildEnd() {
const posts = await createContentLoader('posts/*.md').load()
// generate files based on posts metadata, e.g. RSS feed
}
}
類型
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>
}
類型化資料載入器
使用 TypeScript 時,您可以輸入載入程式和 data
輸出,如下所示
import { defineLoader } from 'vitepress'
export interface Data {
// data type
}
declare const data: Data
export { data }
export default defineLoader({
// type checked loader options
watch: ['...'],
async load(): Promise<Data> {
// ...
}
})
設定
若要取得載入程式中的設定資訊,您可以使用類似以下的程式碼
import type { SiteConfig } from 'vitepress'
const config: SiteConfig = (globalThis as any).VITEPRESS_CONFIG