虽然 hexo 本身的功能已经很不错了,但是难免会有人有各种各样小众的需求。 比如说,emacs 用户会想用 org 模式写博文等等。 hexo 当然也照顾到了这部分人,它提供了简单易用的 API 用以创建插件。 这样,有独特需求的人,就可以方便的扩展 hexo。
我最近发现我的博客不支持 emoji 表情 ,但是搜索了一圈没有发现好用的插件。 所以我在看了文档了解了一些情况后,决定自己动手写一个简单支持 emoji 的插件来。 本文介绍了如何利用 hexo 的 API 写出一个简单的插件来。
hexo 是用 nodejs(服务器端的 javascript)写成的,它的插件也是要用 nodejs 写的。 所以要想自己动手写插件扩展 hexo,得会一点儿 nodejs 的基本知识。 像我这样不熟悉 javacript 的人,都能使用 hexo 的 API 来写插件扩展我需要的功能。 所以 hexo 的 API,设计的是非常优秀的。
众所周知 javascript 的语法有很多黑点,不熟悉它的人常常被搞的头晕眼花。 不过 hexo 的 API 和各种库的 API 设计的很好,作为使用者你不要知道太多的乱七八糟的语法。 所以你只需要懂得 javascript 的一个最小的特性,能完成你的需求就行了。 像基本的控制流,基本的数据结构,基本的函数定义,以及最最重要的, 闭包 。
1. hexo 插件结构
为了进一步方便扩展,hexo 支持两种形式的插件。
1.1. scripts 文件
这是第一种形式。 如果你的需求非常的小,简单的十几行代码就能解决。 直接在博文目录下建立 scripts
文件夹,建立一个 js 脚本文件,把代码写进去就行了。 hexo 启动的时候,会自动载入 scripts
目录下的所有脚本。
1.2. packages
第二种形式就是一个完整的 npm 包了。 首先你要给你的插件取一个名字。 要注意的是,hexo 的插件,名称必须要以 hexo-
开头。 比如说,我想写一个能给我的博客添加 emoji 表情支持的插件,我把它命名成 hexo-article-emoji
。
之后,你需要在博客目录下的 node_modules
下建立文件夹,名称是你的插件名称。
在这里文件夹里面,至少要有两个文件: index.js
和 package.json
。 package.json
是关于插件的一些信息, index.js
一般来说是插件的启动入口(这个需要在 package.json
中配置)。
在博客目录下,省略去无关文件,大致是这样的结构:
.
└── node_modules
└── hexo-article-emoji
├── index.js
└── package.json
package.json
是 json 格式,最小的需要包含的内容是:
|
|
name 是插件名称,version 是插件版本,main 是插件的启动的 js 文件。
index.js 是插件的入口文件,之后的事情就是在这个插件目录里面开始编写插件扩展功能了。
值的注意的是,hexo 查找插件是和博客目录下的 package.json 文件中的记录有关系的。 这个文件是受 npm 包管理器管理的。 如果你发现你的插件好像没有被加载,检查下这个文件里可能有相关的线索。
2. 依赖包的安装
对于有些稍微复杂点的功能,你的插件可能只单单用最基本 nodejs 库是无法完成的。 这就需要第三方库的支持。 比如说,我为了给我的博客加上 emoji 表情支持,需要用到一个叫做 cheerio 的库。 这个库,是服务器端的 jquery,用来处理 HTML 非常好用。
以 cheerio 为例,在你的插件目录安装第三方的库。 在你的插件目录 执行:
|
|
之后,它会把 cheerio 安装到你的插件目录去,如果你注意的话会发现你的插件目录多了一个 nodemodules 文件夹。 而且,它还会修改你插件目录下的 package.json
文件,你会发现多了一个 dependencies
字段(如果之前没有的话), 在这个字段下面还附上了这个库的名称和版本要求。
这个字段有什么作用呢?如果你把你的插件发布到 github 上去, 别人通过 npm 来安装你的插件,npm 就能根据这个字段,自动的把所有的依赖包都安装好,很方便吧。
3. hexo 的 API
3.1. hexo 对象
既然是插件,自然要提供能访问 API 的接口。在 index.js
里面,你能访问到一个全局变量, hexo
。 你可以把它当成插件访问 hexo API 的通道。
3.2. 获取 hexo 配置
我们知道,博客目录下的 _config.yml
文件,记录了 hexo 博客的大部分配置。 yml 文件的结构类似 json,hexo 在启动的时候会加载它。 在我们编写插件的时候,通过 hexo.config
这个数组,就能访问到这些配置。
我们要编写的插件可能能提供给用户一些自定义的选项,这些配置也可以放在博客目录下的 _config.yml
中。 之后在插件中通过 hexo.config
就能访问到它了。
比如说,我的 hexo-article-emoji 插件能够配置是否解析完整版的 emoji。 我们在插件文档里告诉用户,在 _config.yml
的后面加上:
|
|
之后我们在插件中通过 hexo.config.article-emoji.full
就能取得对应配置项的值了。比如:
|
|
这些配置的字段是怎么样的,完全由你决定。不过要注意两点:
- 不要和其它的配置选项冲突
- 尽量能直接从配置中看出是哪个插件的配置
3.3. 过滤器
好,现在我们开始构思一个支持文章 emoji 表情的插件。 为了实现这个功能,这个插件要做的最主要的事情就是,把文章里面的类似以下的 emoji 语法:
:smile:
把它替换成图片链接,如:
<img title=":smile:" src="/images/emoji/smile.png"></img>
那么就得使用 hexo 的 API 来修改文章。 hexo 提供了一类很简单却很强大的 API 就是过滤器。
所谓过滤器,说白了就是你定义的用于处理文章的函数。 使用 hexo 提供的 API 将它注册成过滤器。 之后,hexo 在将你的文章解析成 HTML 静态页面时,有这样一个步骤:
- 执行
before_post_render
过滤器 - 使用渲染器将博客文件(Mrkdown 或者其它格式)渲染成 HTML
- 执行
after_post_render
过滤器
可以看到,hexo 先把原始的 markdown 文件的内容传入你的 beforepostrender 注册器函数, 这样你就有机会去修改原始的 markdown 格式的内容。 再将得到的结果用渲染器渲染成 HTML。 最后的这个 HTML 还能传入你的 afterpostrender 注册器函数, 这样你又有机会去修改最终生成的 HTML。
hexo 的 API 提供了一些函数,用于将我们自己写的一个函数设置成某种过滤器:
|
|
上面我们定义了两个函数,并通过 hexo 的 API 把它们分别设置成某种过滤器。 由于 javascript 中函数是 first-class 的,所以你能把它当成参数传入另一个函数里面,也能把它保存到数据结构里面。 hexo 充分利用了这一点,设计出了易用强大的 API。
注意到函数会有一个参数,hexo 在执行我们定义的过滤器函数时,会把文章的信息从这个参数传入进来。 传入的是一个数组,有如下的键值:
键值 | 类型 | 含义 |
---|---|---|
title | 字符串 | 文章标题 |
excerpt | 字符串 | 文章摘要 |
more | 字符串 | 文章出摘要以外的内容 |
content | 字符串 | 文章内容 |
excerpt,more,content 这三个值,如果你的过滤器是 beforepostrender,里面是原始的(markdown 等)内容。 如果你的过滤器是 afterpostrender,那么里面的是解析后的 HTML。 之后你可以在函数里面修改这些值,再把整个数组返回。
好了,现在有了这两个过滤器,从技术的角度,实现 emoji 表情的支持,是毫无问题了。
更多键值请参考:https://hexo.io/zh-cn/docs/variables.html。 更多的过滤器请参考:https://hexo.io/zh-cn/api/filter.html
4. 最后
最终,我凭着蹩脚的 javascript 的水平,终于写出了插件实现了我想要的 emoji 功能! 我把它放在了 github 上面:https://github.com/frapples/hexo-article-emoji 虽然它的功能很简单,但是也足够满足我的需求了。 我的 emacs 在 org-mode 是能很方便的插入 emoji 语法,现在,我的博客终于能识别他们了!
5. 更新记录
- 由于发现博客存在一个 bug,修复后发现 hexo 的一个特点,故此补充。