CLOVER🍀

That was when it all began.

フロントエンドのビルドツール、ViteでReactを始めてみる

これは、なにをしたくて書いたもの?

少し、Reactを扱ってみたいと思いまして。

React

とはいえ、どこから入ったらいいのかな?ということで、今回はViteを試してみることにしました。

あまりReact自体は出てこないんですけど。

今のReactの始め方

ここでReactの新しいプロジェクトを始め方を見てみます。

If you want to build a new app or a new website fully with React, we recommend picking one of the React-powered frameworks popular in the community. Frameworks provide features that most apps and sites eventually need, including routing, data fetching, and generating HTML.

Start a New React Project – React

今はReactをベースにしたフレームワークを利用することを勧められているようです。

このページでは、Next.js、Remix、Gatsby、Expo(ネイティブアプリ向け)が挙げられています。

個人的にはまずはフレームワークなしの使い方が知りたいのですが、これについてはフレームワークの紹介の後に隠れています。

ここを開いてみると、フレームワークを使わなくてもできるけれどフレームワークの利用を勧めると書かれています。
必要になるものがいろいろ足りてないし、セットアップが必要になるけれどそれでも頑張るのならどうぞ?という感じです。

You can definitely use React without a framework—that’s how you’d use React for a part of your page. However, if you’re building a new app or a site fully with React, we recommend using a framework.

Here’s why.

〜省略〜

If you’re still not convinced, or your app has unusual constraints not served well by these frameworks and you’d like to roll your own custom setup, we can’t stop you—go for it! Grab react and react-dom from npm, set up your custom build process with a bundler like Vite or Parcel, and add other tools as you need them for routing, static generation or server-side rendering, and more.

Start a New React Project / Can I use React without a framework?

ここで、ViteとParcelが出てきます。

Vite | Next Generation Frontend Tooling

Parcel

お勧めはしないぞ、とは言われているものの、まずはReactにフォーカスしたいのでViteを選んでみます。

Vite

Viteのオフィシャルサイトはこちらで、次世代のフロントエンドツールであると書かれています。

Vite | Next Generation Frontend Tooling

The State of JS 2022のビルドツールのカテゴリーでも人気のようです。

State of JavaScript 2022: Build Tools

なぜViteが良いのか?というページは、こちら。

Why Vite | Vite

ここを見ると、以下の特徴が謳われています。

  • 開発サーバーの起動時間の短縮
  • 更新(Hot Module Replacement:HMR)の高速化
  • 本番環境向けのバンドル

機能についてはこちら。

Features | Vite

  • モジュールインポート
  • Hot Module Replacement(HMR)
  • TypeScriptのサポート
  • Vue、JSX、CSS
  • Static AssetsやJSONのインポート
  • Globインポート、動的インポート、WebAssemblyの利用
  • Web Workerのサポート
  • ビルドの最適化
TypeScriptのサポートについて

TypeScriptのサポートについてはちょっと気になるので、もう少し見ておきます。

Features / TypeScript

Viteは.tsファイルのトランスパイルのみを実行し、型チェックは行いません。型チェックはIDEやビルドプロセスで確認することを
想定しているようです。

Note that Vite only performs transpilation on .ts files and does NOT perform type checking. It assumes type checking is taken care of by your IDE and build process.

Features / TypeScript / Transpile Only

isolatedModules、useDefineForClassFieldsには注意する必要があるようです。

Features / TypeScript / TypeScript Compiler Options

その他、影響を与えるものとしてextends、importsNotUsedAsValues、preserveValueImports、jsxFactory、jsxFragmentFactoryが
挙げられています。

ViteはデフォルトでNode.js APIを使用するため、クライアント側のコードであることを示すために、以下の宣言を追加する必要が
あるようです。

/// <reference types="vite/client" />

これはtsconfig.jsonでも設定できるようです。

{
  "compilerOptions": {
    "types": ["vite/client"]
  }
}

Features / TypeScript / Client Types

Create React Appは?

ところで、Reactを始めるのに使うのはCreate React Appだと思うのですが、こちらはどうなったのでしょう?

Reactのこちらのページには名前がありませんでした。

Start a New React Project – React

Create React App

現時点での最終リリースは、2022年4月の5.0.1です。

Release v5.0.1 · facebook/create-react-app · GitHub

以下あたりも参考に。

We need regualr CRA maintainer · Issue #11180 · facebook/create-react-app · GitHub

今後は見なくなっていくツールになっていきそうですね。

話を戻して、今回はViteを使ってみます。

環境

今回の環境は、こちら。

$ node --version
v18.17.1


$ npm --version
9.6.7

Viteを始めてみる

こちらを見ながら、Viteを始めてみます。

Getting Started | Vite

まずはViteプロジェクトを作成するようです。

テンプレートをサポートしているようで、JavaScript、TypeScriptで以下があるようです。

JavaScript TypeScript
vanilla vanilla-ts
vue vue-ts
react react-ts
preact preact-ts
lit lit-ts
svelte velte-ts
solid solid-ts
qwik qwik-ts

コミュニティがメンテナンスしているテンプレートもあるようです。

GitHub - vitejs/awesome-vite: ⚡️ A curated list of awesome things related to Vite.js

今回は、React+TypeScript(react-ts)を選んでみます。

$ npm create vite vite-getting-started -- --template react-ts

出力結果。

Scaffolding project in /path/to/vite-getting-started...

Done. Now run:

  cd vite-getting-started
  npm install
  npm run dev

プロジェクトができたようなので、ディレクトリ内に移動してみます。

$ cd vite-getting-started

ディレクトリ内の構成。

$ tree
.
├── README.md
├── index.html
├── package.json
├── public
│   └── vite.svg
├── src
│   ├── App.css
│   ├── App.tsx
│   ├── assets
│   │   └── react.svg
│   ├── index.css
│   ├── main.tsx
│   └── vite-env.d.ts
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts

3 directories, 13 files

各種設定ファイルを見てみましょう。

package.json

{
  "name": "vite-getting-started",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
    "preview": "vite preview"
  },
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  },
  "devDependencies": {
    "@types/react": "^18.2.15",
    "@types/react-dom": "^18.2.7",
    "@typescript-eslint/eslint-plugin": "^6.0.0",
    "@typescript-eslint/parser": "^6.0.0",
    "@vitejs/plugin-react": "^4.0.3",
    "eslint": "^8.45.0",
    "eslint-plugin-react-hooks": "^4.6.0",
    "eslint-plugin-react-refresh": "^0.4.3",
    "typescript": "^5.0.2",
    "vite": "^4.4.5"
  }
}

tsconfig.json

{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,

    /* Bundler mode */
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",

    /* Linting */
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true
  },
  "include": ["src"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

tsconfig.node.json

{
  "compilerOptions": {
    "composite": true,
    "skipLibCheck": true,
    "module": "ESNext",
    "moduleResolution": "bundler",
    "allowSyntheticDefaultImports": true
  },
  "include": ["vite.config.ts"]
}

vite.config.ts

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

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

ソースコードの一部。Reactを使ったものですね。

src/main.tsx

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
import './index.css'

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

src/App.tsx

import { useState } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'

function App() {
  const [count, setCount] = useState(0)

  return (
    <>
      <div>
        <a href="https://vitejs.dev" target="_blank">
          <img src={viteLogo} className="logo" alt="Vite logo" />
        </a>
        <a href="https://react.dev" target="_blank">
          <img src={reactLogo} className="logo react" alt="React logo" />
        </a>
      </div>
      <h1>Vite + React</h1>
      <div className="card">
        <button onClick={() => setCount((count) => count + 1)}>
          count is {count}
        </button>
        <p>
          Edit <code>src/App.tsx</code> and save to test HMR
        </p>
      </div>
      <p className="read-the-docs">
        Click on the Vite and React logos to learn more
      </p>
    </>
  )
}

export default App

こちらは、クライアント側であることを宣言するファイルですね。

src/vite-env.d.ts

/// <reference types="vite/client" />

Features / TypeScript / Client Types

依存関係をインストール。

$ npm i

開発サーバーを起動。

$ npm run dev

実体はviteコマンドですね。

  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
    "preview": "vite preview"
  },

Command Line Interface | Vite

開発サーバーが起動したようです。

  VITE v4.4.9  ready in 970 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose
  ➜  press h to show help

確認してみます。http://localhost:5173へアクセスしてみます。

動作しているのが確認できました。

クリックでカウントアップするサンプルなので、少し遊んでみます。

src/vite-env.d.ts

ここで、開発サーバーを1度止めます。

今度はプロダクション用にビルドしてみましょう。

$ npm run build

出力結果。

> vite-getting-started@0.0.0 build
> tsc && vite build

vite v4.4.9 building for production...
✓ 34 modules transformed.
dist/index.html                   0.46 kB │ gzip:  0.30 kB
dist/assets/react-35ef61ed.svg    4.13 kB │ gzip:  2.14 kB
dist/assets/index-d526a0c5.css    1.42 kB │ gzip:  0.74 kB
dist/assets/index-c7e05d32.js   143.41 kB │ gzip: 46.10 kB
✓ built in 1.37s

distディレクトリ内にファイルが生成されたようです。

$ tree dist
dist
├── assets
│   ├── index-d526a0c5.css
│   ├── index-c7e05d32.js
│   └── react-35ef61ed.svg
├── index.html
└── vite.svg

1 directory, 5 files

こちらを確認してみましょう。PythonのHTTPサーバーを起動。

$ python3 -m http.server --directory dist

http://localhost:8000/へアクセスして確認。

OKですね。

HMRを確認してみます。開発サーバーを起動。

$ npm run dev

App.tsxを以下のように修正。

      <h1>Vite + React</h1>

すると、コンソールに以下のように表示され

22:14:16 [vite] hmr update /src/App.tsx

変更が反映されたことが確認できました。

あとは型チェックですが。npm run buildの時はtscで確認してくれますが、開発サーバーを使っている時はそうはいきません。

tsc --watchを追加しておくのがいいでしょうか。

  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
    "preview": "vite preview",
    "typecheck:watch": "tsc --watch"
  },

こんな感じで。

$ npm run typecheck:watch

まとめ

ViteでReactを使ったプロジェクトを始めてみました。このあたり、全然追っていないのでトレンドとかやり方がいまひとつわかりません。
まあ、ちょっとずつ追っていければいいかなと思います。

気長にやっていこうかなと。