Viteの設定とは、プロジェクト直下の vite.config.js(または .ts)に defineConfig() で書く、開発サーバーとビルドの動作設定です。 何も書かなくても動きますが、パスの別名(alias)、APIのプロキシ、デプロイ先のパス(base)、チャンク分割などは設定で調整します。

公式の設定リファレンスは「共通・サーバー・ビルド・プレビュー」などページごとに分かれています。この記事では、よく使う設定を「やりたいこと → コピペ設定」の一覧表にまとめ、Vite 8.3.1 で実際に vite build と開発サーバーを動かした出力を載せました。proxyが効かない、環境変数が undefined、base の設定ミスで404 といったつまずきも実際に再現し、直す前と後を比べています。Vite 8で既定になったRolldownでの manualChunks の扱いも、実行結果で確認しています。

vite.config の早見表(用途 → コピペ設定)

やりたいこと 設定キー コピペ例
Vue / React を使う plugins plugins: [vue()] / plugins: [react()]
@/ で src/ を指す resolve.alias alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) }
開発サーバーのポートを固定 server.port / strictPort server: { port: 5173, strictPort: true }
スマホ等から開発サーバーに接続 server.host server: { host: true }(CLIなら vite --host)
/api をバックエンドへ転送 server.proxy proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true } }
起動時にブラウザを開く server.open server: { open: true }
サブディレクトリに公開 base base: '/shop/'
出力先を変える build.outDir build: { outDir: 'public/app' }
ソースマップを出す build.sourcemap build: { sourcemap: true }
ライブラリを別チャンクに分ける build.rolldownOptions.output.codeSplitting 下の「チャンク分割」参照
警告が出るチャンクサイズを変える build.chunkSizeWarningLimit build: { chunkSizeWarningLimit: 1000 }(kB)
対象ブラウザを変える build.target build: { target: 'es2022' }
ビルド時に定数を埋め込む define define: { __APP_VERSION__: JSON.stringify('1.4.0') }
環境変数の接頭辞を変える envPrefix envPrefix: ['VITE_', 'PUBLIC_']
CSS Modules のクラス名形式 css.modules css: { modules: { localsConvention: 'camelCase' } }
Sass に共通変数を読み込む css.preprocessorOptions scss: { additionalData: '@use "@/styles/vars" as *;' }
vite preview のポート preview.port preview: { port: 4173 }
モードで設定を切り替える 関数形式 defineConfig(({ command, mode }) => ({ ... }))

迷ったらまず plugins・resolve.alias・server.proxy・base の4つを押さえると、多くのプロジェクトで必要な設定がそろいます。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「vite.configの書き方|用途別コピペ一覧とVite 8の変更点」

検証環境

項目 バージョン
Node.js 22.22.2
vite 8.3.1(内部のRolldownは1.2.11)
@vitejs/plugin-vue 6.0.9
@vitejs/plugin-react 6.1.1
vue 3.5.43
画面確認 Playwright 1.56.1 + Chromium

検証用アプリは、Vue 3の画面に「日付表示(dayjs)」「遅延読み込みのレポート画面」「環境変数の表示」「/api/items の取得ボタン」を置いた小さな構成です。

Vite 8での主な変更点

公式の移行ガイド(Migration from v7)で確認した、設定ファイルに関わる変更です。

項目 Vite 7まで Vite 8
本番ビルドのバンドラー Rollup Rolldown(Rust製)
JS変換・圧縮 esbuild Oxc(build.minify: 'esbuild' で戻せる)
CSS圧縮 esbuild Lightning CSS
バンドラーのオプション build.rollupOptions build.rolldownOptions(旧名も変換される)
手動チャンク分割 output.manualChunks output.codeSplitting(関数形式の manualChunks は非推奨、オブジェクト形式は削除)
変換の設定 esbuild オプション oxc オプション(旧名は非推奨)
依存の事前バンドル optimizeDeps.esbuildOptions optimizeDeps.rolldownOptions
既定の build.target — Chrome 111 / Edge 111 / Firefox 114 / Safari 16.4

既存の設定の多くはそのまま動きますが、manualChunks をオブジェクトで書いている場合はビルドが止まります(後述の実行結果参照)。

基本形:すべての設定の土台

// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { fileURLToPath, URL } from 'node:url'

export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) },
  },
})

defineConfig で囲むと、エディタで設定キーの補完と型チェックが効きます。 TypeScriptで書くなら vite.config.ts にして同じ内容を書けます。

React の場合はプラグインを差し替えます(@vitejs/plugin-react@6.1.1 + Vite 8.3.1 でビルドできることを確認済み)。

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

export default defineConfig({ plugins: [react()] })

package.json に "type": "module" を書く

"type": "module" がないプロジェクトで起動すると、Vite 8.3.1 では次の警告が表示されました。

