← 返回列表

Blog 项目全解

2026-03-23

博客项目全解

一、项目概览

这是一个基于 Next.js 16 + React 19 + TypeScript 的个人博客系统,使用 App Router 组织页面,内容来源于本地 Markdown 文件,并支持从外部文章仓库按需同步。
项目定位是「深色优先、内容驱动、轻交互」的技术博客,核心能力包括:

  • Markdown 文章渲染(含代码高亮、图片灯箱)
  • 博客列表与详情页路由生成
  • 运行期异步内容同步(拉取远端仓库最新文章)
  • Tailwind CSS v4 + Shadcn/ui 风格化界面

二、技术栈详解

1) 前端与框架层

  • Next.js 16.2.0:全栈 React 框架,负责路由、服务端渲染与构建产物。
  • React 19.2.4:组件与 UI 逻辑核心。
  • TypeScript 5:静态类型系统,提升可维护性与重构安全。

2) 样式与 UI 层

  • Tailwind CSS v4:原子化样式方案。
  • @tailwindcss/typography:优化 Markdown 排版(prose)。
  • Shadcn/ui(基于 Radix 生态组件):构建一致化基础组件。
  • next-themes:主题(亮/暗)切换基础能力。

3) 内容与渲染层

  • react-markdown:将 Markdown 转成 React 组件。
  • remark-gfm:支持 GFM 语法(表格、任务列表等)。
  • PrismJS:代码块高亮。
  • Velite:内容集合配置与 Markdown 内容处理能力。
  • rehype-shiki + shiki:可选高质量语法高亮管线(在 Velite 配置中启用)。

4) 工程与质量层

  • eslint@9 + eslint-config-next:代码规范与静态检查。
  • postcss:样式处理链路。

三、目录结构(核心)

NewBlog/
├─ src/
│  ├─ app/
│  │  ├─ (site)/page.tsx           # 站点首页
│  │  ├─ blog/page.tsx             # 博客列表页
│  │  └─ blog/[slug]/page.tsx      # 博客详情页
│  ├─ components/
│  │  └─ blog/PostImageLightbox.tsx# 图片灯箱
│  └─ lib/
│     ├─ post-source.ts            # 读取并解析 Markdown
│     └─ content-sync.ts           # 远端内容仓库同步逻辑
├─ content/posts/                  # 本地文章目录(Markdown)
├─ public/static/                  # 静态资源
├─ velite.config.ts                # Velite 配置
└─ package.json                    # 脚本与依赖

四、关键代码片段与逻辑说明

下面代码为项目内关键逻辑摘录(便于理解整体运行机制)。

1) 启动脚本:内容构建与开发服务并行

{
  "scripts": {
    "dev": "velite dev & next dev",
    "build": "next build",
    "start": "next start",
    "lint": "eslint"
  }
}

说明:

  • npm run dev 会同时启动 velite devnext dev
  • build/start 分离,符合生产环境常见流程(先构建,再启动)。

2) 文章同步:运行期异步触发内容拉取

首页/列表/详情页都在请求结束后触发:

after(() => {
  void ensureContentFresh();
});

说明:

  • after 让同步任务在响应后执行,降低首屏阻塞概率。
  • ensureContentFresh() 内部有 TTL、并发锁与远端 SHA 校验,避免重复拉取。

3) 远端更新判定:基于分支 HEAD SHA

const { stdout } = await runGit(
  ["ls-remote", authedRepoUrl, `refs/heads/${branch}`],
  process.cwd()
);

说明:

  • 通过 git ls-remote 获取远端分支最新 SHA。
  • 若与本地记录一致,则仅刷新检查时间,不做同步。

4) Markdown 读取:递归扫描并解析 Frontmatter

if (entry.isFile() && entry.name.toLowerCase().endsWith(".md")) {
  files.push(full);
}

说明:

  • 递归读取 content/posts 下所有 .md
  • 同时兼容 YAML (---) 与 TOML (+++) Frontmatter。
  • 最终按日期降序排序,供列表页渲染。

5) 详情页渲染:Markdown + 代码高亮 + 图片灯箱

const highlighted = Prism.highlight(
  codeText.replace(/\n$/, ""),
  grammar,
  language ?? "markup"
);

说明:

  • react-markdown 负责结构化渲染。
  • Prism 对代码块做语法高亮。
  • img 节点替换为 PostImageLightbox,提升阅读体验。

