import XXX from ../../../components/XXX を from @/components/XXXにする！

```tsx
import { DOWNLOAD_IMAGE_BUTTON_TEXT } from "../../../constants/messages";
```

ここが問題の部分です。ちょっと嫌ですね

```tsx
import { DOWNLOAD_IMAGE_BUTTON_TEXT } from "@/constants/messages";
```


# 良く忘れるのでメモ

- ビルドツール（今回はvite）が@でのエイリアスを解決できるようにする
- エディタ（今回はVS Code）が@でのエイリアスを解決できるようにする

このふたつが必要です

# 先に結論
```vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { resolve } from 'path'

// https://vite.dev/config/
export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      '@': resolve(__dirname, 'src')
    }
  },
})
```

```tsconfig.app.json
{
  "compilerOptions": {
    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": [
      "ES2020",
      "DOM",
      "DOM.Iterable"
    ],
    "module": "ESNext",
    "skipLibCheck": true,
    /* Bundler mode */
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "isolatedModules": true,
    "moduleDetection": "force",
    "noEmit": true,
    "jsx": "react-jsx",
    /* Linting */
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,
    "noUncheckedSideEffectImports": true,
    "baseUrl": ".",
    "paths": {
      "@/*": [
        "src/*"
      ]
    }
  },
  "include": [
    "src"
  ]
}
```


# やってみる
## プロジェクトの準備
```bash
pnpm create vite ailias-demo --template react-ts
```

React + Viteのひな型ができました。

適当なコンポーネントを作ります。

```src/constants/messages.ts
/**
 * 画像をダウンロードするボタンの文言
 * @constant {string}
 */
export const DOWNLOAD_IMAGE_BUTTON_TEXT = "画像をダウンロード";
```

```src/hukuzatsu/na/path/DownloadButton.tsx
import {DOWNLOAD_IMAGE_BUTTON_TEXT} from "../../../constants/messages";

const DownloadButton: React.FC = () => {

    return (
        <button>{DOWNLOAD_IMAGE_BUTTON_TEXT}</button>
    );
};

export default DownloadButton;
```

```tsx
import {DOWNLOAD_IMAGE_BUTTON_TEXT} from "../../../constants/messages";
```

ここが問題の部分です。ちょっと嫌ですね

```tsx
import {DOWNLOAD_IMAGE_BUTTON_TEXT} from "@/constants/messages";
```

こうなるのが理想です。ビルドが通らないことなどを確認するため、あえてエイリアス設定を行う前に変更します。

```src/hukuzatsu/na/path/DownloadButton.tsx
import {DOWNLOAD_IMAGE_BUTTON_TEXT} from "@/constants/messages";

const DownloadButton: React.FC = () => {

    return (
        <button>{DOWNLOAD_IMAGE_BUTTON_TEXT}</button>
    );
};

export default DownloadButton;
```

また、viteのビルド対象としたいので、このコンポーネントをApp.tsxから呼び出すよう変更します。

```src/App.tsx
import './App.css'
import DownloadButton from './hukuzatsu/na/path/DownloadButton'

function App() {

  return (
    <>
      <DownloadButton />
    </>
  )
}

export default App
```

![cap1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/2aa1665e-da4e-9077-8766-dc573d66320c.png)

VS Codeが怒りました。


viteでローカルサーバーを起動してアクセスします。

![cap2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/392d2bb5-c685-c48b-38ee-f6744beb63e1.png)

怒られました。いいですね。

## ビルドツール（今回はvite）が@でのエイリアスを解決できるようにする
まずはviteがエイリアスを解決できるようにします
方法は簡単で、以下の変更をvite.config.tsに記載するだけです。

```diff_typescript
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
+ import { resolve } from 'path'

// https://vite.dev/config/
export default defineConfig({
  plugins: [react()],
+ resolve: {
+   alias: {
+     '@': resolve(__dirname, 'src')
+   }
+ },
})
```

完成形はこんな感じ
```vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { resolve } from 'path'

// https://vite.dev/config/
export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      '@': resolve(__dirname, 'src')
    }
  },
})
```

ローカルホストへ再度アクセスすると、ボタンが表示されています！

![cap3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/94ca4a04-e41f-e61b-dc63-1fd6d860041d.png)

ビルド時のエイリアス解決ができてそうですね。

## エディタ（今回はVS Code）が@でのエイリアスを解決できるようにする
VS Codeはrootにあるtsconfig.jsonを読み込んでパスを解決します。
viteとは違う解決法なので、VSCodeが解決できるようtsconfig.jsonを変更する必要があります。

こちらも方法は簡単で、以下を追加するだけです。

```diff_json
{
  "compilerOptions": {
    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": [
      "ES2020",
      "DOM",
      "DOM.Iterable"
    ],
    "module": "ESNext",
    "skipLibCheck": true,
    /* Bundler mode */
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "isolatedModules": true,
    "moduleDetection": "force",
    "noEmit": true,
    "jsx": "react-jsx",
    /* Linting */
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,
-   "noUncheckedSideEffectImports": true
+   "noUncheckedSideEffectImports": true,
+   "baseUrl": ".",
+   "paths": {
+     "@/*": [
+       "src/*"
+     ]
+   }
  },
  "include": [
    "src"
  ]
}
```

完全なtsconfig.app.jsonはこうなります。
```tsconfig.app.json
{
  "compilerOptions": {
    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": [
      "ES2020",
      "DOM",
      "DOM.Iterable"
    ],
    "module": "ESNext",
    "skipLibCheck": true,
    /* Bundler mode */
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "isolatedModules": true,
    "moduleDetection": "force",
    "noEmit": true,
    "jsx": "react-jsx",
    /* Linting */
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,
    "noUncheckedSideEffectImports": true,
    "baseUrl": ".",
    "paths": {
      "@/*": [
        "src/*"
      ]
    }
  },
  "include": [
    "src"
  ]
}
```

![cap4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/fdacf83e-a782-ed6b-0643-3b54be4e55dc.png)

エラーもでなくなりました。めでたし。