HEXO 开发笔记(2)插件
创建于 2024-12-28
更新于 2025-11-23
科技
hexo
插件
开发

前言

在上一篇 HEXO 开发笔记(1)主题 中简要提到了 Hexo 的插件体系,本文将深入探讨插件的安装、配置、使用与自定义开发。Hexo 的强大之处在于其丰富的插件生态,通过插件可以扩展:SEO 优化、部署自动化、内容加密、搜索功能、RSS 订阅等。

本文将结合实际已安装的插件(hexo-generator-sitemaphexo-deployer-githexo-blog-encrypthexo-abbrlink 等)进行讲解,并介绍如何开发自己的插件。撰写参考官方文档版本:Hexo 7.x

一、插件基础概念

1.1 插件分类与作用

Hexo 插件按功能可分为以下类型:

类型 作用 典型插件
生成器(Generator) 生成额外的静态页面或数据 hexo-generator-sitemaphexo-generator-feed
渲染器(Renderer) 扩展模板引擎或预处理器支持 hexo-renderer-pughexo-renderer-stylus
部署器(Deployer) 自动化部署到各种平台 hexo-deployer-githexo-deployer-s3
过滤器(Filter) 对内容进行预处理或后处理 hexo-filter-* 系列
标签(Tag) 在 Markdown 中使用自定义语法 各种嵌入式扩展(视频、图表等)
辅助函数(Helper) 在模板中使用的工具函数 主题内置或插件提供
功能增强 特定功能实现 hexo-blog-encrypt(加密)、hexo-abbrlink(短链接)

1.2 插件安装方式

bash
1
2
3
4
5
6
7
8
9
10
11
# 方式一:npm 安装(推荐) npm install <plugin-name> --save # 方式二:yarn 安装 yarn add <plugin-name> # 卸载插件 npm uninstall <plugin-name> # 查看已安装插件 npm list --depth=0 | grep hexo

安装后插件会记录在 package.jsondependencies 中,Hexo 启动时会自动加载所有 hexo-* 命名的包。

1.3 插件配置位置

插件配置通常写在根目录 _config.yml 中,部分插件也支持独立配置文件。配置结构:

yaml
1
2
3
4
# _config.yml plugin_name: option1: value1 option2: value2

二、常用插件实战

2.1 站点地图生成:hexo-generator-sitemap

安装

bash
1
npm install hexo-generator-sitemap --save

配置

_config.yml 中添加:

yaml
1
2
3
4
5
6
7
8
9
sitemap: 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.xmlsitemap.txt,提交给搜索引擎以提升 SEO。

自定义模板示例plugins/hexo-generator-sitemap/sitemap_template.xml):

xml
1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8"?> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> {% for post in posts %} {{ post.permalink }} {{ post.updated.toISOString() }} weekly 0.8 {% endfor %} </urlset>

2.2 自动部署:hexo-deployer-git

安装

bash
1
npm install hexo-deployer-git --save

配置

_config.ymldeploy 段落配置:

yaml
1
2
3
4
5
6
7
8
deploy: 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 部署器类型(gits3ftp 等)
message Git commit 信息(支持模板变量)
repo 仓库地址(可配置多个,实现多平台部署)
branch 目标分支

使用

bash
1
2
3
4
5
# 一键部署 hexo deploy # 或组合命令 hexo clean && hexo g && hexo d

工作原理

  1. public/ 目录内容推送到指定 Git 仓库
  2. 服务器端配置 Git Hooks 自动更新网站目录

SSH 密钥配置

bash
1
2
3
4
5
6
7
8
9
10
11
# 生成密钥对 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

安装

bash
1
npm install hexo-blog-encrypt --save

配置

_config.yml 中启用:

yaml
1
2
3
4
encrypt: enable: true # 全局默认密码(不推荐,建议文章单独设置) # password: default_password

使用

在文章的 Front Matter 中添加加密字段:

yaml
1
2
3
4
5
6
7
8
9
--- 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 中(可通过配置排除)

安装

bash
1
npm install hexo-abbrlink --save

配置

_config.yml 中修改:

yaml
1
2
3
4
5
6
7
8
permalink: :year/:month/:abbrlink/ # 或纯短链接 # permalink: posts/:abbrlink/ # 插件配置(可选) abbrlink: alg: crc32 # 算法:crc16 或 crc32 rep: dec # 进制:dec(十进制) 或 hex(十六进制)

