vite、TypeScript、Jestのconfig、setupファイルを見てみる

# 問題
「SyntaxError: "undefined" is not valid JSON」の解決方法 ChakraUI Jest React.js TypeScript
https://qiita.com/like-mountain/items/1551689329b3e1a82f72
上記が解けませんでした。
どこをどう調べればいいのかわからず、そもそもconfig系、setup系のファイルが何をやっているか理解できていませんでした。
まずはそれらを理解する必要があると感じました。

# 分析
Copilotに質問しまくり、それぞれが何をやっているかを理解できるようにしました。

<details open><summary>vite.config.ts</summary>

```vite.config.ts
// Vite の設定ファイル
// TypeScript で記述された Vite の設定ファイルで、プロジェクトのビルドや開発サーバーの設定を行う

import react from '@vitejs/plugin-react';
import { defineConfig } from 'vite';
import tsconfigPaths from 'vite-tsconfig-paths';
import envCompatible from 'vite-plugin-env-compatible';

export default defineConfig({
  plugins: [
    react(),
    tsconfigPaths(),
    envCompatible({
      prefix: 'VITE', // 環境変数のプレフィックス
      mountedPath: 'process.env', // 環境変数をマウントするパス
    }),
  ],
});

// 設定の詳細
// defineConfig
// defineConfig は、Vite の設定を定義するための関数
// TypeScript の型補完が有効になる

// plugins
// plugins 配列には、Vite のプラグインを設定
// この例では、3つのプラグインが設定されている
        // a. react()
        // react プラグインは、Vite で React をサポートするためのプラグイン
        // React コンポーネントを使用した開発が可能になる

        // b. tsconfigPaths()
        // tsconfigPaths プラグインは、TypeScript の tsconfig.json ファイルに定義されたパスエイリアスを Vite で解決するためのプラグイン
        // tsconfig.json に設定されたパスエイリアスを Vite のビルドプロセスで使用できます。

        // c. envCompatible
        // envCompatible プラグインは、環境変数を Vite のプロジェクトに適用するためのプラグイン
        // 特定のプレフィックスを持つ環境変数を読み込み、指定されたパスにマウント

// prefix: 'VITE':
// 環境変数のプレフィックスを指定
        // プレフィックス（prefix）とは、文字列の先頭に付加される特定の文字列や記号のことを指す
// VITE で始まる環境変数が対象となる

// mountedPath: 'process.env':
// 環境変数をマウントするパスを指定
// 環境変数が process.env にマウント
        // 1 .env ファイル
        // VITE_API_URL=https://api.example.com
        // 2 vite.config.ts
        // vite.config.ts ファイルで envCompatible プラグインを使用して、環境変数を process.env にマウント
        // 3 アプリケーション内で process.env を通じて環境変数にアクセス
        // console.log(process.env.VITE_API_URL); // 環境変数を使用
```
</details>


<details open><summary>tsconfig.json</summary>

