記事一覧に戻る

ViteでReactプロジェクトを作成する方法

はじめに

Reactの旧ドキュメントでは、Reactプロジェクトのセットアップ方法として、npxコマンドのcreate-react-appが案内されていました。私も初めてReactに触れた時は、このコマンドでセットアップしていました。

しかし2023年3月に新しくなった新ドキュメントでは、create-react-appの記載はなくなってしまいました。代わりに、Next.jsやRemixといったReact用フレームワークを使ったセットアップ方法が推奨されています。create-react-app自体はまだ使うことが出来るようですが、公式ドキュメントでも触れられていない以上、もう推奨されていないのでしょう。

じゃあ、もうフレームワークを使わないとReactが使えないのかというと、そんなことはありません。Viteというビルド・ツールが、create-react-appの代替としてよく使われているようです。

私も最近、CSSでちょっと試したいことがあったので、Viteで素のReactプロジェクトをセット・アップしてみました。

create-react-appと比べて、セットアップも速く、非常にサクサク動いています。なかなか快適です。

今回はViteのセットアップ方法と、簡単な使い方を解説します。

Viteとは

概要

Vite(『ヴィィッ』と発音)は、フロントエンド向けのビルド・ツールです。Vue.jsの開発者が作成しています。

create-react-appでセットアップした場合と同じように、開発サーバやHMR(Hot Module Replacement: スクリプト等を修正した時に、ブラウザのリロード無しで変更箇所のみ描写してくれる機能)もついてきます。

Reactだけでなく、Preact、Svelte、Vue、Solid、Vanilla-JS(素のJavaScript)等でも利用することが出来ます。

ちなみに、新ReactドキュメントのReact プロジェクトを始めるでも、「Next.jsやRemixのようなフレームワークを使いたくない場合は、ViteやParcelといったツールを使えば出来るよ」といった趣旨の記載もされています。

Viteを使うメリット

create-react-appでReactをセットアップした場合と比較して、以下のメリットがあります。

  • プロジェクトフォルダが軽量

create-react-appでプロジェクト作成すると、約320MBくらいの容量になります。環境やバージョンによって多少変わると思いますが、かなり大きいです。

Viteの場合、100MBくらいです。

create-react-appだとJestのようなテスト用パッケージや、Babel等も一緒にインストールされますが、Viteだとインストールされません。

シンプルに必要なものだけをインストールするのがコンセプトのようですね。

  • HMRやビルドが速い

速いことが公式でも推されています。私の体感ですが、確かに速く感じます。create-react-appは遅いと言われていたので、HMRやビルドの速度で不満は感じないと思います。

セットアップ

おおまかな流れは以下のとおりです。

  1. プロジェクト・フォルダの作成
  2. パッケージのインストール
  3. 開発サーバを起動して確認

なお、Viteを使うためにはNode.jsのバージョン18以上が必要です。

1.プロジェクト・フォルダの作成

まずは以下のコマンドでViteのプロジェクトフォルダを作成します。

npm create vite@latest

プロジェクト名を聞かれるので、任意の名前を入力します。デフォルトはvite-projectになっています。今回はvite-blogにしておきます。

? Project name: » vite-blog

フレームワークを選びます。↓矢印キーでReactを選んでエンターを押します。

? Select a framework: » - Use arrow-keys. Return to submit.
    Vanilla
    Vue
>   React
    Preact
    Lit
    Svelte
    Solid
    Qwik
    Others

TypeScriptを使うか聞かれます。今回は上から2番上のTypeScript + SWCを選びます。SWCはRustベースのコンパイラです。従来のコンパイラより高速と言われています。

? Select a variant: » - Use arrow-keys. Return to submit.
    TypeScript
>   TypeScript + SWC
    JavaScript
    JavaScript + SWC

エンターを押して確定すると、以下の指示が表示されます。

Done. Now run:

cd vite-blog
npm install
npm run dev