使用

创建文章后,插件会自动在 Front Matter 中生成 abbrlink 字段:

yaml
1
2
3
4
5
--- 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

安装

bash
1
npm install hexo-generator-feed --save

配置

yaml
1
2
3
4
5
6
7
8
9
10
11
12
feed: 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 配置文件组织

对于大型站点,可将插件配置分离:

code
1
2
3
4
5
. ├── _config.yml # 主配置 ├── _config.plugins.yml # 插件专用配置(可选) └── plugins/ # 自定义插件目录 └── custom-plugin/

3.2 环境区分配置

通过环境变量区分开发与生产配置:

yaml
1
2
3
4
5
# _config.yml deploy: type: git repo: <%= process.env.DEPLOY_REPO %> branch: <%= process.env.DEPLOY_BRANCH || 'master' %>
bash
1
2
3
# 使用 export DEPLOY_REPO="git@github.com:user/repo.git" hexo deploy

3.3 插件冲突排查

常见问题:

  1. 渲染器冲突:同时安装 hexo-renderer-markedhexo-renderer-markdown-it 可能冲突

    • 解决:卸载其中一个
  2. 生成器重复:多个插件生成同名文件

    • 解决:检查 path 配置,避免重复
  3. 执行顺序问题:过滤器执行顺序影响结果

    • 解决:使用优先级参数(见下文自定义开发)

四、自定义插件开发

4.1 插件基本结构

最简单的插件只需一个 index.js

code
1
2
3
4
plugins/my-custom-plugin/ ├── index.js # 插件入口 ├── package.json # 插件元信息 └── README.md # 说明文档

package.json 示例

json
1
2
3
4
5
6
7
8
9
{ "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):

javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
// 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' }; });

注册方式

javascript
1
2
3
4
5
6
7
8
hexo.extend.generator.register(name, function(locals) { // locals 包含:posts, pages, categories, tags return { path: 'output/path.html', // 输出路径 data: {}, // 传递给模板的数据 layout: 'layout-name' // 使用的布局模板 }; });

4.3 开发过滤器插件

在内容渲染前后进行处理:

javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 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 中使用自定义语法:

javascript
1
2
3
4
5
6
7
// 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});

使用示例

markdown
1
2
3
{% note warning %} 这是一个警告提示框 {% endnote %}

标签类型

javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 行内标签(不处理内容) 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)

在模板中使用的工具函数:

javascript
1
2
3
4
5
6
7
8
9
// 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):

ejs
1
<p>阅读时长:<%= reading_time(page.content) %></p>

在模板中使用(Pug):

pug
1
p 阅读时长:#{reading_time(page.content)}

4.6 开发渲染器插件

扩展新的文件类型支持:

javascript
1
2
3
4
5
6
7
8
// 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 插件调试技巧

javascript
1
2
3
4
5
6
7
8
9
10
// 添加日志输出 hexo.log.info('插件已加载'); hexo.log.warn('警告信息'); hexo.log.error('错误信息'); // 调试时输出数据 console.log('Debug:', data); // 使用 hexo 内置工具 const { stripHTML, escapeHTML, slugize } = hexo.extend.helper.list();

本地测试插件

bash
1
2
3
4
5
6
7
8
9
10
11
# 在项目根目录创建插件 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 插件发布

bash
1
2
3
4
5
6
7
8
# 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 性能优化

javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// ❌ 避免:每次都重新计算 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 错误处理

javascript
1
2
3
4
5
6
7
8
9
hexo.extend.filter.register('my_filter', function(data) { try { // 处理逻辑 return processData(data); } catch (err) { hexo.log.error('插件错误:', err); return data; // 返回原始数据,避免中断构建 } });

5.4 配置验证

javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 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 兼容性考虑

javascript
1
2
3
4
5
6
7
8
9
10
11
// 检查 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'); }

六、实战案例:开发文章字数统计插件

完整示例:开发一个显示文章字数和阅读时长的插件。

javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 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):

pug
1
2
3
4
5
6
7
article 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 规范

7.3 插件开发参考

参考

本文作者: 有次元袋的 tiger
本文链接: https://www.superheaoz.top/2024/12/55499/
版权声明: 本站点所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 我的个人天地