東京都庁展望室

東京都庁 展望室のご利用案内

よく訪れている北展望室(半分がカフェ&レストランになっている方)が、来年1月まで改装工事中だそうで、珍しく南展望室でした。
南は、エレベーターのある側を除いたほぼ全周が見えるのが良いですね。

今回はあまり良い写真が撮れませんでした。
せっかく夕暮れ時だったのに、ちょうど日が落ちる間合いに、ボサッとして他のことに気を取られていたのが敗因。
あとは言い訳ですが、地平線付近の透明度があまり良くなかったのと、雲の具合があまり好みの感じでもなかったな😰。

Hexo 内部探訪 (6) DevToolsを使ったデバッグ

恥ずかしながらデバッカーを使い慣れておらず、こういった実行時コンテキストの解析に、手間取っていました。
今回は、DevToolsプロトコルを使って解析してみよう。

$ cd <path-to-your-blog-dir>
$ hexo clean
$ node --inspect-brk node_modules/hexo-cli/bin/hexo g --debug

このようにinspectを有効化してから、ブラウザ(Chromiumを利用)でchrome://inspectを開き、Remote Targetの中に現れるinspect thisから、デバッカーを開始する。

これだと、デバッカーに馴れていない私にとっては、見たいところにたどり着くまでに手間取ってしまった。

そこで、自身で開発中のプラグインの中に、任意のブレークポイントをあらかじめ挿入してしまう。

debugger;

そして

$ node --inspect node_modules/hexo-cli/bin/hexo g --debug

-brk の有無が異なる点に注意。

これで、ようやく調査がやりやすくなりました。
デバッカーの使い方は、これが詳しい。

コードをステップ実行する方法 | Tools for Web Developers | Google Developers

Hexo 内部探訪 (3) コンテキストとしての"hexo"変数

調査の開始にあたって

プラグイン(さしあたりTagプラグインを想定)の実装中にて参照できる変数やオブジェクトを、調べてまとめよう。

ドキュメント | Node.jsProcess 等もためになる。

ところで、Node.jsでは、グローバルな空間を参照するためのキーワードがある。
globalである。

また、次のようなやり方で参照する方法もあるようだ。

const { inspect } = require('util');
var g = Function('return this')();
console.log(inspect(g, { depth: 0 }));

これらを駆使しつつ、Hexoの場合には、私が見たところほとんど全ての場所で、hexoという、トップレベルの変数が見えるので、これを足がかりにしたい。
また、他にも使える要素がもしあるなら、確かめたい。

グローバル汚染はなかった

調査を進めてから理解できたことだが、Hexoではグローバル変数、またはグローバル・オブジェクトを使ってはいない。

何らかのプラグインで、グローバルを意図して使うのならばともかくとして、少なくともHexoの本体と言える範囲や、純正/バンドルされた各プラグインでは、グローバル変数は使わないようだ。いわゆる「グローバル汚染」はない。

プラグイン含めて各所で見かけるhexoという変数が存在し、トップレベルの階層にあるし、自ら呼び出しているわけでもないので、私は当初これがグローバル変数なのかな?と勘違いしていました。

しかしこれは、実際には、module.exportsの仕組みによって与えられたもので、各モジュール(概ね各jsファイルに相当)毎にそれぞれエクスポートされていました。

私はこれまでmodule.exportsについて理解していないままでしたが、今回勉強になりました。

(調査中)

Hexoオブジェクト

{
_events: [Object: null prototype] {},
_eventsCount: 0,
_maxListeners: undefined,
base_dir: '/home/naoto/www/MyBlog/',
public_dir: '/home/naoto/www/MyBlog/public/',
source_dir: '/home/naoto/www/MyBlog/source/',
plugin_dir: '/home/naoto/www/MyBlog/node_modules/',
script_dir: '/home/naoto/www/MyBlog/scripts/',
scaffold_dir: '/home/naoto/www/MyBlog/scaffolds/',
theme_dir: '/home/naoto/www/MyBlog/themes/stage/',
theme_script_dir: '/home/naoto/www/MyBlog/themes/stage/scripts/',
env: [Object],
extend: [Object],
config: [Object],
log: [Logger],
render: [Render],
route: [Router],
post: [Post],
scaffold: [Scaffold],
_dbLoaded: true,
_isGenerating: true,
database: [Database],
config_path: '/home/naoto/www/MyBlog/_config.yml',
source: [Source],
theme: [Theme],
locals: [Locals]
}

(進捗途中)

Hexo 内部探訪 (2) 準備 npm linkメモ

npm linkを使いこなすには

npm linkという、ありがたい仕組みがあって、非公開のモジュール(または開発中のバージョン)を、node_modulesの中に配置することができる。
基本的には、シンボリック・リンクである。