```tsconfig.json
// TypeScript コンパイラの設定ファイルで、プロジェクト全体のコンパイルオプションやファイルのインクルード/エクスクルード設定を指定
// このファイルを使用して、TypeScript コンパイラがどのようにコードを解釈し、コンパイルするかを制御
// TypeScript におけるコンパイルとは、TypeScript のコードを JavaScript のコードに変換するプロセスのこと

{
        // TypeScript コンパイラのオプションを指定
        "compilerOptions": {
                "target": "ESNext",
                "useDefineForClassFields": true,
                "lib": ["DOM", "DOM.Iterable", "ESNext"],
                "module": "ESNext",
                "skipLibCheck": true,
                "allowJs": false,
                "moduleResolution": "Bundler",
                "allowImportingTsExtensions": true,
                "isolatedModules": true,
                "noEmit": true,
                "jsx": "react-jsx",
                "strict": true,
                "allowSyntheticDefaultImports": true,
                "esModuleInterop": false,
                "forceConsistentCasingInFileNames": true,
                "resolveJsonModule": true,
                "types": ["node", "jest", "@testing-library/jest-dom"],
                "baseUrl": ".",
                "paths": {
                        "@/*": ["./src/*"]
                }
        },
        // コンパイル対象のファイルやディレクトリを指定
        "include": ["src"],
}

// compilerOptions:
// TypeScript コンパイラのオプションを指定する。これには、ターゲットの ECMAScript バージョン、モジュールシステム、型チェックの厳密さなどが含まれる。
// include:
// コンパイル対象のファイルやディレクトリを指定する。
// exclude:
// コンパイル対象から除外するファイルやディレクトリを指定する。
// files:
// コンパイル対象の特定のファイルを指定する。

// compilerOptions の各オプションの解説
// target: "ESNext"
// コンパイルされたJavaScriptのターゲットバージョンを指定する。ESNext は最新のECMAScript標準をターゲットにする。
// useDefineForClassFields: true
// クラスフィールドの初期化に define プロパティを使用する。これにより、クラスフィールドがより標準に準拠した方法で定義される。
// lib: ["DOM", "DOM.Iterable", "ESNext"]
// プロジェクトで使用するライブラリを指定する。DOM と DOM.Iterable はブラウザ環境のAPIを含み、ESNext は最新のECMAScript標準を含む。
// module: "ESNext"
// モジュールシステムを指定する。ESNext は最新のECMAScriptモジュールシステムを使用する。
// skipLibCheck: true
// ライブラリファイル（node_modules 内の型定義ファイル）の型チェックをスキップする。これにより、コンパイル時間が短縮される。
// allowJs: false
// JavaScriptファイルのコンパイルを許可しない。TypeScriptファイルのみをコンパイル対象とする。
// moduleResolution: "Bundler"
// モジュール解決戦略を指定する。Bundler はバンドラー（WebpackやRollup）と同じ方法でモジュールを解決する。
// allowImportingTsExtensions: true
// TypeScriptファイルのインポート時に拡張子を含めることを許可する。
// isolatedModules: true
// 各ファイルを独立したモジュールとして扱う。これにより、TypeScriptのトランスパイルが簡素化される。
// noEmit: true
// コンパイル時に出力ファイルを生成しない。型チェックのみを行う。
// jsx: "react-jsx"
// JSXの構文をReactのJSXトランスフォーマーに変換する。
// strict: true
// TypeScriptの厳格な型チェックオプションを有効にする。これには、noImplicitAny や strictNullChecks などが含まれる。
// allowSyntheticDefaultImports: true
// デフォルトエクスポートがないモジュールでも、デフォルトインポートを許可する。
// esModuleInterop: false
// ESモジュールとCommonJSモジュールの互換性を向上させるオプション。false に設定されているが、true にすると、import と require の互換性が向上する。
// forceConsistentCasingInFileNames: true
// ファイル名の大文字小文字の一貫性を強制する。これにより、異なる大文字小文字のファイル名によるエラーを防ぐ。
// resolveJsonModule: true
// JSONファイルをモジュールとしてインポートすることを許可する。
// types: ["node", "jest", "@testing-library/jest-dom"]
// プロジェクトで使用する型定義ファイルを指定する。node、jest、および @testing-library/jest-dom の型定義が含まれている。
// baseUrl: "."
// モジュール解決の基準となるディレクトリを指定する。"." はプロジェクトのルートディレクトリを指す。
// paths: { "@/": ["./src/"] }
// モジュール解決のエイリアスを指定する。@/ を src にマッピングする。これにより、@/components のようなインポートが可能になる。

// include の解説
// include: ["src"]
// コンパイル対象のファイルを含むディレクトリを指定する。この場合、src ディレクトリ内のファイルがコンパイル対象となる。
```
</details>

<details open><summary>jest.config.js</summary>

