前言
在上一篇 HEXO 开发笔记(1)主题 中简要提到了 Hexo 的插件体系,本文将深入探讨插件的安装、配置、使用与自定义开发。Hexo 的强大之处在于其丰富的插件生态,通过插件可以扩展:SEO 优化、部署自动化、内容加密、搜索功能、RSS 订阅等。
本文将结合实际已安装的插件(hexo-generator-sitemap、hexo-deployer-git、hexo-blog-encrypt、hexo-abbrlink 等)进行讲解,并介绍如何开发自己的插件。撰写参考官方文档版本:Hexo 7.x。
一、插件基础概念
1.1 插件分类与作用
Hexo 插件按功能可分为以下类型:
| 类型 | 作用 | 典型插件 |
|---|---|---|
| 生成器(Generator) | 生成额外的静态页面或数据 | hexo-generator-sitemap、hexo-generator-feed |
| 渲染器(Renderer) | 扩展模板引擎或预处理器支持 | hexo-renderer-pug、hexo-renderer-stylus |
| 部署器(Deployer) | 自动化部署到各种平台 | hexo-deployer-git、hexo-deployer-s3 |
| 过滤器(Filter) | 对内容进行预处理或后处理 | hexo-filter-* 系列 |
| 标签(Tag) | 在 Markdown 中使用自定义语法 | 各种嵌入式扩展(视频、图表等) |
| 辅助函数(Helper) | 在模板中使用的工具函数 | 主题内置或插件提供 |
| 功能增强 | 特定功能实现 | hexo-blog-encrypt(加密)、hexo-abbrlink(短链接) |
1.2 插件安装方式
bash1234567891011# 方式一:npm 安装(推荐) npm install <plugin-name> --save # 方式二:yarn 安装 yarn add <plugin-name> # 卸载插件 npm uninstall <plugin-name> # 查看已安装插件 npm list --depth=0 | grep hexo
安装后插件会记录在 package.json 的 dependencies 中,Hexo 启动时会自动加载所有 hexo-* 命名的包。
1.3 插件配置位置
插件配置通常写在根目录 _config.yml 中,部分插件也支持独立配置文件。配置结构:
yaml1234# _config.yml plugin_name: option1: value1 option2: value2
二、常用插件实战
2.1 站点地图生成:hexo-generator-sitemap
安装
bash1npm install hexo-generator-sitemap --save
配置
在 _config.yml 中添加:
yaml123456789sitemap: path: - sitemap.xml - sitemap.txt template: ./plugins/hexo-generator-sitemap/sitemap_template.xml template_txt: ./plugins/hexo-generator-sitemap/sitemap_template.txt rel: false tags: true categories: true
字段说明:
| 字段 | 说明 |
|---|---|
path |
生成的文件路径(可同时生成 XML 和 TXT 格式) |
template |
自定义 XML 模板路径(可选) |
template_txt |
自定义 TXT 模板路径(可选) |
rel |
是否在 <head> 中添加 <link rel="sitemap"> |
tags |
是否包含标签页 |
categories |
是否包含分类页 |
使用
执行 hexo generate 后,会在 public/ 目录生成 sitemap.xml 和 sitemap.txt,提交给搜索引擎以提升 SEO。
自定义模板示例(plugins/hexo-generator-sitemap/sitemap_template.xml):
xml1234567891011<?xml version="1.0" encoding="UTF-8"?> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> {% for post in posts %}{% endfor %} </urlset> {{ post.permalink }} {{ post.updated.toISOString() }} weekly 0.8
2.2 自动部署:hexo-deployer-git
安装
bash1npm install hexo-deployer-git --save
配置
在 _config.yml 的 deploy 段落配置:
yaml12345678deploy: type: git message: "Site updated: {{ now('YYYY-MM-DD HH:mm:ss') }}" repo: origin: ssh://git@example.com/home/git/hexo.git # 示例占位,替换为实际仓库 # 可配置多个仓库同时部署 github: git@github.com:example/example.github.io.git # 示例 GitHub Pages branch: master
字段说明:
| 字段 | 说明 |
|---|---|
type |
部署器类型(git、s3、ftp 等) |
message |
Git commit 信息(支持模板变量) |
repo |
仓库地址(可配置多个,实现多平台部署) |
branch |
目标分支 |
使用
bash12345# 一键部署 hexo deploy # 或组合命令 hexo clean && hexo g && hexo d
工作原理:
- 将
public/目录内容推送到指定 Git 仓库 - 服务器端配置 Git Hooks 自动更新网站目录
SSH 密钥配置:
bash1234567891011# 生成密钥对 ssh-keygen -t rsa -C "your_email@example.com" # 将公钥添加到服务器 ~/.ssh/authorized_keys cat ~/.ssh/id_rsa.pub # 测试连接 # 测试连接(示例占位) ssh git@example.com # 如使用自定义端口: # ssh -p 2222 git@example.com
2.3 文章加密:hexo-blog-encrypt
安装
bash1npm install hexo-blog-encrypt --save
配置
在 _config.yml 中启用:
yaml1234encrypt: enable: true # 全局默认密码(不推荐,建议文章单独设置) # password: default_password
使用
在文章的 Front Matter 中添加加密字段:
yaml123456789--- title: 敏感内容文章 date: 2025-11-23 10:00:00 password: your_secure_password abstract: 这是一篇加密文章,请输入密码查看 message: 请输入密码访问 wrong_pass_message: 密码错误,请重试 wrong_hash_message: 文章不能被校验,请联系作者 ---
字段说明:
| 字段 | 说明 |
|---|---|
password |
访问密码 |
abstract |
加密提示摘要(显示在首页) |
message |
密码输入框上方提示 |
wrong_pass_message |
密码错误提示 |
wrong_hash_message |
校验失败提示 |
注意事项:
- 密码存储在
public/的 JS 中,是客户端加密,安全性有限 - 适用于分享给特定人群,不适合高安全需求
- 加密后的文章仍会生成在 sitemap 中(可通过配置排除)
2.4 永久链接短 ID:hexo-abbrlink
安装
bash1npm install hexo-abbrlink --save
配置
在 _config.yml 中修改:
yaml12345678permalink: :year/:month/:abbrlink/ # 或纯短链接 # permalink: posts/:abbrlink/ # 插件配置(可选) abbrlink: alg: crc32 # 算法:crc16 或 crc32 rep: dec # 进制:dec(十进制) 或 hex(十六进制)
使用
创建文章后,插件会自动在 Front Matter 中生成 abbrlink 字段:
yaml12345--- title: 示例文章 date: 2025-11-23 10:00:00 abbrlink: 5139 # 自动生成 ---
优势:
- ✅ URL 超短且稳定(修改标题不影响链接)
- ✅ 避免中文 URL 转码问题
- ✅ 方便迁移与分享
算法对比:
| 配置 | 示例 ID | 特点 |
|---|---|---|
crc32 + dec |
5139 |
短数字,易记 |
crc32 + hex |
a5f2b |
字母数字混合 |
crc16 + dec |
1234 |
更短但碰撞概率高 |
2.5 RSS 订阅:hexo-generator-feed
安装
bash1npm install hexo-generator-feed --save
配置
yaml123456789101112feed: enable: true type: atom # atom 或 rss2 path: atom.xml limit: 20 # 最多包含文章数(0 或 false 为全部) hub: content: true # 是否包含文章全文 content_limit: 140 # 摘要字数限制 content_limit_delim: ' ' order_by: -date icon: /images/favicon.png autodiscovery: true # 自动在 <head> 中添加 RSS 链接
使用
生成后访问 https://yoursite.com/atom.xml 即可订阅。
2.6 其他实用插件推荐
| 插件名称 | 功能 | 场景 |
|---|---|---|
| hexo-generator-search | 本地搜索数据生成 | 静态博客站内搜索 |
| hexo-filter-nofollow | 外链自动添加 rel="nofollow" |
SEO 优化 |
| hexo-wordcount | 字数统计与阅读时长 | 文章信息展示 |
| hexo-lazyload-image | 图片懒加载 | 性能优化 |
三、插件配置管理最佳实践
3.1 配置文件组织
对于大型站点,可将插件配置分离:
code12345. ├── _config.yml # 主配置 ├── _config.plugins.yml # 插件专用配置(可选) └── plugins/ # 自定义插件目录 └── custom-plugin/
3.2 环境区分配置
通过环境变量区分开发与生产配置:
yaml12345# _config.yml deploy: type: git repo: <%= process.env.DEPLOY_REPO %> branch: <%= process.env.DEPLOY_BRANCH || 'master' %>
bash123# 使用 export DEPLOY_REPO="git@github.com:user/repo.git" hexo deploy
3.3 插件冲突排查
常见问题:
-
渲染器冲突:同时安装
hexo-renderer-marked和hexo-renderer-markdown-it可能冲突- 解决:卸载其中一个
-
生成器重复:多个插件生成同名文件
- 解决:检查
path配置,避免重复
- 解决:检查
-
执行顺序问题:过滤器执行顺序影响结果
- 解决:使用优先级参数(见下文自定义开发)
四、自定义插件开发
4.1 插件基本结构
最简单的插件只需一个 index.js:
code1234plugins/my-custom-plugin/ ├── index.js # 插件入口 ├── package.json # 插件元信息 └── README.md # 说明文档
package.json 示例:
json123456789{ "name": "hexo-custom-plugin", "version": "1.0.0", "description": "My custom Hexo plugin", "main": "index.js", "keywords": ["hexo", "plugin"], "author": "Your Name", "license": "MIT" }
4.2 开发生成器插件
生成自定义页面示例(生成 about.html):
javascript12345678910111213// plugins/hexo-generator-about/index.js 'use strict'; hexo.extend.generator.register('about', function(locals) { return { path: 'about/index.html', data: { title: '关于我', content: '<p>这是关于页面</p>' }, layout: 'page' }; });
注册方式:
javascript12345678hexo.extend.generator.register(name, function(locals) { // locals 包含:posts, pages, categories, tags return { path: 'output/path.html', // 输出路径 data: {}, // 传递给模板的数据 layout: 'layout-name' // 使用的布局模板 }; });
4.3 开发过滤器插件
在内容渲染前后进行处理:
javascript123456789101112131415// plugins/hexo-filter-example/index.js 'use strict'; // 在渲染后处理 HTML(添加版权声明) hexo.extend.filter.register('after_post_render', function(data) { const copyright = '<p class="copyright">本文版权归作者所有</p>'; data.content += copyright; return data; }); // 设置优先级(数字越小越先执行,默认 10) hexo.extend.filter.register('before_post_render', function(data) { // 预处理 Markdown return data; }, 5);
常用过滤器钩子:
| 钩子名称 | 触发时机 | 参数 |
|---|---|---|
before_post_render |
文章渲染前 | data(文章对象) |
after_post_render |
文章渲染后 | data(包含 content HTML) |
before_generate |
生成静态文件前 | 无 |
after_generate |
生成静态文件后 | 无 |
server_middleware |
本地服务器中间件 | app(Express 实例) |
4.4 开发标签插件
在 Markdown 中使用自定义语法:
javascript1234567// plugins/hexo-tag-note/index.js 'use strict'; hexo.extend.tag.register('note', function(args, content) { const type = args[0] || 'info'; return `<div class="note note-${type}">${hexo.render.renderSync({text: content, engine: 'markdown'})}</div>`; }, {ends: true});
使用示例:
markdown123{% note warning %} 这是一个警告提示框 {% endnote %}
标签类型:
javascript1234567891011121314// 行内标签(不处理内容) hexo.extend.tag.register('myTag', function(args) { return `<span>${args.join(' ')}</span>`; }); // 块级标签(处理内容) hexo.extend.tag.register('myBlock', function(args, content) { return `<div>${content}</div>`; }, {ends: true}); // 异步标签 hexo.extend.tag.register('asyncTag', function(args) { return Promise.resolve('<span>异步内容</span>'); }, {async: true});
4.5 开发辅助函数(Helper)
在模板中使用的工具函数:
javascript123456789// plugins/hexo-helper-reading-time/index.js 'use strict'; hexo.extend.helper.register('reading_time', function(content) { const wordsPerMinute = 200; const words = content.split(/\s+/).length; const minutes = Math.ceil(words / wordsPerMinute); return `${minutes} 分钟`; });
在模板中使用(EJS):
ejs1<p>阅读时长:<%= reading_time(page.content) %></p>
在模板中使用(Pug):
pug1p 阅读时长:#{reading_time(page.content)}
4.6 开发渲染器插件
扩展新的文件类型支持:
javascript12345678// plugins/hexo-renderer-custom/index.js 'use strict'; const customCompiler = require('custom-compiler'); hexo.extend.renderer.register('custom', 'html', function(data, options) { return customCompiler.compile(data.text); }, true);
参数说明:
- 第一个参数:输入文件扩展名
- 第二个参数:输出文件扩展名
- 第三个参数:渲染函数
- 第四个参数:是否同步(
true为同步,省略或false为异步)
4.7 插件调试技巧
javascript12345678910// 添加日志输出 hexo.log.info('插件已加载'); hexo.log.warn('警告信息'); hexo.log.error('错误信息'); // 调试时输出数据 console.log('Debug:', data); // 使用 hexo 内置工具 const { stripHTML, escapeHTML, slugize } = hexo.extend.helper.list();
本地测试插件:
bash1234567891011# 在项目根目录创建插件 mkdir -p scripts/custom-plugin cat > scripts/custom-plugin/index.js << 'EOF' hexo.extend.filter.register('after_post_render', function(data) { console.log('自定义插件运行'); return data; }); EOF # 启动调试 hexo s --debug
4.8 插件发布
bash12345678# 1. 完善 package.json # 2. 添加 README.md 与 LICENSE # 3. 发布到 npm npm login npm publish # 4. 提交到 Hexo 插件列表 # https://hexo.io/plugins/
五、插件开发最佳实践
5.1 命名规范
- 使用
hexo-前缀(自动加载) - 功能明确:
hexo-generator-*、hexo-deployer-*、hexo-filter-* - 小写字母 + 连字符
5.2 性能优化
javascript12345678910111213141516// ❌ 避免:每次都重新计算 hexo.extend.filter.register('after_post_render', function(data) { data.content = heavyComputation(data.content); return data; }); // ✅ 推荐:使用缓存 const cache = new Map(); hexo.extend.filter.register('after_post_render', function(data) { const key = data._id; if (!cache.has(key)) { cache.set(key, heavyComputation(data.content)); } data.content = cache.get(key); return data; });
5.3 错误处理
javascript123456789hexo.extend.filter.register('my_filter', function(data) { try { // 处理逻辑 return processData(data); } catch (err) { hexo.log.error('插件错误:', err); return data; // 返回原始数据,避免中断构建 } });
5.4 配置验证
javascript1234567891011121314151617// plugins/hexo-plugin-example/index.js const defaultConfig = { enable: true, option1: 'default' }; const config = Object.assign({}, defaultConfig, hexo.config.my_plugin); if (!config.enable) { hexo.log.info('插件已禁用'); return; } // 验证必需配置 if (!config.required_option) { throw new Error('缺少必需配置项:required_option'); }
5.5 兼容性考虑
javascript1234567891011// 检查 Hexo 版本 const hexoVersion = hexo.version; if (hexoVersion < '6.0.0') { hexo.log.warn('插件建议在 Hexo 6.0+ 环境使用'); } // 检查依赖插件 const hasMarkdownIt = hexo.extend.renderer.get('md'); if (!hasMarkdownIt) { throw new Error('需要安装 hexo-renderer-markdown-it'); }
六、实战案例:开发文章字数统计插件
完整示例:开发一个显示文章字数和阅读时长的插件。
javascript123456789101112131415161718192021222324252627282930313233343536// scripts/wordcount.js 'use strict'; function stripHTML(str) { return str.replace(/<[^>]+>/g, ''); } function countWords(str) { const content = stripHTML(str); const cn = (content.match(/[\u4E00-\u9FA5]/g) || []).length; const en = (content.replace(/[\u4E00-\u9FA5]/g, '').match(/[a-zA-Z0-9_\u0392-\u03c9\u0400-\u04FF]+/g) || []).length; return cn + en; } function readingTime(count) { const wordsPerMinute = 200; return Math.ceil(count / wordsPerMinute); } // 注册辅助函数 hexo.extend.helper.register('wordcount', function(content) { return countWords(content); }); hexo.extend.helper.register('reading_time', function(content) { const count = countWords(content); return readingTime(count); }); // 在文章数据中添加统计信息 hexo.extend.filter.register('before_post_render', function(data) { const count = countWords(data.content); data.wordcount = count; data.reading_time = readingTime(count); return data; });
在模板中使用(Pug):
pug1234567article header h1= page.title .meta span.wordcount #{wordcount(page.content)} 字 span.reading-time 阅读时长 #{reading_time(page.content)} 分钟 .content!= page.content
七、插件生态与资源
7.1 官方插件列表
访问 Hexo 插件目录 查看社区维护的插件列表,包含:
- 功能分类
- 下载量统计
- 最近更新时间
- GitHub Stars
7.2 选择插件的标准
| 维度 | 推荐标准 |
|---|---|
| 维护状态 | 最近 6 个月内有更新 |
| 下载量 | npm 周下载 > 100 |
| 文档完整性 | 有详细的 README 和配置说明 |
| Issue 响应 | Maintainer 活跃处理问题 |
| 代码质量 | 有测试、遵循 ESLint 规范 |