プロジェクト・フォルダの作成はこれで完了です。次は、上記の指示に従って依存パッケージのインストールを行います。

2.パッケージのインストール

cd vite-blogでプロジェクトのフォルダに移動し、npm installを実行します。

cd vite-blog
npm install

私の場合、35秒ほどでパッケージのインストールが終わりました。

added 154 packages, and audited 155 packages in 35s

37 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

これでセットアップは完了です。

ちなみに、package.jsonは以下の内容になっています。

{
  "name": "vite-blog",
  "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.37",
    "@types/react-dom": "^18.2.15",
    "@typescript-eslint/eslint-plugin": "^6.10.0",
    "@typescript-eslint/parser": "^6.10.0",
    "@vitejs/plugin-react-swc": "^3.5.0",
    "eslint": "^8.53.0",
    "eslint-plugin-react-hooks": "^4.6.0",
    "eslint-plugin-react-refresh": "^0.4.4",
    "typescript": "^5.2.2",
    "vite": "^5.0.0"
  }
}

React以外は、ViteとTypeScriptとEslint関連のパッケージのみなので、だいぶシンプルですね。

3.開発サーバを起動して確認

後は開発サーバを起動させ、セットアップが正常に終わっているか確認します。

npm run devを入力し、テンプレートのページがブラウザで表示されればOKです。

> npm run dev

  VITE v5.0.2  ready in 506 ms

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

localhostのポート5173で起動したことが分かります。Viteではデフォルトのポートは5173になっています。後述しますが、後から変えることができます。

リンクをクリックしブラウザでhttp://localhost:5173/を開くと、ちゃんとテンプレートのページが表示されました!

template-page

エラーが出る場合

セットアップ後、場合によってはvite.config.tsに以下のエラーが表示される場合があります。

Cannot find module '@vitejs/plugin-react' or its corresponding type declarations.

もし出た場合、エディタを開きなおすと解消する場合があります。

それでも解消しない場合、vite.config.tsを開き、2行目を確認してください。

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

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

「TypeScript + SWC」を選択している場合、2行目はimport react from '@vitejs/plugin-react-swc' になっている必要があります。

もし'@vitejs/plugin-react'になっていたら、-swcをつけて下さい。

再現方法は分かっていないのですが、環境なのかバージョンなのか、稀に -swcがつかない場合があるようです。

なお、SWCが無いほうの「TypeScript」を選択している場合は、import react from '@vitejs/plugin-react'で正しいです。念のため。

フォルダ構成

セットアップが完了した状態のフォルダ構成です。

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----        2023/11/27     23:10                node_modules
d-----        2023/11/27     23:07                public
d-----        2023/11/27     23:07                src
-a----        2023/11/21     22:40            436 .eslintrc.cjs
-a----        2023/11/21     22:40            253 .gitignore
-a----        2023/11/21     22:40            366 index.html
-a----        2023/11/27     23:08          88653 package-lock.json
-a----        2023/11/27     23:07            750 package.json
-a----        2023/11/21     22:40           1300 README.md
-a----        2023/11/21     22:40            605 tsconfig.json
-a----        2023/11/21     22:40            213 tsconfig.node.json
-a----        2023/11/27     23:07            167 vite.config.ts

直下のファイル

ESLint、TypeScriptのconfigファイルに加え、Viteのconfigファイルも作成されています。私もまだ試せていませんが、Viteのconfigファイルでプラグインを指定することで、機能の拡張が行えます。

後は、README.mdとか.gitignoreのようなファイルです。

基本的には、create-react-appでフォルダを作成した場合と大きな違いはありません。

index.htmlについて

create-react-appの場合と1つ異なるのは、Reactのエントリーポイントとなるindex.htmlが、publicフォルダ内ではなく、プロジェクト直下に配置されていることです。

Viteのドキュメントにも、これは意図的なものと記載されています。publicフォルダに移さないようにしましょう。

セットアップ直後のindex.htmlは以下の内容になっています。

