サイトをリニューアルしました!使っている技術要素とサイト更新のモチベーション

こんにちは。

最後にブログを更新してから2ヶ月が経過してしまいました。単純に忙しくて更新できなかったのもありますが、サイトのリニューアルを進めていたというのが大きな理由です。ついに新サイトを公開することができたので、今回はその話です。

元々リニューアルは進めていたが・・・

【祝】パン工房1周年 人気記事の振り返りと今後の展望【microCMS化へ】で書いていますが、当サイトはNuxt Contentを使ったブログ記事管理から脱却してmicroCMSによるコンテンツ管理を行うべく、リニューアル作業を進めていました。Nuxt Contentによるコンテンツ管理が難しくなってきたのと、単純にページの読み込みが重いという問題を解決したかったからです。詳しくは記事をご覧ください。

とはいえリニューアルをしないままでもブログの更新は問題なくできたため、リニューアルに対するモチベーションはそこまで高くありませんでした。上の記事にも

リニューアルが済まないまま2周年を迎えることだけは避けたいです(フラグ)

と書いていたぐらいです。このまま4月にならなくて良かったです。

リニューアルが急に進んだ理由

ではなぜゆっくり進めていたリニューアルが急に進んで公開に至ったのでしょうか。実は、元々のプログラムがローカルで上手く起動しなくなってしまったのです。原因ははっきりしていないのですが、Nuxt.jsをローカルでビルドしたときコンポーネントごとのJSファイルがブラウザで読み込めなくなってしまいました。ブログはローカルでプレビューしながら書いているので、ローカルで起動しなければ更新ができません。つまり、リニューアルを完了しないとブログが更新できないという状態に陥ってしまったのです。

それなりの時間をかけてググってみましたが解決できず、もっと時間をかけて調べてもよかったのですが、これは早くリニューアルを完了させなさいという神のお告げに違いないと思い、書きたいブログのネタがあっても抑え込んで開発をしていたのです。おかげで2周年まで半年を残した10月の公開となりました。

新サイトの構成

リニューアル後の新サイトは2つのプロジェクトで構成されています。1つはNuxt.jsのSSG(Static Site Generation=静的サイト生成)を用いたメイン部分(ブログやABOUTページなど)、もう1つは同じくNuxt.jsでこちらはSSR(Server Side Rendering=サーバーサイドレンダリング)によるWORKSページです。

一度はやめた分割構成

実はサイト公開から既に1回大規模リニューアルをしており、そのリニューアル以前はブログやWORKSはサブドメインで公開していました。

(このときもブログが2ヶ月ぶりの更新になってますね)

このときはNuxt.jsすら使っておらず、コンテンツによってプロジェクトも分かれていました(当時は今は亡きPHOTOSなんていうページもありました)。同じサイト内で共通のヘッダー・フッターであるにも関わらず別のプロジェクトだったため、ソースが分散して管理しにくいというデメリットがあり、リニューアル後はNuxt.jsでブログもWORKSも全て1つのプロジェクトに収めてしまうという方法を取ったのです。

プロジェクトを1つにしたこと自体はコンポーネントが共通化できたためメリットが大きかったですが、WORKSページで大量のデータや複雑なグラフを扱うようになったり、Nuxt Contentで書いているブログの記事(Markdownファイル)が増えてきたりしたこともあって、サイトのビルドや動作が遅くなるというデメリットが徐々に上回ってきました

共通部分が分かれることより大きいメリット

結局また初期の考えに戻ってプロジェクトを分けることになりましたが、今回は片方はSSG、もう片方はSSRと役割をはっきり分けているため、メリットが大きくなっています。ヘッダー・フッターやその他コンポーネントは同じ内容のファイルを2箇所で同時に管理する必要が出てしまいましたが、一方でそれぞれでしか使わないモジュールやコンポーネントをもう片方では削除することで、お互いに軽量化することができました(メインプロジェクトではグラフのモジュールは使わない、WORKSプロジェクトではブログ記事表示用のコンポーネントは使わない、など)。サイト全体で共通の部分を頻繁に触るということは無いと思うので、メリットのほうが大きいのではないかと感じています。