ここまでは、すぐに把握できたけど、実はうまく動作させるための、さらなる条件があった。

モジュールを読み込む側と、読み込まれる側のモジュールが、ファイルシステム上で同階層になるように配置されている必要があるのだった。

私の場合だけど、開発中のリポジトリは、ある場所にまとめてある。
例:~/repository/hexo-tag-google-photos-album/
これが、Hexoプラグインを開発する場所。

一方で、ただ使うだけのものは、別の場所にある。
Hexoで構成しているブログの作業場所は、こんな感じ。
例:~/www/MyBlog/

つまり、自分のブログに自分のプラグインを組み込むとすると、
例:~/www/MyBlog/node_modules/hexo-tag-google-photos-album/
ということになる。

しかしながら、npm link的には、上記の2箇所を直接リンクすることはできないわけだ。

なので、さらに回りくどいが、以下のようにして、解決してみる。

naoto@MyComputer:~/www/MyBlog$ cd ..
naoto@MyComputer:~/www$ ln -s ../repository/hexo-tag-google-photos-album
naoto@MyComputer:~/www$ ls -l hexo-tag-google-photos-album
lrwxrwxrwx 1 naoto naoto 42 5月 6 01:46 hexo-tag-google-photos-album -> ../repository/hexo-tag-google-photos-album

こうすることで、開発中のプラグイン実体は従来通りのままとしつつ、link可能な場所にも配置できた。

呼び出される側のlinkは、以下の通り。

naoto@MyComputer:~/www$ cd hexo-tag-google-photos-album
naoto@MyComputer:~/www/hexo-tag-google-photos-album$ sudo npm link
(snip)
/usr/lib/node_modules/hexo-tag-google-photos-album -> /home/naoto/repository/hexo-tag-google-photos-album

そして、呼び出す方で使う側の、つまりブログ側の(しつこい)linkはこの通り。

naoto@MyComputer:~/www/hexo-tag-google-photos-album$ cd ../MyBlog
naoto@MyComputer:~/www/MyBlog$ npm link hexo-tag-google-photos-album
/home/naoto/www/MyBlog/node_modules/hexo-tag-google-photos-album -> /usr/lib/node_modules/hexo-tag-google-photos-album -> /home/naoto/repository/hexo-tag-google-photos-album
naoto@MyComputer:~/www/MyBlog$ grep photos package.json
"hexo-tag-google-photos-album": "git+https://github.com/isnot/hexo-tag-google-photos-album.git",
naoto@MyComputer:~/www/MyBlog$ ls -l node_modules/hexo-tag-google-photos-album
lrwxrwxrwx 1 naoto naoto 64 5月 6 01:50 node_modules/hexo-tag-google-photos-album -> ../../../../../usr/lib/node_modules/hexo-tag-google-photos-album

これで、毎度git pushとnpm upを繰り返すこと無く、作業ができるようになる(はず)。
確かめてみよう。

開発中のプラグインの中に、以下を書き加える。

~/repository/hexo-tag-google-photos-album/index.js
const { inspect } = require('util');
var g = Function('return this')();
console.log(inspect(g, { depth: 0 }));
console.log(inspect(hexo, { depth: 0 }));

これを、コミットもせず、コピーもせず、動かしたい。

naoto@MyComputer:~/www/MyBlog$ hexo list page
Object [global] {
global: [Circular],
process: [process],
Buffer: [Function],
clearImmediate: [Function: clearImmediate],
clearInterval: [Function: clearInterval],
clearTimeout: [Function: clearTimeout],
setImmediate: [Function],
setInterval: [Function: setInterval],
setTimeout: [Function] }
Hexo {
_events: [Object: null prototype] {},
_eventsCount: 0,
_maxListeners: undefined,
base_dir: '/home/naoto/www/MyBlog/',
public_dir: '/home/naoto/www/MyBlog/public/',
source_dir: '/home/naoto/www/MyBlog/source/',
plugin_dir: '/home/naoto/www/MyBlog/node_modules/',
script_dir: '/home/naoto/www/MyBlog/scripts/',
scaffold_dir: '/home/naoto/www/MyBlog/scaffolds/',
theme_dir: '/home/naoto/www/MyBlog/themes/stage/',
theme_script_dir: '/home/naoto/www/MyBlog/themes/stage/scripts/',
env: [Object],
extend: [Object],
config: [Object],
log: [Logger],
render: [Render],
route: [Router],
post: [Post],
scaffold: [Scaffold],
_dbLoaded: false,
_isGenerating: false,
database: [Database],
config_path: '/home/naoto/www/MyBlog/_config.yml',
source: [Source],
theme: [Theme],
locals: [Locals] }
INFO Start processing
INFO ---- START COPYING TAG CLOUD FILES ----
INFO ---- END COPYING TAG CLOUD FILES ----
Date Title Path
2019-04-09 Tags tags/index.md
2019-04-13 About いしだなおと / isnot N3 about/index.md

