🐋

VitestのProject設定環境で「React is not defined」が出る理由と対策

に公開

導入(なぜこの記事を書くのか)

React 19とVitest 3.2.4を使用したプロジェクトで、「React is not defined」エラーが発生しました。
当初は設定の不整合と考えていましたが、結局のところ、VitestでProject設定を使っており、それぞれでpluginの指定をしていなかったことが原因でした。

TL;DR どうやったら解決するの?

Vitestで複数のProject設定を使用している場合、各プロジェクトに独立してplugins: [react()]設定が必要です。メイン設定のプラグインは継承されないようです。

発生した問題

vitestでテストを実行していると以下のようにReactインポートエラーが発生しました。
コンポーネント自体は正常に動作していました。

FAIL src/components/app/__tests__/****.test.tsx
ReferenceError: React is not defined

React 17+ ではimportは必要ないはずでは...??

React 17で導入された新しいJSX Transformにより、JSXを使用する際にReactの手動インポートが不要になりました。追加で@vitejs/plugin-reactをインストールすれば、Vitestでも同様に不要になります。

vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [react()]
})

VitestのProject設定を行っていた

VitestではProject設定を使用して、単一のvite.config.tsで複数の異なるテスト環境を管理できます。
これにより、単体テストと統合テストをvitestのフレームワークで一度に実行できるため、
本プロジェクトでは、Vitestのproject設定を利用していました。

vite.config.ts
export default defineConfig({
  test: {
    projects: [
      // プロジェクト1:単体テスト
      {
        name: 'unit',
        test: {
          setupFiles: ['./unit-setup.ts'],
          exclude: ["**/*.integration.test.{js,ts,jsx,tsx}"],
          include: ["src/**/*.test.{js,ts,jsx,tsx}"],
        }
      },
      // プロジェクト2:統合テスト  
      {
        name: 'integration',
        test: {
          setupFiles: ['./integration-setup.ts'],
          include: ["**/*.integration.test.{js,ts,jsx,tsx}"],
        }
      }
    ]
  }
});

参考URL:https://vitest.dev/guide/projects

エラーが発生していた設定

pluginsの設定は両者共通だったため、以下のように設定していました。

vite.config.ts
const integrateConfig: TestProjectConfiguration = {
  test: {
    // テスト設定
  },
};

const unitTestConfig: TestProjectConfiguration = {
  test: {
    // テスト設定
  },
};

export default defineConfig({
  plugins: [react()],  // ← 共通なので、ここで定義していた
  test: {
    projects: [integrateConfig, unitTestConfig],
  },
});

どうやらpluginsの設定はそれぞれのプロジェクトの設定には引き継がれないようで、
以下のように修正する必要がありました。

修正した内容

vite.config.ts
const integrateConfig: TestProjectConfiguration = {
  plugins: [react()],  // ← 各プロジェクトごとに設定が必要
  test: {
    // テスト設定
  },
};

const unitTestConfig: TestProjectConfiguration = {
  plugins: [react()],  // ← 各プロジェクトごとに設定が必要 
  test: {
    // テスト設定
  },
};

export default defineConfig({
  plugins: [react()],  // ← メイン設定
  test: {
    projects: [integrateConfig, unitTestConfig],
  },
});

これでバッチリ、通過するようになりました!

感想

Claude Codeを使っていてこのエラーに直面しました。なんとか直ったので、ブログ記事を書こうとして再検証していたら、ほとんど意味のない変更ばかりでした。意味のない変更の方は、付録として載せておきます。
ちゃんと再検証しておいてよかった〜という気持ちと、断片的にVitestとtsconfigに詳しくなってしまった徒労感がすごいです。検証はClaudeCodeにやらせたので、手間はかかっていません。(APIをめちゃくちゃに食い尽くすので良くない)AIに振り回されず、俺達が振り回そうな、ということでまた業務に戻ります。

参考資料

環境構成

  • React 19.0.0
  • Vitest 3.2.4
  • @vitejs/plugin-react 4.6.0
  • TypeScript 5.x
  • Next.js 15.3.5

付録: 不要だった設定(検証済み)

以下にやってみたけど意味のなかった例を書いておきます。参考になれば幸いです

vite.config.ts
// ❌ 不要だった設定
export default defineConfig({
  plugins: [react(
  // jsxImportSource: "react"  ← デフォルトで"react"なので意味なし
  )],
  esbuild: {
    jsx: "automatic",  // これもうまくいかない
    jsxInject: `import React from 'react'`, //試してないけど、リファレンスには書いてある。テストケースに直接書いても無駄だったので、これもだめだと思う。
  },

});

参考URL: https://www.npmjs.com/package/@vitejs/plugin-react
参考URL: https://ja.vite.dev/config/shared-options.html#esbuild

tsconfig

tsconfig.json
{
  "compilerOptions": {
    "jsx": "react-jsx",  // ← preserve から変更
    "jsxImportSource": "react"
  }
}

こうするとnext devを実行した際に自動的に書き換えられてしまいます:

 Starting...

We detected TypeScript in your project and reconfigured your tsconfig.json file for you.
The following mandatory changes were made to your tsconfig.json:

    - jsx was set to preserve (next.js implements its own optimized jsx transform)

Discussion