もし今後PHOTOSページを復活させる、完全に新しいコンテンツをスタートする、などがあるとこのあたりの管理は煩雑になってきそうではあります。一旦はこの形がベストだと落ち着いたというわけです。もし別の形が良いと思い始めたら、またリニューアルしましょう。

技術的な要素

今回リニューアルするにあたって新たに導入した技術要素について紹介します。

microCMS

microCMS国産のヘッドレスCMSで、有名企業への導入も多い今勢いのあるサービスです。個人の趣味利用では無料で使うことができ、何かと使い勝手の悪いContentfulからの乗り換え先として使っています。1周年記事の時点で既にmicroCMSを使ったリニューアルサイトの構築を始めており、またTwitterで要望を送るなどかなり利用していたため、本番公開はしていなかったにもかかわらずかなり使っている気持ちになっています。

このようにTwitterで突然送ったような要望にも素早く応えていただき、ユーザーとして非常に頼りになると感じています。こういうとき国産サービスだと距離が近く感じてありがたいです。

microCMSは基本的にリッチテキストエディタでのコンテンツ編集となり、見出しや太字、引用、箇条書きなど基本的な書式は簡単に設定することができます。また、APIを使って取得した際はHTMLとして返却されるため、Vue.jsにおいてはv-html 属性に入れるだけでコンテンツが表示できます。

一般的なブログサービスとCMSとの違いですが、コンテンツ形式を独自に作成できるところだと思っています。もちろん単純にブログを作成するのであればリッチテキストエディタがあれば十分ですが、やはりNuxt.jsを使ってリッチなサイトにしたいと考えると、自動で作成されるHTMLでは少し頼りないのです。

例えば画像もリッチテキストエディタに追加することはできますが、本文の一部としてimg要素で返ってきてしまうため、source 要素を使った複数形式の出し分けや、figcaption 要素を使った画像の説明の表示などの実装は難しくなっています。また、コードブロックもシンタックスハイライトを実装しようとすると何の言語かという情報も含めなくてはならないため、リッチテキストエディタ上のコードブロックでは不十分なのです。

microCMSはそういった問題も解決してくれます。カスタムフィールド繰り返しフィールドという仕組みがあり、文字列・画像といった入力欄を複数組み合わせて新たなコンテンツ形式を作ることができ、さらに1つの項目に対して複数のコンテンツ形式を繰り返し好きな順番で入力することができるようになっています。上の例で言うと、画像と説明文字列をセットにした本文画像という新しいカスタムフィールドを作り、ブログ本文は通常のリッチテキストと本文画像を好きな順番でいくつでも並べられるようにしています。こうすることで柔軟な記事作成が可能になります。というような複雑な構成にしてもAPI返却の形式がシンプルで分かりやすいのもContentfulと比べたmicroCMSの優位なポイントです。

細かい使い方の話になってしまいましたが、結局言いたいのはmicroCMSは神、ということです。機能アップデートも頻繁に行われており、Twitterなどのやりとりも温かいです。今後ともよろしくお願いします。

Tailwind CSS

続いて紹介するのはTailwind CSSです。こちらも最近アツいCSSフレームワークですが、他のCSSフレームワークとは一線を画すコンセプトになっています。

Tailwind CSSはUtility-Firstというコンセプトを掲げています。従来のCSSフレームワークのように、既にデザインされたパーツをクラスで呼び出すといった形ではなく、よく使うCSSプロパティを簡潔な形で記述できるように作られています。例えば、文字を中央揃えにするtext-align: center;text-center 、ブロックを中央揃えにするmargin-left: auto; margin-right: auto;mx-auto といった具合です。最初は大量のクラスを書き並べることや省略の仕方に違和感がありましたが、慣れてくるとなかなか気持ち良いものです。

もちろんNuxt.js上でも使うことができ、単一ファイルコンポーネントのstyle ブロックの中でも使うことができます。@apply ディレクティブを使えば、独自のCSSに対してユーティリティクラスを適用でき、非常に簡単に好みのデザインを作ることができます。