(!) Your Vite config uses features that are unsupported by `configLoader: 'native'`, which is planned to become the default in a future major version of Vite:
  - ESM syntax in a file loaded as CommonJS (vite.config.js:1:1). Use a `.mjs` extension or set `"type": "module"` in the closest package.json
Set `VITE_CONFIG_NATIVE_IGNORE_WARNING=true` to suppress this warning.

package.json に "type": "module" を追加するか、設定ファイルを vite.config.mjs にすると警告は消えます。 将来の既定(ネイティブ読み込み)に備える意味でも、先にそろえておくと安心です。

resolve.alias:@/ でインポートする

alias を設定せずに import { today } from '@/utils/format' と書いてビルドすると、次のエラーになりました。

✗ Build failed in 157ms
error during build:
Build failed with 1 error:

Error: [vite]: Rolldown failed to resolve import "@/utils/format" from "/…/src/App.vue".
This is most likely unintended because it can break your application at runtime.

上の基本形の resolve.alias を加えると、ビルドが通ります。TypeScriptを使う場合は tsconfig.json の compilerOptions.paths にも "@/*": ["./src/*"] を書き、エディタの型解決と合わせます(Viteの alias は tsconfig を自動では読みません)。

server:ポート・host・proxy

proxy のコピペ設定

// vite.config.js(抜粋)
server: {
  port: 7313,
  strictPort: true,          // ポート使用中なら別ポートに逃げずに止まる
  proxy: {
    '/api': {
      target: 'http://localhost:7314',
      changeOrigin: true,
      rewrite: (path) => path.replace(/^\/api/, ''),
    },
  },
},

バックエンド(ポート7314)は /items にだけ ["ノート","ペン"] を返す簡単なNode.jsサーバーです。画面のボタンから fetch('/api/items') を呼び、表示とバックエンドが受け取ったパスを記録しました。

実行結果:3パターンの比較

設定 画面に表示された結果 バックエンドが受け取ったパス
proxy + rewrite あり 200 ["ノート","ペン"] /items
proxy あり・rewrite なし 404 not found /api/items
proxy なし 200 <!doctype html> …(index.html) (届かない)

「proxyが効かない」の多くは、この2つのどちらかです。

  • rewrite がない:/api を付けたままバックエンドに転送されます。バックエンド側のルートが /api/... なら rewrite は不要、/... なら必要です。
  • proxy がない(キーが一致しない):開発サーバーがSPAとして index.html を ステータス200で 返します。res.json() で Unexpected token '<' のようなエラーになるときは、これを疑います。

もう1つ、fetch('http://localhost:8080/api/items') のように完全なURLで呼ぶと proxy を通りません。 proxy を使うときは /api/items のようにパスだけで呼びます。proxy は vite(開発サーバー)と vite preview でだけ働き、本番のWebサーバーには同じ転送設定が別途必要です。

他の端末から開発サーバーにつなぐ

server: { host: true }   // 0.0.0.0 で待ち受け。CLI なら npx vite --host

既定では localhost のみで待ち受けます。同じネットワークのスマホやDockerコンテナ外から開くときは host: true にします。

環境変数:.env と import.meta.env

ファイルとコード

# .env
VITE_API_URL=http://localhost:7314
SECRET_KEY=do-not-expose

# .env.staging
VITE_API_URL=https://staging.example.com
// 画面側のコード
const env = {
  apiUrl: import.meta.env.VITE_API_URL,
  secret: import.meta.env.SECRET_KEY,
  mode: import.meta.env.MODE,
  base: import.meta.env.BASE_URL,
}

実行結果

開発サーバーで表示した JSON.stringify(env) です(undefined のキーは JSON から省かれます)。

{"apiUrl":"http://localhost:7314","mode":"development","base":"/"}

VITE_ で始まらない SECRET_KEY は undefined になり、画面から読めません。 これは意図された仕様で、APIキーなどの秘密情報がブラウザに配られるのを防ぐためです。逆に、VITE_ を付けた値はビルド後のJSに文字列として埋め込まれるので、秘密情報には付けないようにします。

--mode staging でビルドし、生成されたJSに含まれる文字列を調べた結果です。

npx vite build --mode staging
grep -o 'staging.example.com|do-not-expose|localhost:7314' dist/assets/index-*.js | sort | uniq -c
      1 staging.example.com

.env.staging の値が優先され、SECRET_KEY の値はJSに含まれていません。

.env の読み込み順と mode

ファイル 読み込まれる場面
.env すべてのモード
.env.local すべてのモード(git管理外にする用途)
.env.[mode] 指定モードのみ(例:.env.production)
.env.[mode].local 指定モードのみ・git管理外

後ろの行ほど優先されます。 vite(開発)の既定モードは development、vite build は production です。

