
こんにちは、SmartHR の基本機能の開発を担当しているプロダクトエンジニアの sakata です。
先日、担当しているプロダクトのフロントエンドテストフレームワークを Jest から Vitest へ移行しました。 その過程で直面した、モノレポ(monorepo)における React バージョンの不整合に関するエラーとその解決方法について解説します。
モノレポの構成と React バージョンの混在状況
私が担当しているプロダクトでは pnpm の Workspace という機能を使って1つのリポジトリで複数のプロダクトのコードを管理するモノレポの形を取っています。
ディレクトリ構造はざっくりとですが以下のようになっています。
.
├── package.json
├── pnpm-workspace.yaml
└── apps
├── app1 (react@18)
│ └── package.json
└── app2 (react@19)
└── package.json
共通して使用するライブラリはルートの package.json に定義し、各プロダクトでのみ使用するライブラリはそれぞれの package.json に定義しています。
また、各プロダクトで使用している React のバージョンは異なっています。
Vitest実行時に発生したエラー
app1 のフロントエンドテストフレームワークを Jest から Vitest へ移行しようとしたところ、Vitest の実行時に以下のエラーが発生しました。
# テスト実行時のエラー(一部抜粋) A React Element from an older version of React was rendered. This is not supported. It can happen if: - Multiple copies of the "react" package is used. - A library pre-bundled an old copy of "react" or "react/jsx-runtime". - A compiler tries to "inline" JSX instead of using the runtime.
う〜ん、何が起きているんだろう。React のバージョンが原因になっていそうということは分かります。 アプリケーション自体は問題なく動くので、テストの実行環境に問題がありそうです。
エラー原因の調査と分析 ── pnpm whyによる依存関係の解明
はじめに、エラーの内容から app1 と app2 で使用している React のバージョンを揃えることで解消されるのではないかと考えました。
app2 で使用している React を v18 に戻すのは避けたいので、app1 で使用している React を v19 にアップデートするのが理想的です。
しかしながらプロダクトの規模が大きく、一朝一夕でアップデートすることが難しいので、もう少し根本原因を深ぼってみることにしました。
pnpm why コマンドで依存関係を調査
pnpm why コマンドを使って React のバージョンがどのように解決されているか調べてみました。
以下は pnpm why コマンドで出力されるログの内容を便宜的に修正したものです。
% pnpm why react -r ルートの package.json で定義しているライブラリ devDependencies: @testing-library/react 16.3.0 ├── react 19.1.0 peer └─┬ react-dom 19.1.0 peer └── react 19.1.0 peer (省略) app1の package.json で定義しているライブラリ dependencies: @dnd-kit/core 6.3.1 ├─┬ @dnd-kit/accessibility 3.1.1 │ └── react 18.3.1 peer ├─┬ @dnd-kit/utilities 3.2.2 │ └── react 18.3.1 peer ├── react 18.3.1 peer └─┬ react-dom 18.3.1 peer └── react 18.3.1 peer (省略)
上記を見ると、ルートの package.json に定義している @testing-library/react が React v19 に依存しており、app1 で定義しているライブラリは React v18 に依存していることが分かります。
app1 のテストコードでは @testing-library/react を利用しているため、テスト実行時に要素を作成する処理は React v18、要素を描画する処理は React v19 で行われることになり、React バージョンの不整合が起き、エラーが発生したと考えられます。
このことから、アプリケーション自体は問題なく動作し、テスト実行時にのみエラーが起きるという点も納得です。
解決策 ── Reactに依存するライブラリの配置場所変更による解決
今回は、React に依存しているライブラリを各プロダクトの package.json に定義するという解決方法を取りました。
これにより、@testing-library/react が React v18 に依存するようになり、テスト実行時のエラーが解消されました。
% pnpm why react -r --filter app1 app1の package.json で定義しているライブラリ dependencies: @dnd-kit/core 6.3.1 ├─┬ @dnd-kit/accessibility 3.1.1 │ └── react 18.3.1 peer ├─┬ @dnd-kit/utilities 3.2.2 │ └── react 18.3.1 peer ├── react 18.3.1 peer └─┬ react-dom 18.3.1 peer └── react 18.3.1 peer devDependencies: @testing-library/react 16.3.0 ├── react 18.3.1 peer └─┬ react-dom 18.3.1 peer └── react 18.3.1 peer
おわりに
今回発生したエラーの原因を調査する過程で、pnpm の Workspace 機能の仕組みや pnpm why コマンドの使い方など、多くの学びがありました。
本記事が同じ現象でお困りの方々の解決の一助になれば幸いです。
We Are Hiring!
SmartHR では一緒に SmartHR を作りあげていく仲間を募集中です!
少しでも興味を持っていただけたら、カジュアル面談でざっくばらんにお話ししましょう!