什么是Scripts

如果您的代码很简单,建议您编写脚本,您只需要把 JavaScript 文件放到 scripts 文件夹,在启动时就会自动载入。

scripts 其实就是一个迷你插件,它可以实现类似于插件的功能,同时可以无侵入式的增强我们的Hexo.

scripts中我们可以尽情使用HexoApi

可以使用哪些Api

控制台(Console)

控制台是 Hexo 与开发者之间沟通的桥梁。

1
2
3
hexo.extend.console.register(name, desc, options, function(args){
// ...
});
参数描述
name名称
desc描述
options选项

示例:

1
2
3
hexo.extend.console.register('config', 'Display configuration', function(args){
console.log(hexo.config);
});

控制台嘛,跟浏览器控制台差不多,这里我们可以使用console最为辅组工具,便于我们调试其他API

部署器(Deployer)

部署器帮助开发者将网站快速部署到远程服务器上,避免了复杂的指令。

1
2
3
hexo.extend.deployer.register(name, function(args){
// ...
});

在函数中会传入 args 参数,该参数包含了 _config.yml 中的 deploy 参数值,以及开发者在终端中所传入的参数。

关于部署器,Hexo插件库拥有各种各样的部署插件,可以轻松将我的Hexo站点部署到GitHub PagesNetlify、腾讯云、阿里云,七牛云。。。

过滤器(Filter)

过滤器用于修改特定文件,Hexo 将这些文件依序传给过滤器,而过滤器可以针对文件进行修改

这里重点介绍这个过滤器,博主大部分主题扩展功能都是通过过滤器实现的。比如图片懒加载、loading 加载页、cdn替换、Alayer播放器、PWA等。

下面是博主的scripts目录:

Hexo提供多种不同类型的过滤器:

before_post_render

在文章开始渲染前执行。比如把标题转为小写:

1
2
3
4
hexo.extend.filter.register('before_post_render', function(data){
data.title = data.title.toLowerCase();
return data;
});

after_post_render

在文章渲染完成后执行。比如把 @username 取代为 Twitter 的开发者链接。

1
2
3
4
hexo.extend.filter.register('after_post_render', function(data){
data.content = data.content.replace(/@(\d+)/, '<a href="http://twitter.com/$1">#$1</a>');
return data;
});

before_exit

Hexo 即将结束时执行,也就是在 hexo.exit 被调用后执行。

1
2
3
hexo.extend.filter.register('before_exit', function(){
// ...
});

before_generate

在生成器解析前执行。

1
2
3
hexo.extend.filter.register('before_generate', function(){
// ...
});

after_generate

在生成器解析后执行。

1
2
3
hexo.extend.filter.register('after_generate', function(){
// ...
});

template_locals

修改模板的 局部变量。

比如在模板的局部变量中新增当前时间:

1
2
3
4
hexo.extend.filter.register('template_locals', function(locals){
locals.now = Date.now();
return locals;
});

after_init

Hexo 初始化完成后执行,也就是在 hexo.init 执行完成后执行。

1
2
3
hexo.extend.filter.register('after_init', function(){
// ...
});

new_post_path

用来决定新建文章的路径,在建立文章时执行。

1
2
3
hexo.extend.filter.register('new_post_path', function(data, replace){
// ...
});

post_permalink

用来决定文章的永久链接。

1
2
3
hexo.extend.filter.register('post_permalink', function(data){
// ...
});

after_render

在渲染完成后,Hexo 会自动执行相对应的 after_render 过滤器,举例来说,我们可以通过这个功能实现 JavaScript 的压缩。

after_render实在渲染完成之后,这里我们可以直接修改渲染之后的文件。

在这之前先了解先Hexo的渲染:

  • 渲染字符串:
    在渲染字符串时,您必须指定 engine,如此一来 Hexo 才知道该使用哪个渲染引擎来渲染。
    engine就是渲染引擎,比如 ejs ,swig, md 等。
1
2
3
hexo.render.render({text: 'example', engine: 'swig'}).then(function(result){
// ...
});
  • 渲染文件:
    在渲染文件时,您无须指定 engineHexo 会自动根据扩展名猜测所要使用的渲染引擎,当然您也可以使用 engine 指定。
1
2
3
hexo.render.render({path: 'path/to/file.swig'}).then(function(result){
// ...
});
  • 检查文件是否可被渲染:
    您可以通过 isRenderableisRenderableSync 两个方法检查文件路径是否可以被渲染,只有在相对应的渲染器(renderer)已注册的情况下才会返回 true。
1
2
hexo.render.isRenderable('layout.swig') // true
hexo.render.isRenderable('image.png') // false
  • 获取文件的输出扩展名:
    您可以通过 getOutput 方法取得文件路径输出后的扩展名,如果文件无法渲染,则会返回空字符串。
