普段はあまり使うことがないと思いますし、実際この手のIssueはほとんど上がってきたことがない(自分がメンテナやりはじめてから記憶にある範囲で1つか2つ)ので需要は無いと思うんですが、ちょっと自分が試すことになったのでメモ。

公式ドキュメントは下記の通り。改めてみるともうちょっと具体的なサンプルがあった方が良い気がするので、そのうちPR出すかもしれない。

Hexo: API

まえがき


既に書いた通り実際に使うことはそんなにないと思う。実際はプラグインを作るか、theme/scriptsフォルダに拡張を作成するケースが大半だと思うので。ただ、今回はその前に保持しているデータや自分のやりたいことができそうか試したかったというのが動機。

コード


基本はこんな感じになる。実行結果は長いので端折るが、記事のMarkdownに書いたFront-matterなどが一式確認できる。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
const Hexo = require('hexo');
const hexo = new Hexo(process.cwd(), {silent: true});

hexo.init().then(() => {
hexo.call('generate', {}).then(() => {
const posts = hexo.locals.get('posts');
console.log(posts);
});
});

// 実行結果(実際は記事分の配列)

_Document {
title: 'Docker Compose 1.9.0はyamlのキーにcommandが含まれていると起動できない?',
date: Moment<2016-12-30T14:26:47+09:00>,
_content: '\n' ...(省略)...
raw: '---\n' ...(省略)...
slug: 'docker-compose-1-9-0-has-error-if-yaml-contain-commandkey',
published: true,
updated: Moment<2019-09-15T19:24:51+09:00>,
comments: true,
layout: 'post',
photos: [],
link: '',
_id: 'ckbezwi21008g5stvfziz45db',
content: '<p>という問題に直面しました。</p> ...(省略)...
path: [Getter],
permalink: [Getter],
full_source: [Getter],
asset_dir: [Getter],
tags: [Getter],
categories: [Getter],
prev: [_Document],
next: [_Document],
__post: true
},

postsはただのArray<object>(正確にはwarehouseというHexo向けのDBのDocument型)なのでforEachとかでグルグルまわしたり、filterしたりできる。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 更新日が3日以内のものを取得して表示
let date = new Date();
date = date.setDate(date.getDate() - 3);

hexo.init().then(() => {
hexo.call('generate', {}).then(() => {
const posts = hexo.locals.get('posts');
posts.filter(p => p.updated > date).forEach(post => {
console.log('-------------------');
console.log(post.permalink);
console.log(post.title);
console.log(post.updated);
})
});
});

// 実行結果

...

-------------------
https://yoshinorin.net/2020/06/13/read-joshikouhei/
「女子攻兵」を読んだ
Moment<2020-06-13T22:51:25+09:00>
-------------------
https://yoshinorin.net/2020/06/13/stress/
静かな場所
Moment<2020-06-14T18:43:30+09:00>
-------------------
https://yoshinorin.net/2020/06/14/create-search-server/
このサイトを検索するAPIサーバを作り始めた
Moment<2020-06-14T20:37:40+09:00>
-------------------
https://yoshinorin.net/2020/06/14/finally-uniqlo-cut-hair/
結局ユニクロ・美容院
Moment<2020-06-14T18:56:46+09:00>

結果をJSONに保存したりなど。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const Hexo = require('hexo');
const hexo = new Hexo(process.cwd(), {silent: true});
const fs = require("fs");

let date = new Date();
date = date.setDate(date.getDate() - 3);
const data = [];

hexo.init().then(() => {
hexo.call('generate', {}).then(() => {
const posts = hexo.locals.get('posts');
posts.filter(p => p.updated > date).forEach(post => {
data.push({
'url': post.permalink,
'title': post.title,
'content': post.content
});
});
fs.writeFileSync('data.json', JSON.stringify(data));
});
});

こんな感じ。

余談


このサイトを検索するAPIサーバを作り始めたをするために調べた。どうやってデータをDBに登録するかがずっと悩ましい問題だった。

自分の頭の中に更新した記事だけ取得して登録するという考えがすっぽり抜け落ちていた。静的サイトジェネレータなので更新日をとれないという思い込みがあった。更新日の話題は過去何度かIssueで上がっていたり自分もレビューしたりしたことがあるんだけれども、全く持ってサッパリ忘れてしまうとは恐ろしい。

毎回全データを放り込むか、プロダクト側からsitemap.xmlなどを参照して更新されたページをクロールするか…などとややこしいことを考えていた。しかし、よくよく思い出すとupdatedを保持していなかったか???sitemap.xmlに更新日が出ている以上は更新日とれるのでは???というのを確かめてみた次第。よかった。これで初回だけ全件登録して、後は更新された記事のみAPIにPOSTすればイケそう。

ちなみにHexoの更新日はFront-matterに何も指定しなければファイルの更新日時(タイムスタンプ)が適用される。