vite.config.js の中で環境変数を使う

設定ファイルの中では import.meta.env が使えないため、loadEnv で読み込みます。

import { defineConfig, loadEnv } from 'vite'

export default defineConfig(({ command, mode }) => {
  const env = loadEnv(mode, process.cwd(), '')   // 第3引数 '' で接頭辞なしも読む
  console.log(`[config] command=${command} mode=${mode} VITE_API_URL=${env.VITE_API_URL}`)
  return {
    server: { proxy: { '/api': { target: env.VITE_API_URL, changeOrigin: true } } },
  }
})

実行結果です。

[config] command=serve mode=development VITE_API_URL=http://localhost:7314
[config] command=build mode=production VITE_API_URL=http://localhost:7314
[config] command=build mode=staging VITE_API_URL=https://staging.example.com

base:サブディレクトリに公開する

ビルドした dist を https://example.com/shop/ のようなサブディレクトリに置く場合の設定です。検証では Python の簡易サーバーで /shop/ 配下に置き、Chromiumで開きました。

設定 結果
base 未設定(/) HTTP 404 /assets/index-BlvVNnZP.js、画面は描画されない
base: '/shop/' 日付 2026/09/28 が表示され、BASE_URL は /shop/
export default defineConfig({
  base: '/shop/',   // 前後のスラッシュを付ける
})

base: '/shop/' でビルドした index.html の読み込みパスです。

src="/shop/assets/index-BZZqLJlw.js"

「ビルドしたら真っ白」「JSやCSSが404」のときは base を確認します。 公開先が決まっていない場合は base: './'(相対パス)も使えます。画面内でパスを組み立てるときは import.meta.env.BASE_URL を使うと、base の変更に追従します。

build:出力先・ソースマップ・チャンク分割

sourcemap

build: { sourcemap: true },   // 'hidden' にすると .map は出すがJSから参照しない
dist/assets/Report-BSEZOzft.js   0.30 kB │ gzip:  0.29 kB │ map:   0.48 kB
dist/assets/index-BlvVNnZP.js   72.81 kB │ gzip: 28.88 kB │ map: 583.94 kB

チャンク分割:設定の前後で比較

既定(設定なし) では、動的インポートした画面だけが分かれ、Vueとdayjsはアプリ本体と同じファイルに入ります。

dist/assets/Report-BSEZOzft.js   0.26 kB │ gzip:  0.25 kB
dist/assets/index-BlvVNnZP.js   72.76 kB │ gzip: 28.84 kB

Vite 8 の書き方(rolldownOptions + codeSplitting) でライブラリを分けます。

build: {
  rolldownOptions: {
    output: {
      codeSplitting: {
        groups: [
          { name: 'vue', test: /node_modules[\\/]@?vue/ },
          { name: 'vendor', test: /node_modules/ },
        ],
      },
    },
  },
},
dist/assets/Report-BpRU6MPx.js             0.26 kB │ gzip:  0.25 kB
dist/assets/rolldown-runtime-CbXtAM7H.js   0.58 kB │ gzip:  0.36 kB
dist/assets/index-zGQggCgR.js              2.88 kB │ gzip:  1.52 kB
dist/assets/vendor-CiA2wo4k.js             7.18 kB │ gzip:  3.09 kB
dist/assets/vue-BhGQAgx-.js               62.54 kB │ gzip: 24.66 kB

アプリ本体が 72.76 kB から 2.88 kB になり、Vue(62.54 kB)とその他のライブラリ(7.18 kB)が別ファイルに分かれました。 ライブラリはアプリのコードより更新頻度が低いので、分けておくとデプロイ後もブラウザのキャッシュが効きやすくなります。groups は上から順に判定されるため、細かい条件を先に書きます。

Vite 7 以前の書き方はどうなるか

書き方 Vite 8.3.1 での結果
rollupOptions.output.manualChunks(id) {...}(関数) ビルド成功(vendor チャンク 69.74 kB が出力)
rollupOptions.output.manualChunks: { vue: ['vue'] }(オブジェクト) ビルド失敗
rolldownOptions.output.codeSplitting ビルド成功(推奨)

オブジェクト形式の実行結果です。

Warning: Invalid output options (1 issue found)
- For the "manualChunks". Invalid type: Expected Function but received Object.
✓ 15 modules transformed.
✗ Build failed in 108ms
error during build:
Build failed with 1 error:

TypeError: manualChunks is not a function

関数形式は今も動きますが非推奨です。移行するときは codeSplitting.groups の name と test に書き換えます。 Rolldownの型定義には、manualChunks と codeSplitting を両方書いた場合は manualChunks が無視されると記載されています。

define:ビルド時に定数を埋め込む

define: { __APP_VERSION__: JSON.stringify('1.4.0') },
{"apiUrl":"http://localhost:7314","mode":"production","base":"/shop/","appVersion":"1.4.0"}

