Skip to content

feat(browser): migrate from webextension-toolbox to WXT framework#859

Merged
yamadashy merged 7 commits intomainfrom
feat/browser-wxt
Sep 21, 2025
Merged

feat(browser): migrate from webextension-toolbox to WXT framework#859
yamadashy merged 7 commits intomainfrom
feat/browser-wxt

Conversation

@yamadashy
Copy link
Owner

Summary

This PR migrates the browser extension from the deprecated webextension-toolbox to the modern WXT framework. The migration addresses the issue where webextension-toolbox hasn't been updated in 4 years and provides significant improvements to the development experience.

Why this change?

  • webextension-toolbox status: Last npm release was 4 years ago, considered inactive/discontinued
  • WXT advantages: Active development, modern toolchain, better developer experience with HMR and Vite integration
  • Build optimization: Smaller bundle size (~70% reduction in dependencies) and faster builds
  • TypeScript-first: Better type safety and modern development practices

Key Changes

Framework Migration

  • ✅ Replace webextension-toolbox with WXT framework (v0.20.11)
  • ✅ Restructure project to use entrypoints/ and public/ directories (WXT convention)
  • ✅ Convert background/content scripts to WXT format with defineBackground/defineContentScript
  • ✅ Add wxt.config.ts for centralized configuration replacing manual manifest.json

Functionality Preservation

  • ✅ Maintain all 11 languages i18n support (en, ja, de, fr, es, pt-br, id, vi, ko, zh-cn, zh-tw, hi)
  • ✅ Preserve original behavior: URL format, button placement, navigation handling
  • ✅ Keep manifest V3 compatibility and cross-browser support (Chrome/Firefox/Edge)
  • ✅ Maintain existing icon set and web accessible resources

Build System Updates

  • ✅ Update package.json scripts for WXT commands (wxt, wxt build, wxt zip)
  • ✅ Add TypeScript configuration extending WXT types
  • ✅ Remove webextension-toolbox dependencies and configurations
  • ✅ Clean up browserslist and other unused configurations

Verification

  • ✅ All builds successful (Chrome, Firefox, Edge)
  • ✅ All 11 language locales correctly bundled
  • ✅ Extension icons properly configured and displayed
  • ✅ Content script behavior preserved (URL format, button insertion, event handling)
  • ✅ Tests passing and lint checks clean
  • ✅ No security vulnerabilities

Files Changed

Added:

  • browser/entrypoints/background.ts - Background script in WXT format
  • browser/entrypoints/content.ts - Content script in WXT format
  • browser/entrypoints/styles.css - Content script styles
  • browser/wxt.config.ts - WXT configuration

