2026年5月。ゴールデンウィークの余暇を利用して、本ブログを Next.js 15 と React 19 へアップデートしようと試みた。
構築当時の記憶では、フロントエンド界隈の「安定化した技術」を選択したつもりであり、今回の作業も「依存関係を修正して、型を合わせるだけ」のルーチンワークで終わる想定だった。
構築当時の記憶では、フロントエンド界隈の「安定化した技術」を選択したつもりであり、今回の作業も「依存関係を修正して、型を合わせるだけ」のルーチンワークで終わる想定だった。
だが、結果から言えば、私は Next.js 14.2 / React 18.3 への切り戻し(ロールバック) という決断を下した。
一見すれば「アップデートの断念」だが、その裏には現代フロントエンド特有の「魑魅魍魎」とした内部仕様の変更と、自身のライフステージの変化に伴う「技術との向き合い方」の再定義があった。
一見すれば「アップデートの断念」だが、その裏には現代フロントエンド特有の「魑魅魍魎」とした内部仕様の変更と、自身のライフステージの変化に伴う「技術との向き合い方」の再定義があった。
1. 楽観的なスタートと、最初のアラート
Next.js 15 への第一歩は、動的ルーティングにおける params や searchParams が Promise に変更される という破壊的変更への対応だった。
コンパイラーに指摘される型エラーを一つずつ潰し、コードを Next.js 15 向けに「翻訳」していく。この時点ではまだ、静的型付けの恩恵と AI の支援に感謝しながら、最後まで走り切れる予感があった。
2. 泥沼の recentlyCreatedOwnerStacks
本当の地獄は、開発サーバー(
画面には 500 エラー。ブラウザのコンソールには、Google で検索しても当時の私には正体不明だった不気味な TypeError が無限に流れていた。
npm run dev)を起動した後に待っていた。画面には 500 エラー。ブラウザのコンソールには、Google で検索しても当時の私には正体不明だった不気味な TypeError が無限に流れていた。
react-server-dom-webpack-client.browser.development.js:2396
Uncaught TypeError: Cannot read properties of undefined (reading 'recentlyCreatedOwnerStacks')
最初は自分のコードの凡ミスを疑い、MDX のレンダリング部分をコメントアウトし、コンポーネントを一つずつ剥がし、ついにはレンダリングを「空」にするまで切り分け作業を繰り返した。数時間に及ぶ泥臭い検証の末に辿り着いたのは、「MDX をレンダリングしようとすると、React 本体のデバッグ機能が自爆している」 という、あまりにも救いのない事実だった。
「Owner Stacks」という親切な自爆装置
React 公式ブログ (Improvements to Error Reporting) によれば、React 19 からは要素の生成元を追跡する仕組みが、従来の Render Stacks から Owner Stacks 方式へと刷新された。
しかし、私のブログのように
next-mdx-remote/rsc を使い、サーバーサイドで動的に VDOM を生成してコンポーネントを注入する構成では、この「親切な機能」が所有権(Owner)を見失い、内部で undefined を参照して自爆してしまう。なんで注入したらこのエラーがでるのか、フロントエンドのメンタルモデルが未熟な私にはメカニズムの想像さえつかない。まして対処法など AI とネットの情報が頼りだ。
この魔物は私だけの問題ではなかった。React 18 環境下であっても、Storybook のような主要な開発ツールにおいてさえ同様の惨状が報告されていることを知り、事態の深刻さを悟った。
3. Chakra UI という「詰み」の宣告
さらに追い打ちをかけたのが UI ライブラリだ。Chakra UI v2 が依存する
Emotion(Runtime CSS-in-JS)は、React 19 が目指す並行レンダリングの世界において、公式に 非推奨に近い扱い となりつつある。Chakra v3 に上げれば解決の芽はあるが、それはもはや別ライブラリへの「強制移住」と言えるほど破壊的で、週末の空き時間で対応できる規模を超えていた。古いままでも死ぬが、新しくしても死ぬ。まさに「詰み」の状態だった。
4. 2019 年からの航跡と、「覚悟」の欠如
私がソフトウェアエンジニアとなった 2019 年当時、React は関数型記法をデファクトスタンダードにし、Next.js は盤石な地位を築きつつあった。「長く続いたと語り継がれるフロントエンド論争に結論が出た」――そう信じて疑わなかった。
しかし、今回経験したメジャーアップグレード前後の断絶は、それらがもはや別物であることを突きつけてきた。バックエンドで慣れ親しんだ「枯れた技術」とは比べるべくもない。
振り返れば、2年前の MDX 導入の際も、私は 本来互換性のないものを無理やり繋ぎ合わせるハック を行っていた。負債に依存させた実装が、土台の崩壊とともに連鎖的に崩れていく様を見て、私に不足していたのは 「使用している技術と運命を共にする」という覚悟 だったのだと痛感した。
5. 戦略的撤退:今の私にとって真に価値あるもの
一晩の試行錯誤を経て、私はアップデートを断念した。
エラーを隠蔽するために
エラーを隠蔽するために
use client を多用し、サーバーサイドの利点を殺してまで最新版に居座ることに、合理性を見出せなかったからだ。フルスタックで領域を抑えると息巻いていた当時とは異なり、選択と集中をせざるを得ない現状を認めざるを得なくなった今の私は、インフラの堅牢性や、爆発的に進化する AI(Generative AI)技術 の活用にリソースを投資すべきフェーズにいる。
フロントエンドの気難しい内部仕様変更に振り回され、貴重な時間を修理に費やすよりも、「確実に動く安定した環境(Last Known Good)」 を維持し、その上でアウトプットを継続することを選択した。
結論
今回の検証は、結果として「アップグレード不可」という結論に終わった。
きっと数年後、この構成の技術は真の EOL を迎え、サイトのクローズを余儀なくされるだろう。だが、それまではこの「延命された Next.js 14」を今の自分の相棒として選び、負債を噛み締めながら、今の自分にとって真に価値のある対象に時間を投資することにする。
エンジニアに求められるのは、常に最新のバージョン番号を追うことではない。「コンテキストに応じて最適な技術を選択し、システムの価値を最大化し続けること」。そのために、時には潔く引き返す「損切りの勇気」も、また一つのスキルなのだと自分に言い聞かせている。