1
2
hexo.render.getOutput('layout.swig') // html
hexo.render.getOutput('image.png') // '''

那么在渲染完成之后就开始这行我们的after_render过滤器:

在渲染完成后,Hexo 会自动执行相对应的 after_render 过滤器,举例来说,我们可以通过这个功能实现 JavaScript 的压缩。

1
2
3
4
5
6
var UglifyJS = require('uglify-js');

hexo.extend.filter.register('after_render:js', function(str, data){
var result = UglifyJS.minify(str);
return result.code;
});

那么我们想在渲染完成之后为我们的站点添加Aplayer播放器,也可以通过after_render 过滤器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
hexo.extend.filter.register('after_render:html', function (htmlContent) {
// 注入 js
if (/<\/body>/gi.test(htmlContent)) {
let lastIndex = htmlContent.lastIndexOf('</body>');
htmlContent = htmlContent.substring(0, lastIndex) + injectAPlayer + htmlContent.substring(lastIndex, htmlContent.length);
}
return htmlContent;
}, 0);
const injectAPlayer =
'<!-- APlayer -->'+
'<link href="https://unpkg.com/aplayer/dist/APlayer.min.css" rel="stylesheet">'+
'<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>'+
'<script src="https://unpkg.com/aplayer/dist/APlayer.min.js"></script>'+
'<script src="/assets/aplayer.js" type="text/javascript"></script>';

生成器(Generator)

生成器根据处理后的原始文件建立路由。

1
2
hexo.extend.generator.register(name, function(locals){
});

在函数中会传入一个 locals 参数,等同于 网站变量,请尽量利用此参数取得网站数据,避免直接存取资料库。

生成器主要功能是复制文件,通过生成器我们可以在不修改主题目录文件的情况下,动态生成我们的page

比如我们想使用腾讯公益404作为我的 404页面,除了我们可以在 source 目录新建一个 404.html以外,可以通过生成器轻松实现。

1
2
3
4
5
6
hexo.extend.generator.register('page-not-found', function (locals) {
return {
path: '404.html',
data: '<!doctypehtml><html lang=en><meta charset=UTF-8><title>Page Not Found</title><body><script charset=utf-8 homepagename=回到我的主页 homepageurl=https://blog.hvnobug.com src=//qzonestyle.gtimg.cn/qzone/hybrid/app/404/search_children.js></script>'
};
});

或者我们想为我们的站点一个这样的导航页,我们可以将源文件放到 source 目录下,但是如果我们想动态去生成呢

1
2
3
4
5
6
7
8
9
10
11
12
const pug = require('pug');
const pathFn = require('path');
const fs = require('fs');
const tmp_src = pathFn.join(__dirname, '../layouts/pug/nav.pug');
const template = fs.readFileSync(tmp_src, 'utf8')
hexo.extend.generator.register('nav', function (locals) {
const navs = locals.data['nav'];
return {
path: 'nav/index.html',
data: pug.render(template, { doctype: 'html', ns: navs, cdn: 'https://cdn.jsdelivr.net/gh/hvnobug/assets/blog/nav' })
};
});

导航的渲染过程分为以下几个步骤:

  1. 加载 nav.pug 模板
  2. 加载 本地 data 文件,文件在 source/_data.nav.json
    主要是通过这个配置文件来动态修改导航
  3. 使用 pug 去渲染模板生成 html
  4. 将生成的 html 输出到 nav/index.html

按照这个方法,你可以生成任何不依赖主题layout的页面。

或者你只是想简单的复制一些文件,生成器也同样可以实现。

1
2
3
4
5
6
7
8
9
10
var fs = require('hexo-fs');

hexo.extend.generator.register('asset', function(locals){
return {
path: 'file.txt',
data: function(){
return fs.createReadStream('path/to/file.txt')
}
};
});

又或者你只是想生成类似robots.txt这样的文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
hexo.extend.generator.register('robots', function (locals) {
return {
path: 'robots',
data: 'User-agent: *\n' +
'Allow: /\n' +
'Allow: /post/\n' +
'Allow: /categories/\n' +
'Allow: /archives/\n' +
'Allow: /about/\n' +
'Allow: /tags/\n' +
'Allow: /album/\n' +
'Disallow: /images/\n' +
'Disallow: /js/\n' +
'Disallow: /css/\n' +
'Disallow: /fonts/\n' +
'Sitemap: https://blog.hvnobug.com/sitemap.xml'
};
});

同样的,博主的相册功能同样是通过Generator生成的。
不同的是, 相册需要使用主题的 layout,很难做到在不侵入主题的情况下动态生成主题。
顺便提一下,楼主是使用 GitHub Action 生成站点文件,并同步到 GitHub Pages,Coding Pages的,也是在hexo generate 之前将相册的layout 复制到主题的 layout 目录下。

关于Github Action 持续集成可以查看这篇文章

更多Api请点击Hexo - API官方文档