← ブログに戻る
EngineeringBuild in PublicSEO

Next.js のページが Bing には大きすぎた。RSC ペイロードが HTML の 58 %

Next.js の 3 ページが Bing で「検出されたがクロールされていない」のまま。App Router は全バイトを 2 回送る。1 ページを 48 KB 削ったらインデックスされた。

2026年10月8日

Next.js のページが Bing には大きすぎた。RSC ペイロードが HTML の 58 %

Katto は AI による動画クリッピングツールです。長い動画を渡すと、見どころを見つけて字幕つきの縦型クリップに切り出します。私は Next.js の App Router を使い、ひとりで、公開しながら開発しています。この記事は、ページの書き方を変えた計測と、人前で自信を持って出して間違っていた数字と、108 バイトの価値しかなかった私の仮説についてです。

症状

Bing Webmaster Tools が、いくつかのページを「検出されましたがクロールされていません」と表示していました。robots.txt でブロックしておらず、noindex でもなく、遅くもなく、リダイレクトもしていません。検出され、そのまま放置される。Google はインデックスしていました。サイトマップにも載っていました。誰が叩いても 200 を返していました。

拒否されたページには共通点がひとつあり、それは内容ではありませんでした。

境界と、私たちがそれをどれほど知らないか

Microsoft はクローラーが諦めるサイズを公表していません。手元にあるのは自分たちのページだけです。Bing Webmaster Tools で読み取った状態と、同じ日に bingbot のユーザーエージェントで非圧縮のまま測った配信サイズです。

線の向こう側にページが 1 枚あるだけでは法則になりません。ただしこのリストには、残り全部より価値のある観測がひとつ含まれています。同じ URL が 2 回登場しているからです。/compare/ai-video-clippers は 172,295 バイトを配信し、何週間も「検出されたがクロールされていない」のまま止まっていました。約 124 KB まで削りました。今日はインデックスされていて、サイズは 127,951 バイトです。同じ URL、同じテンプレート、同じ種類の内容で、大きすぎた状態から、十分小さい状態へ。

1 週間前の私なら別の数字を出していて、それは間違いでした。3 件の状態と、サイズ分布にあった目立つ空白があり、そこに 125 KB 付近の境界を読み込んでしまったのです。そのうち 2 ページはその後、128 KB をわずかに下回るサイズでインデックスされました。自分のサイトが本当に言えるのは、線は 128 KB から 140 KB のあいだにあり、その向こう側はいまだに正確にページ 1 枚ぶんの幅しかない、ということだけです。

数字を求めて来たのなら、正直な答えは「自分で測ってください」です。私が擁護できる主張はもっと狭く、そしてどのみちもっと役に立ちます。検出で止まったページは、書き直す価値を考える前に重さを量る価値がある。そして、小さくしたあとにクロールされ始めたページこそ、本当に意味のある唯一の証拠です。

ソースファイルを量っても何もわからない

ここからが React Server Components に固有の話です。App Router はレンダリング済みのツリーを同じ HTML ドキュメントの中に、self.__next_f.push(...) というスクリプトタグの連なりとしてシリアライズします。クライアント側のナビゲーションが往復なしで再開できるようにするためです。このペイロードはクローラーが飛ばせる別リクエストではありません。ドキュメントの中にあります。

あるページで測ると、配信 125,981 バイトのうち 73,571 バイトがそのペイロードでした。ドキュメントの 58 パーセントが、残り 42 パーセントがすでに言っていることのシリアライズされた複製です。

つまり 24 行のループの中に 1 回書いたユーティリティクラスは、24 回送られるのではありません。48 回送られます。

いちばん気づくのに時間がかかったこと

これはページを倍にするのではありません。ページがすでに抱えている「表現」ひとつひとつを倍にします。

私たちのロードマップは、各項目を意図的に 2 回描いていました。1 回は見える本文として、もう 1 回は JSON-LD の ItemList ブロックの中に。機械の読み手に、名前と日付とステータスを解釈すべき散文ではなくデータとして渡すためです。筋は通っています。そのうえで、ある 1 項目の説明文が配信ドキュメントに何回現れるか数えたら、4 回でした。

表現が 2 つ、それぞれが倍。同じ文の複製が 4 つ。数えるという発想がそれまでありませんでした。

直し方は圧縮ではありませんでした。JSON-LD が持っていた description は、読者が 30 行下で見るのとまったく同じ文を、同じ言語で複製していただけでした。得るものはなく、4 つの複製のうち 2 つを食べていました。削ると、ブロックには名前と日付とステータスが残ります。散文が機械に明示しないのはまさにそこです。このページは 121,196 バイトから 115,350 バイトになり、情報は何も失われませんでした。どちらの数字も同じビルドの、その 1 箇所の変更の前と後です。前後比較が意味を持つのはこの形だけです。

