C
chrome-extension-multiple-entry-points
About chrome-extension-multiple-entry-points
A build pattern for Chrome extensions with background, content, and popup entry points. It uses a separate Vite config for each entry to emit self-contained IIFE bundles without shared chunks.
Key features
- 01Separate Vite config per entry point
- 02Self-contained IIFE output
- 03Inline dynamic imports
- 04Append builds to dist/
- 05Cross-platform asset copy commands
Use cases
- 01Bundling background, content, and popup scripts
- 02Avoiding shared chunks across extension contexts
- 03Building extension assets into dist/
Install
Copy the command and run it in a terminal.
$
npx skills add https:/ / github.com/ gkwa/ volcanicviper --skill chrome-extension-multiple-entry-pointsAfter installing, type/chrome-extension-multiple-entry-pointsin Claude Code to confirm it loaded.
Bundled filestile.json
Details
From the project READMEThe Problem
Chrome extensions need multiple entry points (background, content, popup), but modern bundlers create shared chunks that Chrome cannot load across isolated execution contexts.
The Solution
Use a separate Vite config file for each entry point. Each build produces a self-contained IIFE file with no shared chunks.
Project Structure
my-extension/
├── src/
│ ├── background/background.ts
│ ├── content/content.ts
│ ├── popup/
│ │ ├── popup.ts
│ │ ├── popup.html
│ │ └── popup.css
│ └── manifest.json
├── vite.background.config.ts
├── vite.content.config.ts
├── vite.popup.config.ts
└── package.json
package.json Scripts
{
"scripts": {
"build": "shx rm -rf dist && shx mkdir -p dist && pnpm run build:all && pnpm run copy:assets",
"build:all": "pnpm run build:background && pnpm run build:content && pnpm run build:popup",
"build:background": "vite build --config vite.background.config.ts",
"build:content": "vite build --config vite.content.config.ts",
"build:popup": "vite build --config vite.popup.config.ts",
"copy:assets": "shx cp src/manifest.json src/popup/popup.html src/popup/popup.css dist/",
"dev": "pnpm run build && pnpm run build --watch"
},
"devDependencies": {
"@types/chrome": "^0.0.323",
"typescript": "^5.8.3",
"vite": "^6.3.5",
"shx": "^0.3.4"
}
}
Vite Config Pattern
Each config follows the same pattern — only the input file and output filename differ:
import { defineConfig } from "vite"
import { resolve } from "path"
export default defineConfig({
build: {
emptyOutDir: false,
rollupOptions: {
input: resolve(__dirname, "src/background/background.ts"),
output: {
entryFileNames: "background.js",
dir: "dist",
format: "iife",
inlineDynamicImports: true,
},
},
target: "es2020",
},
define: {
'process.env': {},
'global': 'globalThis'
},
})
Key Rules
- Use
format: "iife"— not ES modules - Set
inlineDynamicImports: true— no shared chunks - Use
emptyOutDir: false— each build appends todist/, not overwrites - Use
shxfor cross-platform copy/rm commands - Accept that dependencies are duplicated across bundles — that is intentional
Comments
Markdown supported