实现 hexo 文章和资源在同一目录下

前言

最近起了写博客的欲望,但是感觉 typecho 用起来不是很喜欢,于是通过先找主题再确定博客系统的原则选择了 hexo。

但是发现 hexo 的这个文件结构属实是比较丑陋。

一般有两种结构

  1. 图片和图片在单独的目录下,文章通过相对/绝对路径引用
  2. 开启 post_asset_folder,得到这样的结构
    1
    2
    3
    4
    5
    _posts
    ├── article1/
    ├── article2/
    ├── article1.md
    ├── article2.md

即使是第二种结构,也不够优雅,因为 title 出现太多次了,文章一多找依赖也麻烦。搜索了老半天居然没发现有人吐槽这个,我差点想换 hugo。

实现

看了下 hexo 的源码,找到了结构二的实现。

1
2
3
4
5
6
7
8
9
10
// hexo/lib/plugins/processor/post.js
function scanAssetDir(ctx, post) {
if (!ctx.config.post_asset_folder) return;

const assetDir = post.asset_dir;
const baseDir = ctx.base_dir;
const baseDirLength = baseDir.length;
const PostAsset = ctx.model('PostAsset');
// ...
}

如果开启了 post_asset_folder,就会把 md 同名的资源文件夹里识别为资源文件夹。

那么 asset_dir 是如何定义的呢?

1
2
3
4
5
6
// hexo/lib/models/post.js
// 声明了一个 getter
Post.virtual('asset_dir').get(function() {
const src = this.full_source;
return src.substring(0, src.length - extname(src).length) + sep;
});

所以思路很简单,只要把 asset_dir 改成 md 所在就可以了。

这里就用到了 hexo 的插件机制,把这个 getter patch 了一下,改成了 md 所在的目录。

1
2
3
4
5
6
7
8
'use strict';

const { dirname, sep } = require('path');

hexo.database.model('Post').schema.virtual('asset_dir').get(function() {
const src = this.full_source;
return dirname(src) + sep;
});

使用方式

我把这个插件发布到了 npm 上,可以直接安装使用。

1
2
3
4
// npm
npm install hexo-asset-dir --save
// pnpm
pnpm i hexo-asset-dir

然后在 _config.yml 里面设置 post_asset_folder: truenew_post_name: :title/index.md

这样的目录结构就会是

1
2
3
4
5
6
7
_posts
├── example
├── image.jpg
└── index.md
├── example2
├── image.jpg
└── index.md

效果

image

还有

不过我用的这个 fluid 主题的缩略图功能不支持这样的相对路径,还需要再一次插件 hack。

1
2
3
4
5
6
7
const relative = /^[^/](?!.*:\/\/)/

hexo.extend.filter.register('before_post_render', function(data){
if (data.index_img && relative.test(data.index_img))
data.index_img = data.path + data.index_img;
return data;
});

把以上脚本命名为 hexo-fluid-index-img.js 放置到 scripts 目录下即可。


实现 hexo 文章和资源在同一目录下
https://hunsh.net/20230806/实现-hexo-文章和资源在同一目录下/
发布于
2023年8月6日
许可协议