在应用中使用内容集合
Velite 会将您的内容构建为 JSON 文件,并为 TypeScript 生成类型推断,您可以放心地在应用中使用输出的数据。
输出结构
diff
root
+├── .velite
+│ ├── posts.json # posts 集合输出
+│ └── others.json # others 集合输出
├── content
│ ├── posts
│ │ ├── hello-world.md
│ │ └── hello-world-2.md
│ └── others
├── public
+│ └── static
+│ ├── cover-2a4138dh.jpg # 来自 frontmatter 引用
+│ ├── img-2hd8f3sd.jpg # 来自内容引用
+│ ├── plain-37d62h1s.txt # 来自内容引用
+│ └── video-72hhd9f.mp4 # 来自 frontmatter 引用
├── package.json
└── velite.config.js在 .velite 目录中,Velite 会为每个集合生成输出文件,以及供您应用程序使用的 index.js 和 index.d.ts 文件。
js
export { default as posts } from './posts.json'
export { default as others } from './others.json'js
import type __vc from '../velite.config.js'
type Collections = typeof __vc.collections
export type Post = Collections['posts']['schema']['_output']
export declare const posts: Post[]
export type Other = Collections['others']['schema']['_output']
export declare const others: Other[]json
[
{
"title": "Hello world",
"slug": "hello-world",
"date": "1992-02-25T13:22:00.000Z",
"cover": {
"src": "/static/cover-2a4138dh.jpg",
"height": 1100,
"width": 1650,
"blurDataURL": "data:image/webp;base64,UklGRjwAAABXRUJQVlA4IDAAAACwAQCdASoIAAUADMDOJbACdADWaUXAAMltC0BZxTv24bHUX8EibgVs/sPiTqq6QAA=",
"blurWidth": 8,
"blurHeight": 5
},
"video": "/static/video-72hhd9f.mp4",
"metadata": {
"readingTime": 1,
"wordCount": 1
},
"excerpt": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse",
"content": "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse</p>\n<p><img src=\"/static/img-2hd8f3sd.jpg\" alt=\"some image\" /></p>\n<p><a href=\"/static/plain-37d62h1s.txt\">link to file</a></p>\n",
"permalink": "/blog/hello-world"
}
]json
[
...
]TIP
如果您使用 Git 进行版本控制,我们建议通过将 .velite 添加到您的 .gitignore 中来忽略该目录。这会告诉 Git 忽略此目录及其中的任何文件。
sh
echo '\n.velite' >> .gitignore在项目中使用
以下是在 Next.js 项目中使用输出数据的示例。
tsx
import { notFound } from 'next/navigation'
import { posts } from './.velite'
interface PostProps {
params: {
slug: string
}
}
function getPostBySlug(slug: string) {
return posts.find(post => post.slug === slug)
}
export default function PostPage({ params }: PostProps) {
const post = getPostBySlug(params.slug)
if (post == null) notFound()
return (
<article className="prose dark:prose-invert py-6">
<h1 className="mb-2">{post.title}</h1>
{post.description && <p className="mt-0 text-xl text-slate-700 dark:text-slate-200">{post.description}</p>}
<hr className="my-4" />
<div className="prose" dangerouslySetInnerHTML={{ __html: post.content }}></div>
</article>
)
}
export function generateMetadata({ params }: PostProps) {
const post = getPostBySlug(params.slug)
if (post == null) return {}
return { title: post.title, description: post.description }
}
export function generateStaticParams() {
return posts.map(({ slug }) => ({ slug }))
}数据访问器
由于每个用户的使用场景不同,Velite 是与框架无关的,并且不希望规定用户内容的结构或如何使用它生成的输出。因此,Velite 没有内置与数据访问相关的 API。
您可以按自己喜欢的方式在应用程序中使用输出数据,例如使用函数通过 slug 获取单篇文章,或使用函数通过类别获取文章列表。
ts
import { authors, posts } from '../.velite'
import type { Author, Post } from '../.velite'
export const getPostBySlug = (slug: string) => {
return posts.find(post => post.slug === slug)
}
export const getPostsByCategory = (category: string) => {
return posts.filter(post => post.category === category)
}
export const getAuthors = async <F extends keyof Author>(
filter: Filter<Author>,
fields?: F[],
limit: number = Infinity,
offset: number = 0
): Promise<Pick<Author, F>[]> => {
return authors
.filter(filter)
.sort((a, b) => (a.name > b.name ? -1 : 1))
.slice(offset, offset + limit)
.map(author => pick(author, fields))
}
export const getAuthorsCount = async (filter: Filter<Author> = filters.none): Promise<number> => {
return authors.filter(filter).length
}
export const getAuthor = async <F extends keyof Author>(filter: Filter<Author>, fields?: F[]): Promise<Pick<Author, F> | undefined> => {
const author = authors.find(filter)
return author && pick(author, fields)
}
export const getAuthorByName = async <F extends keyof Author>(name: string, fields?: F[]): Promise<Pick<Author, F> | undefined> => {
return getAuthor(i => i.name === name, fields)
}
export const getAuthorBySlug = async <F extends keyof Author>(slug: string, fields?: F[]): Promise<Pick<Author, F> | undefined> => {
return getAuthor(i => i.slug === slug, fields)
}简而言之,它只是原始的 JSON 数据,您可以用任何您想要的方式使用它。
路径别名
您可以在 tsconfig.json 中定义路径别名:
json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"#site/content": ["./.velite"]
}
}
}然后您就可以在项目中导入输出文件:
tsx
import { posts } from '#site/content'
// ...