前言
Hexo和Hugo都是优秀的静态网站生成器,但由于性能考虑或个人喜好,你可能想从Hexo迁移到Hugo。本文将详细记录完整迁移过程,包括配置、文章转换、多语言支持等方面。
准备工作
在开始迁移前,你需要先安装Hugo并了解基本的站点创建流程。以下是官方文档链接,建议按照官方文档进行操作:
1. 安装Hugo
Hugo提供了多种安装方式,包括预编译二进制文件和包管理器。请根据你的操作系统,参考官方安装文档:
2. 创建Hugo站点
安装完Hugo后,你可以使用以下命令创建一个新的Hugo站点:
hugo new site your-site-name
cd your-site-name
更多关于创建站点的详细信息,请参考:
3. 安装主题
Hugo有丰富的主题可供选择,你可以在Hugo主题页面浏览并选择适合的主题。
安装主题的基本步骤如下:
git init
git submodule add https://github.com/theme-author/theme-name.git themes/theme-name
然后在配置文件中设置主题:
echo "theme = 'theme-name'" >> hugo.toml
站点配置
创建hugo.toml配置文件:
baseURL = 'https://www.mfun.ink/'
defaultContentLanguage = 'zh-cn'
title = "Mengboy's Blog"
theme = 'PaperMod'
hasCJKLanguage = true
# Google Analytics配置
GoogleAnalytics = "G-xxxxxxx" # 请替换为您的Google Analytics ID
# 添加permalink配置,使得链接格式与Hexo兼容
[permalinks]
post = '/:year/:month/:day/:contentbasename/'
# PaperMod主题参数
[params]
# 设置环境为生产环境,这对于Google Analytics和AdSense加载非常重要
env = "production"
# 作者信息
author = "mengboy"
# 主要部分
mainSections = ['post']
defaultTheme = "auto"
ShowReadingTime = true
ShowShareButtons = true
ShowPostNavLinks = true
ShowBreadCrumbs = true
ShowCodeCopyButtons = true
ShowRssButtonInSectionTermList = true
disableSpecial1stPost = false
disableScrollToTop = false
hideMeta = false
hideFooter = false
# 网站favicon设置
[params.assets]
favicon = "/images/site/favicon.png"
favicon16x16 = "/images/site/favicon.png"
favicon32x32 = "/images/site/favicon.png"
apple_touch_icon = "/images/site/favicon.png"
# Google AdSense配置 需要自定义扩展,或者主题支持
googleAdsense = "ca-pub-xxxxxxxxxx" # 请替换为您的Google AdSense发布商ID
googleAdsenseSlot = "xxxxxxxx" # 请替换为您的Google AdSense广告单元ID
# 侧边栏配置
[params.profileMode]
enabled = false
title = "mengboy"
subtitle = "记录学习与生活点滴"
imageUrl = "images/site/favicon.png"
imageWidth = 120
imageHeight = 120
# 社交图标
[[params.socialIcons]]
name = "github"
url = "https://github.com/mengboy"
# 搜索设置
[params.fuseOpts]
isCaseSensitive = false
shouldSort = true
location = 0
distance = 1000
threshold = 0.4
minMatchCharLength = 0
keys = ["title", "permalink", "summary", "content"]
# 允许HTML
[markup.goldmark.renderer]
unsafe = true
# 忽略HTML警告
ignoreWarnings = ['raw-html']
ignoreLogs = ['warning-goldmark-raw-html']
[languages]
[languages.zh-cn]
contentDir = 'content'
languageName = '简体中文'
weight = 10
title = "Mengboy's Blog"
# 中文主页信息
[languages.zh-cn.params]
[languages.zh-cn.params.homeInfoParams]
Title = "记录学习与生活点滴"
# 中文菜单
[languages.zh-cn.menu]
[[languages.zh-cn.menu.main]]
identifier = "home"
name = "首页"
url = "/"
weight = 10
[[languages.zh-cn.menu.main]]
identifier = "categories"
name = "分类"
url = "/categories/"
weight = 20
[[languages.zh-cn.menu.main]]
identifier = "tags"
name = "标签"
url = "/tags/"
weight = 30
[[languages.zh-cn.menu.main]]
identifier = "archives"
name = "归档"
url = "/archives/"
weight = 40
[[languages.zh-cn.menu.main]]
identifier = "about"
name = "关于我"
url = "/about/"
weight = 50
[languages.en]
contentDir = 'content/english'
languageName = 'English'
weight = 20
title = "Mengboy's Blog"
# 英文主页信息
[languages.en.params]
[languages.en.params.homeInfoParams]
Title = "Recording Learning and Life"
# 英文菜单
[languages.en.menu]
[[languages.en.menu.main]]
identifier = "home"
name = "Home"
url = "/"
weight = 10
[[languages.en.menu.main]]
identifier = "categories"
name = "Categories"
url = "/en/categories/"
weight = 20
[[languages.en.menu.main]]
identifier = "tags"
name = "Tags"
url = "/en/tags/"
weight = 30
[[languages.en.menu.main]]
identifier = "archives"
name = "Archives"
url = "/en/archives/"
weight = 40
[[languages.en.menu.main]]
identifier = "about"
name = "About Me"
url = "/en/about/"
weight = 50
创建内容目录
mkdir -p content/post
mkdir -p content/post/english # 英文文章目录
创建基础页面
关于页面
mkdir -p content/about
创建中文关于页面 content/about/index.md:
---
title: "关于我"
date: 2023-06-01T12:00:00+08:00
---
这是关于我的页面内容...
创建英文关于页面 content/english/about/index.md:
---
title: "About Me"
date: 2023-06-01T12:00:00+08:00
---
This is about me page...
其他基础页面参考about页面。
编写转换脚本
创建一个Python脚本来转换Hexo文章到Hugo格式:
#!/usr/bin/env python3
# 将Hexo的Markdown文件转换为Hugo格式
import os
import re
import datetime
import shutil
from pathlib import Path
# 设置路径
hexo_posts_dir = "hexo/source/_posts"
hugo_posts_dir = "hugo/content/post"
hexo_img_dir = "hexo/source/images"
hugo_static_dir = "hugo/static/images"
# 确保目标目录存在
os.makedirs(hugo_posts_dir, exist_ok=True)
os.makedirs(hugo_static_dir, exist_ok=True)
# 复制图片文件夹
def copy_images():
if os.path.exists(hexo_img_dir):
print(f"正在复制图片文件从 {hexo_img_dir} 到 {hugo_static_dir}")
# 复制文件夹内容
for item in os.listdir(hexo_img_dir):
s = os.path.join(hexo_img_dir, item)
d = os.path.join(hugo_static_dir, item)
if os.path.isdir(s):
shutil.copytree(s, d, dirs_exist_ok=True)
else:
shutil.copy2(s, d)
# 处理YAML front-matter
def convert_front_matter(content):
# 提取front-matter
match = re.match(r'^---\s+(.*?)\s+---\s*', content, re.DOTALL)
if not match:
return content
front_matter = match.group(1)
rest_content = content[match.end():]
# 转换标签和分类
new_front_matter = []
categories = []
tags = []
date = None
for line in front_matter.strip().split('\n'):
line = line.strip()
# 处理日期
if line.startswith('date:'):
date_str = line[5:].strip()
try:
date = datetime.datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S')
new_front_matter.append(f'date: {date.strftime("%Y-%m-%dT%H:%M:%S+08:00")}')
# 添加lastmod
new_front_matter.append(f'lastmod: {date.strftime("%Y-%m-%dT%H:%M:%S+08:00")}')
except ValueError:
new_front_matter.append(line)
# 处理标签
elif line.startswith('tags:'):
tags_str = line[5:].strip()
if tags_str.startswith('[') and tags_str.endswith(']'):
# 格式为 tags: [tag1, tag2]
tags = [tag.strip(' "\'') for tag in tags_str[1:-1].split(',')]
else:
# 可能是多行格式
continue
# 处理分类
elif line.startswith('categories:'):
cats_str = line[11:].strip()
if cats_str.startswith('[') and cats_str.endswith(']'):
# 格式为 categories: [cat1, cat2]
categories = [cat.strip(' "\'') for cat in cats_str[1:-1].split(',')]
else:
# 可能是多行格式
continue
# 复制其他行
elif not (line.startswith('- ') and ('tags:' in front_matter or 'categories:' in front_matter)):
new_front_matter.append(line)
# 添加分类和标签
if categories:
new_front_matter.append(f'categories: {categories}')
if tags:
new_front_matter.append(f'tags: {tags}')
# 添加slug
if 'slug:' not in front_matter:
filename = os.path.splitext(os.path.basename(content))[0]
new_front_matter.append(f'slug: "{filename}"')
# 组合新的front-matter
new_content = '---\n' + '\n'.join(new_front_matter) + '\n---\n\n' + rest_content
return new_content
# 转换Markdown内容
def convert_markdown_content(content):
# 替换图片链接
content = re.sub(r'!\[(.*?)\]\((.*?)/images/(.*?)\)', r'', content)
# 处理更多标记
content = re.sub(r'<!--\s*more\s*-->', '
', content)
return content
# 主转换函数
def convert_posts():
print(f"开始转换文章从 {hexo_posts_dir} 到 {hugo_posts_dir}")
files = os.listdir(hexo_posts_dir)
for file in files:
if not file.endswith('.md'):
continue
source_file = os.path.join(hexo_posts_dir, file)
target_file = os.path.join(hugo_posts_dir, file)
print(f"转换: {source_file} -> {target_file}")
# 读取源文件
with open(source_file, 'r', encoding='utf-8') as f:
content = f.read()
# 转换内容
content = convert_front_matter(content)
content = convert_markdown_content(content)
# 写入目标文件
with open(target_file, 'w', encoding='utf-8') as f:
f.write(content)
# 检测语言并创建多语言文件
def handle_multilingual():
print("处理多语言文章...")
for file in os.listdir(hugo_posts_dir):
if not file.endswith('.md'):
continue
filepath = os.path.join(hugo_posts_dir, file)
# 读取文件内容
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
# 检查是否有language标记
lang_match = re.search(r'language:\s*[\'"]?([a-z\-]+)[\'"]?', content)
if lang_match:
lang = lang_match.group(1)
if lang.startswith('en'):
# 创建英文版本
en_file = os.path.splitext(file)[0] + '.en.md'
en_filepath = os.path.join(hugo_posts_dir, en_file)
# 移除语言标记并写入新文件
content = re.sub(r'language:\s*[\'"]?[a-z\-]+[\'"]?\n', '', content)
with open(en_filepath, 'w', encoding='utf-8') as f:
f.write(content)
# 删除原文件
os.remove(filepath)
print(f" 创建英文文章: {en_filepath}")
if __name__ == "__main__":
copy_images()
convert_posts()
handle_multilingual()
print("转换完成!")
运行转换脚本
cd ~/dev/book
python3 convert_hexo_to_hugo.py
创建启动脚本
创建start.sh:
#!/bin/bash
# 启动Hugo服务器
hugo server -D
添加执行权限:
chmod +x start.sh
创建部署脚本
创建deploy.sh:
#!/bin/bash
echo -e "\033[0;32m部署博客到GitHub Pages...\033[0m"
# 生成静态文件
hugo
# 进入public目录
cd public
# 初始化git仓库
if [ ! -d ".git" ]; then
git init
git remote add origin YOUR_GITHUB_REPOSITORY_URL # 替换为您的GitHub仓库URL
fi
# 添加文件
git add .
# 提交更改
msg="rebuilding site $(date)"
if [ $# -eq 1 ]; then
msg="$1"
fi
git commit -m "$msg"
# 推送到GitHub
git push -u origin master
# 返回上层目录
cd ..
添加执行权限:
chmod +x deploy.sh
测试运行
./start.sh
创建多语言文章示例
中文文章
hugo new post/my-first-post.md
编辑content/post/my-first-post.md:
---
title: "我的第一篇博客"
date: 2023-06-10T15:30:00+08:00
lastmod: 2023-06-10T15:30:00+08:00
categories: ["博客"]
tags: ["Hugo", "入门"]
slug: "my-first-post"
description: "这是我使用Hugo创建的第一篇博客文章"
---
## 介绍
这是我的第一篇Hugo博客文章。
<!--more-->
这是摘要后的内容。
英文文章
hugo new post/english/my-first-post.md
编辑content/english/post/my-first-post.md:
---
title: "My First Blog Post"
date: 2023-06-10T15:30:00+08:00
lastmod: 2023-06-10T15:30:00+08:00
categories: ["Blog"]
tags: ["Hugo", "Getting Started"]
slug: "my-first-post"
description: "This is my first blog post created with Hugo"
---
## Introduction
This is my first Hugo blog post.
<!--more-->
This is the content after the summary.
结语
至此,我们已经完成了从Hexo到Hugo的迁移全过程,包括文章转换、多语言设置和部署准备。Hugo强大的性能和灵活的功能将为你的博客带来新的体验。