使用Next.js - tailwind - shadcn/ui - velite搭建的Blog
1. 项目初始化
通过使用 Vercel 提供的 Next.js
模板快速创建项目, 项目创建完成后 Vercel 会自动部署项目, 并且会在GitHub仓库上创建项目,后面提交新代码会自动部署
2. 安装Velite
-
Velite 介绍
Velite 是一个用于构建类型安全数据层的工具,它将 Markdown / MDX、YAML、JSON 或其他文件转换为具有 Zod 模式的应用程序数据层。
Zod 是一个基于TypeScript的模式声明和验证库,它允许开发者声明数据模式,并自动推断出静态的TypeScript类型。使用Zod可以确保数据的完整性和一致性
-
Velite 配置文件
Velite 安装完成后 在项目根目录添加velite.config.ts
配置文件
import {defineConfig, defineCollection, s} from "velite"
import rehypeSlug from "rehype-slug"
import rehypePrettyCode from "rehype-pretty-code"
import rehypeAutolinkHeadings from "rehype-autolink-headings"
const computedFields = <T extends {slug: string}>(data : T) => ({
...data,
slugAsParams: data.slug.split("/").slice(1).join("/")
})
const posts = defineCollection({
name: "Post",
pattern: "blog/**/*.mdx",
schema: s.object({
slug: s.path(),
title: s.string().max(99),
description: s.string().max(999).optional(),
date: s.isodate(),
published: s.boolean().default(true),
body: s.mdx()
})
.transform(computedFields)
});
export default defineConfig({
root: "content",
output:{
data:".velite",
assets: "public/static",
base: "/static/",
name:"[name]-[hash:6].[ext]",
clean: true,
},
collections: {posts},
mdx:{
rehypePlugins:[rehypeSlug,
[rehypePrettyCode, {theme: "houston"}],
[
rehypeAutolinkHeadings,
{behavior:"wrap", properties:{className:["subheading-anchor"],
ariaLabel:"Link to section"}}
]
],
remarkPlugins:[]
}
})
defineCollection
函数定义了文件位置, 以及创建Zod 数据结构
rehypePlugins
定义插件 目前该项目使用了 rehype-slug
生成唯一标题, rehype-pretty-code
代码块样式,rehype-autolink-headings
将标题加入到链接
defineConfig
配置函数中的 output.data
是mdx文件转为数据结构文件输出位置 在 tsconfig.josn
配置路径别名
{
"compilerOptions": {
"paths": {
"#site/content": ["./.velite"]
}
}
}
路径别名的在/app/xx/[xxx]/page.tsx中使用
import { posts } from '#site/content';
async function getPostFromParams(params: {params:Promise<{slug:string[]}>}) {
const slug = (await params.params).slug.join("/")
const psot = posts.find((psot) => psot.slugAsParams === slug)
return psot;
}
- next.js 配置文件
const isDev = process.argv.indexOf('dev') !== -1
const isBuild = process.argv.indexOf('build') !== -1
if (!process.env.VELITE_STARTED && (isDev || isBuild)) {
process.env.VELITE_STARTED = '1'
const { build } = await import('velite')
await build({ watch: isDev, clean: !isDev })
}
/** @type {import('next').NextConfig} */
export default {
// next config here...
}