Compile TS Background Script for Angular 21 Chrome Extension
Fix custom-webpack issues in Angular 21: compile TypeScript background scripts for Chrome extensions using tsc or esbuild. Integrate with angular.json and manifest.json for seamless builds without peer deps.
How to Compile TypeScript Background Script for Chrome Extension in Angular 21 Build?
I’m developing a Chrome extension using Angular 21 and TypeScript. I need to compile the background script (written in TypeScript) as part of the Angular build process.
Problem with @angular-builders/custom-webpack:
This builder worked with Angular 20 but fails in Angular 21 due to peer dependency issues:
npm error code ERESOLVE
npm error ERESOLVE unable to resolve dependency tree
npm error While resolving: angular-v21-webex@0.0.0
npm error Found: @angular/compiler-cli@21.0.6
npm error Could not resolve dependency:
npm error peer @angular/compiler-cli@"^20.0.0" from @angular-builders/custom-webpack@20.0.0
Relevant package.json:
{
"name": "angular-v21-webex",
"devDependencies": {
"@angular/build": "^21.0.4",
"@angular/cli": "^21.0.4",
"@angular/compiler-cli": "^21.0.0",
"@types/chrome": "^0.1.32",
"typescript": "~5.9.2"
}
}
What are alternative builders, configurations, or methods to compile and include TypeScript background scripts in an Angular 21 Chrome extension build? (Not about forcing npm dependencies with --legacy-peer-deps.)
In Angular 21 Chrome extension development, skip the broken @angular-builders/custom-webpack due to peer dependency conflicts with @angular/compiler-cli@21.x—compile your TypeScript background script separately using tsc from your tsconfig.json or the lightning-fast esbuild tool. Add a custom script to package.json that runs alongside ng build, outputting a clean background.js to your dist folder, then reference it directly in manifest.json for seamless integration. This build process keeps everything TypeScript-powered without hacks like --legacy-peer-deps, and it’s battle-tested in real projects.
Contents
- Chrome Extension Background Scripts in Angular 21
- Why custom-webpack Breaks in Angular 21
- Solution 1: Standalone tsc Compilation
- Solution 2: esbuild for Multiple Entry Points
- Integrating with angular.json and manifest.json
- Advanced Tips and Alternatives
- Sources
- Conclusion
Chrome Extension Background Scripts in Angular 21
Ever tried jamming a TypeScript background script into an Angular app only to watch Chrome yell about missing files? Background scripts in Chrome extensions run persistently in the background—think handling notifications, API calls, or context menus—separate from your popup or content scripts. They’re declared in manifest.json like "background": { "service_worker": "background.js" }, but Angular’s build process chunks everything for the main app, hashing filenames (background-abc123.js) and leaving your extension broken.
Angular 21’s shift to esbuild makes this trickier. No more easy Webpack hooks for extra entry points. But don’t sweat it—your TypeScript background script can still compile cleanly. You just need to treat it as a standalone module, borrowing Angular’s TypeScript setup without bundling it into the app.
Why separate? Angular CLI’s scripts in angular.json expect JS, not TS, and won’t spit out a predictable background.js. Community fixes, like those in Stack Overflow threads, point to external tools.
Why custom-webpack Breaks in Angular 21
You hit the nail on the head with that npm error. @angular-builders/custom-webpack@20.0.0 demands @angular/compiler-cli@^20.0.0, but Angular 21 bumps it to 21.x. Even the latest custom-webpack (21.0.3 on npm) might lag, and Angular’s new application builder (@angular-devkit/build-angular:application) doesn’t play nice—no direct equivalent exists.
Just-jeb’s repo confirms this: it’s built for older browser builders, not esbuild/Vite era. Angular 17+ ditched heavy Webpack customization for speed, so forcing it feels like duct-taping a Ferrari. Reddit devs echo this—fewer need custom Webpack now, but Chrome extensions demand it for background scripts.
Result? Hashed outputs mess up manifest.json, and no live reload for dev. Time for smarter paths.
Solution 1: Standalone tsc Compilation
Simplest fix: Leverage TypeScript’s own compiler. Your package.json already has typescript@~5.9.2—perfect.
Create src/background.ts:
// src/background.ts
import type chrome from 'types/chrome'; // Or @types/chrome
chrome.runtime.onInstalled.addListener(() => {
console.log('Extension installed!');
// Add context menu, alarms, etc.
chrome.contextMenus.create({
id: 'my-extension',
title: 'Do something',
contexts: ['page']
});
});
chrome.contextMenus.onClicked.addListener((info) => {
if (info.menuItemId === 'my-extension') {
console.log('Clicked!');
}
});
Add to package.json:
{
"scripts": {
"build:background": "tsc src/background.ts --outDir dist --target es2022 --module none --declaration false",
"build:extension": "ng build && npm run build:background"
}
}
Run npm run build:extension. Boom—dist/background.js appears, no hashing. Tweak tsconfig.json for stricter types or Chrome APIs:
{
"compilerOptions": {
"target": "es2022",
"module": "none",
"lib": ["es2022", "dom"],
"types": ["chrome"]
}
}
Angular docs on compiler options guide the rest. Load unpacked in Chrome: chrome://extensions → Load unpacked → dist folder. Works? Your background script is live.
This mirrors fixes in older SO posts—Angular CLI never natively compiled solo TS files anyway.
Solution 2: esbuild for Multiple Entry Points
Want speed and tree-shaking? esbuild crushes tsc—sub-second builds. Angular 21 uses it under the hood, so why not extend?
Install: npm i -D esbuild
scripts/build-background.js:
// scripts/build-background.js
const esbuild = require('esbuild');
esbuild.build({
entryPoints: ['src/background.ts'],
bundle: true,
outfile: 'dist/background.js',
format: 'iife',
target: 'es2022',
external: ['chrome'], // Chrome APIs are global
minify: process.env.NODE_ENV === 'production'
}).catch(() => process.exit(1));
package.json:
{
"scripts": {
"build:background": "node scripts/build-background.js",
"build:extension": "ng build && npm run build:background"
}
}
GitHub examples like wandri’s angular-chrome-extension use this exact script for background.js. For dev live-reload, add --watch flag and chrome.runtime.reload().
Handles imports too—even Angular services if you export them. DEV Community posts on React/TS extensions adapt easily to Angular.
Pro tip: Multiple entries? entryPoints: ['src/background.ts', 'src/content.ts'] → background.js and content.js.
Integrating with angular.json and manifest.json
Copy assets automatically. angular.json:
{
"projects": {
"your-app": {
"architect": {
"build": {
"options": {
"assets": [
"src/favicon.ico",
"src/assets",
{
"glob": "**/*",
"input": "src/manifest.json",
"output": "/"
},
{
"glob": "background.js",
"input": "dist",
"output": "/"
}
]
}
}
}
}
}
}
manifest.json (v3, since service_worker):
{
"manifest_version": 3,
"name": "Angular Chrome Extension",
"version": "0.0.1",
"background": {
"service_worker": "background.js"
},
"action": {
"default_popup": "index.html"
},
"permissions": ["contextMenus", "activeTab"]
}
Ng build now includes everything. Reload extension—done. SitePoint’s Angular extension guide nails the basics, updated for v3.
Advanced Tips and Alternatives
Nx monorepo? It supports esbuild entry points via plugins—Reddit users swear by it. Bundle background into main app? Risky, bloats size, but Medium posts suggest it for simple logic.
@angular-builders/custom-esbuild? Similar issues, per npm. Standalone Webpack? Overkill, but cookbook example for entry points.
Troubleshoot: Chrome ignores hashed JS? Check console. No types? Add ///
Starters: jprivet-dev’s kit or larscom’s scaffold.
Sources
- How to use TypeScript import in Chrome extension background page?
- Chrome Extension with Angular — from zero to a little hero
- GitHub - wandri/angular-chrome-extension
- Can’t load background script - manifest.json - Angular Chrome Extension
- Custom webpack config in angular esbuild
- GitHub - just-jeb/angular-builders
- @angular-builders/custom-webpack - npm
- Angular compiler options
- Angular CLI how to compile a specific ts file?
- GitHub - jprivet-dev/chrome-extension-angular-starter-kit
Conclusion
Ditch custom-webpack headaches in Angular 21 Chrome extension builds—tsc or esbuild delivers your TypeScript background script reliably, integrated via angular.json assets and a crisp manifest.json. Start with tsc for simplicity, scale to esbuild for prod polish, and you’ll have a reloadable, type-safe extension in minutes. This approach future-proofs your workflow as Angular evolves, keeping dev fast and Chrome happy. Dive in, tweak those scripts, and extend away.