WXT Framework

repository·main·Indexed 27 days ago

https://github.com/wxt-dev/wxt

A next-generation framework for developing web extensions featuring HMR, auto-imports, and a module system. It includes a suite of official packages and modules such as @wxt-dev/analytics for event tracking, @wxt-dev/browser for type-safe extension APIs, @wxt-dev/runner for programmatic browser automation, and framework integrations for Vue, React, Svelte, and SolidJS.

Tokens
50.2K
Snippets
176
Records
306
Agent score
95%

What's inside WXT

  1. Overview of WXT features

    main

    WXT is a next-generation framework for developing web extensions, designed to be frontend framework agnostic. Key features include:

    • Browser Support: Works across all browsers and supports both Manifest V2 (MV2) and Manifest V3 (MV3).
    • Developer Experience: Includes a dev mode with Hot Module Replacement (HMR) and fast reload, TypeScript support, and auto-imports.
    • Project Structure: Uses file-based entrypoints and provides bundle analysis.
    • Extensibility: Features a module system for reusing code between extensions and is compatible with Vue, React, Svelte, and other frameworks.
    • Automation: Supports automated publishing.
  2. Introduction to WXT

    main
    WXT is a modern, open-source framework for building web extensions. Inspired by Nuxt, it is designed to provide a high-quality developer experience (DX) and first-class support for all major browsers. It does not change how you use standard extension APIs; instead, it provides a framework to build them more efficiently.
  3. Compare vanilla i18n vs third-party libraries

    main

    While you can use third-party libraries like i18next, react-i18n, or vue-i18n, WXT recommends using the vanilla API or @wxt-dev/i18n because:

    • Manifest/CSS Support: They can localize text in your manifest and CSS files.
    • Synchronous Loading: Translations are loaded synchronously.
    • Efficiency: Translations are not bundled multiple times, keeping the extension size small.
    • Zero Config: They require minimal setup.

    Major Limitation: With the vanilla API (and packages built on top of it), the language cannot be changed within the extension without changing the browser or system language settings.

  4. Understand WXT Virtual Entrypoints constraints

    main

    WXT uses virtual entrypoints (scripts loaded as JS entrypoints or included in HTML files) that are bundled and shipped with WXT. Because Vite treats these as part of the project's source code rather than WXT's internal code, they have strict import restrictions to ensure compatibility with strict package managers like pnpm (with --shamefully-hoist=false) and Yarn PnP.

    Import Rules for Virtual Entrypoints:

    • Allowed: Imports from wxt/* or internal utilities that do not import from node_modules (e.g., the logger).
    • Forbidden: Direct imports of 3rd party modules from node_modules.

    When WXT is bundled for NPM, wxt/* imports are marked as external and resolved at your application's build time, while other allowed imports are added inline.

  5. Understand the default WXT project structure

    main

    By default, WXT uses a flat folder structure. Key directories and files include:

    • entrypoints/: Contains all entrypoints that get bundled into your extension.
    • assets/: Contains CSS, images, and other assets to be processed by WXT.
    • public/: Files copied to the output folder as-is without processing.
    • components/, composables/, hooks/, utils/: Directories that are auto-imported by default.
    • modules/: Contains local WXT Modules.
    • wxt.config.ts: The main configuration file.
    • app.config.ts: Contains Runtime Config.
    • .output/: Destination for all build artifacts.
    • .wxt/: WXT-generated directory containing TS config.
  6. Explore WXT community resources

    main
    WXT has a growing ecosystem of community-driven resources including blog posts, tutorials, and NPM packages designed to work with the framework. You can find educational content on building modern cross-browser extensions and specialized utility packages to extend WXT's capabilities.
  7. Install and configure @wxt-dev/module-react

    main

    To use React in your WXT web extension (including HTML pages and content scripts), you must install the React dependencies and the WXT React module, then register the module in your wxt.config.ts file.

    This module automatically adds @vitejs/plugin-react to your Vite configuration and enables React auto-imports.

    pnpm i react react-dom
    pnpm i -D @wxt-dev/module-react
    // wxt.config.ts
    export default defineConfig({
      // Required
      modules: ['@wxt-dev/module-react'],
    
      // Optional: Pass options to the module:
      react: {
        vite: {
          // ...
        },
      },
    });
  8. Nesting constraints for entrypoints

    main

    WXT does not support deeply nested entrypoints like some web frameworks (e.g., Nuxt or Next.js). Entrypoints must be either zero or one level deep within the entrypoints/ directory to be discovered and built.

    Correct (0-1 levels deep):

    • entrypoints/youtube.content/index.ts
    • entrypoints/youtube-injected/index.ts
    • entrypoints/background/index.ts

    Incorrect (Deeply nested):

    • entrypoints/youtube/content/index.ts (Too deep)
  9. Set custom browser binaries

    main

    If WXT cannot automatically discover your browser or if you want to use a specific version (like Chrome Beta or Firefox Developer Edition), you can manually specify the binary paths in your configuration.

    import { defineWebExtConfig } from 'wxt';
    
    export default defineWebExtConfig({
      binaries: {
        chrome: '/path/to/chrome-beta',
        firefox: 'firefoxdeveloperedition',
        edge: '/path/to/edge',
      },
    });
  10. Add UIs to a page using IFrame UI

    main

    Use createIframeUi to host your UI inside an <iframe>. This provides the highest level of isolation for both styles and events, and it is the only method that supports HMR.

    Setup Steps:

    1. Create an HTML page (e.g., entrypoints/example-iframe.html) to be loaded into the iframe.
    2. Add the page to web_accessible_resources in your wxt.config.ts.
    3. Use createIframeUi in your content script and call ui.mount().
    // wxt.config.ts
    export default defineConfig({
      manifest: {
        web_accessible_resources: [
          {
            resources: ['example-iframe.html'],
            matches: [...],
          },
        ],
      },
    });
    
    // entrypoints/example-ui.content.ts
    export default defineContentScript({
      matches: ['<all_urls>'],
    
      main(ctx) {
        // Define the UI
        const ui = createIframeUi(ctx, {
          page: '/example-iframe.html',
          position: 'inline',
          anchor: 'body',
          onMount: (wrapper, iframe) => {
            // Add styles to the iframe like width
            iframe.width = '123';
          },
        });
    
        // Show UI to user
        ui.mount();
      },
    });
  11. Organize multiple app entrypoints in WXT

    main

    Web extensions often require multiple UIs (popup, options, side panel, etc.). In WXT, you should create an individual app instance for each entrypoint. The recommended pattern is to use a directory for each entrypoint containing its own index.html and mounting logic.

    📂 {srcDir}/
       📂 assets/          <---------- Put shared assets here
          📄 tailwind.css
       📂 components/
          📄 Button.tsx
       📂 entrypoints/
          📂 options/       <--------- Use a folder with an index.html file in it
             📁 pages/      <--------- A good place to put your router pages if you have them
             📄 index.html
             📄 App.tsx
             📄 main.tsx    <--------- Create and mount your app here
             📄 style.css   <--------- Entrypoint-specific styles
             📄 router.ts
  12. Choose a storage implementation for WXT extensions

    main

    When managing data in a WXT extension, you have three primary options:

    1. WXT's built-in storage API (Recommended): Use wxt/utils/storage. This is a wrapper around vanilla storage APIs designed to simplify common use cases.
    2. Vanilla Web Extension APIs: Use the standard chrome.storage or browser.storage APIs directly.
    3. Third-party NPM packages: Use existing libraries like webext-storage or @webext-core/storage if you have specific requirements.

    If you are migrating an existing project to WXT, you can continue using your current storage wrapper to avoid unnecessary code changes.