Tailwind CSSを採用した理由として、自由度と統一性の両立が可能なことがあります。最初はVuetifyなどのいわゆるUIフレームワークも検討しましたが、そこまでユーザーがボタンやリストでいろいろ操作するようなサイトではありませんし、フレームワークを使うとデザインが似通ってしまうという問題もあります。つまりカスタマイズがしにくいのです。一方でTailwind CSSは、UI要素単位ではなくあくまでCSSプロパティ単位でスタイルを当てていきます。ボタンを作るとなっても好きなようにスタイルを当てられるので非常に自由度が高いです。該当するクラスが存在しなければ通常のCSSを書けばいいわけで、そういった縛りの少なさという点でも自由度が高いと言えます。また自由度は高くありつつも、例えば色はbg-gray-200bg-green-600 のようにあらかじめ多彩な色が用意されており、細かい指定になりがちな部分をCSS変数のような感覚で当てはめていくことができます。カラーコードを書かなくても簡単に色を統一することができるのです。パン工房は緑を基調にしたシンプルなデザインにしたいため、必要最小限で好きなようにスタイルを当てられるところがTailwind CSS導入の決め手となりました。

パン工房は極力スマホでもPCと変わらない情報量で見ることができるよう、1カラム下固定メニューというレイアウトにしています。サイドバーなどに気が散らず、最後まで読んだ後に関連記事や他のカテゴリ、他のコンテンツに進んでもらうことを狙ったレイアウトです(実際狙い通りになっているかは分かりませんが)。

SSG

続いてはNuxt.jsのSSG(静的サイト生成)です。リニューアル以前、Nuxt Contentで記事を管理しているときはSSR(サーバーサイドレンダリング)による表示だったため、記事が増えれば増えるほど動作が重くなるという問題がありました。かなり前になってしまいますが、2020年6月にNuxt.jsがAPI通信をしない完全なSSGに対応したので、これは試すしかないと思っていたものです。

SSGはSSRと違い、各ページをHTMLファイルとして事前に生成しておくものになります。表示後の動作はSSRと同じSPA(シングルページアプリケーション)になりますが、初回読み込み時にサーバー側の処理が走らないため、読み込みが素早くなります。サイトの更新もHTMLファイル類をアップロードすればよく、サーバー上でのNuxt.jsのビルドや再起動は必要ありません。今回microCMSを使っていますが、完全静的化によって生成時のみAPIアクセスをするようになり、サイトのアクセスが増えてもAPIアクセスが増えなくなったのが嬉しいポイントです。

実はNuxt Contentを使っていた頃にも一度SSG化を試したのですが、WORKSページで大量のデータやスクリプトを使っている関係か、メモリか何かの上限を超えてしまい生成ができないことに悩まされていました。今回WORKSページだけSSRのまま別プロジェクトに切り出したのもこれが理由です。ABOUTページやCONTACTページなども含め静的な動作のみで問題ないページは今回SSG化することができ、表示までの速度がかなり改善したと思います。

実はLighthouse系の数値がひどいものだったので改善したかったのですが、今回リニューアル後にPage Speed Insightsで測定してみたところあまり数値としては良くありませんでした。処理をブロックしているスクリプトを確認してくださいとのことですが、Google AdSenseのスクリプトだったためあなたがどうにかしてください・・・と言いたくなりました。余談でした。パフォーマンス改善もできたら記事にしてみたいですね。

ちなみにこれまた余談ですが、WappalyzerというChromeの拡張機能を使うと、そのサイトで使われている技術要素を検出して表示してくれます。他のサイトがどういった技術で動いているか見ることができるので面白いです。ちなみにパン工房はこんな感じです。

パン工房のWappalyzerの検出結果画面
WappalyzerによってmicroCMSやNuxt.jsなどが検出されている

関連記事の表示

関連記事自体は記事の最後に必ず載せていましたが、これまではカテゴリとタグの一致度のみを使った非常に簡易的なものでした。カテゴリが一致していると●ポイント、タグが一致する個数に応じて■ポイント、といった具合にポイントを付けていき、全記事の中でポイントの高い順に3件を表示していました。マネーフォワードやLINE Pay系の記事は一致するタグが多くかなり精度は出ていましたが、あまりタグを付けていないちょっとしたTips系記事や、大きなジャンルはかぶっていてもタグがかぶっていない記事は出ないなどの問題がありました。