できた!

いいね。これで行こう。

運用中の注意事項

上記のような手順でプラグインをlinkしてある状況下で、もしnpm updateしたら、どういうことになるのだろうか?
試したところ、答えはlink状態が解除されて、package.jsonの記述内容の通りにモジュールが上書きされるということのようです。

ところが、開発中のプラグインとは無関係に、他も含めたnpmモジュールをアップデートしたいということはあるだろうと考えられる。
こういった状態を回避するには、どうするべきか考えると、いくつか選択肢が思い浮かぶ。

  • updateする頻度が低い場合は、毎回linkし直すという方法。あまり解決してない
  • linkを維持したいモジュールは、package.jsonに書かなければいいのかな?試してない
  • それ以外。何かあるかな?

Hexo 内部探訪 (1) はじめに

Hexoを選択した理由は、Node.jsだから、Javascriptだから、つまりいろいろと、自身で内部構造を含めて手を加えるため。
それは使い始めるとすぐに現実になり、早速プラグインを作成したりもした。(参照 hexo-tag-google-photos-album 公開しました

だんだんとHexoの内部構造やAPIについて理解をしはじめたところです。しかしながら開発においてはまだまだ、暗中模索です。

特に、記事やブログのメタデータや状態などを処理の過程で参照しようと思った時と、jsやcssの挿入(インジェクション)が、掴みにくいポイントだと思う。

インジェクションの方法

はじめにhexo-injectを見つけた時、これでかなり楽ができそうだなと思いました。
しかし実際に使おうと思い、試してみるのですが、思い通りに動かすことができませんでした。

This package has been deprecated
Author message:

The author does not use Hexo any more. This plugin is no longer maintained.

とのことで、現段階ではコレに頼るのは諦めました。
なお、元作者以外のメンテナの動きがあるようなので、少し期待しつつ成り行きを見守っています。

で、他のプラグインを(少しだけ)調査したのですが、インジェクションにはまだ定説というかベスト・プラクティスが確立しているようには見えませんでした。
いくつかアプローチがあるものの、私の望む動作とは少し違っているようです。
それというのも、Hexoのプラグイン機構の動作と、うまくマッチしていないように思いました。

postもしくはpageの中で、1回だけ呼び出す限りにおいては、いくつかの手法で(私の実装でも)問題なく動いています。

同じくpostもしくはpageの中で、複数回同じプラグイン(この場合はTagプラグインを想定)が呼び出されたときにどうなるかというと、私の手法ではマズイ部分があります。

探してみると、ランダムな文字列をうまく使って、重複したインジェクションの問題を回避しているプラグインがあることがわかりました。
それはそれで良いのですが、私の目的では、単に同一html文書内ではインジェクションが1回だけ、というような動きにしたく思い、引き続き調査中です。

もう一つの問題は、アーカイブもしくはインデックスでの挙動。特にインデックス。

私が使っているテーマ(Stage)だとアーカイブ系(カテゴリー別、タグ別一覧も同様)ではタイトルのみで本文が入らないのでまだ問題になっていないのですが、インデックスではそうもいきません。

ここでも、複数回の呼び出しが発生することを想定した作り込みが必要になりますが、私の実装では対応できていません。(不完全だが、1画面内で最初のTagプラグイン記述のみ、動いている)

あと、挿入位置も。
コンテンツの中(body要素の途中)ではなく、head要素の最後とか、body要素の最後に挿入したい。

状態の参照

ドキュメントの、APIを見ればおおよそは分かります。
でも、もっと細かい部分を確かめようと思うと、上記のドキュメントでは物足りなさを感じました。

私もhexo-tag-google-photos-albumを開発している過程で、その場しのぎ的に調査したのですが、効率的にやれていなかったのと、今後のことを思うと、まとまった形でどこかに書き出しておいたほうがいいなと思いました。

このあと、Hexoプラグイン開発に役立つよう、hexo-tag-google-photos-albumの開発を題材にとって、それらをまとめていきたいです。

他にも、開発の役に立ちそうなこと

まだまだ理解できていないこと。

Hexoの一連のライフサイクル。
それぞれの段階で、どんな処理が走るのか。
とか。

それとテーマ。

あとは、プラグインのロードあたりも、おいおい調べる必要が出てくるかも。

それと、npm linkを効果的に使う方法をちゃんと理解しておかないと、開発の効率が悪すぎる……。

そういったことを、連載形式でまとめていけたらと思います。