五、本地部署步骤(详细)

1) 环境准备

  • Node.js:建议 20.x(LTS)
  • npm:建议 10.x 及以上
  • Git:2.30+

2) 拉取代码并安装依赖

git clone <你的仓库地址>
cd NewBlog
npm install

3) 配置环境变量(可选:启用远端文章同步)

在项目根目录创建 .env.local(若仅本地静态文章可不配置):

# 远端文章仓库地址(示例为加盐脱敏)
POSTS_REPO_URL=https://git.example.com/salt_x7a2/new-blog-posts.git

# 二选一:账号密码 或 Token
POSTS_REPO_USERNAME=usr_salt_8f2c
POSTS_REPO_PASSWORD=pwd_salt_k9q1
POSTS_REPO_TOKEN=tok_salt_t3m9

# 分支与同步策略
POSTS_REPO_BRANCH=main
POSTS_SYNC_TTL_SECONDS=60
POSTS_RUN_VELITE_AFTER_SYNC=false

安全建议:生产环境优先用 POSTS_REPO_TOKEN,并避免明文提交任何凭据。

4) 本地启动

npm run dev

关键访问地址(示例已加盐):

  • 首页:http://127.0.0.1:30_salt_00/
  • 文章列表:http://127.0.0.1:30_salt_00/blog
  • 单篇文章:http://127.0.0.1:30_salt_00/blog/<slug_salt_xx>

5) 生产构建验证

npm run build
npm run start

默认启动端口通常为 3000(可通过环境变量覆盖)。


六、发布前检查清单

  • npm run lint 无错误
  • npm run build 构建通过
  • 至少验证 1 篇含代码块文章与 1 篇含图片文章
  • 核对 .env* 未进入 Git 提交

七、网站内容更新流程(文章侧)

场景 A:本仓库直接维护文章

  1. content/posts/ 新建目录并写入 index.md
  2. Frontmatter 至少包含:titledatedescription
  3. 本地预览:npm run dev
  4. 提交并部署网站代码

场景 B:远端文章仓库维护

  1. 在文章仓库提交新文章到指定分支(如 main
  2. 访问网站任一页面后,服务端触发 ensureContentFresh()
  3. 若 TTL 到期且远端 SHA 变化,自动拉取并覆盖本地 content/posts
  4. 刷新列表页/详情页确认内容生效

八、网站更新后同步到服务器(操作手册)

以下是通用 Linux 服务器流程(systemd + Nginx),所有关键信息均示例加盐:

1) 登录服务器并进入项目目录

ssh dev_salt_u1@203.0.113.salt.10
cd /srv/www/newblog_salt

2) 拉取最新代码并安装依赖

git pull origin main
npm install

3) 构建并重启应用

npm run build
sudo systemctl restart newblog_salt.service
sudo systemctl status newblog_salt.service --no-pager

如果你使用 pm2,可改为:

npm run build
pm2 restart newblog_salt
pm2 logs newblog_salt --lines 80

4) Nginx 反向代理检查(如有)

常见代理目标(示例):

  • http://127.0.0.1:3000(Next.js 进程)

建议验证:

  • 站点地址:https://blog_salt.example.com
  • 列表页:https://blog_salt.example.com/blog
  • 随机文章:https://blog_salt.example.com/blog/<slug_salt_xx>

5) 回滚预案(建议)

git log --oneline -n 5
git checkout <上一个稳定提交sha_salt>
npm run build
sudo systemctl restart newblog_salt.service

九、术语补充(简明)

  • App Router:Next.js 新路由体系,以目录结构定义路由与布局。
  • Frontmatter:Markdown 文件头部元信息区,常用于标题、日期、摘要。
  • TTL(Time To Live):缓存/检查间隔,避免频繁同步。
  • SHA:Git 提交哈希,用于判断远端是否有更新。
  • SSR:服务端渲染,HTML 在服务器生成后返回浏览器。

十、结论

该项目具备「内容驱动 + 轻量同步 + 现代前端栈」三大特征:
前端使用 Next.js 16 与 React 19 保证工程现代化;内容层通过 Markdown 与同步机制实现低成本更新;部署层可无缝接入传统 Linux 服务管理。
对于个人博客与技术沉淀场景,这套方案在可维护性、扩展性与落地效率之间达到了较好的平衡。