今回SSG化にあたり、ファイル生成時に一緒に関連記事一覧も作ってしまおうということで、同じプロジェクト内に関連記事を生成する処理を含めています。そして今回はより関連記事の精度を上げるため、TF-IDF法というものを利用しました。TF-IDFは文書中の単語の重要度を計算するための手法で、その文書の特徴語を抽出する時に使われています。形態素解析で各記事から名詞を抽出しTF-IDFを計算、各記事同士のTF-IDFのコサイン類似度を元に関連度を計算しています。このあたりも記事にできたら面白そうです。

本当はより本格的にWord2VecやDoc2Vecといったものも使ってみたかったのですが、自然言語処理については全然知らないのでまた今後勉強することにします。とりあえず現状でもまあまあな精度が出ているかと思います。そもそも関連記事欄がどの程度使われているかは分からないので、こういったこともGoogle Analyticsなど使って調査してみたいですね。

残っている問題

もうリニューアルとして公開してしまったものの、実は残っている問題がいくつかあります。

タグ検索が実は上手くいっていない

このブログには各記事にタグが付いており、それぞれそのタグが付いている記事を検索することができるようになっています(カテゴリも同様です)。カテゴリは問題ないのですが、実はタグは部分一致での検索になってしまっています。つまり、「LINE」タグの検索ページに行くと、「LINE Pay」タグが付いた記事も出てしまうという状態です。

実はタグはmicroCMSの繰り返しフィールド機能でタグ名のみ指定する形で運用しています。タグはポンポン増やすことになり過去にそのタグを使ったかどうかなどの管理が面倒なため、コンテンツ参照機能は使いませんでした。そのためタグごとにidが無く文字列での検索になってしまうのですが、microCMSのAPIの検索クエリでは繰り返しフィールドは部分一致でしか検索することができませんでした。完全一致にできればいいのでフロントで処理をしてもいいですが、ページングなどが上手くいかなくなりそうなので諦めてそのまま公開してしまいました。どの程度需要がある機能追加になるか分かりませんが、機会があれば要望してみようかなと思っています。

TypeScriptの導入を断念

Nuxt.jsはnuxt-tsというモジュールでTypeScriptでの開発・ビルドに対応しており、仕事で使っていることもあるので勉強も兼ねてTypeScriptで開発しようと思っていました。というかかなり終盤までTypeScriptで作っていました。しかし、VSCodeの設定が甘いのか何かライブラリが足りていないのか、解消できないビルドエラーが起こるようになってしまいローカルビルドはできるものの本番ビルドができない状態になってしまいました。また、WORKSページではグラフに表示するために配列やオブジェクトが入り組んだかなり膨大なデータを扱っており、型の管理が難しいという問題がありました(そういう複雑な場合でも安全に開発できるのがTypeScriptだと思ってはいますが)。結局早く公開することを優先し、今までTypeScriptで書いていた型指定などを全て消してJavaScriptでの開発に切り替えています。Nuxt.jsをJavaScriptからTypeScriptに切り替えたり、その逆をしたりは結構時間と労力がかかるものなので、しばらくはTypeScriptの導入はしない気がします。

関連記事の生成が重い

関連記事の生成はNuxt.jsのプラグインという形で行われているため、ページをサーバー側で読み込むたびに全記事の形態素解析、TF-IDFの計算が行われてしまっています。そのためSSGでサイト生成する際も、各ブログ記事の生成のたびに関連記事生成処理が行われてしまっているようで、時間とメモリをかなり消費しています。ここは今後記事が増えていけばさらに重くなっていってしまうところなので、早急な改善が必要です。

generate時に全てのデータを取得し、payloadで各ページに渡すことでこれを回避することはできるはずですが、元々各ページで読み込むようにしていたものをpayloadで渡すように改修したところ上手く動かなくなってしまい、ここも後回しにしてしまった状態です。また、関連記事の生成は別プロジェクトで行ってJSONファイルに出力しそれを読み込むという方法も考えましたが、ブログ更新の手間が増えるので考えものです。

