Jekyll Hooks
使用 Hooks(钩子),你的插件可以对构建流程中的各个阶段进行更细粒度的控制。如果你的插件定义了任何 hook,Jekyll 会在预定义的时机调用它们。
Hooks 通过 owner(所有者)和 event name(事件名)进行注册。要注册一个 hook,需要调用 Jekyll::Hooks.register,并传入 hook owner、事件名称,以及在 hook 被触发时要执行的代码。
例如,如果你希望在 Jekyll 每次渲染页面后执行一些自定义逻辑,可以这样注册一个 hook:
Jekyll::Hooks.register :pages, :post_render do |page|
# code to call after Jekyll renders a page
end
注意:下文提到的 :post_convert 事件是 v4.2.0 中引入的功能。
开箱即用的情况下,Jekyll 为所有者 :site、:pages、:documents 和 :clean 预定义了 Hook 点。此外,为 :documents 定义的 Hook 点,也可以通过调用具体的集合类型来单独用于某个集合。也就是说,_posts 集合中的文档可使用 :posts,_movies 集合中的文档可使用 :movies。在所有情况下,Jekyll 都会将所有者对象作为第一个回调参数传递给你的 Hook。
每个已注册的 Hook 所有者都支持以下事件 — :post_init、:pre_render、:post_convert、:post_render、:post_write
— 不过,:site 所有者被设置为可以 响应 特殊事件名称。详情请参阅后续章节。
所有 :pre_render Hook 以及 :site, :post_render Hook 还会额外提供一个 payload 哈希作为第二个参数。在 :pre_render 事件中,payload 让你可以完全控制渲染期间可用的变量;而在 :site, :post_render 事件中,payload 则包含整个站点渲染完成后的最终值(适用于 sitemap、feed 等场景)。
内置 Hook Owners 和 Events
完整可用 hooks 列表如下:
| Owner | Event | 触发时机 |
|---|---|---|
|
表示整个网站 |
|
网站初始化完成后立即触发。适合用于修改网站配置。每次 build / serve 会话只触发一次 |
|
|
网站在重新生成(regeneration)期间 reset 完成后立即触发 |
|
|
|
所有源文件从磁盘读取并加载完成后触发 |
|
|
|
整个网站开始渲染之前触发 |
|
|
|
整个网站渲染完成后、文件写入磁盘之前触发 |
|
|
|
所有渲染后的文件写入磁盘后触发 |
|
|
允许对网站中的所有页面进行细粒度控制 |
|
每当页面初始化时触发 |
|
|
页面开始渲染之前触发 |
|
|
|
页面内容转换完成后、页面 layout 渲染之前触发 |
|
|
|
页面渲染完成后、写入磁盘之前触发 |
|
|
|
页面写入磁盘后触发 |
|
|
允许对网站中的所有文档进行细粒度控制,包括文章和用户自定义集合中的文档 |
|
每当任意文档初始化时触发 |
|
|
文档开始渲染之前触发 |
|
|
|
文档内容转换完成后、文档 layout 渲染之前触发 |
|
|
|
文档渲染完成后、写入磁盘之前触发 |
|
|
|
文档写入磁盘后触发 |
|
|
允许对网站中的所有文章进行细粒度控制,而不会影响用户自定义集合中的文档 |
|
每当文章初始化时触发 |
|
|
文章开始渲染之前触发 |
|
|
|
文章内容转换完成后、文章 layout 渲染之前触发 文章内容转换完成后、文章 layout 渲染之前触发 |
|
|
|
文章渲染完成后、写入磁盘之前触发 |
|
|
|
文章写入磁盘后触发 |
|
|
用于在网站清理阶段,对被判定为过期并即将删除的文件列表进行细粒度控制。 |
|
在网站构建前,对目标目录进行清理时触发 |
自定义 Jekyll 对象的 Hooks
你也可以为你的插件引入的 Jekyll 对象注册并触发 Hook。你只需要在自定义类中合适的位置、使用合适的 owner 名称放置 trigger 调用,并在插件中注册该 owner 即可。
下面通过一个示例来说明。假设有这样一个插件,它会为每个初始化的自定义 Excerpt 对象实现自定义功能:
module Foobar
class HookedExcerpt < Jekyll::Excerpt
def initialize(doc)
super
trigger_hooks(:post_init)
end
def output
@output ||= trigger_hooks(:post_render, renderer.run)
end
def renderer
@renderer ||= Jekyll::Renderer.new(
doc.site, self, site.site_payload
)
end
def trigger_hooks(hook_name, *args)
Jekyll::Hooks.trigger :excerpts, hook_name, self, *args
end
end
end
Jekyll::Hooks.register :excerpts, :post_init do |excerpt|
Jekyll.logger.debug "Initialized:",
"Hooked Excerpt for #{excerpt.doc.inspect}"
end
Jekyll::Hooks.register :excerpts, :post_render do |excerpt, output|
return output unless excerpt.doc.type == :posts
Foobar.transform(output)
end