DEV Community

Suguru Inatomi
Suguru Inatomi

Posted on • Originally published at blog.lacolaco.net on

Building Browser Extensions with WXT + Angular

I created a starter template for developing browser extensions by combining WXT and Angular. You can efficiently develop extensions for multiple browsers including Chrome and Firefox using Angular’s latest features.

GitHub logo lacolaco / wxt-angular-starter

Browser extension starter template using WXT and Angular

WXT + Angular Starter

A browser extension starter template using WXT and Angular.

Features

  • Angular 21 with zoneless change detection
  • Tailwind CSS v4 for styling
  • WXT for cross-browser extension development
  • Vite 7 powered build system
  • TypeScript with strict mode

Quick Start

# Clone the repository
git clone https://github.com/user/wxt-angular-starter.git
cd wxt-angular-starter

# Install dependencies
pnpm install

# Start development server (Chrome)
pnpm dev

# Start development server (Firefox)
pnpm dev:firefox
Enter fullscreen mode Exit fullscreen mode

Available Scripts

Script Description
pnpm dev Start dev server for Chrome
pnpm dev:firefox Start dev server for Firefox
pnpm build Build for Chrome
pnpm build:firefox Build for Firefox
pnpm zip Build and package for Chrome
pnpm zip:firefox Build and package for Firefox
pnpm compile Type-check without emitting

Project Structure

├── entrypoints/
│   ├── popup/          # Angular popup entrypoint
│   │   ├── index.html
│   │   ├── main.ts     # Angular bootstrap
│   │   ├── app.ts      # Root component
│   │   └── style.css

What is WXT

https://wxt.dev/

WXT is a framework that streamlines browser extension development. Built on Vite, it provides a comfortable development experience with fast HMR (Hot Module Replacement) and a file-based manifest auto-generation system.

Particularly useful is its ability to generate extensions for multiple browsers including Chrome, Firefox, Edge, and Safari from a single codebase. It supports both Manifest V2 and V3, absorbing browser-specific differences.

Building Browser Extensions with Angular

For the UI part of browser extensions, you’ll be loading HTML. WXT officially supports several libraries. When you run the wxt init command, you can choose templates like Vanilla, React, or Vue, but there’s no Angular template yet. However, the setup isn’t too difficult - you can simply configure Angular on top of the Vanilla base.

Note that to run Angular with Vite, you need the @analogjs/vite-plugin-angular plugin. This plugin is provided by the AnalogJS project and enables Angular to work within the Vite ecosystem.

https://www.npmjs.com/package/@analogjs/vite-plugin-angular

Project Structure

The starter template has the following structure:

├── entrypoints/
│ ├── popup/ # Angular popup interface
│ │ ├── index.html
│ │ ├── main.ts # Angular bootstrap
│ │ ├── app.ts # Root component
│ │ └── style.css # Tailwind CSS
│ ├── background.ts # Background script
│ └── content.ts # Content script
├── wxt.config.ts # WXT configuration
├── tsconfig.json # Base TypeScript config
└── [tsconfig.app](http://tsconfig.app/).json # Angular-specific config
Enter fullscreen mode Exit fullscreen mode

In WXT, manifests are automatically generated from files in the entrypoints directory. The popup directory serves as the entry point for the Angular application, while background.ts and content.ts can be written in plain TypeScript.

Setup Steps

Here are the steps to build from scratch.

1. Initialize WXT Project

First, create a WXT project:

pnpm dlx wxt@latest init my-extension
cd my-extension
Enter fullscreen mode Exit fullscreen mode

2. Install Dependencies

Install Angular core and build tools:

# Angular core
pnpm add @angular/core @angular/common @angular/compiler @angular/platform-browser rxjs

# Build tools
pnpm add -D @analogjs/vite-plugin-angular @angular/build @angular/compiler-cli

# Tailwind CSS (optional)
pnpm add -D tailwindcss @tailwindcss/vite
Enter fullscreen mode Exit fullscreen mode

3. Pin Vite Version

Since @analogjs/vite-plugin-angular requires Vite 7.x, pin the version in package.json:

{
  "pnpm": {
    "overrides": {
      "vite": "^7.3.0"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

After adding this, run pnpm install to apply the version.

4. Configure WXT

Configure Vite plugins in wxt.config.ts:

import { defineConfig } from 'wxt';
import angular from '@analogjs/vite-plugin-angular';
import tailwindcss from '@tailwindcss/vite';

export default defineConfig({
  vite: () => ({
    resolve: {
      mainFields: ['module'], // Prioritize ESM
    },
    plugins: [
      angular({
        tsconfig: '[tsconfig.app](http://tsconfig.app/).json',
        // Limit Angular compilation to specific entrypoints
        transformFilter: (_code: string, id: string) => {
          return id.includes('/entrypoints/popup/');
        },
      }),
      tailwindcss(),
    ],
  }),
});
Enter fullscreen mode Exit fullscreen mode

The key is the transformFilter configuration. This ensures that only files in the entrypoints/popup/ directory are processed by the Angular compiler. Background and content scripts are treated as plain TypeScript, allowing coexistence of code that doesn’t use Angular.

5. Configure TypeScript

Separate project-wide configuration from Angular-specific configuration.

tsconfig.json (project-wide):

{
  "extends": "./.wxt/tsconfig.json",
  "compilerOptions": {
    "experimentalDecorators": true,
    "useDefineForClassFields": false
  },
  "angularCompilerOptions": {
    "strictInjectionParameters": true,
    "strictInputAccessModifiers": true,
    "strictTemplates": true
  }
}
Enter fullscreen mode Exit fullscreen mode

tsconfig.app.json (Angular-specific):

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ES2022",
    "moduleResolution": "bundler",
    "lib": ["ES2022", "DOM"],
    "strict": true,
    "experimentalDecorators": true,
    "useDefineForClassFields": false,
    "skipLibCheck": true,
    "isolatedModules": true
  },
  "angularCompilerOptions": {
    "strictInjectionParameters": true,
    "strictInputAccessModifiers": true,
    "strictTemplates": true
  },
  "include": ["entrypoints/popup/**/*.ts"]
}
Enter fullscreen mode Exit fullscreen mode

The include limits the files processed by the Angular compiler. If you want to use Angular in other entrypoints like options pages, add them here.

6. Create Angular Popup

Finally, create the entry point for the Angular application.

entrypoints/popup/index.html:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>My Extension</title>
    <meta name="manifest.type" content="browser_action" />
  </head>
  <body>
    <app-root></app-root>
    <script type="module" src="./main.ts"></script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

entrypoints/popup/main.ts:

import './style.css';
import { bootstrapApplication } from '@angular/platform-browser';
import { provideZonelessChangeDetection } from '@angular/core';
import { App } from './app';

bootstrapApplication(App, {
  providers: [provideZonelessChangeDetection()],
}).catch((err: unknown) => console.error(err));
Enter fullscreen mode Exit fullscreen mode

entrypoints/popup/app.ts:

import { ChangeDetectionStrategy, Component } from '@angular/core';

@Component({
  selector: 'app-root',
  changeDetection: ChangeDetectionStrategy.OnPush,
  host: { class: 'block p-4' },
  template: `
    <h1 class="text-lg font-bold">Hello from Angular!</h1>
  `,
})
export class App {}
Enter fullscreen mode Exit fullscreen mode

entrypoints/popup/style.css:

@import 'tailwindcss';
Enter fullscreen mode Exit fullscreen mode

Since we’re now on Angular v21, I’m using provideZonelessChangeDetection() to enable change detection without Zone.js. In limited environments like browser extensions, Zone.js overhead is often wasteful, so this reduces bundle size and minimizes runtime overhead.

Development and Build

Once setup is complete, you can start the development server:

# Chrome dev server
pnpm dev

# Firefox dev server
pnpm dev:firefox
Enter fullscreen mode Exit fullscreen mode

image

For production builds and packaging:

# Chrome build
pnpm build

# Firefox build and ZIP
pnpm zip:firefox
Enter fullscreen mode Exit fullscreen mode

Summary

Combining WXT and Angular enables modern browser extension development. The appeal is being able to leverage both WXT’s excellent developer experience and Angular’s powerful features. Using this starter template, you can start development immediately without the setup hassle.

The repository mentioned at the beginning is published as a GitHub template repository, so if you’re interested, click Use this template on the repository to create your own browser extension.

image

Top comments (0)