viteでReact×TypeScript環境を爆速で作る最小版

# viteでReact×TypeScript環境を作る
色々bundleツールがありますが、
esbuildベースのviteがビルドが早く、かつwebpackのような細かい設定までできるため、
最近はよく使っています。
また開発ビルド時にはソースコード変更時に自動的にブラウザ反映してくれるHMRが動作するため、
非常に快適に開発できます。

身も蓋もないやり方だと、以下のviteコマンドのインタラクションを選ぶだけでテンプレート作ってくれます。

```shell
// pnpmの場合は
$ pnpx create-vite 
// yarnの場合は
$ yarn create vite@latest
// npmの場合は
$ npm create vite@latest
```

frameworkはReactを選択します
![スクリーンショット 2023-10-09 11.00.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55077/584b2e9f-ac05-8ccd-46a2-a35753ff2b8b.png)
SWCを選択したほうがより高速にビルドしてくれます。
![スクリーンショット 2023-10-09 11.00.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55077/94402e5a-7b2b-54fe-f5fa-3b3de73ab063.png)


それだけだと芸がないので軽く解説します。

サンプル
[github](https://github.com/teradonburi/vite-react)

サンプルのフォルダ構成は簡易のため、以下のように変更しています。

```
.
├── README.md
├── .github/workflow/static.yaml
├── biome.json
├── package.json
├── pnpm-lock.yaml
├── src
│   ├── App.tsx
│   ├── app.css.ts
│   ├── global.css.ts
│   ├── index.html
│   ├── main.tsx
│   └── vite-env.d.ts
├── tsconfig.json
├── tsconfig.tsbuildinfo
└── vite.config.ts
```

package.jsonは以下のようになっています。
`npm dev`で開発ビルド、`npm build`で本番ビルドできます。

```package.json
{
  "name": "vite-react",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build"
  },
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  },
  "devDependencies": {
    "@types/node": "^20.6.0",
    "@types/react": "^18.2.15",
    "@types/react-dom": "^18.2.7",
    "@vitejs/plugin-react-swc": "^3.3.2",
    "typescript": "^5.0.2",
    "vite": "^4.4.5"
  }
}
```

viteのbuild設定は`vite.config.ts`に記述します。
`@vitejs/plugin-react-swc`のプラグイン設定が必要です。
buildプロパティに細かい設定を書いていきます。
サンプルではproduction build向けの設定を書いています。

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

// https://vitejs.dev/config/
export default defineConfig({
	base: "./",
	root: "src",
	plugins: [react()],
	publicDir: resolve(__dirname, "public"),
	build: {
		// distフォルダに出力
		outDir: resolve(__dirname, "dist"),
		// 存在しないときはフォルダを作成する
		emptyOutDir: true,
		copyPublicDir: true,
		rollupOptions: {
			// entry pointがあるindex.htmlのパス
			input: {
				"": resolve(__dirname, "src/index.html"),
			},
			// bundle.jsを差し替えする
			output: {
				entryFileNames: "assets/bundle.js",
			},
		},
	},
});
```

src/index.htmlにReact Applicationを埋め込むhtmlが記述してあります。

```src/index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8" />
    <title>タイトル</title>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <script type="module" src="/main.tsx"></script>
  </head>
<body>
  <div id="root" />
</body>
</html>
```

src/main.tsxはReactの初期化処理を書いています。

```src/main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App.tsx';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
);
```

src/vite-env.d.tsは環境変数の型を定義するためのものです。
viteは内包している[dotenv](https://github.com/motdotla/dotenv)ライブラリで環境変数を定義することができるため、
環境変数の型定義をこのファイルに追記することで環境変数の型を参照先で使うことができます。

[TypeScript 用の自動補完](https://ja.vitejs.dev/guide/env-and-mode.html#typescript-%E7%94%A8%E3%81%AE%E8%87%AA%E5%8B%95%E8%A3%9C%E5%AE%8C)

```vite-env.d.ts
/// <reference types="vite/client" />

// 以下にReactで参照する環境変数の型定義を書く
```

# Biome導入
文法チェックとコードフォーマッターを導入します。

```package.json
  "devDependencies": {
	"@biomejs/biome": "^1.9.1",
    ...
  },
```

`biome init`で`biome.json`を作成します。

```biome.json
{
	"$schema": "https://biomejs.dev/schemas/1.9.1/schema.json",
	"vcs": {
		"enabled": false,
		"clientKind": "git",
		"useIgnoreFile": false
	},
	"files": {
		"ignoreUnknown": false,
		"ignore": []
	},
	"formatter": {
		"enabled": true,
		"indentStyle": "tab"
	},
	"organizeImports": {
		"enabled": true
	},
	"linter": {
		"enabled": true,
		"rules": {
			"recommended": true,
			"style": {
				"useImportType": "off"
			}
		}
	},
	"javascript": {
		"formatter": {
			"quoteStyle": "double"
		}
	}
}
```


# CSSライブラリ導入

CSSをインラインで直接書いたり、vite自体もCSSモジュールをサポートしていますが、

- cssをモジュール化したい
- global style書きたい
- media query書きたい
- Themeで一括にアプリ全体のCSSを適用したい

みたいなことがよくあるので

vanilla-extractが軽量ミニマムでかつ上記の機能備えていてtype safeで
最小の開発時は便利なので入れます。
https://vanilla-extract.style/

導入自体は簡単です。
`package.json`にパッケージを追加してインストール。

```package.json
  "dependencies": {
    "@vanilla-extract/css": "^1.13.0",
  }
  "devDependencies": {
    "@vanilla-extract/vite-plugin": "^3.9.0",
  }
```

`vite.config.ts`にプラグインを追加

```vite.config.ts
import { vanillaExtractPlugin } from '@vanilla-extract/vite-plugin'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react(), vanillaExtractPlugin()],
```

# Github Pagesにリリース

Github Pagesを有効にすると静的ページをGithub上でリリースできます。
https://teradonburi.github.io/vite-react/

![スクリーンショット 2024-09-16 21.22.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55077/268fa1b8-5e04-8a74-d81e-cbaf71dda298.png)

CIでビルドし、デプロイするために`.github/workflow/static.yaml`を作成します。

```yaml
# 静的コンテンツを GitHub Pages にデプロイするためのシンプルなワークフロー
name: Deploy static content to Pages

on:
  # デフォルトブランチを対象としたプッシュ時にで実行されます
  push:
    branches: ["main"]

  # Actions タブから手動でワークフローを実行できるようにします
  workflow_dispatch:

# GITHUB_TOKEN のパーミッションを設定し、GitHub Pages へのデプロイを許可します
permissions:
  contents: read
  pages: write
  id-token: write

# 1 つの同時デプロイメントを可能にする
concurrency:
  group: "pages"
  cancel-in-progress: true

jobs:
  # 単一のデプロイジョブ
  deploy:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Setup pnpm
        uses: pnpm/action-setup@v4
        with:
          version: 9.10.0
      - name: Install dependencies
        run: pnpm install --frozen-lockfile
      - name: Build
        run: pnpm run build
      - name: Setup Pages
        uses: actions/configure-pages@v5
      - name: Upload artifact
        uses: actions/upload-pages-artifact@v3
        with:
          # dist フォルダーのアップロード
          path: "./dist"
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v4
```