<!doctype html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <link rel="icon" type="image/svg+xml" href="/vite.svg" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Vite + React + TS</title>
</head>

<body>
  <div id="root"></div>
  <script type="module" src="/src/main.tsx"></script>
</body>

</html>

faviconやタイトル等を変えたい場合は、このhtmlを修正すればOKです。viewportのようなmetaタグもあらかじめ設定されています。

後、<html lang="en">は日本人なら"ja"に修正しておいたほうが良いかと思います。

create-react-appの場合、index.html内にpublicフォルダのパスを指す %PUBLIC_URL% 変数がありましたが、Viteの場合は存在しません。publicフォルダのファイルは、上記の <link> タグのhref属性のように「/パス名」で指定します。例えば、publicフォルダ直下にあるvite.svgファイルならば、「/vite.svg」と記述すればOKです。

publicフォルダ

画像やCSS等、クライアント側から取得可能な資産を配置するフォルダです。外部から参照な可能なフォルダとなります。

デフォルトではfaviconとして使われているvite.svgが配置されています。

ReactであればCSSや画像はimportできるので、直接ここに配置するのはfaviconやrobots.txt等、特殊なファイルが中心になるかと思います。

上述のとおり、クライアント側からpublicフォルダのファイルにアクセスする場合、「/パス名」で指定します。

srcフォルダ

セットアップ直後のsrcフォルダの構成です。

C:.
│  App.css
│  App.tsx
│  index.css
│  main.tsx
│  vite-env.d.ts
│
└─assets
        react.svg

Reactのソース関連ファイルが格納されています。初期で入っているのはテンプレート・ページのソースです。

vite-env.d.tsはvite用に定義した環境変数について与える型情報ファイルとなります。私もまだ深く触れられていないため、今回は割愛します。

後は、通常のReactのプロジェクトと扱いは同じです。main.tsxがエントリポイントです。プロジェクト・フォルダの直下のindex.htmlの<div id="root"></div>に対応しています。

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>,
)

直下のindex.cssやApp.tsxをimportして使っています。いずれもテンプレートのものなので、不要であればファイルごと削除してしまい、自身のコンポーネントやCSSに差し替えていきましょう。

create-react-appの場合、ファイル名はindex.tsxで作成されていましたが、中身と役割は同じですね。

assetsサブフォルダもありますが、テンプレート・ページで使われているReactロゴのsvgファイルが入っているだけです。

基本的な使い方

次に基本的な使い方を見てみます。

私が使ったものを中心に紹介しますが、他にもたくさんあるので詳細はドキュメントをご確認ください。

開発サーバを起動

以下のコマンドで開発サーバを起動します。

npm run dev

デフォルトだとport5173で稼働します。後はブラウザでhttp://localhost:5173/を開けば作ったページの確認ができます。

余談ですが、実際に実行されているのはviteコマンドです。package.jsonを見れば分かります。

{
   "scripts": {
    "dev": "vite",
    ...
   }
}

node_modules/.binフォルダの中にスクリプトが格納されています。

ビルド

以下のコマンドでビルドできます。

npm run build

ビルドすると、プロジェクト直下にdistフォルダが作成され、ビルド後のファイルが格納されます。

セットアップ後の状態でビルドすると、distフォルダの中身は以下のようになっていました。

C:.
│  index.html
│  vite.svg
│
└─assets
        index-4sK4E3Wk.css
        index-YnIXOLyF.js
        react-h3aPdYU7.svg

index.htmlやfaviconの画像に加え、assetsサブフォルダ内にJavaScriptファイルや、JavaScript内でimportしていたロゴの画像やcssが入っていることが確認できます。

本番にデプロイする際は、このdistフォルダをまるっとコピーすることになるかと思います。

ポート変更

開発サーバのportを変更したい場合、プロジェクト直下のvite.config.tsで指定します。

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

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],
  // serverオプションを追加
  server: {
    // port番号を指定
    port: 5000,
  }
})

