摘要:记录了一个 17 年老博客从 Netlify 迁移至 Cloudflare Pages 的全过程。涵盖了构建环境配置、Profile Mode 深度定制、以及基于 Python 脚本的 URL 架构重构(中文转 Slug + 301 重定向闭环)。
1. 基础设施:Cloudflare Pages 构建环境
为了解决 Hugo PaperMod 主题 CSS 不生效的问题,必须锁定 Hugo 的 Extended 版本。
Cloudflare 后台设置:
- 位置:Settings -> Environment variables
- 变量名:
HUGO_VERSION - 值:
0.147.0(推荐使用较新的稳定版,务必与本地一致)
2. 视觉系统:文人风骨与极客之魂
针对 PaperMod Profile Mode(极简个人主页模式),我们定制了一套**“宋体标题 + 黑体正文 + 极客蓝交互”**的 CSS 方案。
文件路径:assets/css/extended/custom.css
最终代码:
/* ========================================================
ChowRay.org - 全站样式终极定制版
======================================================== */
/* 1. 全局变量定义 */
:root {
/* 字体栈:标题优先宋体(人文感),正文优先系统黑体(易读性) */
--font-serif: "Noto Serif SC", "Source Han Serif SC", "Songti SC", "SimSun", "Times New Roman", serif;
--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif;
--font-mono: "JetBrains Mono", "Fira Code", Consolas, monospace;
/* 品牌色:极客蓝 (Geek Blue) */
--geek-blue: #3b82f6;
--geek-blue-rgb: 59, 130, 246;
}
/* 2. 字体与排版 */
h1, h2, h3, h4, h5, h6, .entry-header h2, .post-title {
font-family: var(--font-serif) !important;
font-weight: 700 !important;
letter-spacing: 0.5px !important;
}
/* 文章详情页大标题 (控制大小,建立层级) */
.post-title {
font-size: 2.5rem !important; /* 约40px,确立视觉中心 */
line-height: 1.3 !important;
margin-bottom: 20px !important;
}
/* 文章正文 */
.post-content {
font-family: var(--font-sans) !important;
font-size: 17px !important;
line-height: 1.8 !important;
text-align: justify;
color: #333 !important;
}
[data-theme="dark"] .post-content { color: #c4c4c5 !important; }
/* 3. 内容层级修正 (Visual Hierarchy) */
/* 防止正文内的 H1 喧宾夺主 */
.post-content h1 { font-size: 1.8rem !important; color: #111 !important; margin-top: 3rem !important; }
.post-content h2 { font-size: 1.5rem !important; color: #222 !important; margin-top: 2.5rem !important; }
.post-content h3 { font-size: 1.25rem !important; font-weight: 700 !important; }
/* 4. 引用块 (Blockquote) */
.post-content blockquote {
font-family: var(--font-serif) !important;
font-style: italic;
border-left: 3px solid var(--geek-blue) !important; /* 3px 极客蓝边框 */
background: #f9fafb;
padding: 10px 20px !important;
color: #555 !important;
}
[data-theme="dark"] .post-content blockquote {
background: #2e2e33 !important;
border-left-color: #444 !important;
color: #b0b0b0 !important;
}
/* 5. 交互特效 (The Soul) */
/* 头像呼吸 + 歪头杀 */
@keyframes breathing {
0% { transform: scale(1); box-shadow: 0 0 0 rgba(var(--geek-blue-rgb), 0); }
50% { transform: scale(1.02); box-shadow: 0 0 20px rgba(var(--geek-blue-rgb), 0.4); }
100% { transform: scale(1); box-shadow: 0 0 0 rgba(var(--geek-blue-rgb), 0); }
}
.profile img {
animation: breathing 4s ease-in-out infinite;
transition: all 0.5s cubic-bezier(0.25, 0.8, 0.25, 1);
backface-visibility: hidden;
}
.profile img:hover {
animation: none; /* 悬停时停止呼吸,触发歪头 */
transform: scale(1.08) rotate(5deg);
box-shadow: 0 0 25px rgba(var(--geek-blue-rgb), 0.6);
cursor: pointer;
}
/* 按钮与菜单的物理反馈 */
.button, .social-icons a, #menu a {
transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
border-radius: 8px;
}
.button:hover, .social-icons a:hover, #menu a:hover {
transform: translateY(-3px); /* 悬停上浮 */
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.15);
}
#menu a { background: transparent; padding: 4px 12px; } /* 菜单平时透明 */
#menu a:hover { background: var(--entry); color: var(--geek-blue) !important; }
3. URL 架构重构:告别中文乱码
为了解决旧文章 URL 包含中文、日期前缀冗余的问题,同时保证 SEO 链接不变成 404,我们开发了 refactor_v6_final.py 脚本。
核心逻辑:
- 清洗 Slug:自动提取文件夹名,去掉
2011-05-11-日期前缀,保留纯净名称。 - 智能 Aliases:自动计算出当前的中文旧链接,写入
aliases字段,实现 301 无缝跳转。 - 双重保护:如果文章已有 Slug,则基于旧 Slug 生成 Alias,确保万无一失。
Python 脚本 (refactor_v6_final.py):
import os
import frontmatter
import re
TARGET_DIR = os.path.join('content', 'posts')
def sanitize_for_url(text):
# 模拟 Hugo URL 清洗规则:转小写,去标点
text = str(text).lower()
text = re.sub(r'[^\w\u4e00-\u9fa5\-]', '', text)
return text
def main():
print(f"🚀 开始全站 URL 重构 (Folder Slug + Auto Aliases)...")
for root, dirs, files in os.walk(TARGET_DIR):
for file in files:
if file.endswith('.md'):
file_path = os.path.join(root, file)
# 1. 准备基础路径信息
folder_name = os.path.basename(root)
if file != 'index.md': folder_name = os.path.splitext(file)[0]
# 计算旧链接路径 (用于生成 Alias)
rel_path = os.path.relpath(root, 'content')
if file != 'index.md': rel_path = os.path.dirname(rel_path)
else: rel_path = os.path.dirname(rel_path)
# 路径清洗 (确保 Alias 与浏览器访问的真实链接一致)
path_parts = rel_path.split(os.sep)
cleaned_parts = [sanitize_for_url(p) for p in path_parts]
base_url_prefix = '/'.join(cleaned_parts)
try:
post = frontmatter.load(file_path)
is_modified = False
aliases_to_add = []
# --- A. 文件夹名兜底 Alias ---
cleaned_folder = sanitize_for_url(folder_name)
folder_alias = f"/{base_url_prefix}/{cleaned_folder}/"
aliases_to_add.append(folder_alias)
# --- B. 旧 Slug 优先 Alias ---
current_slug = post.metadata.get('slug')
if current_slug:
slug_alias = f"/{base_url_prefix}/{current_slug}/"
aliases_to_add.append(slug_alias)
else:
# --- C. 无 Slug 时,使用文件夹名去日期生成新 Slug ---
# 去掉 YYYY-MM-DD- 前缀
new_slug = re.sub(r'^\d{4}-?\d{2}-?\d{2}-?', '', folder_name)
post.metadata['slug'] = new_slug
is_modified = True
print(f"📝 生成 Slug: {new_slug}")
# --- D. 写入 Aliases ---
if 'aliases' not in post.metadata: post.metadata['aliases'] = []
for alias in aliases_to_add:
if alias not in post.metadata['aliases']:
post.metadata['aliases'].append(alias)
is_modified = True
if is_modified:
with open(file_path, 'wb') as f: frontmatter.dump(post, f)
print(f"✅ 处理: {folder_name}")
except Exception as e:
print(f"❌ 错误: {file_path} - {e}")
if __name__ == "__main__":
main()
配合配置文件 (config.yml):
permalinks:
# 统一为:/年/月/文章名/ (干净,无中文,层级清晰)
posts: "/:year/:month/:slug/"
4. 自动化工作流:极速预览与发布
告别复杂的命令敲击,将日常操作封装为脚本。
预览脚本 (server.sh - 内存模式防闪退):
#!/bin/bash
# 捕捉 Ctrl+C 防止窗口秒关
trap 'echo -e "\n🛑 已停止"; exit' SIGINT
echo -e "🚀 启动极速预览 (内存模式)..."
# 内存渲染,不伤硬盘,无垃圾文件
hugo server -D --renderToMemory
# 保持 Git Bash 窗口打开
echo -e "\n⚡ 窗口保持打开..."
[[ "$OSTYPE" == "msys" ]] && exec bash --login -i
发布脚本 (deploy.sh - 智能推送):
#!/bin/bash
echo -e "🚀 准备推送到 GitHub..."
git add -A
# 支持交互式输入 Commit 信息,回车默认使用时间戳
if [ $# -eq 0 ]; then
echo -e "📝 请输入提交信息 (直接回车用默认时间): "
read input_msg
if [ -z "$input_msg" ]; then
msg="rebuilding site $(date +'%Y-%m-%d %H:%M:%S')"
else
msg="$input_msg"
fi
else
msg="$1"
fi
git commit -m "$msg"
echo -e "📤 推送中..."
git push origin master
echo -e "✅ 完成!"
read -p "按任意键关闭..." -n1 -s
结语: 至此,完成了从“古典博客”到“现代工程化博客”的华丽转身。数据主权在手,排版赏心悦目,架构坚不可摧。
Happy Blogging!