Moved:

  • browser/app/_locales/*browser/public/_locales/* (11 languages)
  • browser/app/images/*browser/public/images/* (icon assets)

Removed:

  • browser/app/manifest.json (now auto-generated by WXT)
  • browser/app/scripts/background.ts (migrated to entrypoints)
  • webextension-toolbox dependency and configurations

Updated:

  • browser/package.json - Scripts, dependencies, removed browserslist
  • browser/tsconfig.json - Extend WXT types
  • browser/.gitignore - WXT-specific directories

Checklist

  • Run npm run test
  • Run npm run lint

Replace deprecated webextension-toolbox with modern WXT framework for improved developer experience and active maintenance. This migration addresses the issue where webextension-toolbox hasn't been updated in 4 years.

Key changes:
- Replace webextension-toolbox with WXT framework
- Restructure project to use entrypoints/ and public/ directories
- Convert background/content scripts to WXT format with defineBackground/defineContentScript
- Add wxt.config.ts for centralized configuration
- Migrate all 11 languages i18n support to new structure
- Update build scripts and dependencies
- Remove deprecated manifest.json (now auto-generated)
- Fix TypeScript configuration to extend WXT types

Benefits:
- Active framework with regular updates
- Better development experience with HMR and Vite integration
- Smaller bundle size and improved build performance
- Modern toolchain with TypeScript-first approach
- Unified cross-browser extension development
…ependencies

Remove unused dependencies and configurations left over from webextension-toolbox migration to WXT.

Changes:
- Remove @types/webextension-polyfill dependency (WXT provides built-in types)
- Remove browserslist configuration (not needed for WXT)
- Update archive script path reference
- Clean up package.json for WXT-only setup

This reduces dependency footprint and eliminates potential conflicts with WXT's built-in tooling.
Copilot AI review requested due to automatic review settings September 21, 2025 06:31
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 21, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Migrates the browser extension to WXT: adds WXT config, entrypoints for background and content scripts, and TypeScript setup; updates package scripts and CI to run wxt prepare; ignores WXT outputs; replaces legacy manifest and background script with WXT-driven equivalents.

Changes

Cohort / File(s) Summary
CI workflow updates
.github/workflows/ci.yml
Adds a “Prepare WXT” step (npm run prepare) to lint-browser and test-browser jobs after dependency install.
Git ignore updates
browser/.gitignore
Ignores .output/ and .wxt/ alongside existing build artifacts.
WXT configuration and tooling
browser/wxt.config.ts, browser/package.json, browser/tsconfig.json, browser/types.d.ts
Adds WXT config with manifest definition and web-ext settings; switches scripts to WXT (prepare, dev, build, zip per-target); removes toolbox-related deps and browserslist; TypeScript now extends ./.wxt/tsconfig.json; introduces ambient types for defineBackground and defineContentScript.
Entry points (WXT)
browser/entrypoints/background.ts, browser/entrypoints/content.ts
Adds background entrypoint that scans tabs and injects content on GitHub URLs; adds content-script entrypoint via defineContentScript with matches/runAt/allFrames and main initialization, importing styles.
Removal of legacy manifest and background
browser/app/manifest.json, browser/app/scripts/background.ts
Removes static manifest and manual injection background script in favor of WXT-driven configuration and entrypoints.

Sequence Diagram(s)

sequenceDiagram
  participant Br as Browser
  participant BG as Background (defineBackground)
  participant Tabs as chrome.tabs
  participant CS as Content Script (defineContentScript)
  note over Br,BG: Extension startup

  Br->>BG: Initialize background
  BG->>Tabs: query({}) to list tabs
  loop For each tab
    BG->>BG: Validate tab (id, url, not discarded, github.com)
    alt Valid GitHub tab
      BG->>Br: Insert CSS (scripting.insertCSS)
      BG->>Br: Execute JS (scripting.executeScript)
    else Invalid/unsupported
      BG-->>BG: Skip
    end
  end

  note over Br,CS: On matched GitHub pages
  Br->>CS: Load content script (matches, runAt, allFrames)
  CS->>CS: main() → init DOM and integration
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The pull request title "feat(browser): migrate from webextension-toolbox to WXT framework" is concise and accurately summarizes the primary change — migrating the browser extension build/tooling to WXT — which is reflected in the changeset (wxt.config.ts, updated package.json scripts, new entrypoints, removed manifest and toolbox configs). The phrasing is clear, scoped to the browser area, and suitable for history scanning.
Description Check ✅ Passed The PR description follows the repository template by including a clear summary and the required checklist, and it provides detailed motivation, key changes, verification results, and a file-level summary that maps to the raw diffs. The checklist items are marked complete and the description gives sufficient context for reviewers to assess scope and verification steps.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/browser-wxt

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @yamadashy, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request undertakes a significant modernization of the browser extension's build infrastructure by migrating from the outdated webextension-toolbox to the contemporary WXT framework. This strategic shift aims to enhance the development experience, leverage a more active and modern toolchain, and achieve build optimizations, all while meticulously preserving the extension's existing functionality, internationalization support, and cross-browser compatibility.

Highlights

  • Framework Migration: The browser extension has been migrated from the deprecated webextension-toolbox to the modern WXT framework (v0.20.11). This involved restructuring the project to use WXT's entrypoints/ and public/ directories, converting background and content scripts to WXT's defineBackground and defineContentScript formats, and centralizing configuration in a new wxt.config.ts file.
  • Functionality Preservation: All existing functionality has been meticulously preserved, including i18n support for 11 languages, original behavior regarding URL format, button placement, and navigation handling. Manifest V3 compatibility, cross-browser support (Chrome/Firefox/Edge), and the existing icon set with web accessible resources are also maintained.
  • Build System Optimization: The build system has been updated to leverage WXT's capabilities, resulting in a significant reduction in bundle size (~70% reduction in dependencies) and faster builds. This includes updating package.json scripts for WXT commands, extending TypeScript configuration with WXT types, and removing obsolete webextension-toolbox dependencies and configurations.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Sep 21, 2025

Deploying repomix with  Cloudflare Pages  Cloudflare Pages

Latest commit: 96a6c17
Status: ✅  Deploy successful!
Preview URL: https://6eabf303.repomix.pages.dev
Branch Preview URL: https://feat-browser-wxt.repomix.pages.dev

View logs

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR migrates the browser extension from the deprecated webextension-toolbox to the modern WXT framework. The migration addresses the maintenance and security concerns of using an unmaintained build tool while preserving all existing functionality.

Key Changes

  • Replace webextension-toolbox with WXT framework (v0.20.11) for modern build tooling
  • Restructure project files to follow WXT conventions with entrypoints/ and public/ directories
  • Convert background and content scripts to WXT format with proper TypeScript definitions

Reviewed Changes

Copilot reviewed 8 out of 42 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
browser/wxt.config.ts New WXT configuration file replacing manual manifest.json with programmatic manifest generation
browser/tsconfig.json Updated to extend WXT's TypeScript configuration
browser/package.json Updated build scripts and dependencies for WXT framework
browser/entrypoints/content.ts Content script migrated to WXT format with defineContentScript wrapper
browser/entrypoints/background.ts Background script migrated to WXT format with defineBackground wrapper
browser/app/scripts/background.ts Removed old background script file
browser/app/manifest.json Removed manual manifest (now auto-generated by WXT)
browser/.gitignore Added WXT-specific build directories

@codecov
Copy link

codecov bot commented Sep 21, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 88.85%. Comparing base (1e4d6e2) to head (96a6c17).
⚠️ Report is 8 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #859   +/-   ##
=======================================
  Coverage   88.85%   88.85%           
=======================================
  Files         109      109           
  Lines        7575     7575           
  Branches     1423     1423           
=======================================
  Hits         6731     6731           
  Misses        844      844           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request successfully migrates the browser extension from the deprecated webextension-toolbox to the modern WXT framework, which is an excellent improvement for the project's long-term maintainability and developer experience. The changes correctly restructure the project, update dependencies, and replace the static manifest with a wxt.config.ts file. My review provides suggestions to enhance the new implementation by improving the robustness and performance of the background script and increasing the maintainability of the WXT configuration file.

Comment on lines +47 to +55
chrome.tabs.query({}, async (tabs: chrome.tabs.Tab[]) => {
for (const tab of tabs) {
try {
await injectContentToTab(tab);
} catch (e) {
console.error(e);
}
}
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current code iterates through tabs and injects scripts sequentially using await in a for...of loop. This can be slow if the user has many tabs open. To improve performance on extension startup, you can process tabs in parallel. Since injectContentToTab handles its own errors, you can call it for each tab without waiting for it to complete.

  chrome.tabs.query({}, (tabs: chrome.tabs.Tab[]) => {
    // Process tabs in parallel for faster startup.
    tabs.forEach((tab) => injectContentToTab(tab));
  });

yamadashy and others added 4 commits September 21, 2025 15:50
Fix TypeScript compilation errors in CI by removing dependency on WXT's auto-generated .wxt/tsconfig.json file which doesn't exist during lint phase.

Changes:
- Remove "extends": "./.wxt/tsconfig.json" from tsconfig.json
- Add manual type definitions for WXT global functions (defineBackground, defineContentScript)
- Include proper file paths and type declarations
- Ensure CI can run lint checks before WXT generates its configuration

This resolves the CI error: "Cannot read file '.wxt/tsconfig.json'" during the lint step.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
.github/workflows/ci.yml (1)

109-111: Cache the browser package lockfile for faster CI.

setup-node’s npm cache currently keys off the root lockfile. Point it at browser/package-lock.json in the browser jobs.

Apply this diff in both “lint-browser” and “test-browser” jobs:

       - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # ratchet:actions/setup-node@v4
         with:
           node-version-file: .tool-versions
-          cache: npm
+          cache: npm
+          cache-dependency-path: browser/package-lock.json

Also applies to: 206-208

browser/entrypoints/content.ts (1)

151-163: Avoid running in iframes unless needed.

Running in all frames can cause redundant observers and work. If you don’t depend on iframes, set allFrames to false.

Apply this diff:

-  allFrames: true,
+  allFrames: false,
browser/package.json (1)

6-17: WXT scripts look solid; a couple of nits.

  • Nice: prepare/dev/build/zip per-browser are aligned with WXT.
  • Consider relaxing "engines.node" to ≥20 to match broader contributor environments and your root test matrix.
  • Optional: document that npm run prepare is required locally before lint/tests (you already do this in CI).

Apply this diff if you want to relax engines:

   "engines": {
-    "node": ">=24.0.1"
+    "node": ">=20.0.0"
   }

Also applies to: 22-23, 43-45

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1e4d6e2 and 96a6c17.

⛔ Files ignored due to path filters (9)
  • browser/package-lock.json is excluded by !**/package-lock.json
  • browser/public/images/icon-128.png is excluded by !**/*.png
  • browser/public/images/icon-16.png is excluded by !**/*.png
  • browser/public/images/icon-19.png is excluded by !**/*.png
  • browser/public/images/icon-32.png is excluded by !**/*.png
  • browser/public/images/icon-38.png is excluded by !**/*.png
  • browser/public/images/icon-48.png is excluded by !**/*.png
  • browser/public/images/icon-64.png is excluded by !**/*.png
  • browser/public/images/icon.svg is excluded by !**/*.svg