```jest.config.js
// Jest テストランナーの設定ファイルで、Jest がどのようにテストを実行するかを制御
// このファイルを使用して、テスト環境、トランスフォーマー、モジュールの解決方法、テストの実行方法などを設定

export default {
        preset: "ts-jest",
        testEnvironment: "jsdom",
        setupFilesAfterEnv: ["./jest.setup.ts"],
        transform: {
                "^.+\\.(ts|tsx)$": "ts-jest", // TypeScript ファイルをトランスパイルするための設定
        },
        moduleNameMapper: {
                "\\.(css|less)$": "identity-obj-proxy", // CSS/LESS ファイルをモックするための設定
                // LESS ファイルは、CSS（Cascading Style Sheets）を拡張したスタイルシート言語である LESS（Leaner Style Sheets）のファイル
                "^@/(.*)$": "<rootDir>/src/$1", // エイリアス設定を追加
        },
};

// ^@/(.*)$:
// ^ は文字列の先頭を示します。
// @/ はエイリアスのプレフィックスです。
// (.*) は任意の文字列にマッチする正規表現です。
// $ は文字列の終わりを示します。
// つまり、@/ で始まる任意の文字列にマッチします。

// <rootDir>/src/$1:
// <rootDir> はプロジェクトのルートディレクトリを示します。
// src は src ディレクトリを示します。
// $1 は、正規表現のキャプチャグループ (.*) にマッチした部分を指します。

// 通常のインポート
// import MyComponent from './src/components/MyComponent';
// エイリアスを使用したインポート
// import MyComponent from '@/components/MyComponent';

// preset:
// Jest のプリセットを指定する。例: ts-jest（TypeScript を使用する場合）。
// testEnvironment:
// テスト環境を指定する。例: jsdom（ブラウザ環境をシミュレートする場合）。
// setupFilesAfterEnv:
// 各テストファイルの実行前に実行するスクリプトを指定する。テストのセットアップやグローバル設定を行うために使用。
// transform:
// ファイルのトランスフォーマーを指定する。例: ts-jest（TypeScript ファイルをトランスパイルする場合）。
// moduleNameMapper:
// モジュールのエイリアスを設定する。特定のパスを別のパスにマッピングするために使用。
// testMatch:
// テストファイルのパターンを指定する。特定のディレクトリ内のファイルをテストファイルとして認識させるために使用。
// collectCoverage:
// カバレッジ情報を収集するかどうかを指定する。
// coverageDirectory:
// カバレッジ情報の出力ディレクトリを指定する。

```
</details>

<details open><summary>jest.setup.ts</summary>

```jest.setup.ts
// Jest テストランナーのセットアップファイルで、各テストファイルの実行前に実行されるスクリプトを定義するために使用される

// @testing-library/jest-dom パッケージをインポートして、Jest のカスタムマッチャを追加する
import '@testing-library/jest-dom';

// require('dotenv').config();
// Node.js 環境で、アプリケーション内で環境変数を設定するためのコード
// 「アプリケーション内」とは、ローカル環境、テスト環境（例えば Jest を使用したテスト環境）、および本番環境など、Node.js が実行されるすべての環境
// require は、Node.js の組み込み関数で、モジュールをインポートするために使用される
// require('dotenv'):で、dotenv パッケージをインポート
// .config():は、dotenv パッケージの config メソッドを呼び出す
// プロジェクトのルートディレクトリにある .env ファイルを読み込み、その内容を process.env オブジェクトに設定
require('dotenv').config();

// structuredClone は、JavaScript のオブジェクトを深くコピーするための標準的なメソッド
// 深いコピーとは、オブジェクトのすべてのプロパティとそのネストされたオブジェクトを再帰的にコピーすることを意味する
// これにより、元のオブジェクトとコピーされたオブジェクトが完全に独立した状態になる
global.structuredClone = (obj) => {
//   console.log("jest.setup.ts", obj);
//   if (obj === undefined) console.log("jest.setup.ts", obj);
if (obj === undefined) return undefined;
  return JSON.parse(JSON.stringify(obj));
};

// structuredClone の特徴
// 深いコピー:
// オブジェクトのすべてのプロパティとそのネストされたオブジェクトを再帰的にコピー
// 循環参照のサポート:
// 循環参照を含むオブジェクトも正しくコピー
// 特殊なオブジェクトのサポート:
// Date オブジェクト、Map、Set、ArrayBuffer などの特殊なオブジェクトも正しくコピー

// JSON.parse(JSON.stringify(obj)):
// オブジェクトを JSON 文字列に変換し、その後 JSON 文字列を再度オブジェクトに変換することで、オブジェクトの深いコピーを作成する方法
// 簡単に深いコピーを作成できる
// 関数やシンボルはコピーされない
// 循環参照を含むオブジェクトはエラーが発生する
// Date オブジェクトや Map、Set などの特殊なオブジェクトは正しくコピーされない
```
</details>


# おわりに
config系、setup系のファイルは苦手ですが、理解しないと解決できない問題がありそうです。
がんばります！