Cloudflare Pages上にJamstack構成で作った趣味ブログをデプロイしてみた感想やtipsについて
Jamstack構成で趣味ブログを作った
趣味のロードバイクに関する話題を扱うブログをCloudflare Pagesで公開しました。作ったばっかりで記事が少ないですし、改善したい点もたくさんありますが、ひとまず公開まではこぎつけたため共有です。
このサイトは以下で作られていますが、今回はCloudflare Pagesの内容に絞って書いていきます。
- Next.js(AppRouter)
- tailwind css(Chakra UIから移行)
- microCMS
Cloudflare Pages を選択した理由
SSGと相性のいいホスティングサービスといえばVercelとNetlifyがまず挙がると思います。この2つも実際に試しましたが、以下の理由で最終的にCloudflare Pagesを選択しました。
Vercelの無料プランでは広告掲載ができない
まず最初に検討したのはVercelでした。理由はNext.jsの開発元が運営しているということもあり、Next.jsとの相性が非常によさそうだったからです。実際に開発段階で使ってみて、特に設定周りを気にすることなくすんなりデプロイすることが出来てとても気に入りました。
ただ、せっかくブログを作るなら広告を貼ってお小遣い稼ぎをしたいと思っていました(強欲)
Vercelの無料プランについて記載のある記事をいろいろと参考にしたところ、現在の利用規約では個人利用であっても広告掲載が明確に禁じられているようでした。参考にさせていただいた記事はこちらです。(コメントでその後の経過が記載されています)
有料プランであるProプランを契約することで商用利用が可能になりますが、その場合月に20ドルの費用がかかります。運営を始めたばかりのブログでは高すぎるという判断で採用を見送りました。
Netlifyはパフォーマンスがいまいち
次に検討したのはNetlifyです。独自ドメインを取得後は実際にNetlifyにデプロイして数日運用していました。
ただし、いろいろな記事で書かれているようにNetlifyは遅いです。Vercelと比較するとNetlifyはTTFBが4~5倍くらい遅かったです。せっかくSSGで作成するのに速度が出ないのは勿体ないなと感じてしまいました。
また、(自分の構成に問題があるのかもしれないですが)Netlify上でビルドが走るタイミングで500エラーが発生することが稀にありました。Vercelでは起きなかったので原因がよく分からず、ホスティングサービスを変えるなら今のうちと思って乗り換えることにしました。
Cloudflare Pagesは無料プランでも商用利用
そんなわけで次にたどり着いたのがCloudflare Pagesでした。
まずは自分の中で重要な、無料プランでも商用利用が可能なのかについて調べました。すると2021年の8月に以下のページで公式から利用可能という回答が出ています。
それに加えてCloudflare Pagesでは無料プランでも転送量の上限が無制限というおまけつきです。あまりにも魅力的すぎるので採用を決めました。
使ってみてどうだったか
前述の2サービスにあるような以下の機能はCloudflare Pagesにも備わっているため、特に困ることなく運用できています。
- gitと連携し、ブランチにpushされたらデプロイ
- デプロイ用のwebookを作成し、microCMS側で記事を更新したらデプロイ
Netlifyでネックだったパフォーマンス面についても改善されました。Vercelと同等くらいの速度が出ています。
SSRができないので注意 →可能(2022/3/23更新)
VercelやNetlifyはSSRに対応しているため、SSGとSSRのハイブリッド構成が可能ですが、Cloudflare Pagesは完全なSSGサイトとしてホストする必要があります(という認識ですが間違っていたら教えてください。。)
具体的には、Next.jsに備わっているプレビューモードのようなSSRが必要となる機能は使えなくなります。私の場合、記事のプレビューはlocalhostで立ち上げたNext.jsアプリでプレビューするという割り切り方をしたのと、これ以外でSSRを利用するページが無かったため問題にはなりませんでした。
コメントでいただきましたが、Cloudflare Workersと併用することでSSRが可能なようです。今のところSSRが必要な機能を実装する予定がないため詳しくは調べられていませんが、時間に余裕があれば調べて記事に使用と思います。
Cloudflare Pagesの設定の注意点やハマった点
前述の通り、当初NetlifyでホストしていたSSGとSSR(プレビュー機能のみ)のハイブリッド構成としていたNext.jsアプリをCloudflare Pagesに移行しました。それにあたってCloudflare Pagesの設定をデフォルトから変更する箇所があったり、エラーが起きた箇所があるので記載します。
完全なSSGサイトとしてホストするための設定
Netlifyでホストしていた時はpackage.jsonのscriptの設定は以下のようになっていました。
{
"scripts": {
"dev": "cross-env NODE_OPTIONS='--inspect' next dev",
"build": "next build",
"postbuild": "next-sitemap --config sitemap.config.js",
"start": "next start",
"lint": "next lint"
},
}
本筋とは外れますが、以下の設定を入れています。
- windows環境で
npm run dev
を動作させるための設定 - サイトマップをnext-sitemapを使って作成するためにpostbuildの設定
この設定を以下のように変更しました。
{
"scripts": {
"dev": "cross-env NODE_OPTIONS='--inspect' next dev",
"build": "next build",
"postbuild": "next-sitemap --config sitemap.config.js",
// ↓追加
"preexport": "npm run build",
"export": "next export",
// ↑追加
// startの設定は不要なので削除
"lint": "next lint"
},
}
その上で、Cloudflare Pagesのビルド設定は以下のように設定します。
ビルドコマンドにnpm run export
を設定することで以下の順にコマンドが実行されることになり、サイトマップの作成処理を走らせたうえでデプロイさせることができました。
-
next build
が実行(preexport
でnpm run build
を指定しているため) -
next-sitemap
のxml作成用コマンドが実行(postbuild
で指定しているため) -
next export
が実行(Cloudflare Pagesのビルドコマンドで指定)
next-sitemapの作成処理でエラーが発生
前述の手順でnext-sitemap
のコマンドが実行されるようになったものの、ビルド時にエラーが発生するようになりました。ログを見たところ以下の内容が出力されていました。
Error: Cannot find module 'node:fs/promises'
Require stack:
- /opt/buildhome/repo/node_modules/next-sitemap/dist/cjs/file/index.js
- /opt/buildhome/repo/node_modules/next-sitemap/dist/cjs/config/index.js
- /opt/buildhome/repo/node_modules/next-sitemap/dist/cjs/cli.js
- /opt/buildhome/repo/node_modules/next-sitemap/bin/next-sitemap
at Function.Module._resolveFilename (internal/modules/cjs/loader.js:966:15)
at Function.Module._load (internal/modules/cjs/loader.js:842:27)
at Module.require (internal/modules/cjs/loader.js:1026:19)
at require (internal/modules/cjs/helpers.js:72:18)
at Object.<anonymous> (/opt/buildhome/repo/node_modules/next-sitemap/dist/cjs/file/index.js:17:36)
at Module._compile (internal/modules/cjs/loader.js:1138:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1158:10)
at Module.load (internal/modules/cjs/loader.js:986:32)
at Function.Module._load (internal/modules/cjs/loader.js:879:14)
at Module.require (internal/modules/cjs/loader.js:1026:19) {
code: 'MODULE_NOT_FOUND',
requireStack: [
'/opt/buildhome/repo/node_modules/next-sitemap/dist/cjs/file/index.js',
'/opt/buildhome/repo/node_modules/next-sitemap/dist/cjs/config/index.js',
'/opt/buildhome/repo/node_modules/next-sitemap/dist/cjs/cli.js',
'/opt/buildhome/repo/node_modules/next-sitemap/bin/next-sitemap'
]
}
調べたところ、Cloudflare PagesのデフォルトのNode.jsのバージョンが12.18.0
であることが原因のようです。環境変数NODE_VERSION
でバージョン16以上を指定することで解消しました。
「pages.dev」のデフォルトドメインをnoindexにする
私のブログは独自ドメインを割り当てていますが、Cloudflare Pagesを初期設定したときに自動で割り当てられるpages.dev
ドメインも有効のままになっています。複数のURLでアクセスできてしまうと、重複コンテンツとみなされてしまいSEO的に不利になるため対策が必要です。
調べたところ、このpages.dev
ドメインを無効にして独自ドメインだけを有効にするという設定は存在しないようです(もし設定できる場合は教えてください)。仕方ないので、pages.dev
ドメインはgoogleにindexされないように対策をします。
Cloudflare Pagesの場合、アプリのルート直下に_headers
というテキストファイルを設置し、そのファイル内にURLのルールとレスポンスヘッダを記載することで、特定のURLにアクセスされた際に設定するレスポンスヘッダを制御することが可能です。
具体的には、私のブログの場合は以下のように設定した_headers
ファイルをpublicフォルダの直下に設置しました。
https://ebifran-roadbike-blog.pages.dev/*
X-Robots-Tag: noindex
こうすることで、pages.dev
ドメインにアクセスされた場合はX-Robots-Tag
にnoindex
を付与し、独自ドメインにアクセスされた場合は何も付与しない、という挙動にできました。
pages.dev
ドメインの場合
独自ドメインの場合↓
まとめ
ホスティングサービス選びについて紆余曲折ありましたが、今のところはCloudflare Pagesを選択して正解だったと思っています。この記事が何かの参考になればうれしいです。
Next.jsとmicroCMSで開発してみて得た知見などは、また別の機会に記事にしようと思います。
Discussion
プレビュー部分のみクライアントサイドレンダリングにするか、Cloudflare WorkersをAPIに利用することで、プレビューできるかと思っていたのですが、いかがでしょうか?
追記: サーバーサイドレンダリングできそうです。 https://blog.cloudflare.com/cloudflare-pages-goes-full-stack/#:~:text=Use server-side rendering,HTML responses with dynamic data.
コメントありがとうございます。自分では詳細を調べられていないですが、いただいた内容を本文に反映しました。
私も一通りの開発を終え、2ヶ月前に無責任に書いたコメントの修正に戻って参りました。下書き画面プレビューの方法は、
以上、この記事を読んで助けられている私のような人の参考になれば。