📒 Files selected for processing (10)
  • .github/workflows/ci.yml (2 hunks)
  • browser/.gitignore (1 hunks)
  • browser/app/manifest.json (0 hunks)
  • browser/app/scripts/background.ts (0 hunks)
  • browser/entrypoints/background.ts (1 hunks)
  • browser/entrypoints/content.ts (2 hunks)
  • browser/package.json (2 hunks)
  • browser/tsconfig.json (1 hunks)
  • browser/types.d.ts (1 hunks)
  • browser/wxt.config.ts (1 hunks)
💤 Files with no reviewable changes (2)
  • browser/app/scripts/background.ts
  • browser/app/manifest.json
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Cloudflare Pages
🔇 Additional comments (4)
browser/.gitignore (1)

10-11: Good addition: ignore WXT build outputs.

Ignoring .output/ and .wxt/ matches WXT’s generated artifacts. No concerns.

browser/entrypoints/content.ts (1)

1-2: Confirm CSS bundling path.

Importing './styles.css' is fine; WXT will bundle it into the content script. Ensure the file lives under entrypoints or is reachable by Vite.

browser/wxt.config.ts (1)

8-36: Keep manifest version in sync, trim permissions, and simplify WAR.

  • Source version from package.json to avoid drift.
  • If background stops injecting, remove "scripting" to reduce attack surface.
  • Use a wildcard for icons to avoid manual maintenance.