サイト更新が手動

これもリニューアルで改善できていないポイントですが、CI/CD機構を特に用意していないためサイトを更新する際は手動でサーバーでの作業が必要になっています。SSGの場合はローカルでビルドしたものをサーバーにアップロード、SSRの場合はプロジェクトまるごとサーバーにアップロードしてサーバーでビルド、といった具合です。Jenkinsなどでポチッと更新できるのが理想ですね。

厳密にはコンポーネントも共通ではない

プロジェクトを分けても基本的にヘッダー・フッターなどのコンポーネントは共通なので、同じファイルを2箇所に置けば問題ないという話は書きました。しかし厳密には全く同じにはなっていません。メイン側から見ればWORKSページはサイト外への遷移になるため、nuxt-link 要素が使えないのです。逆もまた然りとなり、互いを行き来するためのリンクはa 要素で書くことになっています。これにより、ヘッダー・フッターやパンくずリストあたりのコンポーネントが完全な共通化はできていません。プロジェクトをまたいでコンポーネントを共通化する上手い方法があったら教えてください。

コンテンツが減っている

前回のリニューアル時にもPHOTOSページという写真公開ページを落としていますが、今回もWORKSページの一部コンテンツや、ブログ記事をいくつか落としています。WORKSページのコンテンツについてはあまり見られていないにもかかわらず移植が大変なものだったり、ブログ記事についてはサイトについてのお知らせで既に状況が大きく変わっていたものなどを落としています。コンテンツ量としては減ってしまっていますが、例えばF1情報まとめのページを新設してコンテンツも増やしているので、今後の更新にもご期待ください。

とまあこんな具合に様々な問題も残されていますが、一旦運用できるくらいの状態にはなったので公開に至ったというわけです。

何より作るのが楽しい

1周年記事にも書きましたが、私がブログをやっている理由の大きな1つが、ブログを作るのが楽しいから、です。プログラミングを仕事にする前から趣味でWindowsソフトやWebアプリの開発をしていました。趣味プログラミングのメリットは、自分が作りたいものを作れるということです。もちろん多くの人に使ってもらえるアプリを作りたいという動機で趣味プログラミングをやっている人も多いとは思いますが、こういうアプリ作りたいけどもう既に何個もあるんだよなとか、この機能絶対あったら面白いけど自分しか使わなさそうなんだよなといった、自分以外の利用者のことを考えたプログラミングをしないといけない点があると思います。もちろんブログも完全に自己満足では誰にも見てもらえないので、ある程度見られることを考えて作る必要はありますが、例えば関連記事の計算は自分でロジックを作ってみたいとか、CONTACTページは変な問い合わせが来ないように嫌がらせしてみよう、みたいなことはなかなか多くの利用者のことを考えているとやりにくいことです。開発面でも、ソースコードを公開しない個人プログラミングでは自分さえ分かればいいや、が許される世界なので、非常にリラックスして開発することができます。もちろん上に挙げたような様々な問題があり解決できずにストレスが溜まることもありますが、それを自分のために自分自身で解決していく体験もなかなか楽しいものです。仕事には無い充実感があると感じています(仕事でのプログラミングが楽しくないと言っているわけではないので悪しからず)。

個人的に膨大なデータをまとめて分かりやすく可視化することが好きなので、WORKSページはそういったコンテンツが多くなっています。自己満足のものも多いですが、48・46グループのシングル売上枚数のグラフなんかはファンから見てもかなり面白いグラフになっていると感じています。F1系のコンテンツも今後どんどん増やしていきたいと思っています。自分の好きなデータの可視化を、自分のプログラミングで実現できる、こんな楽しいことがあるでしょうか。もちろん日々知ったこと・考えていることを書けるブログも含めて、こういったことがサイト運営のモチベーションになっています。しばらくは続けられそうです。


というわけで今回は、サイト全体のリニューアルが完了したので技術的な要素やサイト更新のモチベーションについて書きました。書く内容がバラバラすぎて固定の閲覧者はなかなか付かないものだとは思いますが、今後もほどよく適当に更新していきたいと思うので、よろしくお願いします。

それではまた。

関連記事