ブログをWordpressからNetlifyに引っ越しましたー
移行した理由
- 旧ホスティング先のサーバのPHPのバージョンが古く、自身がアップグレードするモチベーションも湧かなかった
- 静的ファイルでそんなに凝ったことしてないのにWordpress使っててtoo match感(そして遅い)
- 記事編集で保存や新規記事画面への遷移も遅かった(かといってスケールアップする気にもならない)
- Wordpressのgutenbergが結構厳しくて、以前はプラグインの旧エディタ使っていたけど、旧エディタもMarkdownより書きづらいなーと思うことが増えてきた
- Wordpressのプラグインとか色々入れてて管理できてないし管理するモチベーションが(ry
- もっとシンプルにしてブログ自体を技術的な実験ができる場にしたい
と色々あったのです…。
変わったところ
- Before
- Wordpress
- VPS (DTIの月額500円プラン)でホスティング
- エッジはCloudFront
- オリジンはH2O + php-fpm
- After
- 静的ファイル置くだけ
- その静的ファイルは自前のブログジェネレータで生成
- Netlifyでホスティング
- instantclick.ioで別記事への遷移を爆速にした(やりたかった実験その1)
移行手順
- Wordpressから記事データのXMLをエクスポート
- 記事データのXMLから記事のデータを抽出
- Wordpressから画像データをエクスポート
- 記事をごにょごにょ
- 画像のリンク先が
/wp-content/uploads/...
とかってなってるのを一括置換 - コードのタグを調整(
<pre class="lang:ruby ...>
=> `ruby
) - などなど
- 画像のリンク先が
- 自前ジェネレータでmarkdownからhtml変換
- Netlifyにデプロイ(githubにpushして自動デプロイしたり手元からcliツールで手動デプロイしたり)
記事をごにょごにょするのは結構トライアンドエラーな感じだったのでRubyでちょろっとスクリプトを書きました。
こんな感じ↓
#!/usr/bin/env ruby
require 'nokogiri'
require 'date'
filename = ARGV[0]
doc = Nokogiri::XML(File.open(filename)) do |config|
config.options |= Nokogiri::XML::ParseOptions::HUGE
end
doc.css('item').each do |node|
begin
title = node.xpath("title")[0].inner_text.strip.gsub('"') { '\"' }
postname = node.xpath("wp:post_name")[0].inner_text.strip
content = node.xpath("content:encoded")[0].inner_text.strip
content.gsub!('"') { '"' }
content.gsub!(''') { "'" }
content.gsub!('"') { '"' }
content.gsub!('>') { ">" }
content.gsub!('<') { "<" }
content.gsub!('&') { "&" }
content.gsub!(/<pre class="lang:default\s+[a-zA-Z:\s-]*">/) { "\n```\n" }
content.gsub!(/<pre class="lang:language\-default\s+[a-zA-Z:\s-]*">/) { "\n```\n" }
content.gsub!(/<pre class="lang:language\-([a-zA-Z]+)\s+[a-zA-Z:\s-]*">/) { "\n```#{$1}\n" }
content.gsub!(/<pre class="lang:(.+)\s+[a-zA-Z:\s-]*">/) { "\n```#{$1}\n" }
content.gsub!('```sh') { '```bash' }
content.gsub!(/\n*<\/pre>/) { "\n```" }
...
自前のジェネレータはこれです。 ジェネレータといってもやっていることはこれくらい
- 記事マークダウンからHTMLを生成
- 最終更新からの差分生成も対応
- indexページ(記事一覧)の生成
- rssの生成
記事もindexページもrssも自前のテンプレートエンジンっぽいやつでレンダリングしてます。
正規表現を使わずパーサコンビネータでパースしてます。
instantclick.io
先読みできるpjaxのライブラリです(dev.toの流れで知った)
ちょろっと入れるだけで画面遷移が爆速になるのでオススメ。
ただ、bodyタグのpjaxなのでGAとかSNSボタンの設置など、他のJSの影響がある場合は注意が必要。 最終的にはこんな感じなタグを入れたら上手く動きました。
<script data-no-instant>
InstantClick.on('change', function() {
document.querySelectorAll('pre code').forEach((block) => {
hljs.highlightBlock(block);
});
if (typeof twttr === 'undefined') {
var twitterjs = document.createElement("script");
twitterjs.async = true;
twitterjs.src = 'https://platform.twitter.com/widgets.js';
twitterjs.charset = 'utf-8';
document.getElementsByTagName('body')[0].appendChild(twitterjs);
} else {
twttr.widgets.load();
}
gtag('config', 'UA-36921940-1', {'page_path': location.pathname + location.search});
});
InstantClick.init();
</script>
InstantClickのchangeイベントはinstantclickで画面遷移したときに発火するのですが、初回読み込み時も発火します。
その他
RSSやsitemapやWordpress側で自動生成させていたんですが、移行にあたってこちらの作成も必要でした。
RSSに関しては記事のメタデータをXMLでゴリゴリ自動生成させていけばよいし、sitemapもURLの羅列なのでそんなに苦労せず。
またNetlifyで自作ジェネレータを使いたいときは、ビルド環境に自作ジェネレータとランタイムを置く必要があります。
今回は自作ジェネレータはバイナリだったので、バイナリをポン起きするようなビルドスクリプトを書けばOKです。
今回はこんな感じ↓のを書いておいて make build/netlify
でビルドしました
.PHONY: build/netlify
build/netlify:
curl -O https://s3-ap-northeast-1.amazonaws.com/s3.freedom-man.com/blog-gen
chmod 755 blog-gen
./blog-gen generate
# ...
上の例だとS3にバイナリを置いているのでcurlで取ってきて実行権限与えて相対パスで呼び出しています。
本当は/usr/local/binとかに置きたかったんですがNetlifyのビルド時のユーザに権限が付与されていなかったので置けずorz
ちなみにNetlifyのビルドイメージはこちらのリポジトリになります↓