[Next.js v15 ✖️ Notion API]ブログの速度改善 + Notion APIの画像が1時間でリンク切れする問題の解決
2025/03/16 公開
はじめに
1ヶ月前、ブログを Next.js ✖️ Notion APIを用いて、個人ブログを作成しました。
ブログを書いていると記事量が多い場合あまりにも表示速度が遅いことに気づき(体感5秒以上かかっていました)、これでは誰も読んでくれない悲しいサイトになってしまうと思い改善してみることにしました。
速度が遅くなった原因
結論から言うとforce-dynamic
を設定していたただけでキャッシュも何も設定していなかったので、**毎回サーバーサイドで動的にレンダリング(SSR)**していたためです。(記事のブロック数が多くなってNotion APIが遅くなっているというのも関係はあると思います)
export const dynamic = "force-dynamic"; export default async function Page() { const res = await fetch( `${process.env.NEXT_PUBLIC_BASE_URL}/api/posts?category=all`, { method: "GET", headers: { "Content-Type": "application/json", }, }, ); ... }
(そりゃキャッシュもなく毎回新しいデータ取得してたら重いよな…😇)
ということでfetch時にrevalidateパラメータを入れれば**一度生成されたページは、再生成のタイミングを指定しキャッシュとして保持し、定期定期に再生成されるようになる(ISR)**ので設定してみました。
正直ブログサイトでそんなに頻繁に更新もしないので(週一更新は目指しております🙇🏽♀️)10分より全然長くしても問題ないとは思いますが、検証のため10分にしております。
export default async function Page() { const res = await fetch( `${process.env.NEXT_PUBLIC_BASE_URL}/api/posts?category=all`, { method: "GET", headers: { "Content-Type": "application/json", }, // 10分キャッシュ next: { revalidate: 60 * 10 }, }, );
設定すると記事詳細で毎回表示に5秒くらいかかっていたのが大体1-2秒で表示されるようになりました。
画像がリンク切れしてしまう問題発生
記事の表示速度はかなり改善されたものの、たまにブログの画像が表示されない問題が新たに発生しました。😇ただ、リロードすれば問題なく表示されます。
これは、Notionに画像を登録すると一時的にNotionのS3に一時的な署名つきURLで登録され、URLは1時間だけ有効だからです。公式ドキュメントにも記載されていました。
https://developers.notion.com/docs/working-with-files-and-media
SSRでは毎回新しいデータを取りにいくのでこの問題が発生しなかったものの、ISRにしたことで古い画像URLをキャッシュしている影響で画像が切れる時があります。
画像がリンク切れしてしまう理由についてはこちらの記事の説明がわかりやすかったので載せておきます。
https://alpacat.com/posts/solution-to-image-url-expiration
リンク切れの対策
このリンク切れ問題の対策方法として考えられるのは、
- デプロイを定期的に実行して画像URLの期限が切れないようにする
- SSRに戻す
- 画像取得だけ動的に行う
- 外部ストレージを利用する
- publicフォルダに画像を配置する
などがあると思います。私は外部ストレージ利用を選択しました。理由としましては手間とパフォーマンスの問題を考えた時外部ストレージ利用がこの中ではまだ最適解だと思ったからです。
詳細な理由はこちらです。
デプロイを定期的に実行: 1時間に一回デプロイ設定の手間(github actions使えば可能ではあると思います)とデプロイするたびにキャッシュが切れてしまう。
SSRに戻す: 画像切れの問題は解決するが、表示速度の問題が再発するので100%なし。
画像取得だけ動的に行う: useSWRなどを利用すれば可能ではあるものの、いつ取得し直すとか考慮することが増える。OGPなど外部においた画像は結局画像切れ起こすことになりそう。
外部ストレージを利用する: 無料枠(サービスによるが2GB - 5GBが無料)を超えたら画像配置に費用が発生してしまったり、別で作成した画像URLをNotionに貼り直すのだけ懸念はあるが画像切れの心配がなく、パフォーマンスも安定する。
publicフォルダに配置: 費用が発生しないかつ画像切れの問題は発生しないと思うが、publicフォルダへの画像配置が手間(配置に毎回デプロイ必要)
外部ストレージ利用について
外部ストレージを利用することに決めましたがやはりお金はかけず、簡単に配置できるサービスが良いです。そこで私は、Cloudinaryを選択しました。
Cloudinary
を選んだ理由としては、アカウント登録してすぐ利用できる点や無料枠で結構充実している点です。Amazon S3
やGoogle Cloud Storage
も選択肢として考えましたが、別に複雑な設定がしたいわけでもないし、個人ブログで使うにはちょっと過剰な気がしてやめました。
Cloudinary
の無料枠についての詳しい説明はこちらの記事が参考になりました。
https://zenn.dev/price/articles/fe1a06c7b04472
画像を1GBまで登録できそれを超えるとクレジットというものが使われ、それも使い切ったら課金という流れになるみたいです。
私のブログでは、メイン画像0.5MBとあと1,2個画像があって1記事あたり1MBだと考えると、1000枚くらいは問題なく登録できる想定なので特に問題ないとは思っております。
Cloudinary
の使い方としてはアカウント登録後に、下図のようにUlploadボタンから画像を登録できます。管理画面だとNameがランダム生成されてしまってなんのファイルか少しわかりづらいのでAPI経由であれば名前を決めれるらしいのでAPIで画像を登録しても良いかもしれません。
あとは
- Notionで登録していた画像を
Cloudinary
のURLに置き換え next.config.ts
のremotePatternsでCloudinary
のURLを設定- Notion APIの呼び出し方の変更
// 修正前 const mainImage = post.properties.main_image.files[0]?.file.url; // 修正後 const mainImage = post.properties.main_image.files[0]?.external.url;
これで画像が切れてしまう問題が解決できました!👏
最後に
キャッシュを入れて速度改善すればすぐ終わる話かと思えば、まさかのNotion APIの思わぬ仕様に出会ってしまいました。。。
とりあえず解決したとはいえまだ1,2秒でも遅いですし、執筆中の記事確認をローカル環境でしたりとまだまだ改善するところはあるので引き続き執筆と運営頑張っていきたいと思います。
ここまで読んでいただきありがとうございました!