TS×React import時のpathを絶対パスで書こう！

# 投稿目的
<ul>
<li>よりよい方法をご教授いただきたい</li>
<li>現場での対応の備忘録</li>
</ul>



# 本題
## きっかけ
上長「`import`文を書く際、絶対パスで`path`を記載するようにしましょう」
現場ぼく「承知いたしました(｀･ω･´)ゞ」

`src`配下のファイル同士で`import`をする際、`src`ディレクトリを基準としたパスで`import`文の`path`を記述したいです。
下記のようなディレクトリ構成だとすると、`Page.tsx`内で`Type.d.ts`にて定義された`type Example`を使用したい場合、下記のような感じで記述したい、というイメージです。
とにかく、相対パス(`"../types/Type"`)での`path`記述をやめたい、とご理解ください。
>`import { Example } from "types/Type";`
```
root
|
├── public
├── src
|    ├── pages
|    |     └─ Page.tsx
|    └── types
|          └─ Type.d.ts
├── index.html
├── package.json
├── tsconfig.json
├── tsconfig.app.json
├── tsconfig.node.json
└── vite.config.ts
```

## 環境について
`TypeScript`×`React`×`vite`のプロジェクトです。
主なパッケージ、バージョン、コマンドは以下のようになっているものとします。
```package.json
{
  "scripts": {
    "dev": "npm run build && vite --host",
    "build": "tsc -b && npm run format && vite build",
    "format": "prettier --write src/**/*.{js,ts,jsx,tsx} && npm run lint",
    "lint": "eslint .",
    ...
  },
  "dependencies": {
    "react": "^18.3.1",
    ...
  },
  "devDependencies": {
    "typescript": "~5.6.2",
    "typescript-eslint": "^8.11.0",
    "vite": "^5.4.10"
    ...
  }
}
```
今回は、`tsconfig.json`では具体的な設定を書かず、アプリケーションの設定は`tsconfig.app.json`に記述するものとします。
```tsconfig.json
{
	"files": [],
	"references": [{ "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" }]
}
```

## `alias`を設定して`path`を記載するようにしてみる
`tsconfig.json`に[`compilerOptions.baseUrl`](https://www.typescriptlang.org/tsconfig/#baseUrl)を設定することによって、`TypeScript`が`import`したいモジュールを探す際に基準となるディレクトリを設定することができます。
また「相対パスを使わずに書いているよ~」ということを分かってもらうために「`@src`」というprefixを`import`時の`path`に記載しようと思い、[`compilerOptions.paths`](https://www.typescriptlang.org/tsconfig/#paths)を設定しました。
今回の場合、`baseUrl`が`/src`、`paths`内の`@src/*`は`/src/*`、つまり`src`ディレクトリを指すようなaliasとして設定されました。
よって、下記のように`import`文を記述できます。
>`import { Example } from "@src/types/Type";`

```tsconfig.app.json
{
	"compilerOptions": {
		"baseUrl": "src",
		"paths": {
			"@src/*": ["*"]
		},
        ...
	},
    ...
}
```

各ファイルの`import`文の記載を更新してみると、エラーがなくなり期待通り`import`できるようになりました!
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519885/fe0e1166-480b-19b0-a98d-845c39b3da17.png)

`push`してプルリク作るぞ~と思い`npm run build`(ビルドコマンド)を実行すると、`ESLint`のエラーチェックは通過して、下記のような`vite`のエラーが発生しました。
どうやら、ビルド時に`import`文が正しく解釈されていないようです...
```
vite v5.4.10 building for production...
✓ 3 modules transformed.
x Build failed in 48ms
error during build:
[vite]: Rollup failed to resolve import "@src/page/Page" from "/home/USERNAME/PROJECT_NAME/src/main.tsx".
This is most likely unintended because it can break your application at runtime.
If you do want to externalize this module explicitly add it to
`build.rollupOptions.external`
```

`TypeScript`のコンパイルに関する設定はいじってきましたが、ビルドを実行する`vite`側の設定はいじっていませんでした。
下記の設定を追加します。

```vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react-swc";

export default defineConfig({
	plugins: [react()],
    // 下記を追加
	resolve: { alias: [{ find: "@src", replacement: "/src" }] }
});
```
`@src`というaliasは`/src`に置換してくれ、と`vite`に設定します。
この状態で`npm run build`してみると、ビルドが成功しました!!

## aliasいらなくね?
無事プルリクを作成できましたが、コメントをいただきました。

上長「`@src`のprefixいらなくない?」
ぼく「...」

すみません、勝手に設定してしまいました。
ということで、下記のように`import`文を記載できるように修正します。
>`import { Example } from "types/Type";`

```tsconfig.app.json
{
  "compilerOptions": {
    "baseUrl": "src",
    "paths": {
      "/*": ["src/*"]
    },
    ...
}
```
先ほど`paths`内の`key`に設定していた`@src/*`を`/*`に変換しただけです。
`vite.config.ts`に設定していた`resolve.alias`を削除して... あれ、ビルドがうまくいかないな...
ここから泥沼にはまってしまいました...
```
vite v5.4.10 building for production...
✓ 3 modules transformed.
x Build failed in 48ms
error during build:
[vite]: Rollup failed to resolve import "page/Page" from "/home/USERNAME/PROJECT_NAME/src/main.tsx".
This is most likely unintended because it can break your application at runtime.
If you do want to externalize this module explicitly add it to
`build.rollupOptions.external`
```

### 解決策 `vite-tsconfig-paths`
上長「`vite-tsconfig-paths`を使うといいと思うよ」
ぼく「神ですね」

```bash
$ npm i -D vite-tsconfig-paths@latest
```
```package.json
{
  ...
  "devDependencies": {
    "vite-tsconfig-paths": "^5.1.4",
    ...
  },
  ...
}
```
```vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react-swc";
import tsconfigPaths from "vite-tsconfig-paths";

export default defineConfig({
    // tsconfigPaths()を追加
	plugins: [react(), tsconfigPaths()]
});
```
[`vite-tsconfig-paths`](https://www.npmjs.com/package/vite-tsconfig-paths)は`vite`に`import`解決能力を授けてくれるパッケージのようです。
このパッケージを用いることで、`vite`がいい感じに`import`文を解釈してくれるようになり、無事プルリクもマージされましたとさ。
>`import { Example } from "types/Type";`



# 最後に
いろいろ大変でしたが、`vite-tsconfig-paths`のお陰で一件落着しました、便利なパッケージに感謝です。
`vite.config.ts`や`tsconfig.json`など、環境周りは敬遠してきてしまっていたことを後悔です...

他にも良い方法があったり、`vite.config.ts` `tsconfig.json`などのおすすめ設定があったりしたら、コメントいただけますと幸いです!