个人网站 / 作品集 / 博客一体化站点,基于 Next.js 16 App Router + React 19 + TypeScript + Tailwind CSS 4。
内容以本地 Markdown 管理,评论存本地 SQLite,除可选的统计与音乐/天气接口外不依赖任何外部服务。
- 双语渲染:中英文文案同时进入 DOM,由
html[data-locale]用纯 CSS 切换,无需二次请求或客户端 hydration 抖动 - 博客体系:自动扫描
content/posts生成列表;支持摘要、封面、标签、置顶、草稿、更新时间 - 文章归档:关键词搜索 + 标签筛选 + 分页(
components/blog-archive.tsx) - 标签索引:
/tags总览与/tags/[tag]单标签页,均参与静态生成与 sitemap - 文章详情:目录导航与阅读进度、代码高亮(Shiki)、上一篇/下一篇、相关文章推荐、分享操作
- 项目作品集:
/projects聚合展示,精选卡片锚点跳转到下方详情
- 在线编辑器:
/admin/editor直接在浏览器里新建、编辑、删除文章,中英文各自独立保存,写回content/posts的 Markdown 源文件 - 评论系统:
node:sqlite本地存储,支持三层嵌套回复、审核开关、按 IP 限流与重复内容拦截 - 评论后台:
/admin/comments审核、驳回、删除;与编辑器共用一套会话鉴权
- 双语 RSS:
/rss.xml(中文)与/rss-en.xml(英文),共用lib/feed.ts一套构建逻辑 - 元数据路由:
sitemap.xml、robots.txt、manifest.webmanifest,以及首页/项目页/每篇文章的动态 OG 图与 Twitter 卡片 - 安全响应头:
next.config.ts统一下发X-Content-Type-Options、X-Frame-Options、Referrer-Policy、Permissions-Policy、HSTS,并对/admin/*禁用缓存与索引
- 明暗主题、三档字号、语言切换,偏好写入
localStorage并由beforeInteractive脚本在首帧前应用 - 悬浮侧栏:最新文章、访客天气、随机音乐播放器
- 可选 Plausible 统计(配置了域名才注入脚本)
npm install
npm run dev访问 http://localhost:3000。
其它命令:
npm run build # 生产构建
npm run start # 运行构建产物
npm run lint # ESLint(Next 16 已移除 next lint,直接调用 eslint)评论系统使用
node:sqlite,需要 Node.js 22.5+。
编辑 lib/site.ts:站点名、作者、各页面中英文文案与导航项都在这里,改一处全站生效。
编辑 lib/projects.ts,替换示例项目的技术选型、亮点、成果与关联文章。
在 content/posts 下新建 .md:
---
title: "文章标题"
summary: "一句话摘要"
date: "2026-04-06"
updated: "2026-05-01" # 可选
tags:
- Next.js
- 前端工程化
cover: "/covers/example.jpg" # 可选
featured: false # 是否进入首页精选
draft: false # true 则不会发布
---
正文从这里开始。英文版本放在 content/posts/en/,slug 与中文版保持一致即可自动关联。
也可以直接用 /admin/editor 在线写,效果与手动建文件完全一样。
复制 .env.example 为 .env.local:
| 变量 | 说明 |
|---|---|
NEXT_PUBLIC_SITE_URL |
正式域名,用于 canonical、RSS、sitemap 与分享图的绝对地址 |
COMMENT_ADMIN_PASSWORD |
后台密码,同时守护 /admin/comments 与 /admin/editor;未设置时后台整体不可用 |
COMMENT_REQUIRE_MODERATION |
1 先审后发,0 直接发布 |
TRUSTED_PROXY_HOPS |
前置反向代理层数。x-forwarded-for 可被伪造,直连部署时保持 0;单层 Nginx/Vercel 填 1,Cloudflare→Nginx 填 2。填错会让评论限流失效 |
NEXT_PUBLIC_PLAUSIBLE_DOMAIN |
可选,填写后才注入统计脚本 |
NEXT_PUBLIC_PLAUSIBLE_API_HOST |
可选,自建 Plausible 时指向自己的实例 |
app/
about/ # 关于页
admin/
actions.ts # 登录 / 登出 Server Action
comments/ # 评论审核后台
editor/ # 在线文章编辑器(列表 / [slug] 编辑页 / actions)
api/
comments/ # 评论读写接口
music/ # 随机音乐代理
visitor-context/ # 访客位置与天气
blog/ # 博客列表与 [slug] 详情(含 opengraph-image)
projects/ # 项目作品集
tags/ # 标签索引与 [tag] 单标签页
rss.xml/ rss-en.xml/ # 中英文订阅源
manifest.ts sitemap.ts robots.ts # 元数据路由
opengraph-image.tsx twitter-image.tsx
error.tsx global-error.tsx loading.tsx not-found.tsx
components/ # UI 组件
blog-archive.tsx # 搜索 / 标签筛选 / 分页
post-editor-form.tsx # 编辑器表单
local-comments.tsx # 评论展示与嵌套回复
localized-content.tsx # 双语渲染原语
global-left-rail.tsx # 天气与访客信息侧栏
music-player-*.tsx # 音乐播放器
content/posts/ # Markdown 文章(en/ 存英文版)
lib/
posts.ts # 文章读取、解析、缓存、标签
post-editor.ts # 编辑器的读写与校验
feed.ts # RSS 构建
comments.ts # 评论存储与限流
admin-session.ts # 后台会话
request-ip.ts # 客户端 IP 解析
visitor-weather.ts # 位置与天气(带缓存)
music.ts og.tsx highlight.ts projects.ts site.ts
types/node-sqlite.d.ts # node:sqlite 类型声明
data/comments.db # 运行时生成,已在 .gitignore 中
data/comments.db是唯一的运行时状态,部署前确认它落在持久化卷上并纳入备份COMMENT_ADMIN_PASSWORD请使用足够长的随机值;未设置时后台会直接显示"未配置"而非放行- 站点在代理之后时务必设置
TRUSTED_PROXY_HOPS,否则所有访客会共用同一个限流桶
- 为项目补充独立详情页,替代当前的聚合展示
- 接入邮件订阅(站内文案已预留位置)
- 评论通知与全文搜索索引