Skip to content

Instantly share code, notes, and snippets.

@0RIM0
Last active February 4, 2025 14:56
Show Gist options
  • Save 0RIM0/d728c680dccdf4b0f95bbe6ebf68d1ec to your computer and use it in GitHub Desktop.
Save 0RIM0/d728c680dccdf4b0f95bbe6ebf68d1ec to your computer and use it in GitHub Desktop.
Vite のマルチルート

Vite のマルチルート

Vite のデフォルトだと package.json と同じルートの階層に index.html があって、これがエントリポイント
Vite でエントリポイントを増やす場合は設定ファイルの rollupOptions を使って rollup 側の設定を書くことになる

export default {
	server: {
		host: true,
	},
	build: {
		rollupOptions: {
			input: {
				main: resolve(__dirname, "index.html"),
				sub: resolve(__dirname, "sub.html"),
			},
		},
	},
}

こうすると、 /sub へのアクセスでは sub.html が返され、それ以外はすべて index.html のページになる
sub のアプリも SPA にしたくて、次のように書いても

input: {
	main: resolve(__dirname, "index.html"),
	sub: resolve(__dirname, "sub/index.html"),
},

/sub/* へのアクセスは sub/index.html にならず、 /sub//sub/index.html へのアクセスのみが sub/index.html になる
/sub/abc などへのアクセスは index.html が返される

Vite 自身ではサポートしてないみたいなので、プラグイン等でサーバーの処理を書き換えて /sub/*/sub/index.html になるようしないといけなそう
例)
https://stackoverflow.com/questions/78724231/how-to-setup-vite-multi-pages-react-spa-with-nested-routes-on-one-of-the-pages

マルチルート機能自体が Vite の設定というより rollup の設定を直接触って設定するものだし、完全なサポートになってなさそう
一般ユーザー用と管理者ユーザー用で別アプリだけどコードの多くを共有するのでエントリポイント 2 つでビルドみたいなケースは結構ありそうなのに

  • app/user/index.html
  • app/admin/index.html

みたいなエントリポイントにしたい


また、配置先もバラバラなケースがある

dir1/dir2/app1/*
dir1/dir3/dir4/app2/*

配置するフォルダがエントリポイントごとに違うけど Vite の設定ではサーバーのどこにアプリを設置するかは base を一つ設定できるだけ
base に相対パスの ./ も設定できるけど、これは .html ファイルから ./asset/file.js みたいな読み込みになるだけ
HTML 中で base タグ等で制御してないと、別階層になる SPA ではアセットファイルが読み込めなくてエラーになる

出力先も同様で outDir に一つ場所を指定できるだけ
エントリポイントごとに別々の出力にできない

ひとつの設定にまとめるより、それぞれ別の config ファイルを作ったほうがいいかも
上の 2 パターンでやってみるとこんな感じ

[app1.config.js]

import { dirname, resolve } from "node:path"
import { fileURLToPath } from "node:url"

const __dirname = dirname(fileURLToPath(import.meta.url))

export default {
	server: {
		host: true,
		port: 8001,
	},
	base: "/dir1/dir2/app1",
	build: {
		outDir: "dist-app1",
		rollupOptions: {
			input: {
				app1: resolve(__dirname, "app1.html"),
			},
		},
	},
}

[app2.config.js]

import { dirname, resolve } from "node:path"
import { fileURLToPath } from "node:url"

const __dirname = dirname(fileURLToPath(import.meta.url))

export default {
	server: {
		host: true,
		port: 8002,
	},
	base: "/dir1/dir3/dir4/app2",
	build: {
		outDir: "dist-app2",
		rollupOptions: {
			input: {
				app2: resolve(__dirname, "app2.html"),
			},
		},
	},
}

app1 を watch したいときは

pnpm vite -c app1.config.js

app2 を build したいときは

pnpm vite build -c app2.config.js

package.json に書くなら

{
	"scripts": {
		"app1": "vite -c app1.config.js",
		"app2": "vite -c app2.config.js",
		"build:app1": "vite build -c app1.config.js",
		"build:app2": "vite build -c app2.config.js",
		"build": "pnpm run build:app1 && pnpm run build:app2"
	}
}

のような感じ


本題とそれるけど rollupOptionsinput のオブジェクト

input: {
	foo: resolve(__dirname, "bar.html"),
},

キーは foo で、パスの方が bar.html みたいに名前を揃えなくてもいい
パスは .html ファイルが存在するパスである必要があって、出力される HTML のファイル名は元のまま
この場合は bar.html
foo の方は assets フォルダ内の .js ファイルの名前に使われる
キーを dir/foo にすれば assets フォルダ内に dir フォルダが作られてその中に foo の .js ファイルが出力される
.js ファイルは自動で読み込まれる上にハッシュ値もつくものなので、名前を意識する必要はあまりなさそう
意識する必要のあるエントリポイントの .html ファイルの名前には影響しないので基本 .html のファイル名に合わせるで良さそう

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment