Hexo
Hexo - A fast, simple & powerful blog framework
hexojs/hexo: A fast, simple & powerful blog framework, powered by Node.js.
How Hexo Load Plugins
hexo/lib/hexo/load_plugins.ts at master · hexojs/hexo
Load Modules: package.json 中 hexo- 开头和 hexo-theme- 开头的。
Load Scripts: ${theme_dir}/scripts 和 /scripts 目录下所有的文件。这些文件都可以直接访问全局变量 hexo。
Hexo API
Tag (Plugin)
A tag allows users to quickly and easily insert snippets into their posts.
Inline Tag vs. Block Tag
注册:
1 | // inline tag |
在 .md 中使用:
1 | <!-- inline tag, no `end` --> |
Async Tag
如果 Tag 的处理逻辑中有 async 函数调用,可以将其注册为 async Tag:
1 | hexo.extend.tag.register( |
处理参数 args
比如 foo Tag 支持这样的语法(有必填参数,可选参数,可选的命名参数):
1 | {% foo param1 [param2] [opt1:val1] [opt2:val2] %} |
通过 hexo.args.map() 将传入的 args 转成参数信息对象:
1 | hexo => args => { |
访问 Hexo 实例
如果是 scripts 目录里的文件,就可以直接访问全局变量 hexo:
1 | hexo.extend.tag.register('foo', args => { |
如果分开,则:
1 | module.exports = hexo => args => { |
1 | hexo.extend.tag.register('foo', require("./lib/foo")(hexo)); |
访问当前 Article (Post/Page) 信息
this 即为当前文件的信息,如:
1 | module.exports = hexo => function (args) { |
Caution
这里 function (args) { ... } 不能写成 args => { ... },因为 arrow functions ignore this.
Filters
A filter is used to modify some specified data. Hexo passes data to filters in sequence and the filters then modify the data one after the other. This concept was borrowed from WordPress.
Hexo 内置的 filter type,filter 被调用时,this 就是 Hexo 实例(不要用 arrow functions)。
Type markdown-it:renderer
Provided by hexo-renderer-markdown-it.
This plugin overrides some default behaviors of how markdown-it plugin renders the markdown into html, to integrate with the Hexo ecosystem. It is possible to override this plugin too, without resorting to forking the whole thing.
自定义 filter 的调用逻辑为:
1 | this.hexo.execFilterSync('markdown-it:renderer', this.parser, { context: this }); |
其中 this 为 class Renderer 的实例,this.hexo 即为 Hexo 实例,this.parser 是 class MarkdownIt 的实例。
自定义 filter 的例子:
1 | module.exports = function (parser) { |
Events
Hexo inherits from EventEmitter. Use the
onmethod to listen for events emitted by Hexo, and use theemitmethod to emit events. For more information, refer to the Node.js API documentation.
Hexo Processing Flow
use pnpm hexo generate --debug to output debug level logs.
Add demo filters:
1 | const filterTypes = [ |
Add demo event handlers:
1 | const events = [ |
Add demo tag plugin:
1 | const foobar = ctx => function (args) { |
“hexo generate”
- Database
[D] "Writing database to .../db.json"
- Initialization
[D] "Hexo version: 8.1.1"[D] "Workding directory: ..."[D] "Config loaded: .../_config.yml""Validating config"[D] "Second Theme Config loaded: .../_config.stellar.yml"[D] "Plugin loaded: ..."(perhexo-*and@*/hexo-*dependency)[D] "Script loaded: ..."(perscripts/**/*.js)[D] "Script loaded: ..."(per{theme}/scripts/**/*.js)after_initfilterreadyevent
- Process Source Files (
hexo.sourceandhexo.theme) (see Box | Hexo)"Start processing"[D] "Processed: ..."post_permalinkfilter (per_posts.mdand asset file)
- Content (Posts and Pages) Rendering
generateBeforeevent[D] "Rendering file: ...(per.css,.js, and.jsonfile)post_permalinkfilter (per_posts.mdfile)before_post_renderfilter (per.mdfile)[D] "Rendering post: ..."(per.mdfile)markdown-it:rendererfilter (per.mdfile)- Tag plugins (
markdown-it:rendererfilter might be called if tag plugin calls renderer) - Together:
after_post_renderfilter (per.mdfile)"hexo-esbuild: processed ..."(per.cssfile)
- Content Generation
before_generatefilter- registered generators
post_permalinkfilter (per_posts.mdfile, when"Generator: post")
post_permalinkfilter (per_postsasset file❔)template_localsfilter (called repeatedly)generateAftereventafter_generatefilter
- ❔
"Files loaded in d.dd s"
- HTML Rendering
[D] "Rendering HTML xxx: ....htmlmarkdown-it:rendererfilter (called repeatedly, for 正文之外的部分,如 side bar, footer)
- HTML Generation
- Together:
Generated: ...(outputting files)"hexo-esbuild: processed ..."(per.js,.stylfile)
"n files generated in d.dd s"
- Together:
- Database
[D] "Database saved"
- Exit
before_exitfilterexitevent
“hexo server”
The server starting:
- Database
- Same with
hexo generate
- Same with
- Initialization
- Same with
hexo generate
- Same with
server_middlewarefilter- Process Source Files (
hexo.sourceandhexo.theme) (see Box | Hexo)- Same with
hexo generate
- Same with
- Content (Posts and Pages) Rendering
- Same with
hexo generate
- Same with
- From where:
"正在获取图片长宽比。首次可能耗时较久,请耐心等待...""[image-ratios.json] 生成完成"
- Content Generation
- Same with
hexo generate
- Same with
- Server Started
"Hexo is running at http://localhost:4000/ . Press Ctrl+C to stop."[D] "Database saved"before_exitfilterexitevent
- Generation Again
generateBeforeevent- Same with about “Content Generation”
When browsing a page:
- HTML Rendering
- Same with
hexo generate
- Same with
- HTML Accessing
"GET /... 200 d.ddd ms - - ""hexo-esbuild: processed ..."(per.js,.stylfile)
When a post or page modified:
- Process Source Files
[D] "Processed: ..."(for the modified file)post_permalinkfilter (for the modified file, if in_posts)
- Content (Posts and Pages) Rendering
- Same with
hexo generate, but only for the modified file
- Same with
- Content Generation
- Same with
hexo generate
- Same with
Stopping the server:
- Goodbye
"Have a nice day"or"Bye!"or similar message, twice
- Exit
- Same with
hexo generate
- Same with
“hexo clean”
- Initialization
- Same with
hexo generate
- Same with
- Clean
"Deleted database.""Deleted public folder."
- Exit
- Same with
hexo generate
- Same with
关于 Syntax Highlighting
Hexo 内置了 highlight.js 和 prismjs 两种 syntax highlight libraries,都支持 server-side 和 browser-side 渲染。默认使用 highlight.js。
注意处理的顺序。
内置的 syntax highlight 是通过 before_post_render filter 注入的:
1 | filter.register('before_post_render', require('./backtick_code_block')(ctx)); |
https://github.com/hexojs/hexo/blob/master/lib/plugins/filter/before_post_render/index.ts
因为 hexo generate 的 processing flow 是:
- Content (Posts and Pages) Rendering
- …
before_post_renderfilter[D] "Rendering post: ..."(per.mdfile)- Tag plugins
after_post_renderfilter
即,在 renderer(如 hexojs/hexo-renderer-markdown-it)处理之前就已经完成了 fenced code 的 syntax highlighting 渲染。
所以直接引入 markdown-it 的 插件 @mdit/plugin-snippet,可以将 asset 文件中的代码注入到 markdown,但并不会被 Hexo 内置的 syntax highlighting 处理,而只是得到普通的 <pre><code>...</code></pre> 片段。
自定义的 snippet tag 是手动调用了 Hexo 内置的 syntax highlighting(参考了 Hexo 自带的 include_code tag):
1 | return hexo.extend.highlight.exec(hexo.config.syntax_highlighter, { |