Scripts
Ship extension behavior across background, content scripts, and UI pages with one JavaScript/TypeScript pipeline.
Extension.js collects script entrypoints from manifest.json, HTML pages, and special folders, then compiles them with the default SWC-based setup.
JavaScript capabilities
| Capability |
What it gives you |
| Shared JS/TS pipeline |
Compile extension scripts with one default transformer setup |
| Entrypoint discovery |
Load script entries from manifest, pages, and special folders |
| Runtime-safe outputs |
Emit predictable script artifacts for each extension context |
| Path normalization |
Rewrite supported extension-path literals to output-safe paths |
Supported script entrypoints
| Manifest field |
File type expected |
background.service_worker |
.js, .ts, .mjs, .tsx |
background.scripts |
.js, .ts, .mjs, .tsx |
content_scripts.js |
.js, .ts, .mjs, .tsx |
user_scripts.api_script |
.js, .ts, .mjs, .tsx |
Sample script declaration in manifest.json
Here's an example of defining JavaScript files in manifest.json:
{
"manifest_version": 3,
"name": "My Extension",
"version": "1.0.0",
"background": {
"service_worker": "./scripts/background.ts"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["./scripts/content-script.ts"]
}
]
}
Development behavior
- Content scripts: HMR/remount flow is injected for fast updates.
- Extension pages: Page scripts follow page HMR behavior.
- Background/service worker: script updates can trigger hard extension reload depending on change type.
- Entrypoint list changes: changing manifest script structure may require dev server restart.
Script locations and conventions
- Use
scripts/ at project root for script-centric extension entries.
- Use
pages/ for HTML entrypoints with their own scripts.
- Keep manifest-referenced paths stable; avoid moving entry files without updating manifest.
Transform and bundling defaults
- SWC is the default transformer for JS/TS/JSX/TSX.
- Browser-first resolution (
browser, module, main) is used.
- Entries are emitted predictably without runtime chunk splitting by default.
- Path resolution rewrites static extension-path literals in supported APIs.

Dynamic import caveats
- Content-script dynamic import has runtime constraints; extension loader fallbacks are used where possible.
- Service worker lazy-loading has browser limitations; prefer predictable entry loading in extension runtime-critical code.
Best practices
- Keep entry scripts thin and move feature logic into shared modules.
- Prefer static import paths for extension APIs so path resolution can normalize them safely.
- Avoid unnecessary dynamic import in content scripts and service workers.
- Treat manifest script list edits as structural changes in development workflows.
Next steps