### Install postcss-rem-to-responsive-pixel Source: https://wxt.dev/guide/resources/faq Install the postcss-rem-to-responsive-pixel package as a development dependency using bun. ```sh bun i -D postcss-rem-to-responsive-pixel ``` -------------------------------- ### Create New Project Directory Source: https://wxt.dev/guide/installation.html Navigate into your project directory before initializing or installing WXT. ```sh cd my-project bun init ``` ```sh cd my-project pnpm init ``` ```sh cd my-project npm init ``` ```sh cd my-project yarn init ``` -------------------------------- ### MV3 Manifest Example Source: https://wxt.dev/guide/essentials/config/manifest Example of how WXT generates a Manifest V3 compatible manifest, including `action` and `web_accessible_resources`. ```json { "manifest_version": 3, // ... "action": { "default_title": "Some Title" }, "web_accessible_resources": [ { "matches": ["*://*.google.com/*"], "resources": ["icon/*.png"] } ] } ``` -------------------------------- ### Install and Configure Polyfill Module Source: https://wxt.dev/guide/resources/upgrading To continue using the `webextension-polyfill`, install `webextension-polyfill` and WXT's polyfill module. Then, add the WXT module to your `wxt.config.ts`. ```sh pnpm i webextension-polyfill @wxt-dev/webextension-polyfill ``` ```ts export default defineConfig({ modules: ['@wxt-dev/webextension-polyfill'], }); ``` -------------------------------- ### MV2 Manifest Example Source: https://wxt.dev/guide/essentials/config/manifest Example of how WXT generates a Manifest V2 compatible manifest, including `browser_action` and `web_accessible_resources`. ```json { "manifest_version": 2, // ... "browser_action": { "default_title": "Some Title" }, "web_accessible_resources": ["icon/*.png"] } ``` -------------------------------- ### Run WXT in Development Mode Source: https://wxt.dev/guide/installation.html Start the WXT development server to run your extension in a browser. WXT will automatically open a browser window with your extension installed. ```sh bun run dev ``` ```sh pnpm dev ``` ```sh npm run dev ``` ```sh yarn dev ``` -------------------------------- ### Bootstrap Project with WXT Source: https://wxt.dev/guide/installation.html Initialize a new WXT project using the `init` command. Follow the on-screen prompts to complete the setup. ```sh bunx wxt@latest init ``` ```sh pnpm dlx wxt@latest init ``` ```sh npx wxt@latest init ``` ```sh # Use NPM initially, but select Yarn when prompted npx wxt@latest init ``` -------------------------------- ### Define Background Entrypoint Source: https://wxt.dev/guide/installation.html Create an entrypoint file for your background script. This example logs 'Hello world!' when the background script initializes. ```ts export default defineBackground(() => { console.log('Hello world!'); }); ``` -------------------------------- ### Install and Add a WXT Module Source: https://wxt.dev/guide/essentials/wxt-modules Install a module from NPM and add its package name to the `modules` array in your `wxt.config.ts` file. ```typescript export default defineConfig({ modules: ['@wxt-dev/auto-icons'], }); ``` -------------------------------- ### Install WXT Dependency Source: https://wxt.dev/guide/installation.html Add WXT as a development dependency to your project. ```sh bun add -D wxt ``` ```sh pnpm i -D wxt ``` ```sh npm i -D wxt ``` ```sh yarn add --dev wxt ``` -------------------------------- ### Install WXT Latest, Skipping Scripts Source: https://wxt.dev/guide/resources/upgrading Install the latest WXT version while ignoring scripts to prevent errors during major version upgrades. This is the first step before applying other upgrade changes. ```sh pnpm i wxt@latest --ignore-scripts ``` -------------------------------- ### Install Dependencies and Build Firefox ZIP Source: https://wxt.dev/guide/essentials/publishing These commands are used to install project dependencies and build the Firefox-specific ZIP archive, which includes source code for review. ```sh pnpm i pnpm zip:firefox ``` ```sh npm i npm run zip:firefox ``` ```sh yarn yarn zip:firefox ``` ```sh bun install bun run zip:firefox ``` -------------------------------- ### Load Generated File at Runtime Source: https://wxt.dev/guide/essentials/wxt-modules Example of how to fetch a generated file that has been made web accessible. Use `browser.runtime.getURL` to get the correct path to the resource. ```typescript const res = await fetch(browser.runtime.getURL('/some-text.txt')); ``` -------------------------------- ### Basic WXT Module Structure Source: https://wxt.dev/guide/essentials/wxt-modules A basic WXT module exports a `defineWxtModule` function with a `setup` function. Place this file in the `modules/` directory for automatic discovery. ```typescript import { defineWxtModule } from 'wxt/modules'; export default defineWxtModule({ setup(wxt) { // Your module code here... }, }); ``` -------------------------------- ### Filter Entrypoints by Browser Include Source: https://wxt.dev/guide/essentials/target-different-browsers Use the `include` option in `defineContentScript` to specify browsers for which this entrypoint should be built. This example builds for 'firefox' only. ```ts export default defineContentScript({ include: ['firefox'], main(ctx) { // ... }, }); ``` -------------------------------- ### Migrating Runtime Code to Unlisted Script Source: https://wxt.dev/guide/essentials/entrypoints This example demonstrates how to migrate existing runtime code into an unlisted script. The original code is commented out and replaced with the equivalent logic within the `defineUnlistedScript` structure. ```ts document.querySelectorAll('a').forEach((anchor) => { // [!code --] // ... // [!code --] }); // [!code --] export default defineUnlistedScript(() => { document.querySelectorAll('a').forEach((anchor) => { // [!code ++] // ... // [!code ++] }); // [!code ++] }); ``` -------------------------------- ### Configure Solid Module Source: https://wxt.dev/guide/essentials/frontend-frameworks Add the Solid module to your WXT configuration to enable Solid integration. Ensure the module is installed in your project. ```typescript import { defineConfig } from 'wxt'; export default defineConfig({ modules: ['@wxt-dev/module-solid'], }); ``` -------------------------------- ### Add Build-Time Config to a Module Source: https://wxt.dev/guide/essentials/wxt-modules Define build-time options for your module by extending `InlineConfig` and specifying a `configKey`. The options are passed as the second argument to the `setup` function. ```typescript import { defineWxtModule } from 'wxt/modules'; import 'wxt'; export interface MyModuleOptions { // Add your build-time options here... } declare module 'wxt' { export interface InlineConfig { // Add types for the "myModule" key in wxt.config.ts myModule: MyModuleOptions; } } export default defineWxtModule({ configKey: 'myModule', // Build time config is available via the second argument of setup setup(wxt, options) { console.log(options); }, }); ``` -------------------------------- ### Configure React Module Source: https://wxt.dev/guide/essentials/frontend-frameworks Add the React module to your WXT configuration to enable React integration. Ensure the module is installed in your project. ```typescript import { defineConfig } from 'wxt'; export default defineConfig({ modules: ['@wxt-dev/module-react'], }); ``` -------------------------------- ### Filter Entrypoints by Browser Exclude Source: https://wxt.dev/guide/essentials/target-different-browsers Use the `manifest.exclude` meta tag in HTML to prevent an entrypoint from being built for specific browsers. This example excludes 'chrome'. ```html ``` -------------------------------- ### Set Custom Entrypoint Option Source: https://wxt.dev/guide/essentials/wxt-modules Define custom options directly within your entrypoint configuration. This example shows how to set `myCustomOption` for a background entrypoint. ```typescript export default defineBackground({ myCustomOption: 'custom value', main() { // ... }, }); ``` -------------------------------- ### Create Shadow Root UI with React Source: https://wxt.dev/guide/essentials/content-scripts Embed React components within a Shadow DOM using `createShadowRootUi`. This example demonstrates creating a React root and handling its unmount lifecycle. ```typescript // 1. Import the style import './style.css'; import ReactDOM from 'react-dom/client'; import App from './App.tsx'; export default defineContentScript({ matches: [''], // 2. Set cssInjectionMode cssInjectionMode: 'ui', async main(ctx) { // 3. Define your UI const ui = await createShadowRootUi(ctx, { name: 'example-ui', position: 'inline', anchor: 'body', onMount: (container) => { // Container is a body, and React warns when creating a root on the body, so create a wrapper div const app = document.createElement('div'); container.append(app); // Create a root on the UI container and render a component const root = ReactDOM.createRoot(app); root.render(); return root; }, onRemove: (root) => { // Unmount the root when the UI is removed root?.unmount(); }, }); // 4. Mount the UI ui.mount(); }, }); ``` -------------------------------- ### Import Google Analytics with `url:` Source: https://wxt.dev/guide/essentials/remote-code Use the `url:` prefix to import remote scripts like Google Analytics. Ensure the `gtag` function is correctly defined as shown in the example. ```typescript // utils/google-analytics.ts import 'url:https://www.googletagmanager.com/gtag/js?id=G-XXXXXX'; window.dataLayer = window.dataLayer || []; // NOTE: This line is different from Google's documentation window.gtag = function () { dataLayer.push(arguments); }; gtag('js', new Date()); gtag('config', 'G-XXXXXX'); ``` ```typescript // popup/main.ts import '~/utils/google-analytics'; gtаg('event', 'event_name', { key: 'value', }); ``` -------------------------------- ### Handle SPA Navigation with Location Watcher Source: https://wxt.dev/guide/essentials/content-scripts Listen for URL changes in SPAs to trigger content script logic. This example uses `ctx.locationWatcher.run()` and `ctx.addEventListener` to detect navigation events and conditionally execute `mainWatch`. ```typescript const watchPattern = new MatchPattern('*://*.youtube.com/watch*'); export default defineContentScript({ matches: ['*://*.youtube.com/*'], main(ctx) { ctx.locationWatcher.run(); ctx.addEventListener(window, 'wxt:locationchange', ({ newUrl }) => { if (watchPattern.includes(newUrl)) mainWatch(ctx); }); }, }); function mainWatch(ctx: ContentScriptContext) { mountUi(ctx); } ``` -------------------------------- ### Unlisted CSS Entrypoint Source: https://wxt.dev/guide/essentials/entrypoints CSS entrypoints are always unlisted. This example shows a basic CSS structure. Refer to Vite's guide for setting up CSS preprocessors. ```css body { /* ... */ } ``` -------------------------------- ### Background Entrypoint Structure Source: https://wxt.dev/guide/essentials/entrypoints Illustrates how to structure files for a 'Background' entrypoint, supporting both single file and directory formats. ```html 📂 entrypoints/ 📄 background.ts ``` ```html 📂 entrypoints/ 📂 background/ 📄 index.ts ``` -------------------------------- ### Initialize a new WXT project Source: https://wxt.dev/guide/resources/migrate Use this command to generate a new vanilla WXT project in your existing project directory. Review the project structure and customize directory names in `wxt.config.ts` if needed. ```sh cd path/to/your/project pnpm dlx wxt@latest init example-wxt --template vanilla ``` -------------------------------- ### Build Safari Extension and Package Source: https://wxt.dev/guide/essentials/publishing First, build the Safari extension using WXT, then use the 'safari-web-extension-packager' CLI tool to package it. Ensure you pass the correct output directory to the packager. ```sh pnpm wxt build -b safari xcrun safari-web-extension-packager .output/safari-mv2 ``` -------------------------------- ### Add `wxt prepare` to postinstall script Source: https://wxt.dev/guide/essentials/config/auto-imports Ensure your editor recognizes auto-imported variables by adding the `wxt prepare` command to your `postinstall` script in `package.json`. This command generates necessary type definitions. ```json // package.json { "scripts": { "postinstall": "wxt prepare", // [!code ++] }, } ``` -------------------------------- ### Run WXT Prepare After Upgrade Source: https://wxt.dev/guide/resources/upgrading After addressing breaking changes, run `wxt prepare` to finalize the upgrade process. This command should succeed and resolve any type errors. ```sh pnpm wxt prepare ``` -------------------------------- ### Correcting Entrypoint File Placement Source: https://wxt.dev/guide/essentials/entrypoints Demonstrates the correct way to structure entrypoints by using directories for related files, avoiding direct placement in the `entrypoints/` directory. ```html 📂 entrypoints/ 📄 popup.html 📄 popup.ts 📄 popup.css 📂 popup/ 📄 index.html 📄 main.ts 📄 style.css ``` -------------------------------- ### Get Translated Message Source: https://wxt.dev/guide/essentials/i18n Use `browser.i18n.getMessage()` to retrieve the translated string for a given message ID. ```typescript browser.i18n.getMessage('helloWorld'); ``` -------------------------------- ### Configure Svelte Module Source: https://wxt.dev/guide/essentials/frontend-frameworks Add the Svelte module to your WXT configuration to enable Svelte integration. Ensure the module is installed in your project. ```typescript import { defineConfig } from 'wxt'; export default defineConfig({ modules: ['@wxt-dev/module-svelte'], }); ``` -------------------------------- ### Configure Vue Module Source: https://wxt.dev/guide/essentials/frontend-frameworks Add the Vue module to your WXT configuration to enable Vue integration. Ensure the module is installed in your project. ```typescript import { defineConfig } from 'wxt'; export default defineConfig({ modules: ['@wxt-dev/module-vue'], }); ``` -------------------------------- ### Entrypoint Folder Structure Source: https://wxt.dev/guide/essentials/entrypoints Defines the basic structure for an entrypoint, either as a single file or a directory with an index file. ```html 📂 entrypoints/ 📄 {name}.{ext} ``` ```html 📂 entrypoints/ 📂 {name}/ 📄 index.{ext} ``` -------------------------------- ### Import with Custom Aliases Source: https://wxt.dev/guide/essentials/config/typescript Import modules using the custom aliases defined in `wxt.config.ts`. This example shows importing from 'testing' and 'strings'. ```typescript import { fakeTab } from 'testing/fake-objects'; import { toLowerCase } from 'strings'; ``` -------------------------------- ### Including Related Files in Entrypoints Source: https://wxt.dev/guide/essentials/entrypoints Shows how to organize files related to an entrypoint within its dedicated directory, ensuring only the index file is treated as the entrypoint. ```html 📂 entrypoints/ 📂 popup/ 📄 index.html ← This file is the entrypoint 📄 main.ts 📄 style.css 📂 background/ 📄 index.ts ← This file is the entrypoint 📄 alarms.ts 📄 messaging.ts 📂 youtube.content/ 📄 index.ts ← This file is the entrypoint 📄 style.css ``` -------------------------------- ### Use vite-node Entrypoint Loader Features Source: https://wxt.dev/guide/resources/upgrading Demonstrates importing variables and using Vite-specific APIs like `import.meta.glob` within entrypoint definitions when using `vite-node`. ```typescript import { GOOGLE_MATCHES } from '~/utils/constants' export default defineContentScript({ matches: [GOOGLE_MATCHES], main: () => ... }) ``` ```typescript const providers: Record = import.meta.glob('../providers/*', { eager: true, }); export default defineContentScript({ matches: Object.values(providers).flatMap( (provider) => provider.default.paths, ), async main() { console.log('Hello content.'); }, }); ``` -------------------------------- ### Add Vite Plugins in wxt.config.ts Source: https://wxt.dev/guide/essentials/config/vite Install the desired NPM package for a Vite plugin and include it in the `plugins` array within the Vite configuration function in `wxt.config.ts`. ```typescript import { defineConfig } from 'wxt'; import VueRouter from 'unplugin-vue-router/vite'; export default defineConfig({ vite: () => ({ plugins: [ VueRouter({ /* ... */ }), ], }), }); ``` -------------------------------- ### Background Entrypoint with Manifest Options Source: https://wxt.dev/guide/essentials/entrypoints Defines a background script with manifest options like persistence, type, and build-time include/exclude directives. The main function cannot be asynchronous. ```typescript export default defineBackground({ // Set manifest options persistent: undefined | true | false, type: undefined | 'module', // Set include/exclude if the background should be removed from some builds include: undefined | string[], exclude: undefined | string[], main() { // Executed when background is loaded, CANNOT BE ASYNC }, }); ``` -------------------------------- ### Update Storage `defineItem` without Options Argument Source: https://wxt.dev/guide/resources/upgrading If the second options argument is excluded from `defineItem`, the item will default to being nullable. This example shows how to access the value. ```typescript const item: WxtStorageItem = storage.defineItem('local:count'); const value: number | null = await item.getValue(); ``` -------------------------------- ### Create Integrated UI with Solid Source: https://wxt.dev/guide/essentials/content-scripts Render a SolidJS application into the page's DOM with `createIntegratedUi`. The `onMount` function renders the app, and `onRemove` calls the returned unmount function. ```typescript // entrypoints/example-ui.content/index.ts import { render } from 'solid-js/web'; export default defineContentScript({ matches: [''], main(ctx) { const ui = createIntegratedUi(ctx, { position: 'inline', anchor: 'body', onMount: (container) => { // Render your app to the UI container const unmount = render(() =>
...
, container); return unmount; }, onRemove: (unmount) => { // Unmount the app when the UI is removed unmount(); }, }); // Call mount to add the UI to the DOM ui.mount(); }, }); ``` -------------------------------- ### Options Entrypoint Source: https://wxt.dev/guide/essentials/entrypoints Define an Options entrypoint for your extension's settings page. Customize manifest properties like `open_in_tab` and `chrome_style` using meta tags. Use meta tags for build inclusion/exclusion. ```html Options Title ``` -------------------------------- ### Modify manifest.json with a Build Hook Source: https://wxt.dev/guide/essentials/config/hooks Add a hook to modify the `manifest.json` file during the build process. This example appends '(DEV)' to the manifest name in development mode. ```typescript export default defineConfig({ hooks: { 'build:manifestGenerated': (wxt, manifest) => { if (wxt.config.mode === 'development') { manifest.name += ' (DEV)'; } }, }, }); ``` -------------------------------- ### Continue Using jiti Entrypoint Loader Source: https://wxt.dev/guide/resources/upgrading Configure `wxt.config.ts` to use 'jiti' as the entrypoint loader to maintain the old behavior. Note that this option is deprecated. ```typescript export default defineConfig({ entrypointLoader: 'jiti', }); ``` -------------------------------- ### Configure Package.json Scripts Source: https://wxt.dev/guide/installation.html Add these scripts to your `package.json` to manage WXT development, building, and packaging. ```json { "scripts": { "dev": "wxt", "dev:firefox": "wxt -b firefox", "build": "wxt build", "build:firefox": "wxt build -b firefox", "zip": "wxt zip", "zip:firefox": "wxt zip -b firefox", "postinstall": "wxt prepare" } } ``` -------------------------------- ### Defining HTML Entrypoint Manifest Type Source: https://wxt.dev/guide/essentials/entrypoints Demonstrates how to configure manifest options for HTML entrypoints using `` tags within the HTML file, specifically setting the `manifest.type` to `page_action` for MV2. ```html ``` -------------------------------- ### Handling Assets in Content Scripts Source: https://wxt.dev/guide/essentials/assets When importing assets in content scripts, they resolve to paths relative to the tab's hostname. Use `browser.runtime.getURL()` to get the correct extension URL. ```typescript import iconUrl from '/icon/128.png'; export default defineContentScript({ matches: ['*://*.google.com/*'], main() { console.log(iconUrl); // "/icon/128.png" console.log(browser.runtime.getURL(iconUrl)); // "chrome-extension:///icon/128.png" }, }); ``` -------------------------------- ### Build Extension ZIPs Source: https://wxt.dev/guide/essentials/publishing Build all ZIP files for your extension that will be released. Use `-b` to specify a particular browser. ```sh wxt zip wxt zip -b firefox ``` -------------------------------- ### Update Resolved Config in a Module Source: https://wxt.dev/guide/essentials/wxt-modules Use the `config:resolved` hook within a module's `setup` function to modify WXT's configuration, such as changing the output directory. ```typescript import { defineWxtModule } from 'wxt/modules'; export default defineWxtModule({ setup(wxt) { wxt.hook('config:resolved', () => { wxt.config.outDir = 'dist'; }); }, }); ``` -------------------------------- ### Basic YouTube Content Script Source: https://wxt.dev/guide/essentials/content-scripts A basic content script example for YouTube that logs a message when loaded. This script will only run on full page reloads or direct navigation to the watch page. ```typescript export default defineContentScript({ matches: ['*://*.youtube.com/watch*'], main(ctx) { console.log('YouTube content script loaded'); mountUi(ctx); }, }); function mountUi(ctx: ContentScriptContext): void { // ... } ``` -------------------------------- ### Create Shadow Root UI with Vanilla JS Source: https://wxt.dev/guide/essentials/content-scripts Use `createShadowRootUi` to define and mount a UI within an isolated Shadow DOM. Ensure `cssInjectionMode` is set to 'ui' and import your styles. ```typescript // 1. Import the style import './style.css'; export default defineContentScript({ matches: [''], // 2. Set cssInjectionMode cssInjectionMode: 'ui', async main(ctx) { // 3. Define your UI const ui = await createShadowRootUi(ctx, { name: 'example-ui', position: 'inline', anchor: 'body', onMount(container) { // Define how your UI will be mounted inside the container const app = document.createElement('p'); app.textContent = 'Hello world!'; container.append(app); }, }); // 4. Mount the UI ui.mount(); }, }); ``` -------------------------------- ### Package JSON Version to Manifest Version Source: https://wxt.dev/guide/essentials/config/manifest Demonstrates how the `version` and `version_name` in the output manifest are derived from the `version` field in `package.json`. ```json // package.json { "version": "1.3.0-alpha2" } ``` ```json // .output//manifest.json { "version": "1.3.0", "version_name": "1.3.0-alpha2" } ``` -------------------------------- ### Popup Entrypoint Source: https://wxt.dev/guide/essentials/entrypoints Define a Popup entrypoint for your extension's action button. Customize manifest properties like `default_icon`, `type`, and `default_area` using meta tags. Use meta tags for build inclusion/exclusion. ```html Default Popup Title ``` -------------------------------- ### Prefix User Modules for Execution Order Source: https://wxt.dev/guide/essentials/config/hooks Prefix user module filenames with numbers to control their execution order. Lower numbers are loaded first. ```html 📁 modules/ 📄 0.my-module.ts 📄 1.another-module.ts ``` -------------------------------- ### Accessing and Opening Unlisted Pages Source: https://wxt.dev/guide/essentials/entrypoints This TypeScript code demonstrates how to get the runtime URL of an unlisted page and open it in a new tab. The URL format is 'chrome-extension://{id}/{name}.html'. ```ts const url = browser.runtime.getURL('/{name}.html'); console.log(url); // "chrome-extension://{id}/{name}.html" window.open(url); // Open the page in a new tab ``` -------------------------------- ### Get Registered Content Scripts in Chrome Extension Development Source: https://wxt.dev/guide/resources/faq Use this command in the service worker's console during development to list dynamically registered content scripts. This is useful for debugging content script loading issues. ```javascript await chrome.scripting.getRegisteredContentScripts(); ``` -------------------------------- ### Create Shadow Root UI with Solid Source: https://wxt.dev/guide/essentials/content-scripts Implement Solid.js applications within a Shadow DOM using `createShadowRootUi`. The `render` function from Solid is used for mounting, and its return value handles unmounting. ```typescript // 1. Import the style import './style.css'; import { render } from 'solid-js/web'; export default defineContentScript({ matches: [''], // 2. Set cssInjectionMode cssInjectionMode: 'ui', async main(ctx) { // 3. Define your UI const ui = await createShadowRootUi(ctx, { name: 'example-ui', position: 'inline', anchor: 'body', onMount: (container) => { // Render your app to the UI container const unmount = render(() =>
...
, container); }, onRemove: (unmount) => { // Unmount the app when the UI is removed unmount?.(); }, }); // 4. Mount the UI ui.mount(); }, }); ``` -------------------------------- ### Conditionally Add Vite Plugin Based on Mode Source: https://wxt.dev/guide/essentials/config/vite Some Vite plugins may require specific handling due to WXT's build orchestration. This example shows how to conditionally include `vite-plugin-remove-console` only when building for production by checking the `configEnv.mode`. ```typescript import { defineConfig } from 'wxt'; import removeConsole from 'vite-plugin-remove-console'; export default defineConfig({ vite: (configEnv) => ({ plugins: configEnv.mode === 'production' ? [removeConsole({ includes: ['log'] })] : [], }), }); ``` -------------------------------- ### Importing Assets from /assets Directory in JS Source: https://wxt.dev/guide/essentials/assets Import assets from the /assets directory using a tilde (~) prefix. This allows WXT's bundler to process them. ```javascript import imageUrl from '~/assets/image.png'; const img = document.createElement('img'); img.src = imageUrl; ``` -------------------------------- ### Write Unit Tests with Fake Browser API Source: https://wxt.dev/guide/essentials/unit-testing Demonstrates writing unit tests using Vitest and the fake browser API provided by `@webext-core/fake-browser`. This allows testing extension API interactions, like storage, without needing a real browser environment. Remember to reset the fake browser state before each test. ```typescript import { describe, it, expect } from 'vitest'; import { fakeBrowser } from 'wxt/testing/fake-browser'; const accountStorage = storage.defineItem('local:account'); async function isLoggedIn(): Promise { const value = await accountStorage.getValue(); return value != null; } describe('isLoggedIn', () => { beforeEach(() => { // See https://webext-core.aklinker1.io/fake-browser/reseting-state fakeBrowser.reset(); }); it('should return true when the account exists in storage', async () => { const account: Account = { username: '...', preferences: { // ... }, }; await accountStorage.setValue(account); expect(await isLoggedIn()).toBe(true); }); it('should return false when the account does not exist in storage', async () => { await accountStorage.deleteValue(); expect(await isLoggedIn()).toBe(false); }); }); ``` -------------------------------- ### Minimal Background Entrypoint Source: https://wxt.dev/guide/essentials/entrypoints Defines the minimal background script for your extension. This code is executed when the background process is loaded. ```typescript export default defineBackground(() => { // Executed when background is loaded }); ``` -------------------------------- ### Configure Vitest with WXT Plugin Source: https://wxt.dev/guide/essentials/unit-testing Set up Vitest for your WXT project by importing and using the WxtVitest plugin in your vitest.config.ts file. This plugin handles polyfilling extension APIs, applying Vite configurations, and setting up WXT-specific global variables. ```typescript import { defineConfig } from 'vitest/config'; import { WxtVitest } from 'wxt/testing/vitest-plugin'; export default defineConfig({ plugins: [WxtVitest()], }); ``` -------------------------------- ### Passing Build Modes via CLI Source: https://wxt.dev/guide/essentials/config/build-mode Use the `--mode` flag with WXT commands to specify the build environment. The default mode is 'development' for `dev` and 'production' for other commands. ```sh wxt --mode production wxt build --mode development wxt zip --mode testing ``` -------------------------------- ### Base tsconfig.json Source: https://wxt.dev/guide/essentials/config/typescript Extend the generated tsconfig.json from .wxt/tsconfig.json. This is the minimum required configuration. ```jsonc // /tsconfig.json { "extends": ".wxt/tsconfig.json", } ``` -------------------------------- ### Create Integrated UI with React Source: https://wxt.dev/guide/essentials/content-scripts Inject a React UI into the page using `createIntegratedUi`. The `onMount` callback creates a React root and renders the app, while `onRemove` unmounts it. ```typescript // entrypoints/example-ui.content/index.tsx import ReactDOM from 'react-dom/client'; import App from './App.tsx'; export default defineContentScript({ matches: [''], main(ctx) { const ui = createIntegratedUi(ctx, { position: 'inline', anchor: 'body', onMount: (container) => { // Create a root on the UI container and render a component const root = ReactDOM.createRoot(container); root.render(); return root; }, onRemove: (root) => { // Unmount the root when the UI is removed root.unmount(); }, }); // Call mount to add the UI to the DOM ui.mount(); }, }); ``` -------------------------------- ### GitHub Actions Workflow for Release Source: https://wxt.dev/guide/essentials/publishing Automate the process of zipping and submitting your extension to stores using a GitHub Actions workflow. Ensure all necessary secrets are configured in your repository settings. ```yml name: Release on: workflow_dispatch: jobs: submit: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - uses: pnpm/action-setup@v4 - uses: actions/setup-node@v4 with: node-version: 22 cache: 'pnpm' - name: Install dependencies run: pnpm install - name: Zip extensions run: | pnpm zip pnpm zip:firefox - name: Submit to stores run: | pnpm wxt submit \ --chrome-zip .output/*-chrome.zip \ --firefox-zip .output/*-firefox.zip --firefox-sources-zip .output/*-sources.zip env: CHROME_EXTENSION_ID: ${{ secrets.CHROME_EXTENSION_ID }} CHROME_CLIENT_ID: ${{ secrets.CHROME_CLIENT_ID }} CHROME_CLIENT_SECRET: ${{ secrets.CHROME_CLIENT_SECRET }} CHROME_REFRESH_TOKEN: ${{ secrets.CHROME_REFRESH_TOKEN }} FIREFOX_EXTENSION_ID: ${{ secrets.FIREFOX_EXTENSION_ID }} FIREFOX_JWT_ISSUER: ${{ secrets.FIREFOX_JWT_ISSUER }} FIREFOX_JWT_SECRET: ${{ secrets.FIREFOX_JWT_SECRET }} ``` -------------------------------- ### Submit Extension for Release Source: https://wxt.dev/guide/essentials/publishing Submit new versions of your extension to the specified stores after a successful dry run. Ensure all required ZIP files are generated and paths are correct. ```sh wxt submit \ --chrome-zip .output/{your-extension}-{version}-chrome.zip \ --firefox-zip .output/{your-extension}-{version}-firefox.zip --firefox-sources-zip .output/{your-extension}-{version}-sources.zip \ --edge-zip .output/{your-extension}-{version}-chrome.zip ``` -------------------------------- ### Referencing Assets from /assets Directory in CSS Source: https://wxt.dev/guide/essentials/assets Use the tilde (~) prefix to reference assets from the /assets directory in CSS. WXT's bundler will process these. ```css .bg-image { background-image: url(~/assets/image.png); } ``` -------------------------------- ### Defining Content Script Matches Source: https://wxt.dev/guide/essentials/entrypoints Shows how to define manifest options, specifically `matches` for content scripts, directly within the entrypoint TypeScript file using `defineContentScript`. ```typescript export default defineContentScript({ matches: ['*://*.wxt.dev/*'], main() { // ... }, }); ``` -------------------------------- ### Minimal Content Script Entrypoint Source: https://wxt.dev/guide/essentials/entrypoints Defines the minimal content script for your extension. The `main` function is executed when the content script is loaded and can be asynchronous. ```typescript export default defineContentScript({ // Set manifest options matches: string[], excludeMatches: undefined | [], includeGlobs: undefined | [], excludeGlobs: undefined | [], allFrames: undefined | true | false, runAt: undefined | 'document_start' | 'document_end' | 'document_idle', matchAboutBlank: undefined | true | false, matchOriginAsFallback: undefined | true | false, world: undefined | 'ISOLATED' | 'MAIN', // Set include/exclude if the background should be removed from some builds include: undefined | string[], exclude: undefined | string[], // Configure how CSS is injected onto the page cssInjectionMode: undefined | "manifest" | "manual" | "ui", // Configure how/when content script will be registered registration: undefined | "manifest" | "runtime", main(ctx: ContentScriptContext) { // Executed when content script is loaded, can be async }, }); ``` -------------------------------- ### Correcting Deeply Nested Entrypoints Source: https://wxt.dev/guide/essentials/entrypoints Illustrates the limitation on entrypoint nesting depth, showing how to flatten nested structures to be at most one level deep within the `entrypoints/` directory. ```html 📂 entrypoints/ 📂 youtube/ 📂 content/ 📄 index.ts 📄 ... 📂 injected/ 📄 index.ts 📄 ... 📂 youtube.content/ 📄 index.ts 📄 ... 📂 youtube-injected/ 📄 index.ts 📄 ... ``` -------------------------------- ### Localize Extension Name and Description Source: https://wxt.dev/guide/essentials/i18n Translate your extension's name and description by referencing message IDs in your manifest. Ensure these IDs are defined in your `messages.json` files. ```json { "extName": { "message": "..." }, "extDescription": { "message": "..." }, "helloWorld": { "message": "Hello world!" } } ``` ```typescript export default defineConfig({ manifest: { name: '__MSG_extName__', description: '__MSG_extDescription__', default_locale: 'en', }, }); ``` -------------------------------- ### Sandbox Entrypoint Source: https://wxt.dev/guide/essentials/entrypoints Define a Sandbox entrypoint for sandboxed pages, which are only supported in Chromium browsers. Use meta tags for build inclusion/exclusion. ```html Title ``` -------------------------------- ### Define WebExt Config Source: https://wxt.dev/guide/essentials/config/browser-startup Basic structure for defining web-ext configuration. Use this in `web-ext.config.ts` to ignore version control. ```typescript import { defineWebExtConfig } from 'wxt'; export default defineWebExtConfig({ // ... }); ``` -------------------------------- ### Create Integrated UI with Vanilla JavaScript Source: https://wxt.dev/guide/essentials/content-scripts Use `createIntegratedUi` to inject a UI directly into the page's body. The `onMount` callback receives a container element to append your UI components. ```typescript // entrypoints/example-ui.content.ts export default defineContentScript({ matches: [''], main(ctx) { const ui = createIntegratedUi(ctx, { position: 'inline', anchor: 'body', onMount: (container) => { // Append children to the container const app = document.createElement('p'); app.textContent = '...'; container.append(app); }, }); // Call mount to add the UI to the DOM ui.mount(); }, }); ``` -------------------------------- ### Define Runtime App Configuration Source: https://wxt.dev/guide/essentials/config/runtime Define your application's runtime configuration in `/app.config.ts`. Ensure you declare types for your config in the `WxtAppConfig` interface. ```typescript import { defineAppConfig } from '#imports'; // Define types for your config declare module 'wxt/utils/define-app-config' { export interface WxtAppConfig { theme?: 'light' | 'dark'; } } export default defineAppConfig({ theme: 'dark', }); ``` -------------------------------- ### Target Browser with CLI Flag Source: https://wxt.dev/guide/essentials/target-different-browsers Use the `-b` CLI flag to specify the target browser for a build. Defaults to 'chrome'. ```sh wxt # same as: wxt -b chrome wxt -b firefox wxt -b custom ``` -------------------------------- ### Create Translation Files Source: https://wxt.dev/guide/essentials/i18n Organize translation strings in `messages.json` files within the `public/_locales/` directory, with subdirectories for each language code. ```html 📂 {rootDir}/ 📂 public/ 📂 _locales/ 📂 en/ 📄 messages.json 📂 de/ 📄 messages.json 📂 ko/ 📄 messages.json ``` -------------------------------- ### Update Background Script for Browser Action Source: https://wxt.dev/guide/essentials/entrypoints This snippet shows how to correctly define a background entrypoint in WXT, ensuring that browser action listeners are placed within the `defineBackground` function. ```typescript browser.action.onClicked.addListener(() => { // [!code --] // ... // [!code --] }); // [!code --] export default defineBackground(() => { browser.action.onClicked.addListener(() => { // [!code ++] // ... // [!code ++] }); // [!code ++] }); ``` -------------------------------- ### Listen for Extension Updates Source: https://wxt.dev/guide/essentials/testing-updates Use the `browser.runtime.onInstalled` listener to detect when the extension is updated. The `reason` parameter will be 'update' if the extension was just updated. ```typescript browser.runtime.onInstalled.addListener(({ reason }) => { if (reason === 'update') { // Do something } }); ``` -------------------------------- ### Mocking WXT APIs with Vitest Source: https://wxt.dev/guide/essentials/unit-testing Learn how to mock WXT APIs when using Vitest. Understand that imports from '#imports' are preprocessed, so you need to mock the actual module path (e.g., 'wxt/utils/inject-script') instead of '#imports'. Refer to your project's `.wxt/types/imports-module.d.ts` for correct import paths. ```typescript // What you write import { injectScript, createShadowRootUi } from '#imports'; ``` ```typescript // Vitest sees this: import { injectScript } from 'wxt/utils/inject-script'; import { createShadowRootUi } from 'wxt/utils/content-script-ui/shadow-root'; ``` ```typescript vi.mock("wxt/utils/inject-script", () => ({ injectScript: ... })) ``` -------------------------------- ### Target Manifest Version with CLI Flags Source: https://wxt.dev/guide/essentials/target-different-browsers Use the `--mv2` or `--mv3` CLI flags to target specific manifest versions for your builds. ```sh --mv2 --mv3 ``` -------------------------------- ### Mount UI to Dynamic Element with autoMount Source: https://wxt.dev/guide/essentials/content-scripts Use `autoMount` to automatically mount a UI when a target element appears and unmount it when it disappears. The `anchor` option specifies the target element. ```typescript export default defineContentScript({ matches: [''], main(ctx) { const ui = createIntegratedUi(ctx, { position: 'inline', // It observes the anchor anchor: '#your-target-dynamic-element', onMount: (container) => { // Append children to the container const app = document.createElement('p'); app.textContent = '...'; container.append(app); }, }); // Call autoMount to observe anchor element for add/remove. ui.autoMount(); }, }); ``` -------------------------------- ### Importing Assets from /assets Directory in JSX Source: https://wxt.dev/guide/essentials/assets Import assets from the /assets directory in JSX using the tilde (~) prefix. The bundler will process these imported assets. ```jsx import image from '~/assets/image.png'; ; ``` -------------------------------- ### Create Shadow Root UI with Vue Source: https://wxt.dev/guide/essentials/content-scripts Integrate Vue applications into a Shadow DOM using `createShadowRootUi`. The `onMount` and `onRemove` callbacks handle Vue app creation and cleanup. ```typescript // 1. Import the style import './style.css'; import { createApp } from 'vue'; import App from './App.vue'; export default defineContentScript({ matches: [''], // 2. Set cssInjectionMode cssInjectionMode: 'ui', async main(ctx) { // 3. Define your UI const ui = await createShadowRootUi(ctx, { name: 'example-ui', position: 'inline', anchor: 'body', onMount: (container) => { // Define how your UI will be mounted inside the container const app = createApp(App); app.mount(container); return app; }, onRemove: (app) => { // Unmount the app when the UI is removed app?.unmount(); }, }); // 4. Mount the UI ui.mount(); }, }); ``` -------------------------------- ### Create ZIP for Chrome Web Store Source: https://wxt.dev/guide/essentials/publishing Use this command to generate a ZIP file suitable for publishing to the Chrome Web Store. ```sh wxt zip ``` -------------------------------- ### Configure Output Directory Template in WXT Source: https://wxt.dev/guide/resources/upgrading Set the `outDirTemplate` option to use the old behavior of writing all output to the same directory. ```typescript export default defineConfig({ outDirTemplate: '{{browser}}-mv{{manifestVersion}}', }); ``` -------------------------------- ### Importing Assets from /assets Directory in Vue Source: https://wxt.dev/guide/essentials/assets Import assets from the /assets directory in Vue components using the tilde (~) prefix for bundler processing. ```vue ``` -------------------------------- ### Bookmarks HTML Page Source: https://wxt.dev/guide/essentials/entrypoints An HTML structure for a bookmarks entrypoint. It includes meta tags for build-time include/exclude directives, allowing you to control when this page is included in the build. ```html Title ```