server:{port:5000}を今回追加しています。

これで開発サーバを起動すると、ちゃんとport5000で稼働しているのが分かります。

> npm run dev

> vite-blog@0.0.0 dev
> vite

  VITE v5.0.2  ready in 576 ms

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

指定したportが既に使われている場合、空いているportで稼働します。

publicフォルダを変えたい

クライアント側からアクセスできる静的(static)なフォルダは、デフォルトではpublicフォルダです。

別のフォルダに変えたい場合、vite.config.tsで指定します。publicでなく、staticという名前のフォルダにしたい場合、以下のように指定します。

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

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],
  // 絶対パス、もしくはプロジェクトフォルダからの
  // 相対パスで指定
  publicDir: "./static"
})

publicDirにstaticにしたいフォルダ名を指定しています。今回はプロジェクト・フォルダからの相対パスで指定していますが、絶対パスでも大丈夫です。

これでプロジェクト直下のstaticフォルダがクライアント側からアクセスできる静的なフォルダになります。

別のデバイスからアクセスしたい

スマホやタブレットでの見栄えを確認するために、開発サーバに別端末からアクセスしたい場合もあると思います。

デフォルトでは、別端末からのアクセスは出来ないように制限されているので、vite.config.tsを修正するか、開発サーバ起動時のオプションを指定する必要があります。

なお、前提として同じネットワークに接続している端末である必要があります。

vite.config.jsを修正する場合

server:{host:true}を設定すればOKです。

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

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],
  // 別端末からアクセスを許可
  server: {
    host: true,
  }
})

これで開発サーバを起動すると、urlが3つ表示されます。

>npm run dev  

> vite-blog@0.0.0 dev
> vite

  VITE v5.0.2  ready in 599 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: http://192.168.0.23:5173/
  ➜  Network: http://172.28.128.1:5173/
  ➜  press h + enter to show help

真ん中のurl(私の場合、http://192.168.0.23:5173/)を別のデバイスのブラウザに打ち込むと、ちゃんとページが表示されました。

3つ目のurlは良く分かっていません、、、別端末から開くことは出来ませんでした。ipconfigで確認すると、「イーサネット・アダプター」のIPv4と一致していました。有線で繋げている場合に使うのでしょうかね。ご存知の方いたら教えてください。

開発サーバ起動時のオプションで対応する場合

開発サーバを起動で記載したとおり、npm run devで実行されるコマンドはviteです。

このコマンドに--hostオプションをつければ別端末からアクセスすることができます。

package.jsonで、コマンドにオプションを追加します。

{
 "scripts": {
    "dev": "vite --host",
    ...
 }
}

scriptのdevを、vite --hostに修正しています。これでnpm run devしたときに、vite --hostとオプション付きで実行されるようになります。

この状態で開発サーバを起動すると、同じようにurlが3つ表示されるので、2つ目のurlを別端末のブラウザに打ち込めば、ページが表示されます。

>npm run dev  

> vite-blog@0.0.0 dev
> vite

  VITE v5.0.2  ready in 599 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: http://192.168.0.23:5173/
  ➜  Network: http://172.28.128.1:5173/
  ➜  press h + enter to show help

「毎回オプション付きで起動するのは嫌だ!1回ぽっきりでいいんだ!」という場合は、package.jsonは修正せずに、以下のコマンドで開発サーバを起動すればOKです。

npm run dev -- --host

コマンド実行時にオプションを渡しているので、その回限りで別端末からアクセス可能になります。

Webサーバのエンドポイントと連動させる

vite.config.tsにproxy設定を行うことで、ViteのプロジェクトからWebサーバのエンドポイント向けにリクエストを投げることができます。Webサーバとの連動を確認したい時に便利です。

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

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],
  server: {
    proxy: {
      // http://localhost:5173/api/test -> http://localhost:3000/api/test
      "/api/test": "http://localhost:3000",
    }
  }
})

