CSRからSSG へ
このブログの作りをClient-side renderingからStatic site generatorに変更したときのメモです。
ref. この時点のソースコード (このあとも実験的に変更する可能性が高い)
そもそもなぜCSR?
- Markdownファイルをリポジトリにpushするだけで簡単に記事を公開する仕組みを作りたかった。
- かつ、フロントエンドの基礎を学ぶ目的で、トランスパイラなど使わずにブラウザで動くJavaScriptで何かを作りたかった。(そういうゲーム?)
具体的な動き (例: https://iinm.github.io/posts/?post=2022-02-12--hello-ssg
)
- ブラウザでこのURLにアクセスすると
posts/index.html
をGETする。- HTMLの内容は空で、コンテンツを別途取得して描画するためのJavaScriptが記載されている。
- query parameterからMarkdownファイルのURLを組み立ててGETする。
- Markdown の構造を解析してHTMLに変換。タイトル、本文を書き換える。
ref. CSRだった時のソースコード
CSR だと何が問題か?
(予想はしていたが) 検索エンジンにインデックスされないことが一番の問題です。 趣味とはいえ、実用性を無視して作っていては実世界で役に立つ学びは得られないので方向性を改めることにしました。
以下は、各サイトでの検索結果です。 (site:iinm.github.io
で検索)
Search Engine | Search Result |
---|---|
Bing | |
DuckDuckGo |
※ Googleでの検索結果のみスマホから (古いURLをSearch Consoleから削除してしまったため、以前撮ったスクショを使用)
- Google : タイトル、本文は描画できているが、記事が1つしかインデックスされてない。
- Search Consoleからサイトマップを登録してみたが、なぜかHTTPエラー (404) のため断念。
- Bing : 本文もタイトルも描画できず、なぜか JavaScript のコードが表示されている。変なスパムサイトにしか見えない。
- DuckDuckGo : 本文は描画できているが、タイトルがプレースホルダーのまま。
基本に戻って普通に HTML を返す
Jekyll、Hugoなど便利そうなStatic site generatorがいくつかありますが、 引き続き Webの基礎を学ぶために、これまでに作ったものをベースに簡易的なsite generatorを作りました。
CSR 版からの変更内容
- 記事の URL を
/posts/?post=hoge
から/posts/hoge.html
に変更。- そもそも検索エンジンにインデックスされてないので影響なしと判断
- Markdown parser 自体は特に依存するものがないので変更不要でしたが、HTMLを描画する部分はブラウザのDOMを操作するAPI (
document.createElement
など) を利用していたため jsdom を使うように修正。- (HTMLという宣言的なものを手続き的に組み立てるコードはとても読みやすいとは言えないので、ここはどうにかしたいところ。)
このほか、TypeScriptへの書き換えとテスト環境 (Jest) のセットアップをしました。 型をつける過程で意図せずundefinedを返す関数が見つかったり、LSP の補完が効くようになったり、開発者体験が大幅に改善されました。
現時点ではまだ検索エンジンにインデックスされていないので、しばらくこの状態で様子をみます。
(おまけ) Headless Chrome を SSG として使う
最終的には、開発者体験が良くて既存のコードが流用できるTypeScriptでの実装を選びましたが、 試行錯誤の過程でHeadless Chromeを使えば既存のコードのままでもHTMLを作れることに気が付きました。
# 開発用のサーバ起動
python -m http.server --bind 127.0.0.1 8000
# Headless Chromeで記事を描画、HTMLを出力する
find posts -name '*.md' \
| xargs -n 1 basename \
| sed 's,\.md$$,,g' \
| xargs -I {} bash -c "google-chrome-stable --disable-gpu --disable-software-rasterizer --headless --virtual-time-budget=5000 --dump-dom 'http://127.0.0.1:8000/posts/?post={}' > posts/{}.html"
ref. Makefile