値はコードにそのまま置き換えられるため、文字列は JSON.stringify で囲みます。 囲まないと 1.4.0 という式として埋め込まれ、構文エラーの原因になります。TypeScriptでは declare const __APP_VERSION__: string を型定義ファイルに書きます。

実務でそのまま使える vite.config.js(完成形)

ここまでの設定を1つにまとめた完成形です。Vite 8.3.1 で npm run build(上と同じ5ファイルに分割)と、開発サーバーでの /api/items 取得(200 ["ノート","ペン"])を確認しました。

// vite.config.js(Vite 8.3.1 / package.json に "type": "module")
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import { fileURLToPath, URL } from 'node:url'

export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd(), '')
  return {
    plugins: [vue()],
    base: env.VITE_BASE ?? '/',
    resolve: {
      alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) },
    },
    // npm scripts 経由で起動すると package.json の version が入る
    define: { __APP_VERSION__: JSON.stringify(process.env.npm_package_version ?? '0.0.0') },
    server: {
      port: 7313,
      strictPort: true,
      proxy: {
        '/api': {
          target: env.VITE_API_URL ?? 'http://localhost:7314',
          changeOrigin: true,
          rewrite: (path) => path.replace(/^\/api/, ''),
        },
      },
    },
    preview: { port: 4173 },
    build: {
      outDir: 'dist',
      sourcemap: mode !== 'production',
      rolldownOptions: {
        output: {
          codeSplitting: {
            groups: [
              { name: 'vue', test: /node_modules[\\/]@?vue/ },
              { name: 'vendor', test: /node_modules/ },
            ],
          },
        },
      },
    },
  }
})

よくあるエラーと対処表

症状・エラー文 原因 対処
Rolldown failed to resolve import "@/..." alias 未設定 resolve.alias を追加(TSは paths も)
API が404、バックエンドに /api/... が届く rewrite なし rewrite: (p) => p.replace(/^\/api/, '')
API の応答が index.html(200) proxy のキー不一致・未設定 proxy のキーと fetch のパスを合わせる
import.meta.env.XXX が undefined VITE_ 接頭辞なし 変数名を VITE_XXX に(秘密情報は付けない)
設定ファイルで env が読めない import.meta.env を使った loadEnv(mode, process.cwd(), '')
ビルド後に真っ白・assets が404 base と公開パスが不一致 base: '/サブパス/' または './'
manualChunks is not a function オブジェクト形式の manualChunks codeSplitting.groups に書き換え
configLoader: 'native' の警告 CommonJS扱いでESMを読み込み "type": "module" か .mjs
ポートが勝手に変わる 使用中のため次の番号に移動 strictPort: true で明示的に止める

よくある質問

Q. vite.config.js と vite.config.ts のどちらがよいですか? A. どちらも同じ内容を書けます。TypeScriptのプロジェクトなら .ts にすると、プラグインのオプションも型チェックされます。

Q. Vite 8 に上げたら rollupOptions は書き換える必要がありますか? A. 今回の検証では rollupOptions のままでもビルドできました。公式の移行ガイドでは rolldownOptions への書き換えが案内されているので、更新のタイミングで名前をそろえておくと安心です。オブジェクト形式の manualChunks だけは先に書き換えが必要です。

Q. 本番環境でも proxy は使えますか? A. server.proxy は開発サーバー(と vite preview)の機能です。本番では Nginx などのWebサーバーやホスティングの設定で同じ転送を行うか、APIのURLを環境変数で切り替えます。

Q. 環境変数をブラウザに出したくない値はどう扱いますか? A. VITE_ を付けずに .env に置けば、画面側のコードには埋め込まれません。サーバー側の処理や loadEnv を使った設定ファイル内でだけ使います。

まとめ

  • defineConfig で書くと補完が効き、"type": "module" で将来の読み込み方式にも対応
  • alias・proxy・base・環境変数の4つで、よくある設定の大半をカバーできる
  • proxy が効かないときは rewrite と、index.html が200で返っていないかを確認
  • 環境変数は VITE_ 接頭辞だけが画面に届き、値はJSに埋め込まれる
  • base のずれは assets の404になる。サブパス公開は base: '/shop/'
  • Vite 8 は Rolldown が既定。チャンク分割は rolldownOptions.output.codeSplitting へ
  • 今回の検証では、分割によりアプリ本体が 72.76 kB → 2.88 kB になり、ライブラリを別キャッシュにできた

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「vite.configの書き方|用途別コピペ一覧とVite 8の変更点」

株式会社RJCでは、ビルドツールの設定を実際に動かして確かめ、その結果をプロジェクトの中で仲間と共有しています。こうした知識を共有しながら、日々技術を磨いています。

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?