Apply this diff:

-import { defineConfig } from 'wxt';
+import { defineConfig } from 'wxt';
+import pkg from './package.json' assert { type: 'json' };
@@
-    version: '1.0.1',
+    version: pkg.version,
@@
-    permissions: ['scripting'],
+    // permissions: [], // No programmatic injection needed; rely on content_scripts
@@
-    web_accessible_resources: [
-      {
-        resources: [
-          'images/icon-16.png',
-          'images/icon-19.png',
-          'images/icon-32.png',
-          'images/icon-38.png',
-          'images/icon-48.png',
-          'images/icon-64.png',
-          'images/icon-128.png',
-        ],
-        matches: ['https://github.com/*'],
-      },
-    ],
+    web_accessible_resources: [
+      { resources: ['images/*.png'], matches: ['https://github.com/*'] },
+    ],

Note: JSON import requires Node ≥20 (you’re on ≥24).

browser/entrypoints/background.ts (1)

1-56: Remove manual content-script injection; WXT already injects.

This duplicates the content script declared via defineContentScript and risks double execution, brittle manifest coupling, and slower startup. Let WXT handle injection.

Apply this diff to simplify:

-export default defineBackground(() => {
-  const injectContentToTab = async (tab: chrome.tabs.Tab): Promise<void> => {
-    if (!tab.url) return;
-    if (tab.discarded) return;
-    if (tab.id === undefined) return;
-    if (!tab.url.startsWith('https://github.com/')) return;
-    try {
-      const manifest = chrome.runtime.getManifest();
-      if (manifest.content_scripts?.[0]?.css) {
-        await chrome.scripting.insertCSS({ target: { tabId: tab.id }, files: manifest.content_scripts[0].css });
-      }
-      if (manifest.content_scripts?.[0]?.js) {
-        await chrome.scripting.executeScript({ target: { tabId: tab.id }, files: manifest.content_scripts[0].js });
-      }
-    } catch (error) {
-      console.error('Error injecting content script:', error);
-    }
-  };
-  chrome.tabs.query({}, async (tabs: chrome.tabs.Tab[]) => {
-    for (const tab of tabs) {
-      try {
-        await injectContentToTab(tab);
-      } catch (e) {
-        console.error(e);
-      }
-    }
-  });
-});
+export default defineBackground(() => {
+  // No-op: WXT injects content scripts declared via defineContentScript.
+});

Follow-up: If you adopt this, drop "scripting" from permissions in wxt.config.ts.

@yamadashy yamadashy merged commit 4848e1c into main Sep 21, 2025
51 checks passed
@yamadashy yamadashy deleted the feat/browser-wxt branch September 21, 2025 12:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants