841-biborokuWebフロントエンドの備忘録

CloudflareのEdge RuntimeとmicroCMSのqパラメータを使ってキーワード検索結果ページを作る

getServerSidePropsで検索ページを作る

pages/search/index.tsx

export const runtime = "experimental-edge";

const Home: NextPage<Props> = ({ posts, keyword, totalCount, categories }) => {
  return (
    <>
      <div className={styles.header}>
        <SearchBox />
        <p className={styles.result}>該当:{totalCount}</p>
      </div>
      <div className={styles.wrap}>
        {keyword === "" && <p>キーワードを入力してください</p>}
        {posts && totalCount > 0 && (
          <>
            <div className={styles.wrap}>
              <div className={styles.archive}>
                {posts
                  ? posts.map((post) => <PostItem key={post.id} post={post} />)
                  : ""}
              </div>
            </div>
          </>
        )}
        {totalCount === 0 && keyword && (
          <p className="notfound">
{keyword}」を含む記事はありません。
            <br />
            キーワードを変更して再検索してください。
          </p>
        )}
      </div>
      <CategoryList categories={categories} />
    </>
  );
};
export default Home;

export const getServerSideProps: GetServerSideProps = async (context) => {
  const keyword = context.query.q;
  const posts = keyword
    ? await getAllBlogList({
        q: `${keyword}`,
        fields: "必要なフィールドだけ取得(指定しなくてもいい)",
      })
    : null;
  const totalCount = posts ? posts.length : 0;
  const categories = await getAllCategoryList({ fields: "title,slug" });

  const data = keyword
    ? {
        posts,
        keyword,
        totalCount,
        categories,
      }
    : {
        keyword,
        totalCount,
        categories,
      };

  return {
    props: data,
  };
};

エッジ ランタイムを設定

export const runtime = "experimental-edge";

クエリ文字列(?q=xxx)の取得

const keyword = context.query.q;

microCMSのコンテンツの全文検索用のクエリパラメータを指定

q: `${keyword}`,

getAllBlogListは、microCMS-SDKのコンテンツの全件取得を行うgetAllContents()メソッドを使っています。

export const getAllBlogList = async (queries?: MicroCMSQueries) => {
 const listData = await client.getAllContents<Blog>({
  endpoint: "blog",
  queries,
 });
 return listData;
};

microCMSのドキュメントにもあるように、完全一致する結果を返してくれるわけではありませんが、そこまで厳密にしなくてもいいのでqクエリパラメータを使いました。

qパラメータによる検索は、コンテンツに関する情報を形態素解析した結果を対象に実施されます。検索語句と一致するキーワードの登録がないコンテンツでも、検索結果に含まれることがあります。正確な部分一致検索が必要な場合は、filtersパラメータのcontainsの使用をご検討ください。

クエリパラメータ q https://document.microcms.io/content-api/get-list-contents#ha8abec0b2f

keywordが未指定のとき

keywordが指定されてないときは全件該当してしまうので、結果を返さないようにpostsを含まないようにしています。(もっといい書き方あるだろう・)

Cloudflare PagesでSSRを使えるように設定

設定>ビルド&デプロイ>ビルドの構成のフレームワークプリセット「Next.js」を選択します。(※Next.js(Static HTML Export)ではなくNext.js)
ビルド コマンド、ビルド出力ディレクトリなど選択時に自動で初期値が設定されます。

設定>functions>互換性フラグにnodejs_compatを登録します。

デプロイして検索結果が表示されたら成功です🎉

失敗・起こったエラー

検索ページだけ作ってデプロイした結果

Error occurred prerendering page "/search". Read more: https://nextjs.org/docs/messages/prerender-error

search/index.tsxにexport const runtime = "edge";を設定

Error: Page /search provided runtime 'edge', the edge runtime for rendering is currently experimental. Use runtime 'experimental-edge' instead.

next.config.jsにruntime: 'edge',を設定

experimental: {
  runtime: 'edge',
},
Error: Page /search provided runtime 'edge', the edge runtime for rendering is currently experimental. Use runtime 'experimental-edge' instead.

search/index.tsxにexport const runtime = "erimental-edge";を設定

00:17:31.819Error occurred prerendering page "/search". Read more: https://nextjs.org/docs/messages/prerender-error
00:17:31.819ReferenceError: self is not defined

ビルドの構成からnext exportを削除したら静的ファイルが全部出力されなくなった・・

ビルドの構成をNext.js(Static HTML Export)からNext.jsに変更して再デプロイしたら「Node.JS Compatibility Error」
「互換nodejs_compat性フラグが設定されていません」とのこと。

ローカルの/search/ページでInernet Server Errorがでる

⚠ You are using an experimental edge runtime, the API might change.

まだ解決できず、ローカルで動作確認するときはコメントアウトしています;

middlewareで設定していたBasic認証が効かなくなった

以前、functions/_middleware.tsでBasic認証を設定をしていましたが、Edge runtimeの設定をしたら該当ファイルを読まなくなりBasic認証が解除されてしまいました。なのでBasic認証はNext.jsのmiddlewareに切り替えて実装することにしました。


追記:sitemap.xmlが生成されなくなっていた

cloudflareのビルドコマンドを変更したときにビルド出力ディレクトリが.vercel/output/staticに切り替わったのにnext-sitemap.config.jsが以前の設定のままだったことが原因でした。
next-sitemap.config.jsの設定を変更し再デプロイで生成されるようになりました。

next-sitemap.config.js

//修正前
module.exports = {
  outDir: './out',
}

//修正後
module.exports = {
  outDir: '.vercel/output/static',
}