10年続いているHeadless WordPressサイトのフロントをリニューアルしたので振り返り

. 今回のリニューアルでは、インフラ環境やフレームワークの変更など、大幅な刷新が行われました。WordPressをHeadless WordPressとして利用しているため、一般的なWordPressサイトと異なる点に注意が必要です。SaaSを組み合わせた複数のサービス構成に変更し、生成系AIやStripeなど新たなサービスも導入されました。技術選定ではRemixに置き換えたり、Clerkに認証系を変更するなど、サービスの導入や切り替えが行われました。今後は生成系AIの改善や広告管理、キャッシュコントロールの調整などが課題として挙げられます。.

広告ここから
広告ここまで

目次

    今回のリニューアルでは、インフラ環境やフレームワークの変更など、見た目以外部分を大幅に刷新しました。

    注意

    このサイトはWordPressで記事を管理しています。ただしHeadless WordPressとして利用しているため、一般のWordPressサイト開発・リニューアルの参考にはならない点をご了承ください。

    ざっくり概要

    このウェブサイトのマネタイズをすこし真面目に考えようと思い立ち、いろいろとサイトに手を加えました。その過程にて、個人的に気になっていたサービスやフレームワークをいくつか導入し、収益化モデルも大きめの変更を加えています。

    この記事では、その背景や使ったツールなどについて簡単に振り返ります。

    背景

    このウェブサイトのインフラコストはだいたい70%くらいがAWS上にあるEC2インスタンスの利用料です。そしてそのほとんどはAWS Community BuilderとAlexaスキル開発者に提供されるAWSクーポンにて賄われています。とはいえドメインの維持費用や導入を検討している(た)生成系AIのコスト負担を考えると、広告などの収益化が欠かせません。

    また、これまで使っていたVercelのHobbyプランで転送量の上限に到達したアラートが来ていたことや、そもそもHobbyプランでの商業利用が禁止されていることから、別のホスティング環境に移行する必要もありました。

    そのため、2023年中旬ごろから業務の合間時間を使ってリニューアルを進めていました。

    サービスの選定を簡単に振り返る

    現在の構成は、複数のSaaSを組み合わせたものになっています。具体的には、次のようなサービスを使っています。

    • フロントエンドアプリケーション: Cloudflare
    • WordPress: AWS ( EC2 )
    • バッチ・イベント駆動系処理: AWS ( EventBridge + Lambda )
    • ユーザー認証: Clerk
    • サイト内検索: Algolia
    • 決済: Stripe
    • ベクトルDB: Supabase
    • 生成系AI ( beta ) : Anthropic / OpenAI

    このうち、EC2とAlgolia以外はほぼ新規で導入したサービスです。EC2とAlgoliaについては現状不満もなく、動かすほうが手間なのでそのまま利用を継続する判断をしました。

    生成系AIの素振り環境からそのまま昇格したサービス群

    移行の検討と並行して、生成系AIを利用したRAGの実験を行っていたのですが、その際に利用していたのがSupabase / Anthropic / OpenAIの3サービスでした。OpenAIはEmbeddingにのみ利用し、回答作成等のテキスト生成部分はAnthropicを利用しています。また、Cloudflare AI Gatewayを中継させる形とし、ある程度APIリクエストをキャッシュできるようにもしてあります。

    ちなみに実行環境については、AWS Lambdaを利用しています。素振り環境ではCloudflare Workersだったのですが、WordPressの記事更新時に処理を実行させるEDA( Event Driven Architecture )を簡単に作ろうと考えた際に、Amazon EventBridgeに寄せるのが良いのではと判断しました。

    本業上触っておきたかったサービス群

    Stripeを入れたかったんです。はい。

    前職で使っていたとはいえ、すでに3年が経過しており、そのころから利用できるAPIなども変わってきています。そのため、なんでもよいからStripeを組み込んだものをリリースして、多少なりと開発経験を取り戻しておきたいという思いがありました。

    今回は広告の表示非表示や簡単なブックマーク機能・そして最上位プランの差別化のためにすこし強引にですが生成系AIを組み込みました。これらの機能を利用できるかできないかの判断や、プランの表示・マイページの取り扱いなどは、ここ1・2年でリリースされた機能をふんだんに取り入れています。

    実際に開発してみると、「そういえばこの機能ないのか」と感じることもあったため、この辺りは社内にフィードバックしています。やはり自社サービスの話をする上では、多少なりとも本番リリースできるものを作っておくほうがよいですね。

    開発時間を減らすために導入したサービス群

    認証系をAWS Amplify ( Cognito User Pools )からClerkに変更しました。理由はかなりシンプルで、AWS AmplifyのUI SDKが持つSSR機能がCloudflareで動かなかったためです。Supabase Authも検討したのですが、1年がかりの開発になってきたことによる焦りもあり、UI Componentsが豊富なClerkを最終的に選択しました。organization機能があるのも気になりますが、個人ブログで企業アカウントのようなものを作るのはYAGNIだろうということで、省いています。

    Amplify / Supabase Authどちらも今回の要件とスケジュールでは厳しかっただけですので、次に何かを作る際にはこちらを使ってみたいなと思っています。

    技術選定について

    これまでのサイトから大きく変わったのは、Next.js Page RouterからRemixに置き換えたことです。Next.js App Routerでもよかったのですが、Cloudflare PagesにデプロイするならRemixも触っておきたいなという好奇心が勝ちました。この辺りに詳しい知人と会話していても、「それNext.jsでよくね?」と言われますし、SaaSのドキュメントやライブラリも大体Next.js前提だったりすることが多いため、どっちが良くてどっちが悪いかについては判断を見送っています。次回のリニューアルではしれっとNext.js App Routerにしているかもしれませんし、React Routerとして生まれ変わったRemixにしているかもしれません。それくらいの温度感です。

    触ってみての個人的な感想としては、「Remixを先に触ってからNext.jsにいったほうが段階的に覚えることができてよいかもしれない」というところでしょうか。サーバー側の処理も含めたReactアプリの開発と、キャッシュ等の状態管理についてまとめてやろうとするのは初心者にはちょっと大変かなーと思う部分もあります。なので先にRemixでアプリ開発の経験を積み、キャッシュの管理などを細かくやりたいと思ったタイミングでNext.js App Routerを触る・・・くらいの学習パスでもよいかなと思います。

    また、生成系AIの処理系統にはLangChain.jsを使っています。RAGや生成系AIアプリ開発の素振りに使っていたコードをほぼそのまま組み込んだことが採用理由の80%くらいだと思ってもらえればです。Amazon BedrockやDifyなどがなかなか良い感じであるとは耳にしますので、どこかのタイミングでそちらに切り替えていく可能性は十分にあります。

    広告について

    配信する広告を自分で決めれるようにするため、Google AdSenseを外しました。ひとまずは以下のようなReactコンポーネントを作成し、アフィリエイトサービスで紹介したい広告を見つけては配列に登録する形で運用しています。

    import { FC } from 'react';
    
    type ValueCommerceAdItem = {
      href: string;
      src: string;
    };
    type ValueCommerceAd = {
      horizontal: Array<ValueCommerceAdItem>;
      square: Array<ValueCommerceAdItem>;
    };
    
    const ads: ValueCommerceAd = {
      horizontal: [
        {
          href: '//ck.jp.ap.valuecommerce.com/servlet/referral?sid=xxxxxx',
          src: '//ad.jp.ap.valuecommerce.com/servlet/gifbanner?sid=xxxxxx',
        },
      ],
      square: [
      ],
    };
    
    export const AdValueCommerce: FC<{
      type?: keyof ValueCommerceAd;
    }> = ({ type = 'horizontal' }) => {
      const targetAds = ads[type];
      const randomIndex = Math.floor(Math.random() * targetAds.length);
      const ad = targetAds[randomIndex];
      return (
        <a href={ad.href} rel="nofollow">
          <img src={ad.src} />
        </a>
      );
    };

    広告の更新にデプロイが必要なことや、「この広告なんだっけ?」となる問題があるため、microCMSなりSanityあたりのHeadless CMSを入れて広告管理をし始める・・・かもしれません。あとはタグをうまく使って、Amazonアソシエイト広告も出せたらなーとは思っています。

    今後について

    生成系AIの組み込みと回答精度にまだまだ改善の余地があるため、ここは引き続き試行錯誤していこうと思います。また、Next.jsのISR ( by Page Router )からRemixにした関係で、キャッシュコントロールをある程度自前でやる必要が出てきています。この辺はまだ全然調整も現状把握もできていない状態です。CloudflareのAnalytics系機能を使って、キャッシュの設定や調整もこの先進めていこうと思っています。

    広告ここから
    広告ここまで
    Home
    Search
    Bookmark