title: 静态化部署
description: 将 mdView 动态文档站编译为纯静态 HTML 文件,实现零 PHP 依赖的极速访问体验
keywords: 静态化,部署,编译,CDN,Nginx,GitHub Pages
概述
mdView 内置静态化构建器,可将所有文档预编译为纯静态 HTML 文件。编译后的站点无需 PHP 环境,可直接部署到 Nginx、CDN 甚至 GitHub Pages。
核心思路:只静态化"公开阅读页面",管理后台、登录、分享等动态功能保持不变。
与动态站对比
一键构建
# 默认输出到 static/ 目录
php build-static.php
# 指定输出目录和自定义域名
php build-static.php /var/www/site https://docs.example.com
构建日志示例:
╔══════════════════════════════════════╗
║ mdView 静态网站构建器 ║
╚══════════════════════════════════════╝
输出目录: static/
Base URL: http://localhost
搜索索引: 20 条
═══════════════════════════════════════
构建完成!
文档页: 20 个
═══════════════════════════════════════
输出目录结构
static/
├── index.html ← 首页(自动跳转到 intro)
├── intro/index.html ← 每个文档一个独立目录
├── quickstart/index.html
├── 开发/
│ ├── 01-系统/index.html
│ ├── 01.开发相关/
│ │ ├── 01.开发环境/index.html
│ │ └── 02.前端编译/index.html
│ └── ...
├── 系统指南/
│ ├── api/index.html
│ ├── env/index.html
│ └── ...
├── search.json ← 客户端搜索索引
├── sitemap.xml ← 搜索引擎站点地图
├── robots.txt
├── assets/ ← 静态资源
└── docs/ ← 图片等文档附件
部署方式
方案 A:Nginx
server {
listen 80;
server_name docs.example.com;
root /var/www/mdView/static;
index index.html;
# /intro → /intro/index.html
location / {
try_files $uri $uri/index.html =404;
}
# 静态资源缓存
location /assets/ {
expires 30d;
}
}
方案 B:Apache
<VirtualHost *:80>
ServerName docs.example.com
DocumentRoot /var/www/mdView/static
<Directory /var/www/mdView/static>
Options -Indexes +FollowSymLinks
AllowOverride All
</Directory>
</VirtualHost>
同时确保 static/.htaccess:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^(.*)$ $1.html [L]
方案 C:GitHub Pages / Vercel
直接将 static/ 目录推送到仓库,设置 Pages 源为根目录即可。
方案 D:动态站 + 静态站共存
将 Nginx 配置为:
/admin、/login、/s/ 等路由代理到 PHP 动态站方案 E:动态站内置静态回退(推荐)
适用场景:只需部署一套 PHP 服务,文档页面自动享受静态文件的速度,无需额外 Web 服务器配置。
核心思路:index.php 在处理文档请求时,先检查 static/ 目录下是否有对应的预编译 HTML 文件;存在则直接输出(零数据库开销),不存在则回退到动态渲染。
浏览器请求 /intro
│
▼
index.php(路由分发)
│
├─ /admin /search /login ... → 直接进入对应模块(不检查静态文件)
│
└─ 其他(文档路径)
│
▼
tryServeStatic()
│
static/intro/index.html 存在?
│ │
YES NO
│ │
▼ ▼
readfile() require vitep.php
直接输出 动态渲染(PHP + 数据库)
X-Served-By: static
PHP 层实现(index.php 中 tryServeStatic() 函数):
function tryServeStatic(string $path): bool
{
// 首页 / → static/index.html
if ($path === '') {
$staticFile = __DIR__ . '/static/index.html';
if (file_exists($staticFile)) {
header('Content-Type: text/html; charset=utf-8');
header('X-Served-By: static');
readfile($staticFile);
return true;
}
return false;
}
// 文档路径 → static/{path}/index.html
$staticFile = __DIR__ . '/static/' . $path . '/index.html';
if (file_exists($staticFile)) {
header('Content-Type: text/html; charset=utf-8');
header('X-Served-By: static');
readfile($staticFile);
return true;
}
return false;
}
注意:admin、search、login、logout、upgrade、s/、vitep等动态路由位于index.php中else分支之前,在到达tryServeStatic()前已被提前拦截,无需额外排除逻辑。
Web 服务器层优化(可选,性能更优):
在 .htaccess 或 Nginx 中增加静态文件检查规则,将命中率最高的请求在 Web 服务器层面直接返回,连 PHP 进程都不需要启动。与方案 E 的 PHP 层回退可以叠加使用(Web 服务器先拦,未命中再由 PHP 兜底)。
# Apache .htaccess — 插在原有 RewriteRule 之前
RewriteCond %{REQUEST_URI} !^/admin
RewriteCond %{REQUEST_URI} !^/search
# ... 其余动态路由排除
RewriteCond %{DOCUMENT_ROOT}/static/%{REQUEST_URI}/index.html -f
RewriteRule ^(.*)$ /static/$1/index.html [L,END]
# Nginx — 插入 location / 块
location / {
if ($uri ~ ^/(admin|search|api|vitep|s/|login|logout|upgrade)) {
rewrite ^ /index.php last;
}
try_files /static/$uri/index.html /index.php?$args;
}
路由分类速查
诊断标记
静态文件返回时会携带响应头 X-Served-By: static,可在浏览器开发者工具 Network 面板中查看,便于确认当前命中的是静态还是动态渲染。
静态页面包含的功能
每个生成的 HTML 页面完整包含:
不包含的功能
以下动态功能在静态站中不可用,请通过动态站访问:
/s/{token})定时重建
文档更新后需手动重建。可通过 cron / 计划任务自动执行:
# Linux cron(每小时)
0 * * * * cd /path/to/mdView && php build-static.php static https://docs.example.com
# Windows 计划任务
schtasks /create /tn "mdView-Static" /tr "php E:\mdView\build-static.php" /sc hourly
技术架构
构建流程
┌──────────────┐ ┌─────────────────────────────────┐
│ CLI 入口 │────▶│ StaticBuilder │
│ build-static │ │ │
└──────────────┘ │ ① 读取数据库文档树 │
│ ② 遍历每篇 .md 文件 │
│ ③ MarkdownParser 解析为 HTML │
│ ④ 内联 CSS(assets/vitep.css) │
│ ⑤ 内联 JS(vitep.php + vitep.js │
│ + 客户端搜索模块) │
│ ⑥ 组装完整 HTML 页面 │
│ ⑦ 写入 static/ 目录 │
│ ⑧ 生成 search.json 搜索索引 │
│ ⑨ 复制 assets/ 资源文件 │
└──────────────┬────────────────────┘
│
▼
static/
├── index.html
├── intro/index.html
├── search.json
├── assets/
└── ...
请求服务流程(混合部署模式)
用户浏览器
│
GET /intro HTTP
│
▼
┌─────────────┐
│ Web 服务器 │(可选层:.htaccess / Nginx)
│ 静态检查 │
└──────┬──────┘
│
static/intro/index.html 存在?
│ │
YES NO
│ │
▼ ▼
┌──────────┐ ┌──────────┐
│ 直接返回 │ │index.php │
│ 静态文件 │ │ 动态渲染 │
│ < 1ms │ └────┬─────┘
└──────────┘ │
tryServeStatic()
│
static/intro/index.html 存在?
│ │
YES NO
│ │
▼ ▼
┌──────────┐ ┌──────────────┐
│readfile()│ │vitep.php │
│直接输出 │ │数据库 + 渲染 │
│10~30ms │ │50~200ms │
└──────────┘ └──────────────┘