从 Jekyll 迁移到 Hugo:一个循序渐进的指南
引言
对于许多曾经使用 Jekyll 作为静态网站生成器的开发者来说,迁移到 Hugo 可能是出于对性能提升、更简化的配置或更强大的功能集的需求。Jekyll 是一款成熟且广泛使用的 SSG,但随着技术的发展,Hugo 凭借其极快的构建速度和现代化的特性,吸引了越来越多的用户。本文旨在提供一个详细的指南,帮助您逐步完成从 Jekyll 到 Hugo 的迁移过程,最大程度地减少数据丢失和工作量的同时,充分享受 Hugo 带来的优势。
1. 理解迁移的挑战
迁移过程的主要挑战在于:
- 模板引擎差异: Jekyll 使用 Liquid 模板语言,而 Hugo 使用 Go 的
text/template和html/template。 - Front Matter 格式: 虽然两者都支持 YAML, JSON, TOML,但具体的使用方式和内置变量可能不同。
- 文件结构: Hugo 和 Jekyll 的项目结构有所区别。
- 插件与扩展: Jekyll 的插件生态与 Hugo 的函数和短代码系统需要进行适配。
2. 准备工作:备份与分析
在开始任何迁移之前,请务必:
- 完整备份您的 Jekyll 网站: 包括所有内容文件(Markdown)、图片、CSS/JS 文件以及配置文件。
- 分析您的 Jekyll 网站:
- 内容数量: 估算您的文章、页面数量。
- 主题复杂度: 您的 Jekyll 主题有多复杂?是否大量使用了 Liquid 过滤器或自定义标签?
- 插件依赖: 您使用了哪些 Jekyll 插件?它们在 Hugo 中是否有直接的替代品?
- 文件结构: 您的文件是如何组织的?例如,文章是否在
_posts目录下?页面在根目录还是_pages目录下?
3. 初始化 Hugo 项目
首先,您需要安装 Hugo。然后,在您想要存放新网站的目录下,运行以下命令创建一个新的 Hugo 项目:
hugo new site my-new-hugo-site
cd my-new-hugo-site
这将创建一个基本的 Hugo 项目结构。
4. 迁移内容文件
这是迁移的核心步骤。
4.1. 迁移文章 (Posts)
Jekyll 的文章通常存储在 _posts 目录下,文件名格式为 YYYY-MM-DD-post-title.md。Hugo 的文章默认存放在 content/post/ 目录下,文件名可以是 post-title.md,日期信息放在 Front Matter 中。
您可以编写一个脚本来批量转换:
- 读取 Jekyll 的
_posts目录下的所有.md文件。 - 解析每个文件的 Front Matter (YAML)。
- 提取
date,将其格式化为YYYY-MM-DD。 - 提取
title。 - 保留其他 Front Matter 字段,但注意 Hugo 的内置变量(例如
layout在 Hugo 中有不同含义)。
- 提取
- 提取文件主体内容(Markdown 部分)。
- 创建 Hugo 的 Front Matter:
title = "您的文章标题"date = 2023-10-27T10:00:00+08:00(Hugo 推荐 ISO 8601 格式)draft = false(如果文章不是草稿)tags = ["tag1", "tag2"](如果 Jekyll 中有 tags)categories = ["category1"](如果 Jekyll 中有 categories)
- 将转换后的内容保存到
content/post/目录下,文件名为您的文章标题.md(Hugo 会自动处理 slug)。
示例脚本思路(Python):
import os
import glob
import frontmatter
import datetime
jekyll_posts_dir = '../jekyll-site/_posts' # 假设 Jekyll 网站在上一级目录
hugo_posts_dir = './content/post'
if not os.path.exists(hugo_posts_dir):
os.makedirs(hugo_posts_dir)
for jekyll_file in glob.glob(os.path.join(jekyll_posts_dir, '*.md')):
post = frontmatter.load(jekyll_file)
# 提取日期和标题
date_str = os.path.basename(jekyll_file)[:10]
try:
post_date = datetime.datetime.strptime(date_str, '%Y-%m-%d').isoformat() + "Z" # ISO 8601 for Hugo
except ValueError:
print(f"Skipping file with invalid date format: {jekyll_file}")
continue
# 确保 title 存在
if not post.metadata.get('title'):
print(f"Skipping file with no title: {jekyll_file}")
continue
post_title = post.metadata['title']
# 创建 Hugo Front Matter
hugo_meta = {
'title': post_title,
'date': post_date,
'draft': False, # 默认非草稿
}
# 复制 Jekyll 的其他 Front Matter 字段
for key, value in post.metadata.items():
if key not in ['date', 'title', 'layout', 'permalink']: # 避免覆盖或复制不必要的字段
hugo_meta[key] = value
# 创建 Hugo 内容文件
hugo_content = frontmatter.dumps(post.content, hugo_meta)
hugo_filename = f"{post_title.replace(' ', '-')}.md" # Hugo 会自动处理 slug
hugo_filepath = os.path.join(hugo_posts_dir, hugo_filename)
with open(hugo_filepath, 'w', encoding='utf-8') as f:
f.write(hugo_content)
print(f"Migrated: {jekyll_file} -> {hugo_filepath}")
4.2. 迁移页面 (Pages)
Jekyll 的页面可能在根目录或 _pages 目录下。Hugo 将页面存放在 content/ 目录下的不同子目录中,以区分内容类型(例如 content/about.md, content/contact.md)。
- 将 Jekyll 的页面文件(除了
index.md和about.md等特殊页面)复制到 Hugo 的content/目录下,并确保 Front Matter 包含title和date。
4.3. 迁移图片、CSS 和 JS
- 将 Jekyll 的
images/(或类似目录) 中的图片复制到 Hugo 的static/images/目录下。 - 将 Jekyll 的
css/和js/目录中的文件复制到 Hugo 的static/css/和static/js/目录下。
5. 重建主题
这是迁移中最具挑战性的部分,因为模板语言不同。
- 创建 Hugo 主题骨架: 在
themes/目录下创建一个新主题文件夹(例如mytheme),并创建必要的目录结构 (layouts/,static/,assets/,i18n/等)。 - 逐步转换 Liquid 模板到 Go 模板:
- 基本布局: 将 Jekyll 的