ここから習慣をひとつ持ち帰るなら、これです。何かを軽くしようとする前に、自分の内容の 1 文が配信ドキュメントに何回現れるかを数える。セクションの重さを量っても答えの出ない問いに、これは答えます。

もっと大きい 2 つのてこ

繰り返されるクラス属性をスタイルシートの規則へ。 Tailwind のユーティリティは書くのが驚くほど安く、そしてすべての要素に、2 回ずつ乗って出ていきます。繰り返しの多いものを @apply の規則に移すと、料金インデックスは 172,295 バイトからおよそ 142,000 バイトになりました。それがマークアップの約 51 パーセントでした。

非インタラクティブなブロックをシリアライズ対象のツリーから出す。 正確に言うと、ここは大事です。これらは Server Components なので、クライアントでハイドレートされることはありません。コストはハイドレーションではなく、シリアライズです。クライアント側のナビゲーションが往復なしでツリーを再構築できるよう、要素も props もキーもすべてフライトペイロードに書き込まれます。クライアント側の振る舞いを持たない静的な表でもその代金を払いますし、制約がドキュメントサイズである以上、それが React の要素のままである理由はありません。今はそうしたブロックを、同じデータから HTML 文字列として組み立て、dangerouslySetInnerHTML で差し込んでいます。エスケープがデータの出どころに依存しないよう、補間する値は組み立て時にすべてエスケープします。料金インデックスでさらに 18 KB。ロードマップの 54 行のリストは同じやり方で 157,308 から 119,031 になりました。

うまくいかなかったこと

その前の私は、原因はコンポーネント境界だと確信していました。リストの中に next/link が 54 個あり、それぞれがシリアライズされた名前と props とキーをペイロードに足している。54 個すべてを素のアンカーに置き換えました。

157,200 バイトのうち 108 バイトの節約でした。

Link は安い。それが包んでいる中身が高い。前後を測っていなければ、私はこの仮説のもとに丸一日コンポーネントを書き直していたはずで、この否定的な結果こそその日いちばん役に立った数字でした。

床があり、そして低くない

いちばん軽い実在のページ /contact は、見出しと短いフォームといくつかの質問しか載せていないのに 46,111 バイトを配信します。残りはナビゲーション、フッター、解析、フォントです。この数字より下では、ページ単位で取れるものはもうありません。やるならページの仕事ではなく、外殻の仕事になります。床を知っていると、いつやめるべきかがわかります。

翻訳が食うのはバイトであって語数ではない

このロードマップを 10 言語にしました。同じマークアップ、同じ構造、同じ情報です。英語ページは 116,239 バイト、フランス語は 119,838、日本語は 122,155、ヒンディー語は 135,379 バイトを配信します。

デーヴァナーガリーは UTF-8 で 1 文字あたり 3 バイト、ラテン文字は 1 バイトです。そしてペイロードがそれをもう一度払います。ページ単位の技法ではここに手が届きません。同じマークアップ、同じ情報で、19 キロバイトの差です。

面白いのはヒンディー語ページです。135,379 バイトというのは、私たちが決着をつけられない帯のちょうど内側だからです。Bing がこれを処理するかどうかは、手持ちでいちばん安い実験で、URL 検査 1 回で済みます。

ここにはかつて、超過分は大して問題ではないと主張する段落がありました。超過はドキュメントの末尾に落ち、そのページの末尾はどのみちタイトルが英語のままのリストだから、という理屈です。削りました。クローラーが予算を使い切るまで読んでそこで止まる、と前提しているからです。私が実際に観測したことが言えるのは、ある大きさを超えたページは処理されない、それだけです。ドキュメントが丸ごと拒否されるなら、並び順は何も買えませんし、どちらの証拠も私は持っていません。自分のページについての心地よい理屈であり、そういうものこそ真っ先に消す価値があります。

これは修理ではなく予算

172,295 バイトから 124,202 バイトに落とした料金インデックスは、今日 127,951 バイトです。ツールが増え、列が増え、翻訳が 10 言語増えたからです。それでもインデックスされている、そこが肝心なところで、同時に線まで数キロバイトのところまで戻ってもいます。何も失敗していません。ただ、見張らないまま予算をまた使っただけです。

これが本当の結論です。自分の出力をシリアライズするフレームワークでは、ページの重さは一度やれば終わる掃除ではありません。誰かが良い仕事をするたびに上がっていく数字であり、唯一の防御はソースではなく配信されたドキュメントを、一度に 1 つの変更ずつ測ることです。

自分のページを測る手順

関連記事

動画をバズるクリップに変える準備はできましたか?

Katto は長尺動画を自動でクリップ化・字幕付け・リフレームし、ショート動画に変換します。

Katto を無料で試す →