孅いエンジニアブログ

Viteでimportを使っている複数のtsをそれぞれ1つのjsにバンドルしたい時

Chrome拡張機能をTypeScript作っていて、Viteでビルドしてました。

background.tscontent.tsというファイルを作って開発していました。

その時のViteのコンフィグ設定です。

import { defineConfig } from "vite";

// https://vitejs.dev/config/
export default defineConfig({
	root: "./src/",
	build: {
		outDir: "../dist/",
		rollupOptions: {
			output: {
				entryFileNames: "[name].js",
				chunkFileNames: "[name].js",
				assetFileNames: "[name].[ext]"
			},
			input: {
				content: "./src/content.ts",
				background: "./src/background.ts"
			}
		}
	}
});

これでこうなるんだろう!フン!

↓ 結果

🤔 Huh...?

なんか使ってるライブラリのような名前とともに、ぞろぞろとビルドされてきやがりました。しかもjsの中でimportもそのまま使われています。

Chrome拡張機能として使いたいのでimportは使ってほしくないし、使用してるライブラリ含めbackground.jscontent.jsに全て集約して、これら2つ以外出力してほしくないです。

なんとかしたいと調べてみるとinlineDynamicImportsなるオプションがある様子。これを使うとimportを使わずにバンドルしてくれるっぽい!

Configuration Options | Rollup

ちゃんとあるじゃん~

import { defineConfig } from "vite";

// https://vitejs.dev/config/
export default defineConfig({
	root: "./src/",
	build: {
		outDir: "../dist/",
		rollupOptions: {
			output: {
				entryFileNames: "[name].js",
				chunkFileNames: "[name].js",
				assetFileNames: "[name].[ext]",
				inlineDynamicImports: true // 追加!頼んだで!
			},
			input: {
				content: "./src/content.ts",
				background: "./src/background.ts"
			}
		}
	}
});

じゃあビルドしますね~

🤔🤔 Huh...?

複数inputを指定してるとできないっぽい。おぉい!

じゃあ複数回ビルドするかという話で、それぞれのファイルごとにビルドすることで解決してやります。

もともとビルドコマンドはこんな感じだったのですが、

tsc && vite build

こんな感じに修正!

rm -rf ./dist/* && tsc && printf './src/content.ts ./src/background.ts' | xargs -d ' ' -P0 -I % vite build -- --input=%

printf './src/content.ts ./src/background.ts'でビルド対象のファイルパスをスペース区切りで出力。

xargsでvite buildにファイル名を渡してビルドしています。-d ' 'でスペース区切り、-I %vite build -- --input=%にファイル名を渡しています。

./src/content.ts./src/background.tsに対してそれぞれvite buildする感じですね。

Viteのコンフィグもinputを動的に生成するように修正します。

import { defineConfig } from "vite";

// ↓ process.argvでビルド対象のファイルを読み取ってinputに指定します。
const input = process.argv[4]?.split("=")?.[1];
if (input) {
	console.log("Build: " + input);
}

// https://vitejs.dev/config/
export default defineConfig({
	server: {
		host: "0.0.0.0"
	},
	root: "./src/",
	build: {
		outDir: "../dist/",
		emptyOutDir: false, // 実はこれも追加
		rollupOptions: {
			output: {
				entryFileNames: "[name].js",
				chunkFileNames: "[name].js",
				assetFileNames: "[name].[ext]",
				inlineDynamicImports: true // 次こそ頼んだで!
			},
			input: input
		}
	}
});

実行してみましょう。

😊 それでええんや。

ファイルそれぞれに対してvite buildすることで複数のinputを指定したときにinlineDynamicImportsが使えないという問題を回避できました。

ただ並列実行してるため、ビルド完了が遅れたファイルにどんどん先にビルド終わったファイルたちが上書きされていってしまいます。

なのでemptyOutDirというオプションをfalseにして、ビルド先を勝手に消さないようにしてます。その代わりにビルドコマンドの最初にrm -rf ./dist/*を追加しています。

良いんじゃないでしょうか!