server:{proxy:{"vite側":"サーバ側"}}で指定しています。

仮に、Vite開発サーバがport5173、Webサーバがport3000で稼働していた場合、上記の設定だと http://localhost:5173/api/testへのリクエストはhttp://localhost:3000/api/testにリダイレクトされます。

Vite側で、fetch("/api/test")とすれば、Webサーバ側の /api/test エンドポイントの処理が実行されます。

以下のように正規表現を使うことも可能です。1つ1つリダイレクト先を追加するのが面倒な場合は使えると思います。

export default defineConfig({
  plugins: [react()],
  server: {
    proxy: {
      "^/api/.*": "http://localhost:3000",
    }
  }
})

正規表現を使う場合、バージョンにもよるかもしれませんが、冒頭に^(キャレット)が必要です。上記は「/api/任意の1文字以上」という表現になります。

これで、以下のようにリダイレクトされます。

  • /api/test -> http://localhost:3000/api/test
  • /api/foo/bar -> http://localhost:3000/api/foo/bar

proxy設定は、あくまでVite側のリクエストをWebサーバ側にエンドポイント単位でリダイレクトする機能です。ViteとWebサーバをそれぞれ起動しておく必要があります。

加えて、Webサーバ側はVite外のプロジェクトなので、Webサーバ側からViteのエントリポイント(index.html)を返すことは出来ません。Webサーバ側からはVite側のbundlerやTypeScript等のconfigは見えないので、Viteプロジェクトのコンパイルができないからですね。

vite-expressのようなプラグインを利用すれば、Webサーバ側の処理とViteを統合することも出来るようです。HMRも効くようなので、便利そうですね。試す機会ができたら、別途記事にしたいと思います。

そもそも素のReactプロジェクトは必要か?

React公式ドキュメントから素のReactプロジェクトのセットアップ方法が消えたことについて、様々な意見が出ていました。余談として、私の意見も述べたいと思います。

上述のとおり、公式ではNext.jsやRemixのようなフレームワークを使ったセットアップが推奨されています。

確かに、素のReactだとSPA(シングル・ページ・アプリケーション)になり、複数ページのルーティングは出来なくなります。JavaScriptのサイズも大きくなり、ページの初期表示に時間がかかるようになってしまいます。公式ドキュメントに記載のとおり、結局フレームワークが必要になるケースは多いと思います。事実、このサイトも素のJavaScript→React→Next.jsと移行してきています。

しかし、React初心者がいきなりフレームワークから始めるのは、ちょっとハードルが高い気がします。フレームワーク固有で覚えなければならないことも多いので、Reactと並行して覚えるのは心が折られそうです。私も、初めにReactを触れていたからこそ、Next.jsに移行する際に、SSGのような固有の機能に集中できたのだと思っています。

なので、はじめてReactを触れる場合などに、素のReactを使うニーズはあると私は感じます※。Viteはそういう時にcreate-react-appの代わりに使えると思います。

※「はじめてでもNext.jsやRemixのようなフレームワークを使うべし」という意見もあると思います。確かに、ReactにServer Componentが導入され、Next.jsのようなフレームワーク側の実装に依存する機能も大きくなったのも事実かと思います。上記はあくまで私の意見ということでよろしくお願いします。

最後に

Viteのセットアップ方法と基本的な使い方を解説しました。

私もまだCSSを試すために簡単な使い方をしただけですが、セットアップもHMRも速いので快適に使えています。個人的には、create-react-appより容量を食わないのが嬉しいです。PCの容量をあまり気にせず気軽にセットアップできるのは魅力です。

他にも、.envファイルで環境変数を設定する等、まだ触れられていない機能がたくさんあります。便利な機能を見つけたら、適宜この記事に追加していきます。

サードパーティ製のプラグインも豊富なようなので、機能拡張もいろいろできそうです。触れる機会があったら、また記事にしてみたいと思います。

参考

記事一覧に戻る