blog


博客系统

基于 Node.js + Express + Nunjucks + MySQL + TailwindCSS 的博客系统,支持前台浏览与后台管理,以及模块化CMS功能。

环境要求

  • Node.js >= 18 LTS
  • MySQL 5.7+ / 8.x
  • npm

安装与运行

1. 安装依赖

cd src
npm install

2. 配置环境变量

cp .env.example .env
# 编辑 .env,填写数据库连接信息、JWT 密钥等

主要环境变量说明:

变量 说明 默认值
PORT 服务端口 3300
DB_HOST MySQL 主机地址 117.72.220.18
DB_PORT MySQL 端口 3306
DB_USER 数据库用户名 -
DB_PASSWORD 数据库密码 -
DB_NAME 数据库名 blog
JWT_SECRET JWT 签名密钥(>=32位) -
BUILD_MODE 构建模式:ssrstatic ssr
SITE_NAME 站点名称 我的博客

3. 初始化数据库

npm run init-db

这会创建数据库表结构并插入默认管理员账号:admin / admin123

如需启用模块CMS功能,执行迁移脚本:

mysql -h <host> -u <user> -p <database> < src/scripts/migrations/v2.0.0_module_cms.sql

4. 构建样式

npm run build:css

5. 启动服务

# 开发模式(热重载)
npm run dev

# 生产模式
npm start

一键启动

chmod +x run.sh
./run.sh

目录说明

src/
├── app.js                 # Express 应用入口
├── config/                # 配置文件
│   ├── index.js           # 统一配置(读取 .env)
│   ├── db.js              # MySQL 连接池
│   └── swagger.js         # Swagger API 文档配置
├── middleware/
│   └── auth.js            # JWT 鉴权中间件
├── routes/
│   ├── api/
│   │   ├── auth.js        # POST /api/login
│   │   ├── articles.js    # /api/articles CRUD
│   │   └── categories.js  # /api/categories CRUD
│   └── pages.js           # 前后台页面路由
├── views/                 # Nunjucks 模板
│   ├── layouts/           # 布局模板(前台 base / 后台 admin)
│   ├── index.njk          # 首页/文章列表
│   ├── article.njk        # 文章详情
│   ├── category.njk       # 分类文章列表
│   ├── admin/             # 后台管理页面
│   └── ...
├── public/                # 静态资源
│   ├── css/               # TailwindCSS 样式
│   └── js/                # 前端脚本
├── scripts/
│   ├── init.sql           # 建表 SQL
│   ├── init-db.js         # 数据库初始化脚本
│   └── build.js           # 静态站点构建脚本
└── .env.example           # 环境变量模板

访问地址

地址 说明
http://localhost:3300 前台首页
http://localhost:3300/admin/login 后台登录
http://localhost:3300/api-docs Swagger API 文档

构建静态站点

npm run build

构建产物输出到 src/dist/ 目录,可部署到任意静态服务器(nginx 等)。

前台渲染架构(双轨机制)

系统存在两条并行的前台渲染链路,通过 views/layouts/base.njk 中的 hasPageModules 标志自动切换:

请求进入 → systemModules 中间件查 pages 表匹配 path
         → 有匹配 + 有模块配置 → 链路B:模块组合渲染
         → 无匹配 / 无模块配置 → 链路A:硬编码路由 + views/*.njk

链路A — 传统模板渲染(旧系统)

  • 入口:routes/pages.js 硬编码路由(//articles/:id/categories/:id/about
  • 每个路由手动查数据库,调用 res.render('xxx.njk') 渲染对应 views/*.njk 模板
  • 模板继承 views/layouts/base.njk,通过 {% block content %} 填充页面内容
  • 适用于:未配置模块的页面、后台管理页面

链路B — 模块组合渲染(CMS 系统)

  • 入口:middleware/systemModules.js,在所有页面路由之前执行
  • pages.path 匹配当前 URL(支持精确匹配和动态路由如 /article/:id
  • 查询 page_module_configs 获取该页面绑定的模块(按激活的站点分类过滤)
  • 用 Nunjucks 逐个渲染模块模板,拼接为 allModulesHtml 注入到 base.njk
  • hasPageModules = true 时,base.njk 直接输出模块拼接结果,跳过 {% block content %}

交汇点 — views/layouts/base.njk

{% if hasPageModules %}
  {{ allModulesHtml | safe }}       {# 链路B:整页由模块拼出 #}
{% else %}
  <header>...</header>
  <main>{% block content %}{% endblock %}</main>  {# 链路A:传统模板 #}
  <footer>...</footer>
{% endif %}

关键结论

  • 后台"新建页面"创建的是 pages 表记录(链路B),不会生成 .njk 文件
  • 页面配了模块就走 CMS 渲染,没配就自然回退到传统模板
  • views/*.njk 文件只在链路A中使用,链路B完全由数据库驱动

模块化CMS系统

系统支持灵活的页面模块管理功能,详细文档请查看:MODULE_CMS.md

四层架构:

module_types (模块类型: header/nav/section/footer)
  └── module_templates (模板: 每种类型可有多个模板变体)
       └── module_instances (实例: 绑定模板 + 具体配置数据)
            └── page_module_configs (页面配置: 实例挂载到页面 + 排序 + 站点分类)

站点分类与多配置方案(v2.4.0):

  • 页面路径全局唯一,但同一页面可按站点分类拥有多套模块配置
  • site_category_idpage_module_configs 上,不在 pages
  • 前台渲染时按当前激活的站点分类过滤模块配置
  • 后台可切换分类查看/编辑不同配置方案

核心功能:

  • 模块类型管理(页头、导航、内容区、页脚)
  • 模块模板管理(HTML + CSS + JSON Schema)
  • 模块实例管理(动态配置 + 自定义样式)
  • 保存实例为新模板
  • Nunjucks渲染引擎 + 缓存优化

技术栈:

  • 后端: ajv + ajv-formats(JSON Schema验证)
  • 前端: React 19 + @rjsf/core(动态表单)+ Monaco Editor
  • 缓存: node-cache(5秒TTL)

验收标准对应

模块 验收编号 入口
登录鉴权 AC-001 ~ AC-003 routes/api/auth.js + middleware/auth.js
文章管理 AC-010 ~ AC-016 routes/api/articles.js
回收站 AC-020 ~ AC-022 routes/api/articles.js(DELETE/restore)
分类管理 AC-030 ~ AC-034 routes/api/categories.js
配置管理 AC-040 ~ AC-042 config/index.js + .env
静态构建 AC-043 ~ AC-044 scripts/build.js
API 文档 AC-050 ~ AC-051 config/swagger.js + Swagger JSDoc
模块CMS v2.0.0 routes/api/module-*.js + lib/module-renderer.js

数据库迁移可用命令

npm run migrate:status # 查看迁移状态 npm run migrate:up # 应用所有待执行迁移 npm run migrate:down # 回退最后一个迁移 npm run migrate:reset # 回退所有迁移