Showing preview only (2,392K chars total). Download the full file or copy to clipboard to get everything.
Repository: wxt-dev/wxt
Branch: main
Commit: c528361d0719
Files: 573
Total size: 2.2 MB
Directory structure:
gitextract_x35r4j0y/
├── .codecov.yml
├── .commitlintrc.yml
├── .gitattributes
├── .github/
│ ├── CODEOWNERS
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.yml
│ │ ├── config.yml
│ │ └── feature_request.md
│ ├── actions/
│ │ └── setup/
│ │ └── action.yml
│ ├── dependabot.yml
│ ├── pull_request_template.md
│ └── workflows/
│ ├── auto-label.yml
│ ├── notify-unreleased-commits.yml
│ ├── pkg.pr.new.yml
│ ├── pr-closed.yml
│ ├── pr-title.yml
│ ├── publish-docs.yml
│ ├── release.yml
│ ├── sync-releases.yml
│ ├── update-browser-package.yml
│ ├── validate.yml
│ └── vhs.yml
├── .gitignore
├── .markdownlint.json
├── .markdownlintignore
├── .prettierignore
├── .prettierrc.yml
├── .vscode/
│ ├── extensions.json
│ └── settings.json
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── MAINTAINERS.md
├── README.md
├── SECURITY.md
├── docs/
│ ├── .vitepress/
│ │ ├── Dockerfile
│ │ ├── components/
│ │ │ ├── BlogHome.vue
│ │ │ ├── BlogLayout.vue
│ │ │ ├── BlogPostPreview.vue
│ │ │ ├── EntrypointPatterns.vue
│ │ │ ├── ExampleSearch.vue
│ │ │ ├── ExampleSearchFilterByItem.vue
│ │ │ ├── ExampleSearchResult.vue
│ │ │ ├── Icon.vue
│ │ │ └── UsingWxtSection.vue
│ │ ├── composables/
│ │ │ ├── useBlogDate.ts
│ │ │ └── useListExtensionDetails.ts
│ │ ├── config.ts
│ │ ├── loaders/
│ │ │ ├── blog.data.ts
│ │ │ └── cli.data.ts
│ │ ├── theme/
│ │ │ ├── custom.css
│ │ │ └── index.ts
│ │ └── utils/
│ │ ├── head.ts
│ │ ├── menus.ts
│ │ └── types.ts
│ ├── analytics.md
│ ├── api/
│ │ └── cli/
│ │ ├── wxt-build.md
│ │ ├── wxt-clean.md
│ │ ├── wxt-init.md
│ │ ├── wxt-prepare.md
│ │ ├── wxt-submit-init.md
│ │ ├── wxt-submit.md
│ │ ├── wxt-zip.md
│ │ └── wxt.md
│ ├── auto-icons.md
│ ├── blog/
│ │ ├── .drafts/
│ │ │ └── 2024-10-19-real-world-messaging.md
│ │ └── 2024-12-06-using-imports-module.md
│ ├── blog.md
│ ├── examples.md
│ ├── guide/
│ │ ├── essentials/
│ │ │ ├── assets.md
│ │ │ ├── config/
│ │ │ │ ├── auto-imports.md
│ │ │ │ ├── browser-startup.md
│ │ │ │ ├── build-mode.md
│ │ │ │ ├── entrypoint-loaders.md
│ │ │ │ ├── environment-variables.md
│ │ │ │ ├── hooks.md
│ │ │ │ ├── manifest.md
│ │ │ │ ├── runtime.md
│ │ │ │ ├── typescript.md
│ │ │ │ └── vite.md
│ │ │ ├── content-scripts.md
│ │ │ ├── e2e-testing.md
│ │ │ ├── entrypoints.md
│ │ │ ├── es-modules.md
│ │ │ ├── extension-apis.md
│ │ │ ├── frontend-frameworks.md
│ │ │ ├── i18n.md
│ │ │ ├── messaging.md
│ │ │ ├── project-structure.md
│ │ │ ├── publishing.md
│ │ │ ├── remote-code.md
│ │ │ ├── scripting.md
│ │ │ ├── storage.md
│ │ │ ├── target-different-browsers.md
│ │ │ ├── testing-updates.md
│ │ │ ├── unit-testing.md
│ │ │ └── wxt-modules.md
│ │ ├── installation.md
│ │ ├── introduction.md
│ │ └── resources/
│ │ ├── community.md
│ │ ├── compare.md
│ │ ├── faq.md
│ │ ├── how-wxt-works.md
│ │ ├── migrate.md
│ │ └── upgrading.md
│ ├── i18n.md
│ ├── index.md
│ ├── is-background.md
│ ├── public/
│ │ ├── _redirects
│ │ └── robots.txt
│ ├── runner.md
│ ├── storage.md
│ ├── tapes/
│ │ └── init-demo.tape
│ ├── typedoc.json
│ └── unocss.md
├── package.json
├── packages/
│ ├── analytics/
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── app.config.ts
│ │ ├── entrypoints/
│ │ │ └── popup/
│ │ │ ├── index.html
│ │ │ └── main.ts
│ │ ├── modules/
│ │ │ └── analytics/
│ │ │ ├── background-plugin.ts
│ │ │ ├── client.ts
│ │ │ ├── index.ts
│ │ │ ├── providers/
│ │ │ │ ├── google-analytics-4.ts
│ │ │ │ └── umami.ts
│ │ │ └── types.ts
│ │ ├── package.json
│ │ ├── public/
│ │ │ └── .keep
│ │ ├── tsconfig.json
│ │ ├── tsdown.config.ts
│ │ └── wxt.config.ts
│ ├── auto-icons/
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── __test__/
│ │ │ │ └── index.test.ts
│ │ │ └── index.ts
│ │ ├── tsconfig.json
│ │ └── vitest.config.ts
│ ├── browser/
│ │ ├── README.md
│ │ ├── package.json
│ │ ├── scripts/
│ │ │ └── generate.ts
│ │ ├── src/
│ │ │ ├── __tests__/
│ │ │ │ └── index.test.ts
│ │ │ ├── gen/
│ │ │ │ ├── chrome-cast/
│ │ │ │ │ └── index.d.ts
│ │ │ │ ├── har-format/
│ │ │ │ │ └── index.d.ts
│ │ │ │ └── index.d.ts
│ │ │ ├── index.d.ts
│ │ │ └── index.mjs
│ │ ├── templates/
│ │ │ └── package.json
│ │ └── tsconfig.json
│ ├── i18n/
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── __tests__/
│ │ │ │ ├── build.test.ts
│ │ │ │ ├── index.test.ts
│ │ │ │ ├── types.test.ts
│ │ │ │ └── utils.test.ts
│ │ │ ├── build.ts
│ │ │ ├── index.ts
│ │ │ ├── module.ts
│ │ │ ├── supported-locales.ts
│ │ │ ├── types.ts
│ │ │ └── utils.ts
│ │ ├── tsconfig.json
│ │ ├── tsdown.config.ts
│ │ └── vitest.config.ts
│ ├── is-background/
│ │ ├── README.md
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── __tests__/
│ │ │ │ └── getter.test.ts
│ │ │ ├── getter.ts
│ │ │ └── index.ts
│ │ └── tsconfig.json
│ ├── module-react/
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── components/
│ │ │ └── App.tsx
│ │ ├── entrypoints/
│ │ │ ├── content/
│ │ │ │ └── index.tsx
│ │ │ └── popup/
│ │ │ ├── index.html
│ │ │ └── main.tsx
│ │ ├── modules/
│ │ │ └── react.ts
│ │ ├── package.json
│ │ ├── public/
│ │ │ └── .keep
│ │ ├── tsconfig.json
│ │ └── tsdown.config.ts
│ ├── module-solid/
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── components/
│ │ │ └── App.tsx
│ │ ├── entrypoints/
│ │ │ ├── content/
│ │ │ │ └── index.tsx
│ │ │ └── popup/
│ │ │ ├── index.html
│ │ │ └── main.tsx
│ │ ├── modules/
│ │ │ └── solid.ts
│ │ ├── package.json
│ │ ├── public/
│ │ │ └── .keep
│ │ ├── tsconfig.json
│ │ └── tsdown.config.ts
│ ├── module-svelte/
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── package.json
│ │ ├── src/
│ │ │ └── index.ts
│ │ ├── tsconfig.json
│ │ └── tsdown.config.ts
│ ├── module-vue/
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── package.json
│ │ ├── src/
│ │ │ └── index.ts
│ │ ├── tsconfig.json
│ │ └── tsdown.config.ts
│ ├── runner/
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── demo-extension/
│ │ │ ├── background.js
│ │ │ └── manifest.json
│ │ ├── dev.ts
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── __tests__/
│ │ │ │ ├── install.test.ts
│ │ │ │ └── options.test.ts
│ │ │ ├── bidi.ts
│ │ │ ├── browser-paths.ts
│ │ │ ├── cdp.ts
│ │ │ ├── debug.ts
│ │ │ ├── index.ts
│ │ │ ├── install.ts
│ │ │ ├── options.ts
│ │ │ ├── promises.ts
│ │ │ ├── run.ts
│ │ │ └── web-socket.ts
│ │ ├── tsconfig.json
│ │ └── vitest.config.ts
│ ├── storage/
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── __tests__/
│ │ │ │ └── index.test.ts
│ │ │ └── index.ts
│ │ ├── tsconfig.json
│ │ ├── vitest.config.ts
│ │ └── vitest.setup.ts
│ ├── unocss/
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── package.json
│ │ ├── src/
│ │ │ └── index.ts
│ │ └── tsconfig.json
│ ├── webextension-polyfill/
│ │ ├── README.md
│ │ ├── entrypoints/
│ │ │ ├── content/
│ │ │ │ └── index.ts
│ │ │ └── popup/
│ │ │ ├── index.html
│ │ │ └── main.ts
│ │ ├── modules/
│ │ │ └── webextension-polyfill/
│ │ │ ├── browser.ts
│ │ │ └── index.ts
│ │ ├── package.json
│ │ ├── public/
│ │ │ └── .keep
│ │ ├── tsconfig.json
│ │ └── tsdown.config.ts
│ ├── wxt/
│ │ ├── .oxlintignore
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── bin/
│ │ │ ├── wxt-publish-extension.mjs
│ │ │ └── wxt.mjs
│ │ ├── e2e/
│ │ │ ├── tests/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── auto-imports.test.ts.snap
│ │ │ │ ├── analysis.test.ts
│ │ │ │ ├── auto-imports.test.ts
│ │ │ │ ├── dev.test.ts
│ │ │ │ ├── encoding.test.ts
│ │ │ │ ├── hooks.test.ts
│ │ │ │ ├── init.test.ts
│ │ │ │ ├── manifest-content.test.ts
│ │ │ │ ├── modules.test.ts
│ │ │ │ ├── npm-packages.test.ts
│ │ │ │ ├── output-structure.test.ts
│ │ │ │ ├── react.test.ts
│ │ │ │ ├── remote-code.test.ts
│ │ │ │ ├── typescript-project.test.ts
│ │ │ │ ├── user-config.test.ts
│ │ │ │ └── zip.test.ts
│ │ │ └── utils.ts
│ │ ├── globals.d.ts
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── @types/
│ │ │ │ ├── globals.d.ts
│ │ │ │ ├── modules.d.ts
│ │ │ │ └── project-types.d.ts
│ │ │ ├── __tests__/
│ │ │ │ └── modules.test.ts
│ │ │ ├── browser.ts
│ │ │ ├── builtin-modules/
│ │ │ │ ├── index.ts
│ │ │ │ └── unimport.ts
│ │ │ ├── cli/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.test.ts
│ │ │ │ ├── cli-utils.ts
│ │ │ │ ├── commands.ts
│ │ │ │ └── index.ts
│ │ │ ├── core/
│ │ │ │ ├── build.ts
│ │ │ │ ├── builders/
│ │ │ │ │ └── vite/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── fixtures/
│ │ │ │ │ │ ├── module.ts
│ │ │ │ │ │ └── test.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── plugins/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── devHtmlPrerender.test.ts
│ │ │ │ │ │ └── iifeFooter.test.ts
│ │ │ │ │ ├── bundleAnalysis.ts
│ │ │ │ │ ├── cssEntrypoints.ts
│ │ │ │ │ ├── defineImportMeta.ts
│ │ │ │ │ ├── devHtmlPrerender.ts
│ │ │ │ │ ├── devServerGlobals.ts
│ │ │ │ │ ├── download.ts
│ │ │ │ │ ├── entrypointGroupGlobals.ts
│ │ │ │ │ ├── extensionApiMock.ts
│ │ │ │ │ ├── globals.ts
│ │ │ │ │ ├── iifeAnonymous.ts
│ │ │ │ │ ├── iifeFooter.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── noopBackground.ts
│ │ │ │ │ ├── removeEntrypointMainFunction.ts
│ │ │ │ │ ├── resolveAppConfig.ts
│ │ │ │ │ ├── resolveVirtualModules.ts
│ │ │ │ │ ├── tsconfigPaths.ts
│ │ │ │ │ └── wxtPluginLoader.ts
│ │ │ │ ├── clean.ts
│ │ │ │ ├── create-server.ts
│ │ │ │ ├── define-config.ts
│ │ │ │ ├── define-web-ext-config.ts
│ │ │ │ ├── generate-wxt-dir.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── initialize.ts
│ │ │ │ ├── keyboard-shortcuts.ts
│ │ │ │ ├── package-managers/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── bun.test.ts
│ │ │ │ │ │ ├── fixtures/
│ │ │ │ │ │ │ ├── simple-bun-project/
│ │ │ │ │ │ │ │ ├── bun.lockb
│ │ │ │ │ │ │ │ └── package.json
│ │ │ │ │ │ │ ├── simple-npm-project/
│ │ │ │ │ │ │ │ └── package.json
│ │ │ │ │ │ │ ├── simple-pnpm-project/
│ │ │ │ │ │ │ │ └── package.json
│ │ │ │ │ │ │ └── simple-yarn-project/
│ │ │ │ │ │ │ └── package.json
│ │ │ │ │ │ ├── npm.test.ts
│ │ │ │ │ │ ├── pnpm.test.ts
│ │ │ │ │ │ └── yarn.test.ts
│ │ │ │ │ ├── bun.ts
│ │ │ │ │ ├── deno.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── npm.ts
│ │ │ │ │ ├── pnpm.ts
│ │ │ │ │ ├── types.ts
│ │ │ │ │ └── yarn.ts
│ │ │ │ ├── prepare.ts
│ │ │ │ ├── resolve-config.ts
│ │ │ │ ├── runners/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── index.test.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── manual.ts
│ │ │ │ │ ├── safari.ts
│ │ │ │ │ ├── web-ext.ts
│ │ │ │ │ └── wsl.ts
│ │ │ │ ├── utils/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── arrays.test.ts
│ │ │ │ │ │ ├── content-scripts.test.ts
│ │ │ │ │ │ ├── content-security-policy.test.ts
│ │ │ │ │ │ ├── entrypoints.test.ts
│ │ │ │ │ │ ├── manifest.test.ts
│ │ │ │ │ │ ├── network.test.ts
│ │ │ │ │ │ ├── number.test.ts
│ │ │ │ │ │ ├── package.test.ts
│ │ │ │ │ │ ├── paths.test.ts
│ │ │ │ │ │ ├── picomatch-multiple.test.ts
│ │ │ │ │ │ ├── strings.test.ts
│ │ │ │ │ │ ├── transform.test.ts
│ │ │ │ │ │ ├── validation.test.ts
│ │ │ │ │ │ └── virtual-modules.test.ts
│ │ │ │ │ ├── arrays.ts
│ │ │ │ │ ├── building/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ ├── detect-dev-changes.test.ts
│ │ │ │ │ │ │ ├── find-entrypoints.test.ts
│ │ │ │ │ │ │ ├── group-entrypoints.test.ts
│ │ │ │ │ │ │ └── test-entrypoints/
│ │ │ │ │ │ │ ├── background.ts
│ │ │ │ │ │ │ ├── content.ts
│ │ │ │ │ │ │ ├── imported-option.ts
│ │ │ │ │ │ │ ├── no-default-export.ts
│ │ │ │ │ │ │ ├── react.tsx
│ │ │ │ │ │ │ ├── unlisted.ts
│ │ │ │ │ │ │ └── with-named.ts
│ │ │ │ │ │ ├── build-entrypoints.ts
│ │ │ │ │ │ ├── detect-dev-changes.ts
│ │ │ │ │ │ ├── find-entrypoints.ts
│ │ │ │ │ │ ├── group-entrypoints.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── internal-build.ts
│ │ │ │ │ │ └── rebuild.ts
│ │ │ │ │ ├── cache.ts
│ │ │ │ │ ├── cli.ts
│ │ │ │ │ ├── constants.ts
│ │ │ │ │ ├── content-scripts.ts
│ │ │ │ │ ├── content-security-policy.ts
│ │ │ │ │ ├── entrypoints.ts
│ │ │ │ │ ├── env.ts
│ │ │ │ │ ├── environments/
│ │ │ │ │ │ ├── browser-environment.ts
│ │ │ │ │ │ ├── environment.ts
│ │ │ │ │ │ ├── extension-environment.ts
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── eslint.ts
│ │ │ │ │ ├── fs.ts
│ │ │ │ │ ├── globals.ts
│ │ │ │ │ ├── i18n.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── log/
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── printBuildSummary.ts
│ │ │ │ │ │ ├── printFileList.ts
│ │ │ │ │ │ ├── printHeader.ts
│ │ │ │ │ │ └── printTable.ts
│ │ │ │ │ ├── manifest.ts
│ │ │ │ │ ├── network.ts
│ │ │ │ │ ├── number.ts
│ │ │ │ │ ├── package.ts
│ │ │ │ │ ├── paths.ts
│ │ │ │ │ ├── picomatch-multiple.ts
│ │ │ │ │ ├── strings.ts
│ │ │ │ │ ├── syntax-errors.ts
│ │ │ │ │ ├── testing/
│ │ │ │ │ │ └── fake-objects.ts
│ │ │ │ │ ├── time.ts
│ │ │ │ │ ├── transform.ts
│ │ │ │ │ ├── types.ts
│ │ │ │ │ ├── validation.ts
│ │ │ │ │ ├── virtual-modules.ts
│ │ │ │ │ └── wsl.ts
│ │ │ │ ├── wxt.ts
│ │ │ │ └── zip.ts
│ │ │ ├── index.ts
│ │ │ ├── modules.ts
│ │ │ ├── testing/
│ │ │ │ ├── fake-browser.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── wxt-vitest-plugin.ts
│ │ │ ├── types.ts
│ │ │ ├── utils/
│ │ │ │ ├── README.md
│ │ │ │ ├── __tests__/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── split-shadow-root-css.test.ts.snap
│ │ │ │ │ ├── content-script-context.test.ts
│ │ │ │ │ ├── define-background.test.ts
│ │ │ │ │ ├── define-content-script.test.ts
│ │ │ │ │ ├── define-unlisted-script.test.ts
│ │ │ │ │ └── split-shadow-root-css.test.ts
│ │ │ │ ├── app-config.ts
│ │ │ │ ├── content-script-context.ts
│ │ │ │ ├── content-script-ui/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── index.test.ts
│ │ │ │ │ ├── iframe.ts
│ │ │ │ │ ├── integrated.ts
│ │ │ │ │ ├── shadow-root.ts
│ │ │ │ │ ├── shared.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── define-app-config.ts
│ │ │ │ ├── define-background.ts
│ │ │ │ ├── define-content-script.ts
│ │ │ │ ├── define-unlisted-script.ts
│ │ │ │ ├── define-wxt-plugin.ts
│ │ │ │ ├── inject-script.ts
│ │ │ │ ├── internal/
│ │ │ │ │ ├── custom-events.ts
│ │ │ │ │ ├── dev-server-websocket.ts
│ │ │ │ │ ├── location-watcher.ts
│ │ │ │ │ └── logger.ts
│ │ │ │ ├── match-patterns.ts
│ │ │ │ ├── split-shadow-root-css.ts
│ │ │ │ └── storage.ts
│ │ │ ├── version.ts
│ │ │ ├── virtual/
│ │ │ │ ├── README.md
│ │ │ │ ├── background-entrypoint.ts
│ │ │ │ ├── content-script-isolated-world-entrypoint.ts
│ │ │ │ ├── content-script-main-world-entrypoint.ts
│ │ │ │ ├── mock-browser.ts
│ │ │ │ ├── reload-html.ts
│ │ │ │ ├── tsconfig.json
│ │ │ │ ├── unlisted-script-entrypoint.ts
│ │ │ │ ├── utils/
│ │ │ │ │ ├── keep-service-worker-alive.ts
│ │ │ │ │ └── reload-content-scripts.ts
│ │ │ │ └── virtual-module-globals.d.ts
│ │ │ └── vite-builder-env.d.ts
│ │ ├── tsconfig.json
│ │ ├── tsdown.config.ts
│ │ ├── typedoc.json
│ │ ├── vitest.config.ts
│ │ ├── vitest.globalSetup.ts
│ │ └── vitest.setup.ts
│ └── wxt-demo/
│ ├── eslint.config.js
│ ├── modules/
│ │ ├── auto-icons.ts
│ │ ├── example.ts
│ │ ├── i18n.ts
│ │ └── unocss.ts
│ ├── package.json
│ ├── src/
│ │ ├── app.config.ts
│ │ ├── entrypoints/
│ │ │ ├── __tests__/
│ │ │ │ └── background.test.ts
│ │ │ ├── automount.content/
│ │ │ │ ├── index.ts
│ │ │ │ └── style.css
│ │ │ ├── background.ts
│ │ │ ├── example-2.scss
│ │ │ ├── example-tsx.content.tsx
│ │ │ ├── example.sandbox/
│ │ │ │ └── index.html
│ │ │ ├── iframe-src/
│ │ │ │ ├── index.html
│ │ │ │ └── main.ts
│ │ │ ├── iframe.content.ts
│ │ │ ├── injected.content/
│ │ │ │ └── index.css
│ │ │ ├── location-change.content.ts
│ │ │ ├── main-world.content.ts
│ │ │ ├── options/
│ │ │ │ ├── index.html
│ │ │ │ ├── main.ts
│ │ │ │ └── style.css
│ │ │ ├── popup.html
│ │ │ ├── sandbox.html
│ │ │ ├── sidepanel.html
│ │ │ ├── ui.content/
│ │ │ │ ├── index.ts
│ │ │ │ ├── manual-style.css
│ │ │ │ └── style.css
│ │ │ └── unlisted.ts
│ │ ├── locales/
│ │ │ └── en.yml
│ │ └── utils/
│ │ └── logger.ts
│ ├── tsconfig.json
│ ├── vitest.config.ts
│ └── wxt.config.ts
├── patches/
│ ├── markdown-it-footnote.md
│ └── markdown-it-footnote.patch
├── pnpm-workspace.yaml
├── scripts/
│ ├── benchmarks/
│ │ ├── browser-startup.patch
│ │ └── browser-startup.sh
│ ├── bump-package-version.ts
│ ├── create-github-release.ts
│ ├── generate-readmes.sh
│ ├── git.ts
│ ├── list-unreleased-commits.sh
│ ├── sync-releases.ts
│ └── upgrade-deps.ts
├── templates/
│ ├── react/
│ │ ├── README.md
│ │ ├── _gitignore
│ │ ├── entrypoints/
│ │ │ ├── background.ts
│ │ │ ├── content.ts
│ │ │ └── popup/
│ │ │ ├── App.css
│ │ │ ├── App.tsx
│ │ │ ├── index.html
│ │ │ ├── main.tsx
│ │ │ └── style.css
│ │ ├── package.json
│ │ ├── tsconfig.json
│ │ └── wxt.config.ts
│ ├── solid/
│ │ ├── README.md
│ │ ├── _gitignore
│ │ ├── entrypoints/
│ │ │ ├── background.ts
│ │ │ ├── content.ts
│ │ │ └── popup/
│ │ │ ├── App.css
│ │ │ ├── App.tsx
│ │ │ ├── index.html
│ │ │ ├── main.tsx
│ │ │ └── style.css
│ │ ├── package.json
│ │ ├── tsconfig.json
│ │ └── wxt.config.ts
│ ├── svelte/
│ │ ├── .vscode/
│ │ │ └── extensions.json
│ │ ├── README.md
│ │ ├── _gitignore
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── entrypoints/
│ │ │ │ ├── background.ts
│ │ │ │ ├── content.ts
│ │ │ │ └── popup/
│ │ │ │ ├── App.svelte
│ │ │ │ ├── app.css
│ │ │ │ ├── index.html
│ │ │ │ └── main.ts
│ │ │ └── lib/
│ │ │ └── Counter.svelte
│ │ ├── tsconfig.json
│ │ ├── wxt-env.d.ts
│ │ └── wxt.config.ts
│ ├── vanilla/
│ │ ├── _gitignore
│ │ ├── components/
│ │ │ └── counter.ts
│ │ ├── entrypoints/
│ │ │ ├── background.ts
│ │ │ ├── content.ts
│ │ │ └── popup/
│ │ │ ├── index.html
│ │ │ ├── main.ts
│ │ │ └── style.css
│ │ ├── package.json
│ │ ├── tsconfig.json
│ │ └── wxt.config.ts
│ └── vue/
│ ├── .vscode/
│ │ └── extensions.json
│ ├── README.md
│ ├── _gitignore
│ ├── components/
│ │ └── HelloWorld.vue
│ ├── entrypoints/
│ │ ├── background.ts
│ │ ├── content.ts
│ │ └── popup/
│ │ ├── App.vue
│ │ ├── index.html
│ │ ├── main.ts
│ │ └── style.css
│ ├── package.json
│ ├── tsconfig.json
│ └── wxt.config.ts
├── tsconfig.base.json
└── tsconfig.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .codecov.yml
================================================
coverage:
status:
project:
default:
informational: true
patch:
default:
informational: true
================================================
FILE: .commitlintrc.yml
================================================
extends:
- '@commitlint/config-conventional'
rules:
subject-case:
- 0
- always
- - sentence-case
- start-case
- pascal-case
- upper-case
================================================
FILE: .gitattributes
================================================
# See https://git-scm.com/docs/gitattributes#_pattern_format for more about `.gitattributes`.
# Normalize EOL for all files that Git considers text files
* text=auto eol=lf
# Mark lock files as generated to avoid diffing
pnpm-lock.yaml linguist-generated
package-lock.json linguist-generated
bun.lockb linguist-generated
yarn.lock linguist-generated
# Exclude templates from language statistics
templates/**/* linguist-vendored
# Other generated files
packages/browser/src/gen/** linguist-generated
================================================
FILE: .github/CODEOWNERS
================================================
# Set default
* @aklinker1
# Secure Directories
/.github/ @aklinker1
# Creator of specific wxt modules
/packages/auto-icons/ @Timeraa
/packages/unocss/ @Timeraa
================================================
FILE: .github/FUNDING.yml
================================================
# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/displaying-a-sponsor-button-in-your-repository#about-funding-files
github: wxt-dev
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.yml
================================================
name: "\U0001F41E Bug report"
description: Report an issue with WXT
labels: [pending-triage]
type: Bug
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
- type: textarea
id: bug-description
attributes:
label: Describe the bug
description: A clear and concise description of what the bug is. If you intend to submit a PR for this issue, tell us in the description. Thanks!
placeholder: I am doing ... What I expect is ... What actually happening is ...
validations:
required: true
- type: textarea
id: reproduction
attributes:
label: Reproduction
description: |
Please provide a minimal reproduction. This can include:
- A PR with a failing test case
- A link to a github repo
- A ZIP you upload to this issue
A [minimal reproduction](https://stackoverflow.com/help/minimal-reproducible-example) is required ([Why?](https://antfu.me/posts/why-reproductions-are-required)). If a report is vague (e.g. just a generic error message) and has no reproduction or a partial reproduction, it will be closed immediately and labeled with as "needs-reproduction". Once a reproduction is provided, it will be re-opened.
placeholder: Reproduction URL or attach a ZIP
validations:
required: true
- type: textarea
id: reproduction-steps
attributes:
label: Steps to reproduce
description: Please provide any reproduction steps that may need to be described. E.g. if it happens only when running the dev or build script make sure it's clear which one to use.
placeholder: Run `npm install` followed by `npm run dev`
- type: textarea
id: system-info
attributes:
label: System Info
description: Output of `npx envinfo --system --browsers --binaries --npmPackages wxt,vite`
render: shell
placeholder: System, Binaries, Browsers
validations:
required: true
- type: dropdown
id: package-manager
attributes:
label: Used Package Manager
description: Select the used package manager
options:
- npm
- yarn
- pnpm
- bun
validations:
required: true
- type: checkboxes
id: checkboxes
attributes:
label: Validations
description: Before submitting the issue, please make sure you do the following
options:
- label: Read the [Contributing Guidelines](https://github.com/wxt-dev/wxt/blob/main/CONTRIBUTING.md).
required: true
- label: Read the [docs](https://wxt.dev/guide/installation.html).
required: true
- label: Check that there isn't [already an issue](https://github.com/wxt-dev/wxt/issues) that reports the same bug to avoid creating a duplicate.
required: true
- label: Check that this is a concrete bug. For Q&A open a [GitHub Discussion](https://github.com/wxt-dev/wxt/discussions) or join our [Discord Chat Server](https://discord.gg/ZFsZqGery9).
required: true
- label: The provided reproduction is a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) of the bug.
required: true
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false
contact_links:
- name: Discord Chat
url: https://discord.gg/ZFsZqGery9
about: Ask questions and discuss with other WXT users in real time.
- name: Questions & Discussions
url: https://github.com/wxt-dev/wxt/discussions
about: Use GitHub discussions for message-board style questions and discussions.
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for WXT
title: ''
type: Feature
assignees: ''
---
### Feature Request
Please describe your feature, be clear and concise. If you have a proposal for required type or API changes, list them here.
#### Is your feature request related to a bug?
If so, add a link here. If not, write "N/A"
### What are the alternatives?
A clear and concise description of any alternative solutions or features you've considered.
### Additional context
Add any other context or screenshots about the feature request here.
================================================
FILE: .github/actions/setup/action.yml
================================================
name: Basic Setup
description: Install PNPM, Node, and dependencies
inputs:
install:
default: 'true'
description: Whether or not to run 'pnpm install'
installArgs:
default: ''
description: Additional args to append to "pnpm install"
runs:
using: composite
steps:
- name: 🛠️ Setup PNPM
uses: pnpm/action-setup@f2b2b233b538f500472c7274c7012f57857d8ce0 # v4.1.0
- name: 🛠️ Setup NodeJS
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
with:
node-version: 20
cache: pnpm
- name: 📦 Install Dependencies
if: ${{ inputs.install == 'true' }}
shell: bash
run: pnpm install ${{ inputs.installArgs }}
================================================
FILE: .github/dependabot.yml
================================================
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: npm
directory: /
schedule:
interval: 'monthly'
- package-ecosystem: 'github-actions'
directory: '/'
schedule:
interval: 'monthly'
================================================
FILE: .github/pull_request_template.md
================================================
### Overview
<!-- Describe your changes and why you made them -->
### Manual Testing
<!-- Describe how to test your changes to make sure the PR works as intended -->
### Related Issue
<!-- If this PR is related to an issue, please link it here -->
This PR closes #<issue_number>
================================================
FILE: .github/workflows/auto-label.yml
================================================
name: ✨ Auto-label PR
on:
pull_request_target:
types: [opened, synchronized, reopened]
jobs:
update-pr:
name: Update PR
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- name: Gather Info
id: check
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
with:
script: |
const { data: pr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.payload.pull_request.number
});
// Check if PR has assignees
const hasAssignees = pr.assignees && pr.assignees.length > 0;
core.setOutput('has_assignees', hasAssignees);
core.setOutput('author', pr.user.login);
// Get list of changed files
const { data: files } = await github.rest.pulls.listFiles({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.payload.pull_request.number
});
// Find all packages that were modified
const packagesRegex = /^packages\/([^\/]+)\//;
const affectedPackages = new Set();
for (const file of files) {
const match = file.filename.match(packagesRegex);
if (match) {
affectedPackages.add(match[1]);
}
}
const labels = Array.from(affectedPackages).map(pkg => `pkg/${pkg}`);
core.setOutput('labels', JSON.stringify(labels));
console.log('Detected package labels:', labels);
// Get current labels on the PR that match pkg/* pattern
const currentPkgLabels = pr.labels
.map(label => label.name)
.filter(name => name.startsWith('pkg/'));
core.setOutput('current_pkg_labels', JSON.stringify(currentPkgLabels));
console.log('Current pkg labels:', currentPkgLabels);
- name: Sync Author
if: steps.check.outputs.has_assignees == 'false'
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
with:
script: |
await github.rest.issues.addAssignees({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
assignees: ['${{ steps.check.outputs.author }}']
});
console.log('Assigned PR author: ${{ steps.check.outputs.author }}');
- name: Sync Labels
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
with:
script: |
const newLabels = ${{ steps.check.outputs.labels }};
const currentLabels = ${{ steps.check.outputs.current_pkg_labels }};
// Find labels to add (in newLabels but not in currentLabels)
const labelsToAdd = newLabels.filter(label => !currentLabels.includes(label));
// Find labels to remove (in currentLabels but not in newLabels)
const labelsToRemove = currentLabels.filter(label => !newLabels.includes(label));
// Add new labels
if (labelsToAdd.length > 0) {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
labels: labelsToAdd
});
console.log('Added labels:', labelsToAdd);
}
// Remove obsolete labels
for (const label of labelsToRemove) {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
name: label
});
console.log('Removed label:', label);
}
if (labelsToAdd.length === 0 && labelsToRemove.length === 0) {
console.log('No label changes needed');
}
================================================
FILE: .github/workflows/notify-unreleased-commits.yml
================================================
name: 🔔 Notify Unreleased Commits
on:
workflow_dispatch:
schedule:
- cron: '0 20 * * 1' # Weekly at 8 PM UTC (3 PM CT)
jobs:
notify:
runs-on: ubuntu-22.04
if: github.repository_owner == 'wxt-dev'
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- name: List Commits
id: list-commits
run: |
./scripts/list-unreleased-commits.sh > summary.txt
- name: Discord notification
run: |
PAYLOAD=$(jq -n --arg content "${{ env.MESSAGE }}" '{"content": $content}')
curl -X POST \
-F "payload_json=${PAYLOAD}" \
-F "file1=@summary.txt" \
$DISCORD_WEBHOOK
env:
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK_UNRELEASED_COMMITS }}
MESSAGE: |
If a package needs released, please [run the workflow](<https://github.com/wxt-dev/wxt/actions/workflows/release.yml>).
Before running, consider:
- Are there any breaking changes? If so, prepare a list of breaking changes and update the changelog and release notes after the release.
- Are there any PRs open that we wait to release after they're merged?
================================================
FILE: .github/workflows/pkg.pr.new.yml
================================================
name: ✨ pkg.pr.new
on:
push:
branches:
- main
pull_request:
branches:
- main
permissions:
contents: read
jobs:
build:
name: Publish Test Packages
runs-on: ubuntu-22.04
if: ${{ github.repository == 'wxt-dev/wxt' }}
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup
uses: ./.github/actions/setup
- name: Build All Packages
run: pnpm buildc all
- name: Publish
run: pnpx pkg-pr-new publish --compact --pnpm './packages/*'
================================================
FILE: .github/workflows/pr-closed.yml
================================================
name: 🎉 PR closed
on:
pull_request_target:
types:
- closed
permissions:
contents: read
pull-requests: write
jobs:
thank-you:
runs-on: ubuntu-latest
if: github.event.pull_request.merged == true
steps:
- name: Post Thank You Comment
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
env:
comment: Thanks for helping make WXT better!
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: process.env.comment
})
================================================
FILE: .github/workflows/pr-title.yml
================================================
name: 🛡️ Check PR Title
on:
pull_request:
types: [opened, edited]
jobs:
lint-pr-title:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
# Only fetch the config file from the repository
sparse-checkout-cone-mode: false
sparse-checkout: .commitlintrc.yml
- name: Install dependencies
run: npm install --global @commitlint/config-conventional commitlint
- name: Check PR title with commitlint
env:
PR_TITLE: ${{ github.event.pull_request.title }}
HELP_URL: https://github.com/wxt-dev/wxt/blob/main/CONTRIBUTING.md#conventional-pr-titles
run: echo "$PR_TITLE" | npx commitlint --help-url $HELP_URL
================================================
FILE: .github/workflows/publish-docs.yml
================================================
name: 📝 Publish Docs
on:
push:
branches:
- main
workflow_dispatch:
inputs:
tag:
description: Docker Image Tag
required: true
default: latest
permissions:
contents: read
jobs:
publish:
# Only run if it's the upstream repository, not forks
if: github.repository == 'wxt-dev/wxt'
name: Publish Docs
runs-on: ubuntu-22.04
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup
uses: ./.github/actions/setup
- name: Login to Docker Registry
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with:
registry: https://${{ secrets.DOCKER_REGISTRY_HOSTNAME }}
username: ${{ secrets.DOCKER_REGISTRY_USERNAME }}
password: ${{ secrets.DOCKER_REGISTRY_PASSWORD }}
- name: Build docs
run: |
pnpm docs:build
docker build docs/.vitepress -t ${{ secrets.DOCKER_REGISTRY_HOSTNAME }}/wxt/docs:${{ github.event.inputs.tag || 'latest' }}
- name: Push Image
run: docker push ${{ secrets.DOCKER_REGISTRY_HOSTNAME }}/wxt/docs:${{ github.event.inputs.tag || 'latest' }}
- name: Deploy
run: curl -X POST -i ${{ secrets.UPDATE_DOCS_WEBHOOK }}
================================================
FILE: .github/workflows/release.yml
================================================
name: 🚀 Release
on:
workflow_dispatch:
inputs:
package:
description: Package to release
default: wxt
type: choice
options:
- analytics
- auto-icons
- i18n
- is-background
- module-react
- module-solid
- module-svelte
- module-vue
- runner
- storage
- unocss
- webextension-polyfill
- wxt
permissions:
contents: read
jobs:
validate:
name: Validate
uses: './.github/workflows/validate.yml'
secrets: inherit
publish:
name: Publish
runs-on: ubuntu-24.04
permissions:
contents: write # Push version changes
id-token: write # OIDC for NPM publishing
needs:
- validate
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
ssh-key: ${{ secrets.DEPLOY_KEY }} # https://github.com/sbellone/release-workflow-example
- name: Setup
uses: ./.github/actions/setup
- name: Configure Git
run: |
git config user.name 'github-actions[bot]'
git config user.email 'github-actions[bot]@users.noreply.github.com'
git config --global push.followTags true
- name: Bump and Tag
run: |
pnpm tsx scripts/bump-package-version.ts ${{ inputs.package }}
git push
git push --tags
- name: Publish to NPM
working-directory: packages/${{ inputs.package }}
run: |
pnpm pack
sudo npm i -g npm@latest
/usr/local/bin/npm publish *.tgz
- name: Create GitHub release
run: pnpm tsx scripts/create-github-release.ts ${{ inputs.package }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
================================================
FILE: .github/workflows/sync-releases.yml
================================================
name: 🔄 Sync Releases
on:
workflow_dispatch:
inputs:
package:
description: Package to sync
default: wxt
type: choice
options:
- analytics
- auto-icons
- i18n
- is-background
- module-react
- module-solid
- module-svelte
- module-vue
- runner
- storage
- webextension-polyfill
- wxt
permissions:
contents: read
jobs:
sync:
name: Sync Releases
runs-on: ubuntu-22.04
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup
uses: ./.github/actions/setup
with:
installArgs: --ignore-scripts
- name: Sync Releases
run: pnpm tsx scripts/sync-releases.ts ${{ inputs.package }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
================================================
FILE: .github/workflows/update-browser-package.yml
================================================
name: 🔄 Update @wxt-dev/browser
on:
workflow_dispatch:
schedule:
- cron: '0 0 * * *' # Every day at midnight
permissions:
contents: read
jobs:
sync:
name: 'Sync with @types/chrome'
runs-on: ubuntu-latest
if: github.repository_owner == 'wxt-dev'
permissions:
contents: write # Push version changes
id-token: write # OIDC for NPM publishing
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ssh-key: ${{ secrets.DEPLOY_KEY }}
- name: Setup
uses: ./.github/actions/setup
with:
installArgs: --ignore-scripts
- name: Generate Latest Code
working-directory: packages/browser
run: pnpm gen
- name: Run Checks
working-directory: packages/browser
run: pnpm check
- name: Commit Changes
id: commit
uses: stefanzweifel/git-auto-commit-action@04702edda442b2e678b25b537cec683a1493fcb9 # v7.1.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
commit_message: 'fix: Upgrade `@wxt-dev/browser` to latest `@types/chrome` version'
- name: Publish to NPM
if: steps.commit.outputs.changes_detected == 'true'
working-directory: packages/browser
run: |
pnpm pack
sudo npm i -g npm@latest
/usr/local/bin/npm publish *.tgz
================================================
FILE: .github/workflows/validate.yml
================================================
name: 🛡️ Validate
on:
workflow_call:
pull_request:
push:
branches:
- main
permissions:
contents: read
jobs:
checks:
name: Checks
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup
uses: ./.github/actions/setup
- name: Basic Checks
run: pnpm check
builds:
name: Builds
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup
uses: ./.github/actions/setup
- name: Build All Packages
run: pnpm buildc all
build-demo:
name: Build Demo
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup
uses: ./.github/actions/setup
- name: Build
run: pnpm build:all
working-directory: packages/wxt-demo
- name: ZIP
run: pnpm wxt zip
working-directory: packages/wxt-demo
tests:
name: Tests (${{ matrix.title }})
runs-on: ${{ matrix.os }}
strategy:
matrix:
include:
- title: 'Linux'
os: ubuntu-22.04
coverage: true
- title: 'Windows'
os: windows-latest
coverage: false
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup
uses: ./.github/actions/setup
- name: Setup Bun
uses: oven-sh/setup-bun@3d267786b128fe76c2f16a390aa2448b815359f3 # v2.1.2
- name: Run Tests
if: ${{ ! matrix.coverage }}
run: pnpm test
- name: Run Tests (Coverage)
if: matrix.coverage
run: pnpm test:coverage --reporter=default --reporter=hanging-process
- name: Upload Coverage
if: matrix.coverage
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
template:
name: Template
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
template:
- react
- solid
- svelte
- vanilla
- vue
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup
uses: ./.github/actions/setup
- name: Pack WXT package
run: pnpm pack
working-directory: packages/wxt
- name: Install Dependencies
run: npm i
working-directory: templates/${{ matrix.template }}
- name: Install Packed WXT
run: npm i -D ../../packages/wxt/wxt-*.tgz
working-directory: templates/${{ matrix.template }}
- name: Type Check Template
run: pnpm compile
if: matrix.template != 'svelte'
working-directory: templates/${{ matrix.template }}
- name: Type Check Template
run: pnpm check
if: matrix.template == 'svelte'
working-directory: templates/${{ matrix.template }}
- name: Build Template
run: pnpm build
working-directory: templates/${{ matrix.template }}
================================================
FILE: .github/workflows/vhs.yml
================================================
name: 📼 VHS
on:
push:
paths:
- 'docs/tapes/*.tape'
workflow_dispatch:
permissions:
contents: read
jobs:
vhs:
name: Create VHS
runs-on: macos-latest
if: ${{ github.repository == 'wxt-dev/wxt' }}
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ github.ref_name }}
- name: Setup
uses: ./.github/actions/setup
with:
install: false
- name: Setup Go
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00
with:
go-version: '1.25.1'
# This prevents pnpm dlx from downloading WXT in the video
- name: Pre-install WXT
run: |
pnpm store add wxt@latest
pnpm dlx wxt@latest --version
- name: Record VHS
run: |
brew install ttyd ffmpeg
go install github.com/charmbracelet/vhs@517bcda0faf416728bcf6b7fe489eb0e2469d9b5 # v0.10.0
vhs docs/tapes/init-demo.tape
- name: Save recorded GIF
uses: stefanzweifel/git-auto-commit-action@04702edda442b2e678b25b537cec683a1493fcb9 # v7.1.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
commit_message: 'docs: Update `wxt init` GIF'
commit_user_name: github-actions[bot]
commit_user_email: github-actions[bot]@users.noreply.github.com
commit_author: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
# https://github.com/charmbracelet/vhs#output
file_pattern: 'docs/assets/*.gif'
================================================
FILE: .gitignore
================================================
.DS_Store
.env
.env.*
.idea
.output
.webextrc
.wxt
.wxt-runner
*.log
/docs/.vitepress/cache
docs/.vitepress/.temp
coverage
dist
node_modules
TODOs.md
web-ext.config.js
web-ext.config.ts
templates/*/pnpm-lock.yaml
templates/*/yarn.lock
templates/*/package-lock.json
docs/api/reference
stats.html
.tool-versions
.cache
*-stats.txt
================================================
FILE: .markdownlint.json
================================================
{
"$schema": "https://raw.githubusercontent.com/DavidAnson/markdownlint/refs/heads/main/schema/markdownlint-config-schema.json",
"line-length": false,
"no-inline-html": false,
"first-line-heading": false
}
================================================
FILE: .markdownlintignore
================================================
node_modules
.git
.output
dist
# Generated files
packages/wxt/README.md
packages/*/CHANGELOG.md
docs/api
================================================
FILE: .prettierignore
================================================
.output
coverage
dist
.wxt
docs/.vitepress/cache
pnpm-lock.yaml
CHANGELOG.md
packages/browser/src/gen
================================================
FILE: .prettierrc.yml
================================================
singleQuote: true
endOfLine: lf
plugins:
- prettier-plugin-jsdoc
================================================
FILE: .vscode/extensions.json
================================================
{
"recommendations": [
"davidanson.vscode-markdownlint",
"esbenp.prettier-vscode",
"github.vscode-github-actions"
]
}
================================================
FILE: .vscode/settings.json
================================================
{
// Set default formatter
"editor.defaultFormatter": "esbenp.prettier-vscode",
"[json]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
"[yaml]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
"[typescript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
"[markdown]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
// Additional guidelines for Copilot
"github.copilot.chat.codeGeneration.instructions": [
{ "file": "CONTRIBUTING.md" }
],
"oxc.enable": true
}
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
- Demonstrating empathy and kindness toward other people
- Being respectful of differing opinions, viewpoints, and experiences
- Giving and gracefully accepting constructive feedback
- Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
- Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
- The use of sexualized language or imagery, and sexual attention or
advances of any kind
- Trolling, insulting or derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or email
address, without their explicit permission
- Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
<aaronklinker1@gmail.com>.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
<https://www.contributor-covenant.org/version/2/0/code_of_conduct.html>.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
<https://www.contributor-covenant.org/faq>. Translations are available at
<https://www.contributor-covenant.org/translations>.
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing
Everyone is welcome to contribute to **WXT**!
If you are changing the docs or fixing a bug, feel free to fork and open a PR.
If you want to add a new feature, please create an issue or discussion first so we can decide if the feature is inline with the vision for WXT.
## WXT's Vision
WXT is two things:
1. A build tool
2. A set of runtime utilities
The long term goal of WXT is provide an opinionated build tool that keeps WXT projects standard, while providing light-weight runtime utils that simplify a lot of the boilerplate/overhead when setting up a new extension.
I also want to provide a way for developers to use either one of those two things independently, and not require them to use both. This is why all of WXT's runtime utils are shipped as their own NPM packages, most of them not bundled inside the core `wxt` package. If you just want to use the packages, they're availalbe, and if you just want to use WXT's built tool, you don't have to import any of WXT's utilities, you can use your own.
> The few runtime utils shipped inside WXT are things that should be used by 90% of extensions. That said, they're also legacy utils left in from before I started creating separate NPM packages, and in the future, they may be removed from the core package.
## Conventional Commits
This project uses [Conventional Commit format](https://www.conventionalcommits.org/en/v1.0.0/) to automatically generate a changelog and better understand the changes in the project
Here are some examples of conventional commit messages:
- `feat: add new functionality`
- `fix: correct typos in code`
- `ci: add GitHub Actions for automated testing`
## Conventional PR Titles
The title of your pull request should follow the [conventional commit format](#conventional-commits). When a pull request is merged to the main branch, all changes are going to be squashed into a single commit. The message of this commit will be the title of the pull request. And for every release, the commit messages are used to generate the changelog.
## Breaking Changes Policy
A quick word on WXT's breaking changes policy. I am willing to make breaking changes, but they have to be for a good enough reason - they have to make WXT better as a whole, they can't be based on one opinion.
Breaking changes also require a major release. Major releases have happened once or twice a year, so after you merge your PR, you'll have to wait a little bit before it is released.
To make a breaking change:
1. Make sure you're PR is targeting the `major` branch
2. Add `!` after the conventional commit type (`fix!: ...`, `feat!: ...`, `chore!: ...`, etc) to indicate that it is a breaking change
3. At the top of the PR, provide documentation that will inform developers about the breaking change, why it was done, and how to migrate their extension so nothing breaks.
- This documentation will be put ["Upgrading WXT"](https://wxt.dev/guide/resources/upgrading.html) page in the docs, read through previous breaking change docs for an idea of what is required.
## Setup
WXT uses `pnpm`, so make sure you have it installed.
```sh
corepack enable
```
Then, simply run the install command:
```sh
pnpm i
```
## Development
Here are some helpful commands:
```sh
# Build WXT package
cd packages/wxt
pnpm build
```
```sh
# Build WXT package, then build demo extension
cd packages/wxt-demo
pnpm build
```
```sh
# Build WXT package, then start the demo extension in dev mode
cd packages/wxt-demo
pnpm dev
```
```sh
# Run unit and E2E tests
pnpm test
```
```sh
# Start the docs website locally
pnpm docs:dev
```
## Profiling
```sh
# Build the latest version
pnpm --filter wxt build
# CD to the demo directory
cd packages/wxt-demo
# 1. Generate a flamechart with 0x
pnpm dlx 0x node_modules/wxt/bin/wxt.mjs build
# 2. Inspect the process with chrome @ chrome://inspect
pnpm node --inspect node_modules/wxt/bin/wxt.mjs build
```
## Updating Docs
Documentation is written with VitePress, and is located in the `docs/` directory.
The API reference is generated from JSDoc comments in the source code. If there's a typo or change you want to make in there, you'll need to update the source code instead of a file in the `docs/` directory.
## Testing
WXT has unit and E2E tests. When making a change or adding a feature, make sure to update the tests or add new ones, if they exist.
> If they don't exist, feel free to create them, but that's a lot for a one-time contributor. A maintainer might add them to your PR though.
To run tests for a specific file, add the filename at the end of the test command:
```sh
pnpm test manifest-contents
```
All test (unit and E2E) for all packages are ran together via [Vitest workspaces](https://vitest.dev/guide/#workspaces-support).
If you want to manually test a change, you can modify the demo project for your test, but please don't leave those changes committed once you open a PR.
## Templates
Each directory inside `templates/` is it's own standalone project. Simply `cd` into the directory you're updating, install dependencies with `npm` (NOT `pnpm`), and run the relevant commands
```sh
cd templates/vue
npm i
npm run dev
npm run build
```
Note that templates are hardcoded to a specific version of `wxt` from NPM, they do not use the local version. PR checks will test your PR's changes against the templates, but if you want to manually do it, update the package.json dependency:
```diff
"devDependencies": {
"typescript": "^5.3.2",
"vite-plugin-solid": "^2.7.0",
- "wxt": "^0.8.0"
+ "wxt": "../.."
}
```
Then run `npm i` again.
### Adding Templates
To add a template, copy the vanilla template and give it a new name.
```sh
cp -r templates/vanilla templates/<new-template-name>
```
That's it. Once your template is merged, it will be available inside `wxt init` immediately. You don't need to release a new version of WXT to release a new template.
## Upgrading Dependencies
WXT has custom rules around what dependencies can be upgraded. Use the `scripts/upgrade-deps.ts` script to upgrade dependencies and follow these rules.
```sh
pnpm tsx scripts/upgrade-deps.ts
```
To see all the options, run:
```sh
pnpm tsx scripts/upgrade-deps.ts --help
```
## Install Unreleased Versions
This repo uses <https://pkg.pr.new> to publish versions of all it's packages for almost every commit. You can install them via:
```sh
npm i https://pkg.pr.new/[package-name]@[ref]
```
Or use one of the shorthands:
```sh
# Install the latest build of `wxt` from a PR:
npm i https://pkg.pr.new/wxt@1283
# Install the latest build of `@wxt-dev/module-react` on the `main` branch
npm i https://pkg.pr.new/@wxt-dev/module-react@main
# Install `@wxt-dev/storage` from a specific commit:
npm i https://pkg.pr.new/@wxt-dev/module-react@426f907
```
## Blog Posts
Anyone is welcome to submit a blog post on <https://wxt.dev/blog>!
> [!NOTE]
> Before starting on a blog post, please message Aaron on Discord or start a discussion on GitHub to get permission to write about a topic, but most topics are welcome: Major version updates, tutorials, etc.
- **English only**: Blog posts should be written in English. Unfortunately, our maintainers don't have the bandwidth right now to translate our docs, let alone blog posts. Sorry 😓
- **AI**: Please only use AI to translate or proof-read your blog post. Don't generate the whole thing... We don't want to publish that.
## Become a Maintainer
If you're interested in becoming a maintainer, send an email to Aaron at <aaronklinker1@gmail.com> with your github username saying you're interested. The process is very informal, I will add you quickly if you've contributed code or answered questions and helped out the community!
Maintainers don't have to just write code - they can manage issues, answer questsions, review PRs, organize and prioritize work - there's lots of ways for you to help out.
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2023 Aaron
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: MAINTAINERS.md
================================================
# Maintainers
A couple of things for you to consider before merging a PR or giving the go-ahead on a feature proposal.
## Be picky about new features and packages
We are responsible for maintaining them and fixing related bugs after the PR is merged. The community can always release their own WXT modules or packages, not everything needs to be built into WXT.
## Prefer standards over customization
Don't merge PRs that just add another way to do something, like [this one](https://github.com/wxt-dev/wxt/pull/2053#issuecomment-3857010196).
WXT is opinionated, if you have questions about what is WXT's opinion or we need to create a new one, create an issue and @ me to discuss.
## PRs should be small and targeted
A PR should make one change. They should not make any unrelated changes outside of accomplishing the one thing. This makes PRs easier to review and they get merged more quickly - a win-win for everyone.
## `@wxt-dev/*` packages are separate
We can't make changes to these packages assuming people are using them only with WXT. For example, I almost missed [this PR](https://github.com/wxt-dev/wxt/pull/2049#issuecomment-3861251599).
I want these packages to be usable on their own so if people don't like WXT's build tool, they can still use our other awesome packages.
## Minimize dependencies
I don't like how heavy lots of frameworks are. It's unavoidable to a certain extent, but if you can do something without another dependency, try to.
If you need a dependency, look for one with zero dependencies and that's respectable.
## Look at milestones
I've organized WXT's long term plans into [milestones](https://github.com/wxt-dev/wxt/milestones), check those out to get an idea of my priorities for some of the larger features.
## Require tests
If someone opens a PR to fix a bug but doesn't include tests, don't merge the PR. Tests are required to prevent regressions and maintain a codebase long term.
## Ask for reproductions for bugs
You don't need to triage bugs if someone doesn't give you enough information. You can always ask for a repo with a reproduction or wait for more details.
If there's not an easy way to reproduce a bug, you're wasting your time triaging it. Just be mindful of your own time!
Here's an example of how to ask for a reproduction: <https://github.com/wxt-dev/wxt/issues/2064#issuecomment-3862579110>. You could be more blunt than this.
## Add yourself as a code owner
If you want to be responsible for a specific package or directory, add yourself to the [`.github/CODEOWNERS`](https://github.com/wxt-dev/wxt/blob/main/.github/CODEOWNERS) file to get added as a reviewer to PRs automatically. You can also add yourself to the default list to be added as a reviewer on all PRs.
## Releasing Package Updates
Releases are done with GitHub actions:
- Use the [Release workflow](https://github.com/wxt-dev/wxt/actions/workflows/release.yml) to release a single package in the monorepo. This automatically detects the version change with conventional commits, builds and uploads the package to NPM, and creates a GitHub release.
- Use the [Sync Releases workflow](https://github.com/wxt-dev/wxt/actions/workflows/sync-releases.yml) to sync the GitHub releases with changes to the changelog. To change a release, update the `CHANGELOG.md` file and run the workflow. It will sync the releases of a single package in the monorepo.
## Creating New Packages
Example PR: <https://github.com/wxt-dev/wxt/pull/2152>
1. Create the package.
2. Update CI workflow inputs.
3. Add docs page and version for "Other Packages" dropdown.
4. Merge the PR.
5. Tag the commit (look at other tags for pattern):
```sh
git tag <dir-name>-v<version>
git push --tags
```
6. Publish the package to NPM:
```sh
cd packages/<dir-name>
pnpm publish --access public
```
7. Create a basic release on GitHub mentioning the new package is available.
A couple of things to note:
- pkg.pr.new will fail on the original PR. It's fine to ignore and merge your PR as long as it fails due to your new package not being published to NPM yet.
- The regular release workflow DOES NOT WORK for new packages. You have to have at least one `<dir-name>-v<version>` tag created before you can run that workflow for your new package.
- You don't need to create a CHANGELOG.md file for the package, it will be created automatically after future changes are released via the normal release workflow.
================================================
FILE: README.md
================================================
<div align="center">
# <img align="top" width="44" src="https://raw.githubusercontent.com/wxt-dev/wxt/HEAD/docs/public/hero-logo.svg" alt="WXT Logo"> WXT
[](https://www.npmjs.com/package/wxt)
[](https://www.npmjs.com/package/wxt)
[](https://github.com/wxt-dev/wxt/blob/main/LICENSE)
[](https://codecov.io/github/wxt-dev/wxt)
Next-gen framework for developing web extensions.<br/>⚡<br/><q><i>It's like Nuxt, but for Web Extensions</i></q>
[Get Started](https://wxt.dev/guide/installation.html) •
[Configuration](https://wxt.dev/api/config.html) •
[Examples](https://wxt.dev/examples.html) •
[Changelog](https://github.com/wxt-dev/wxt/blob/main/packages/wxt/CHANGELOG.md) •
[Discord](https://discord.gg/ZFsZqGery9)
</div>

## Demo
<https://github.com/wxt-dev/wxt/assets/10101283/4d678939-1bdb-495c-9c36-3aa281d84c94>
## Quick Start
Bootstrap a new project:
```sh
# npm
npx wxt@latest init
# pnpm
pnpm dlx wxt@latest init
# bun
bunx wxt@latest init
```
Or see the [installation guide](https://wxt.dev/guide/installation.html) to get started with WXT.
## Features
- 🌐 Supports all browsers
- ✅ Supports both MV2 and MV3
- ⚡ Dev mode with HMR & fast reload
- 📂 File based entrypoints
- 🚔 TypeScript
- 🦾 Auto-imports
- 🤖 Automated publishing
- 🎨 Frontend framework agnostic: works with Vue, React, Svelte, etc
- 📦 [Module system](https://wxt.dev/guide/essentials/wxt-modules.html#overview) for reusing code between extensions
- 🖍️ Quickly bootstrap a new project
- 📏 Bundle analysis
- ⬇️ Download and bundle remote URL imports
## Sponsors
WXT is a [MIT-licensed](https://github.com/wxt-dev/wxt/blob/main/LICENSE) open source project with its ongoing development made possible entirely by the support of these awesome backers. If you'd like to join them, please consider [sponsoring WXT's development](https://github.com/sponsors/wxt-dev).
[](https://github.com/sponsors/wxt-dev)
## Contributors
Published under the [MIT](https://github.com/wxt-dev/wxt/blob/main/LICENSE) license.
Made by [@aklinker1](https://github.com/aklinker1) and [community](https://github.com/wxt-dev/wxt/graphs/contributors) 💛
[](https://github.com/wxt-dev/wxt/graphs/contributors)
================================================
FILE: SECURITY.md
================================================
# Security Policy
While WXT is in prerelease, only the latest version will receive security updates. The latest version is:
<img alt="npm version" src="https://img.shields.io/npm/v/wxt?labelColor=black&color=%234fa048">
## Reporting a Vulnerability
If you discover a security vulnerability, please email me at <aaronklinker1@gmail.com>. I will respond within a few days to acknowledge receipt of your report.
If the vulnerability is accepted, I will open a public issue to track the fix. If the vulnerability is not accepted, no further action will be taken.
================================================
FILE: docs/.vitepress/Dockerfile
================================================
FROM lipanski/docker-static-website:latest
COPY dist .
================================================
FILE: docs/.vitepress/components/BlogHome.vue
================================================
<script lang="ts" setup>
import { computed } from 'vue';
// @ts-expect-error: Vitepress data-loader magic, this import is correct
import { data } from '../loaders/blog.data';
import BlogPostPreview from './BlogPostPreview.vue';
const posts = computed(() =>
data
.map((post) => ({
...post,
...post.frontmatter,
date: new Date(post.frontmatter.date),
}))
.sort((a, b) => b.date.getTime() - a.date.getTime()),
);
</script>
<template>
<div class="container">
<div>
<div class="vp-doc">
<h1>Blog</h1>
</div>
<ul>
<BlogPostPreview v-for="post of posts" :key="post.url" :post />
</ul>
</div>
</div>
</template>
<style scoped>
.container {
display: flex;
flex-direction: column;
align-items: center;
}
.container > div {
padding: 32px;
max-width: 900px;
width: 100%;
min-width: 0;
}
h1 {
padding-bottom: 16px;
}
ul {
display: flex;
flex-direction: column;
list-style: none;
}
ul,
li {
padding: 0;
margin: 0;
}
ul li {
padding-top: 16px;
margin-top: 16px;
border-top: 1px solid var(--vp-c-default);
}
ul li:last-child {
padding-bottom: 16px;
margin-bottom: 16px;
border-bottom: 1px solid var(--vp-c-default);
}
</style>
================================================
FILE: docs/.vitepress/components/BlogLayout.vue
================================================
<script lang="ts" setup>
import useBlogDate from '../composables/useBlogDate';
import { useData } from 'vitepress';
const { frontmatter } = useData();
const date = useBlogDate(() => frontmatter.value.date);
</script>
<template>
<div class="vp-doc">
<main class="container-content">
<h1 v-html="$frontmatter.title" />
<p class="meta-row">
<a
class="author"
v-for="author of $frontmatter.authors"
:key="author.github"
:href="`https://github.com/${author.github}`"
>
<img :src="`https://github.com/${author.github}.png?size=96`" />
<span>{{ author.name }}</span>
</a>
<span>•</span>
<span>{{ date }}</span>
</p>
<Content />
</main>
</div>
</template>
<style scoped>
vp-doc {
display: flex;
}
main {
max-width: 1080px;
padding: 32px;
margin: auto;
}
@media (min-width: 768px) {
main {
padding: 64px;
}
}
.meta-row {
display: flex;
color: var(--vp-c-text-2);
gap: 16px;
overflow: hidden;
padding-bottom: 32px;
}
.meta-row > * {
flex-shrink: 0;
}
.author {
display: flex;
gap: 8px;
align-items: center;
color: var(--vp-c-text-2);
font-weight: normal;
text-decoration: none;
}
.author img {
width: 24px;
height: 24px;
border-radius: 100%;
}
.author span {
padding: 0;
margin: 0;
}
.author:hover {
text-decoration: underline;
color: var(--vp-c-text-2);
}
</style>
================================================
FILE: docs/.vitepress/components/BlogPostPreview.vue
================================================
<script lang="ts" setup>
import useBlogDate from '../composables/useBlogDate';
const props = defineProps<{
post: {
title: string;
description?: string;
date: Date;
url: string;
authors: Array<{ name: string; github: string }>;
};
}>();
const date = useBlogDate(() => props.post.date);
</script>
<template>
<li class="blog-list-item">
<a :href="post.url">
<div class="vp-doc">
<h3 class="title" v-html="post.title" />
<p class="description" v-html="post.description" />
<p class="meta">
{{ post.authors.map((author) => author.name).join(', ') }}
•
{{ date }}
</p>
</div>
</a>
</li>
</template>
<style scoped>
li {
padding: 0;
margin: 0;
}
p {
margin: 0;
}
h3 {
margin: 0;
padding: 0;
border: none;
}
li > a > div {
display: flex;
flex-direction: column;
margin: 0 -16px;
padding: 16px;
border-radius: 16px;
}
li > a > div:hover {
background: var(--vp-c-default);
}
li .title {
color: var(--vp-c-text);
margin-bottom: 12px;
}
li .description {
font-size: 16px;
color: var(--vp-c-text-2);
margin-bottom: 8px;
}
li .meta {
font-weight: 400;
font-size: 12px;
color: var(--vp-c-text-2);
}
</style>
================================================
FILE: docs/.vitepress/components/EntrypointPatterns.vue
================================================
<script lang="ts" setup>
const props = defineProps<{
patterns: Array<[intput: string, output: string]>;
}>();
</script>
<template>
<table class="no-vertical-dividers">
<thead>
<tr>
<th style="width: 100%">Filename</th>
<th></th>
<th>Output Path</th>
</tr>
</thead>
<tbody>
<tr v-for="pattern of patterns">
<td style="white-space: nowrap; padding-right: 8px">
<code>entrypoints/{{ pattern[0] }}</code>
</td>
<td style="padding: 6px; opacity: 50%">
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
viewBox="0 0 24 24"
>
<path
fill="currentColor"
d="M4 11v2h12l-5.5 5.5l1.42 1.42L19.84 12l-7.92-7.92L10.5 5.5L16 11H4Z"
/>
</svg>
</td>
<td style="white-space: nowrap; padding-left: 8px">
<code>/{{ pattern[1] }}</code>
</td>
</tr>
</tbody>
</table>
</template>
================================================
FILE: docs/.vitepress/components/ExampleSearch.vue
================================================
<script lang="ts" setup>
import { ref, onMounted, computed, toRaw, Ref } from 'vue';
import ExampleSearchFilterByItem from './ExampleSearchFilterByItem.vue';
import ExampleSearchResult from './ExampleSearchResult.vue';
import { ExamplesMetadata, KeySelectedObject } from '../utils/types';
const props = defineProps<{
tag?: string;
}>();
const exampleMetadata = ref<ExamplesMetadata>();
onMounted(async () => {
const res = await fetch(
'https://raw.githubusercontent.com/wxt-dev/examples/main/metadata.json',
);
exampleMetadata.value = await res.json();
});
const searchText = ref('');
const selectedApis = ref<KeySelectedObject>({});
const selectedPermissions = ref<KeySelectedObject>({});
const selectedPackages = ref<KeySelectedObject>({});
function useRequiredItems(selectedItems: Ref<KeySelectedObject>) {
return computed(() =>
Array.from(
Object.entries(toRaw(selectedItems.value)).reduce(
(set, [pkg, checked]) => {
if (checked) set.add(pkg);
return set;
},
new Set<string>(),
),
),
);
}
const requiredApis = useRequiredItems(selectedApis);
const requiredPermissions = useRequiredItems(selectedPermissions);
const requiredPackages = useRequiredItems(selectedPackages);
function doesExampleMatchSelected(
exampleItems: string[],
requiredItems: Ref<string[]>,
) {
const exampleItemsSet = new Set(exampleItems);
return !requiredItems.value.find((item) => !exampleItemsSet.has(item));
}
const filteredExamples = computed(() => {
const text = searchText.value.toLowerCase();
return exampleMetadata.value.examples.filter((example) => {
const matchesText = example.searchText.toLowerCase().includes(text);
const matchesApis = doesExampleMatchSelected(example.apis, requiredApis);
const matchesPermissions = doesExampleMatchSelected(
example.permissions,
requiredPermissions,
);
const matchesPackages = doesExampleMatchSelected(
example.packages,
requiredPackages,
);
return matchesText && matchesApis && matchesPermissions && matchesPackages;
});
});
</script>
<template>
<div class="example-layout">
<div class="search">
<input v-model="searchText" placeholder="Search for an example..." />
</div>
<div class="filters">
<ExampleSearchFilterByItem
label="APIs"
:items="exampleMetadata?.allApis"
v-model="selectedApis"
/>
<ExampleSearchFilterByItem
label="Permissions"
:items="exampleMetadata?.allPermissions"
v-model="selectedPermissions"
/>
<ExampleSearchFilterByItem
label="Packages"
:items="exampleMetadata?.allPackages"
v-model="selectedPackages"
/>
</div>
<div class="results">
<p v-if="exampleMetadata == null">Loading examples...</p>
<template v-else>
<ul class="search-results">
<ExampleSearchResult
v-for="example of filteredExamples"
:key="example.name"
:example
/>
</ul>
<p v-if="filteredExamples.length === 0">No matching examples</p>
</template>
</div>
</div>
</template>
<style scoped>
.example-layout {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 1fr;
grid-template-areas:
'search'
'results';
gap: 16px;
}
@media only screen and (min-width: 720px) {
.example-layout {
grid-template-columns: 256px 1fr;
grid-template-rows: auto 1fr;
grid-template-areas:
'filters search'
'filters results';
}
}
.search {
grid-area: search;
background: var(--vp-c-bg-soft);
padding: 20px;
width: 100%;
display: flex;
border-radius: 16px;
}
.filters {
display: none;
grid-area: filters;
}
@media only screen and (min-width: 720px) {
.filters {
display: flex;
flex-direction: column;
gap: 2px;
border-radius: 16px;
overflow: hidden;
align-self: flex-start;
}
}
.results {
grid-area: results;
}
.box {
border-radius: 16px;
overflow: hidden;
}
.search input {
min-width: 0;
flex: 1;
font-size: 16px;
}
.checkbox-col {
flex: 1;
padding: 16px;
display: flex;
flex-direction: column;
overflow-y: auto;
max-height: 200px;
font-size: 14px;
gap: 4px;
}
.filter-btn {
color: var(--vp-c-brand-1);
}
.checkbox-col .header {
font-size: 12px;
font-weight: bold;
opacity: 50%;
}
.checkbox-col p {
display: flex;
gap: 4px;
align-items: flex-start;
text-wrap: wrap;
overflow-wrap: anywhere;
line-height: 140%;
}
span {
padding-top: 1px;
}
.checkbox-col input[type='checkbox'] {
width: 16px;
height: 16px;
flex-shrink: 0;
}
.checkbox-col-container {
display: flex;
}
.search-results {
display: grid;
grid-template-columns: repeat(1, 1fr);
gap: 16px;
}
@media only screen and (min-width: 800px) {
.search-results {
grid-template-columns: repeat(2, 1fr);
}
}
@media only screen and (min-width: 1024px) {
.search-results {
grid-template-columns: repeat(3, 1fr);
}
}
a {
background-color: red;
}
</style>
================================================
FILE: docs/.vitepress/components/ExampleSearchFilterByItem.vue
================================================
<script lang="ts" setup>
import { computed, toRaw } from 'vue';
import { KeySelectedObject } from '../utils/types';
const props = defineProps<{
label: string;
items?: string[];
}>();
const selectedItems = defineModel<KeySelectedObject>({
required: true,
});
const count = computed(() => {
return Object.values(toRaw(selectedItems.value)).filter(Boolean).length;
});
function toggleItem(pkg: string) {
selectedItems.value = {
...toRaw(selectedItems.value),
[pkg]: !selectedItems.value[pkg],
};
}
</script>
<template>
<div class="filter-container">
<p class="header">
<span>Filter by {{ label }}</span> <span v-if="count">({{ count }})</span>
</p>
<div class="scroll-container">
<ul>
<li v-for="item in items">
<label :title="item">
<input
type="checkbox"
:checked="selectedItems[item]"
@input="toggleItem(item)"
/>
<span>{{ item }}</span>
</label>
</li>
</ul>
</div>
</div>
</template>
<style scoped>
.filter-container {
height: 300px;
display: flex;
flex-direction: column;
background: var(--vp-c-bg-soft);
}
.scroll-container {
flex: 1;
overflow: hidden;
position: relative;
}
.scroll-container ul {
position: absolute;
overflow-y: auto;
left: 0;
top: 0;
right: 0;
bottom: 0;
display: flex;
flex-direction: column;
gap: 4px;
font-size: small;
padding: 8px 16px 16px 16px;
}
.header {
padding: 8px 16px;
font-size: 12px;
font-weight: bold;
opacity: 50%;
}
label {
display: flex;
gap: 4px;
align-items: flex-start;
text-wrap: wrap;
overflow-wrap: anywhere;
line-height: 140%;
cursor: pointer;
text-wrap: nowrap;
}
span {
padding-top: 1px;
}
input[type='checkbox'] {
width: 16px;
height: 16px;
flex-shrink: 0;
}
</style>
================================================
FILE: docs/.vitepress/components/ExampleSearchResult.vue
================================================
<script lang="ts" setup>
import { Example } from '../utils/types';
const props = defineProps<{
example: Example;
}>();
</script>
<template>
<li>
<a :href="example.url" target="_blank">
<p class="name">{{ example.name }}</p>
<p class="description">{{ example.description }}</p>
<p class="link">Open →</p>
</a>
</li>
</template>
<style scoped>
* {
min-width: 0;
}
a {
padding: 16px;
display: flex;
flex-direction: column;
border: 2px solid var(--vp-c-bg-soft);
border-radius: 16px;
color: var(--vp-c-text-1) !important;
gap: 8px;
}
a:hover {
outline: 2px solid var(--vp-c-brand-2);
}
.name {
font-size: 16px;
font-weight: 500;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
flex-shrink: 0;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.description {
height: 53px;
opacity: 70%;
font-size: 14px;
font-weight: normal;
line-height: 120%;
min-height: 0;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
.link {
opacity: 0;
transition: 250ms;
color: var(--vp-c-brand-2);
font-weight: bold;
text-align: right;
}
a:hover .link {
opacity: 100%;
}
</style>
================================================
FILE: docs/.vitepress/components/Icon.vue
================================================
<script lang="ts" setup>
import { computed } from 'vue';
const props = defineProps<{
name: string;
icon?: string;
}>();
const src = computed(() => {
if (props.icon) return props.icon;
return `https://raw.githubusercontent.com/PKief/vscode-material-icon-theme/main/icons/${props.name.toLowerCase()}.svg`;
});
</script>
<template>
<img :src="src" :alt="`${name} Logo`" />
</template>
<style scoped>
img {
display: inline;
transform: translateY(5px);
margin-right: 8px;
width: 20px;
}
</style>
================================================
FILE: docs/.vitepress/components/UsingWxtSection.vue
================================================
<script lang="ts" setup>
import { computed } from 'vue';
import useListExtensionDetails, {
ChromeExtension,
} from '../composables/useListExtensionDetails';
// Add extension IDs to end of the list. On the website, extensions will be sorted by a combination of weekly active users and rating.
// Change the commit message or PR title to: "docs: Added "[extension name]" to the homepage"
const chromeExtensionIds = [
'ocfdgncpifmegplaglcnglhioflaimkd', // GitHub: Better Line Counts
'mgmdkjcljneegjfajchedjpdhbadklcf', // Anime Skip Player
'bfbnagnphiehemkdgmmficmjfddgfhpl', // UltraWideo
'elfaihghhjjoknimpccccmkioofjjfkf', // StayFree - Website Blocker & Web Analytics
'okifoaikfmpfcamplcfjkpdnhfodpkil', // Doozy: Ai Made Easy
'lknmjhcajhfbbglglccadlfdjbaiifig', // tl;dv - Record, Transcribe & ChatGPT for Google Meet
'oglffgiaiekgeicdgkdlnlkhliajdlja', // Youtube中文配音
'agjnjboanicjcpenljmaaigopkgdnihi', // PreMiD
'aiakblgmlabokilgljkglggnpflljdgp', // Markdown Sticky Notes
'nomnkbngkijpffepcgbbofhcnafpkiep', // DocVersionRedirector
'ceicccfeikoipigeghddpocceifjelph', // Plex Skipper
'aelkipgppclpfimeamgmlonimflbhlgf', // GitHub Custom Notifier
'djnlaiohfaaifbibleebjggkghlmcpcj', // Fluent Read
'nhclljcpfmmaiojbhhnkpjcfmacfcian', // Facebook Video Controls
'mblkhbaakhbhiimkbcnmeciblfhmafna', // ElemSnap - Quick capture of webpage elements and conversion to images,
'oajalfneblkfiejoadecnmodfpnaeblh', // MS Edge TTS (Text to Speech)
'nedcanggplmbbgmlpcjiafgjcpdimpea', // YTBlock - Block any content from YouTube™
'oadbjpccljkplmhnjekgjamejnbadlne', // demo.fun - Interactive product demos that convert
'iopdafdcollfgaoffingmahpffckmjni', // SmartEReply: Elevate Your LinkedIn™ Engagement with AI 🚀📈
'khjdmjcmpolknpccmaaipmidphjokhdf', // WorkFlowy MultiFlow
'fencadnndhdeggodopebjgdfdlhcimfk', // 香草布丁🌿🍮- https://github.com/Xdy1579883916/vanilla-pudding
'bnacincmbaknlbegecpioobkfgejlojp', // MaxFocus: Link Preview
'bcpgdpedphodjcjlminjbdeejccjbimp', // 汇率转换-中文版本
'loeilaonggnalkaiiaepbegccilkmjjp', // Currency Converter Plus
'npcnninnjghigjfiecefheeibomjpkak', // Respond Easy
'cfkdcideecefncbglkhneoflfnmhoicc', // mindful - stay focused on your goals
'lnhejcpclabmbgpiiomjbhalblnnbffg', // 1Proompt
'fonflmjnjbkigocpoommgmhljdpljain', // NiceTab - https://github.com/web-dahuyou/NiceTab
'fcffekbnfcfdemeekijbbmgmkognnmkd', // Draftly for LinkedIn
'nkndldfehcidpejfkokbeghpnlbppdmo', // YouTube Summarized - Summarize any YouTube video
'dbichmdlbjdeplpkhcejgkakobjbjalc', // 社媒助手 - https://github.com/iszhouhua/social-media-copilot
'opepfpjeogkbgeigkbepobceinnfmjdd', // Dofollow Links for SEO
'pdnenlnelpdomajfejgapbdpmjkfpjkp', // ChatGPT Writer: Use AI on Any Site (GPT-4o, Claude, Gemini, and More)
'jobnhifpphkgoelnhnopgkdhbdkiadmj', // discord message translator
'ncokhechhpjgjonhjnlaneglmdkfkcbj', // Habit Tracker app widget for daily habit tracking
'lnjaiaapbakfhlbjenjkhffcdpoompki', // Catppuccin for GitHub File Explorer Icons
'cpaedhbidlpnbdfegakhiamfpndhjpgf', // WebChat: Chat with anyone on any website
'fcphghnknhkimeagdglkljinmpbagone', // YouTube Auto HD + FPS
'lpomjgbicdemjkgmbnkjncgdebogkhlb', // MultiViewer Companion
'ggiafipgeeaaahnjamgpjcgkdpanhddg', // Sync Watch - Watch videos together on any site
'nmldnjcblcihmegipecakhmnieiofmgl', // Keyword Rank Checker
'gppllamhaciichleihemgilcpledblpn', // YouTube Simple View - Hide distractions & more
'pccbghdfdnnkkbcdcibchpbffdgednkf', // Propbar - Property Data Enhancer
'lfknakglefggmdkjdfhhofkjnnolffkh', // Text Search Pro - Search by case and whole-word match!
'mbenhbocjckkbaojacmaepiameldglij', // Invoice Generator
'phlfhkmdofajnbhgmbmjkbkdgppgoppb', // Monthly Bill Tracker
'macmkmchfoclhpbncclinhjflmdkaoom', // Wandpen - Instantly improve your writing with AI
'lhmgechokhmdekdpgkkemoeecelcaonm', // YouTube Hider - Remove Comments By Keywords, Usernames & Tools
'imgheieooppmahcgniieddodaliodeeg', // QA Compass - Record standardized bug reports easily
'npgghjedpchajflknnbngajkjkdhncdo', // aesthetic Notion, styled
'hmdcmlfkchdmnmnmheododdhjedfccka', // Eye Dropper
'eihpmapodnppeemkhkbhikmggfojdkjd', // Cursorful - Screen Recorder with Auto Zoom
'hjjkgbibknbahijglkffklflidncplkn', // Show IP – Live View of Website IPs for Developers
'ilbikcehnpkmldojkcmlldkoelofnbde', // Strong Password Generator
'ocllfkhcdopiafndigclebelbecaiocp', // ZenGram: Mindful Instagram, Your Way
'odffpjnpocjfcaclnenaaaddghkgijdb', // Blync: Preview Links, Selection Search, AI Assistant
'kofbbilhmnkcmibjbioafflgmpkbnmme', // HTML to Markdown - Convert webpages to markdown
'boecmgggeigllcdocgioijmleimjbfkg', // Walmart WFS Profit Calculator
'dlnjcbkmomenmieechnmgglgcljhoepd', // Youtube Live Chat Fullscreen
'keiealdacakpnbbljlmhfgcebmaadieg', // Python Code Runner
'hafcajcllbjnoolpfngclfmmgpikdhlm', // Monochromate
'bmoggiinmnodjphdjnmpcnlleamkfedj', // AliasVault - Open-Source Password & (Email) Alias Manager
'hlnhhamckimoaiekbglafiebkfimhapb', // SnapThePrice: AI-Powered Real-time Lowest Price Finder
'gdjampjdgjmbifnhldgcnccdjkcoicmg', // radiofrance - news & broadcasts (French), music (international)
'jlnhphlghikichhgbnkepenehbmloenb', // Blens - Time Tracker and AI Insight
'njnammmpdodmfkodnfpammnpdcbhnlcm', // Always Light Mode - Setting website always in light mode
'lblmfclcfniabobmamfkdogcgdagbhhb', // DesignPicker - Color Picker & Font Detector
'pamnlaoeobcmhkliljfaofekeddpmfoh', // Web to PDF
'jmbcbeepjfenihlocplnbmbhimcoooka', // Online CSV Viewer
'nkjcoophmpcmmgadnljnlpbpfdfacgbo', // YouTube Video Transcript
'lcaieahkjgeggeiihblhcjbbjlppgieh', // NetSuite Record Scripts
'gmocfknjllodfiomnljmaehcplnekhlo', // VueTracker
'ggcfemmoabhhelfkhknhbnkmeahloiod', // CanCopy - A web extension that allow you to copy any content from website
'modkelfkcfjpgbfmnbnllalkiogfofhb', // Language Learning with AI
'npfopljnjbamegincfjelhjhnonnjloo', // Bilibili Feed History Helper
'edkhpdceeinkcacjdgebjehipmnbomce', // NZBDonkey - The ultimate NZB file download tool
'cckggnbnimdbbpmdinkkgbbncopbloob', // WeChat Markdown Editor(微信 Markdown 编辑器)
'jcblcjolcojmfopefcighfmkkefbaofg', // Tab Grab
'eehmoikadcijkapfjocnhjclpbaindlb', // BrowserLens - https://browserlens.com/
'hfhellofkjebbchcdffmicekjdomkcmc', // Epic Games Library Extension
'gknigcbhlammoakmmdddkblknanpjiac', // Zen Analytics Pixel Tracker - zapt.web.app
'cnklededohhcbmjjdlbjdkkihkgoggol', // Crypto Pulse - Compose your newtab with nature images, widgets & realtime Crypto Price & Bitcoin RSS.
'miponnamafdenpgjemkknimgjfibicdc', // Youtube Video Scheduler
'nhmbcmalgpkjbomhlhgdicanmkkaajmg', // Chatslator: Livestream Chat Translator
'mbamjfdjbcdgpopfnkkmlohadbbnplhm', // 公众号阅读增强器 - https://wxreader.honwhy.wang
'hannhecbnjnnbbafffmogdlnajpcomek', // 토탐정
'ehboaofjncodknjkngdggmpdinhdoijp', // 2FAS Pass - https://2fas.com/
'hnjamiaoicaepbkhdoknhhcedjdocpkd', // Quick Prompt - https://github.com/wenyuanw/quick-prompt
'kacblhilkacgfnkjfodalohcnllcgmjd', // Add QR Code Generator Icon Back To Address Bar
'fkbdlogfdjmpfepbbbjcgcfbgbcfcnne', // Piwik PRO Tracking Helper
'nkbikckldmljjiiajklecmgmajgapbfl', // PIPX - Take Control of Picture-in-Picture, Automatically
'hgppdobcpkfkmiegekaglonjajeojmdd', // Browsely - AI-powered browser extension
'ehmoihnjgkdimihkhokkmfjdgomohjgm', // Filmbudd Pro - Simple, private – and synced ratings and watch notes across all your devices
'alglchohmdikgdjhafiicilegegieafa', // MultiField CopyCat - Copy, Paste & Autofill Web Forms Instantly
'aamihahiiogceidpbnfgehacgiecephe', // ChatSight - Add Table of Contents to ChatGPT
'cndibmoanboadcifjkjbdpjgfedanolh', // BetterCampus (prev. BetterCanvas)
'hinfimgacobnellbncbcpdlpaapcofaa', // Leetcode Fonts - Change fonts in leetcode effortlessly
'kbkbfefhhabpkibojinapkkgciiacggg', // TranslateManga - Manga Translator & Manga Tracker
'emeakbgdecgmdjgegnejpppcnkcnoaen', // SiteData - Free Website Traffic Checker & Reverse AdSense Tool
'gpnckbhgpnjciklpoehkmligeaebigaa', // Livestream Chat Reader - Text-to-Speech for YouTube/Twitch chat
'fjlalaedpfcojcfpkgkglbjjbbkofgnl', // ChatGPT Token Counter - Count tokens in real time on chatgpt conversation
'fbgblmjbeebanackldpbmpacppflgmlj', // LinuxDo Scripts - 为 linux.do 用户提供了一些增强功能
'dfacnjidgbagicaekenjgclfnhdnjjdi', // Zen Virtual Piano - https://zen-piano.web.app/
'naeibcegmgpofimedkmfgjgphfhfhlab', // Crypto Pulse price tracker - https://get-crypto-pulse.web.app/
'ffglckbhfbfmdkefdmjbhpnffkcmlhdh', // Redirect Web - Automatically redirect pages or open them in another app
'eglpfhbhmelampoihamjomgkeobgdofl', // Capture It - Capture & Edit Screenshots
'jmghclbfbbapimhbgnpffbimphlpolnm', // Teams Chat Exporter
'jdcppdokgfbnhiacbeplahgnciahnhck', // Lofi BGM Player - Free lofi focus music for work & study
'cgpmbiiagnehkikhcbnhiagfomajncpa', // Margin - Annotate and highlight any webpage, with your notes saved to the decentralized AT Protocol.
'mfjdonmgmgcijagclnkfhmjiblbfjaid', // KeyFloat - Floating multilingual keyboard with native key mappings, drag, dark mode, sounds, and dynamic layouts for macOS & Windows
'dhiekgdaipindoapjmcnpompdknjeijf', // Glossy New Tab - Say Goodbye to Boring Tabs with live wallpapers
'lapnciffpekdengooeolaienkeoilfeo', // All API Hub – AI Relay & New API Manager - https://github.com/qixing-jk/all-api-hub
'bhgobenflkkhfcgkikejaaejenoddcmo', // Scrape Similar - Extract data from websites into spreadsheets - https://github.com/zizzfizzix/scrape-similar
'kinlknncggaihnhdcalijdmpbhbflalm', // isTrust - https://github.com/Internet-Society-Belgium/isTrust/
'ojpakgiekphppgkcdihbjpafobhnhlkp', // Dymo
'pmgehhllikbjmadpenhabejhpemplhmd', // Extension Rank Checker - Extension Ranker
];
const { data, err, isLoading } = useListExtensionDetails(chromeExtensionIds);
const sortedExtensions = computed(() => {
if (!data.value?.length) return [];
return [...data.value]
.filter((item) => item != null)
.map((item) => ({
...item,
// Sort based on the user count weighted by the rating
sortKey: ((item.rating ?? 5) / 5) * item.weeklyActiveUsers,
}))
.filter((item) => !!item)
.sort((l, r) => r.sortKey - l.sortKey);
});
function getStoreUrl(extension: ChromeExtension) {
const url = new URL(extension.storeUrl);
url.searchParams.set('utm_source', 'wxt.dev');
return url.href;
}
</script>
<template>
<p v-if="isLoading" style="text-align: center; opacity: 50%">Loading...</p>
<p
v-else-if="err || sortedExtensions.length === 0"
style="text-align: center; opacity: 50%"
>
Failed to load extension details.
</p>
<ul v-else>
<li
v-for="extension of sortedExtensions"
:key="extension.id"
class="relative"
>
<img
:src="extension.iconUrl"
:alt="`${extension.name} icon`"
referrerpolicy="no-referrer"
/>
<div class="relative">
<a
:href="getStoreUrl(extension)"
target="_blank"
:title="extension.name"
class="extension-name"
>{{ extension.name }}</a
>
<p class="description" :title="extension.shortDescription">
{{ extension.shortDescription }}
</p>
</div>
<p class="user-count">
<span>{{ extension.weeklyActiveUsers.toLocaleString() }} users</span
><template v-if="extension.rating != null"
>,
<span>{{ extension.rating }} stars</span>
</template>
</p>
</li>
</ul>
<p class="centered pr">
<a
href="https://github.com/wxt-dev/wxt/edit/main/docs/.vitepress/components/UsingWxtSection.vue"
target="_blank"
>Open a PR</a
>
to add your extension to the list!
</p>
</template>
<style scoped>
li img {
width: 116px;
height: 116px;
padding: 16px;
border-radius: 8px;
background-color: var(--vp-c-default-soft);
}
ul {
display: grid;
grid-template-columns: repeat(1, 1fr);
align-items: stretch;
gap: 16px;
list-style: none;
margin: 16px 0;
padding: 0;
}
@media (min-width: 960px) {
ul {
grid-template-columns: repeat(2, 1fr);
}
}
li {
margin: 0 !important;
padding: 16px;
display: flex;
background-color: var(--vp-c-bg-soft);
border-radius: 12px;
flex: 1;
gap: 24px;
align-items: center;
}
.centered {
text-align: center;
}
li a,
li .user-count,
li .description {
padding: 0;
margin: 0;
}
li .user-count {
opacity: 70%;
font-size: small;
position: absolute;
bottom: 12px;
right: 16px;
}
li a {
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
overflow: hidden;
cursor: pointer;
padding: 0;
margin: 0;
text-decoration: none;
}
li a:hover {
text-decoration: underline;
}
li div {
flex: 1;
}
li .description {
opacity: 90%;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
margin-bottom: 16px;
}
li .extension-name {
font-size: large;
}
.pr {
opacity: 70%;
}
.relative {
position: relative;
}
</style>
================================================
FILE: docs/.vitepress/composables/useBlogDate.ts
================================================
import { computed, toValue, MaybeRefOrGetter } from 'vue';
const MONTH_FORMATTER = new Intl.DateTimeFormat(
globalThis?.navigator?.language,
{
month: 'long',
},
);
export default function (date: MaybeRefOrGetter<Date | string>) {
return computed(() => {
const d = new Date(toValue(date));
return `${MONTH_FORMATTER.format(d)} ${d.getDate()}, ${d.getFullYear()}`;
});
}
================================================
FILE: docs/.vitepress/composables/useListExtensionDetails.ts
================================================
import { ref } from 'vue';
export interface ChromeExtension {
id: string;
name: string;
iconUrl: string;
weeklyActiveUsers: number;
shortDescription: string;
storeUrl: string;
rating: number | undefined;
}
const operationName = 'WxtDocsUsedBy';
const query = `query ${operationName}($ids:[String!]!) {
chromeExtensions(ids: $ids) {
id
name
iconUrl
weeklyActiveUsers
shortDescription
storeUrl
rating
}
}`;
export default function (ids: string[]) {
const data = ref<ChromeExtension[]>();
const err = ref<unknown>();
const isLoading = ref(true);
fetch('https://queue.wxt.dev/api', {
method: 'POST',
body: JSON.stringify({
operationName,
query,
variables: { ids },
}),
headers: {
'Content-Type': 'application/json',
},
})
.then(async (res) => {
isLoading.value = false;
const {
data: { chromeExtensions },
} = await res.json();
data.value = chromeExtensions;
err.value = undefined;
})
.catch((error) => {
isLoading.value = false;
console.error(error);
data.value = undefined;
err.value = error;
});
return {
data,
err,
isLoading,
};
}
================================================
FILE: docs/.vitepress/config.ts
================================================
import { DefaultTheme, defineConfig } from 'vitepress';
import typedocSidebar from '../api/reference/typedoc-sidebar.json';
import {
menuGroup,
menuItem,
menuRoot,
navItem,
prepareTypedocSidebar,
} from './utils/menus';
import { meta, script } from './utils/head';
import footnote from 'markdown-it-footnote';
import { version as wxtVersion } from '../../packages/wxt/package.json';
import { version as i18nVersion } from '../../packages/i18n/package.json';
import { version as autoIconsVersion } from '../../packages/auto-icons/package.json';
import { version as unocssVersion } from '../../packages/unocss/package.json';
import { version as storageVersion } from '../../packages/storage/package.json';
import { version as analyticsVersion } from '../../packages/analytics/package.json';
import { version as runnerVersion } from '../../packages/runner/package.json';
import { version as isBackgroundVersion } from '../../packages/is-background/package.json';
import addKnowledge from 'vitepress-knowledge';
import {
groupIconMdPlugin,
groupIconVitePlugin,
localIconLoader,
} from 'vitepress-plugin-group-icons';
import { Feed } from 'feed';
import { writeFile } from 'node:fs/promises';
import { join } from 'node:path';
import llmstxt from 'vitepress-plugin-llms';
const origin = 'https://wxt.dev';
const title = 'Next-gen Web Extension Framework';
const titleSuffix = ' – WXT';
const description =
"WXT provides the best developer experience, making it quick, easy, and fun to develop web extensions. With built-in utilities for building, zipping, and publishing your extension, it's easy to get started.";
const ogTitle = `${title}${titleSuffix}`;
const ogUrl = origin;
const ogImage = `${origin}/social-preview.png`;
const otherPackages = {
analytics: analyticsVersion,
'auto-icons': autoIconsVersion,
i18n: i18nVersion,
storage: storageVersion,
unocss: unocssVersion,
runner: runnerVersion,
'is-background': isBackgroundVersion,
};
const knowledge = addKnowledge<DefaultTheme.Config>({
serverUrl: 'https://knowledge.wxt.dev',
paths: {
'/': 'docs',
'/api/': 'api-reference',
'/blog/': 'blog',
},
layoutSelectors: {
blog: '.container-content',
},
pageSelectors: {
'examples.md': '#VPContent > .VPPage',
'blog.md': '#VPContent > .VPPage',
},
});
// https://vitepress.dev/reference/site-config
export default defineConfig({
extends: knowledge,
titleTemplate: `:title${titleSuffix}`,
title: 'WXT',
description,
vite: {
clearScreen: false,
plugins: [
llmstxt(),
groupIconVitePlugin({
customIcon: {
'wxt.config.ts': localIconLoader(
import.meta.url,
'../public/logo.svg',
),
},
}),
],
},
lastUpdated: true,
sitemap: {
hostname: origin,
},
async buildEnd(site) {
// @ts-expect-error: knowledge.buildEnd is not typed, but it exists.
await knowledge.buildEnd(site);
// Only construct the RSS document for production builds
const { default: blogDataLoader } = await import('./loaders/blog.data');
const posts = await blogDataLoader.load();
const feed = new Feed({
copyright: 'MIT',
id: 'wxt',
title: 'WXT Blog',
link: `${origin}/blog`,
});
posts.forEach((post) => {
feed.addItem({
date: post.frontmatter.date,
link: new URL(post.url, origin).href,
title: post.frontmatter.title,
description: post.frontmatter.description,
});
});
// console.log('rss.xml:');
// console.log(feed.rss2());
await writeFile(join(site.outDir, 'rss.xml'), feed.rss2(), 'utf8');
},
head: [
meta('og:type', 'website'),
meta('og:title', ogTitle),
meta('og:image', ogImage),
meta('og:url', ogUrl),
meta('og:description', description),
meta('twitter:card', 'summary_large_image', { useName: true }),
script('https://umami.aklinker1.io/script.js', {
'data-website-id': 'c1840c18-a12c-4a45-a848-55ae85ef7915',
async: '',
}),
],
markdown: {
config: (md) => {
md.use(footnote);
md.use(groupIconMdPlugin);
},
languageAlias: {
mjs: 'js',
},
},
themeConfig: {
// https://vitepress.dev/reference/default-theme-config
logo: {
src: '/logo.svg',
alt: 'WXT logo',
},
footer: {
message: [
'<a class="light-netlify" href="https://www.netlify.com"> <img src="https://www.netlify.com/v3/img/components/netlify-color-bg.svg" alt="Deploys by Netlify" style="display: inline;" /></a>',
'<a class="dark-netlify" href="https://www.netlify.com"> <img src="https://www.netlify.com/v3/img/components/netlify-color-accent.svg" alt="Deploys by Netlify" style="display: inline;" /></a>',
'Released under the <a href="https://github.com/wxt-dev/wxt/blob/main/LICENSE">MIT License</a>.',
].join('<br/>'),
copyright:
'Copyright © 2023-present <a href="https://github.com/aklinker1">Aaron Klinker</a>',
},
editLink: {
pattern: 'https://github.com/wxt-dev/wxt/edit/main/docs/:path',
},
search: {
provider: 'local',
},
socialLinks: [
{ icon: 'discord', link: 'https://discord.gg/ZFsZqGery9' },
{ icon: 'github', link: 'https://github.com/wxt-dev/wxt' },
],
nav: [
navItem('Guide', '/guide/installation'),
navItem('Examples', '/examples'),
navItem('API', '/api/reference/wxt'),
navItem('Blog', '/blog'),
navItem(`v${wxtVersion}`, [
navItem('wxt', [
navItem(`v${wxtVersion}`, '/'),
navItem(
`Changelog`,
'https://github.com/wxt-dev/wxt/blob/main/packages/wxt/CHANGELOG.md',
),
]),
navItem(
'Other Packages',
Object.entries(otherPackages).map(([name, version]) =>
navItem(`@wxt-dev/${name} — ${version}`, `/${name}`),
),
),
]),
],
sidebar: {
'/guide/': menuRoot([
menuGroup('Get Started', '/guide/', [
menuItem('Introduction', 'introduction.md'),
menuItem('Installation', 'installation.md'),
]),
menuGroup('Essentials', '/guide/essentials/', [
menuItem('Project Structure', 'project-structure.md'),
menuItem('Entrypoints', 'entrypoints.md'),
menuGroup(
'Configuration',
'/guide/essentials/config/',
[
menuItem('Manifest', 'manifest.md'),
menuItem('Browser Startup', 'browser-startup.md'),
menuItem('Auto-imports', 'auto-imports.md'),
menuItem('Environment Variables', 'environment-variables.md'),
menuItem('Runtime Config', 'runtime.md'),
menuItem('Vite', 'vite.md'),
menuItem('Build Mode', 'build-mode.md'),
menuItem('TypeScript', 'typescript.md'),
menuItem('Hooks', 'hooks.md'),
menuItem('Entrypoint Loaders', 'entrypoint-loaders.md'),
],
true,
),
menuItem('Extension APIs', 'extension-apis.md'),
menuItem('Assets', 'assets.md'),
menuItem('Target Different Browsers', 'target-different-browsers.md'),
menuItem('Content Scripts', 'content-scripts.md'),
menuItem('Storage', 'storage.md'),
menuItem('Messaging', 'messaging.md'),
menuItem('I18n', 'i18n.md'),
menuItem('Scripting', 'scripting.md'),
menuItem('WXT Modules', 'wxt-modules.md'),
menuItem('Frontend Frameworks', 'frontend-frameworks.md'),
menuItem('ES Modules', 'es-modules.md'),
menuItem('Remote Code', 'remote-code.md'),
menuItem('Unit Testing', 'unit-testing.md'),
menuItem('E2E Testing', 'e2e-testing.md'),
menuItem('Publishing', 'publishing.md'),
menuItem('Testing Updates', 'testing-updates.md'),
]),
menuGroup('Resources', '/guide/resources/', [
menuItem('Compare', 'compare.md'),
menuItem('FAQ', 'faq.md'),
menuItem('Community', 'community.md'),
menuItem('Upgrading WXT', 'upgrading.md'),
menuItem('Migrate to WXT', 'migrate.md'),
menuItem('How WXT Works', 'how-wxt-works.md'),
]),
]),
'/api/': menuRoot([
menuGroup(
'CLI Reference',
'/api/cli/',
[
menuItem('wxt', 'wxt.md'),
menuItem('wxt build', 'wxt-build.md'),
menuItem('wxt zip', 'wxt-zip.md'),
menuItem('wxt prepare', 'wxt-prepare.md'),
menuItem('wxt clean', 'wxt-clean.md'),
menuItem('wxt init', 'wxt-init.md'),
menuItem('wxt submit', 'wxt-submit.md'),
menuItem('wxt submit init', 'wxt-submit-init.md'),
],
true,
),
menuGroup('API Reference', prepareTypedocSidebar(typedocSidebar), true),
]),
},
},
});
================================================
FILE: docs/.vitepress/loaders/blog.data.ts
================================================
import { createContentLoader } from 'vitepress';
export default createContentLoader('blog/*.md');
================================================
FILE: docs/.vitepress/loaders/cli.data.ts
================================================
import { resolve } from 'node:path';
import consola from 'consola';
import spawn from 'nano-spawn';
const cliDir = resolve('packages/wxt/src/cli/commands');
const cliDirGlob = resolve(cliDir, '**');
export default {
watch: [cliDirGlob],
async load() {
consola.info(`Generating CLI docs`);
const [wxt, build, zip, prepare, clean, init, submit, submitInit] =
await Promise.all([
getWxtHelp(''),
getWxtHelp('build'),
getWxtHelp('zip'),
getWxtHelp('prepare'),
getWxtHelp('clean'),
getWxtHelp('init'),
getPublishExtensionHelp(''),
getPublishExtensionHelp('init'),
]);
consola.success(`Generated CLI docs`);
return {
wxt,
build,
zip,
prepare,
clean,
init,
submit,
submitInit,
};
},
};
async function getHelp(command: string): Promise<string> {
const args = command.split(' ');
const res = await spawn(args[0], [...args.slice(1), '--help'], {
cwd: 'packages/wxt',
});
return res.stdout;
}
function getWxtHelp(command: string): Promise<string> {
return getHelp(`pnpm -s wxt ${command}`.trim());
}
async function getPublishExtensionHelp(command: string): Promise<string> {
const res = await getHelp(
`./node_modules/.bin/publish-extension ${command}`.trim(),
);
return res.replace(/\$ publish-extension/g, '$ wxt submit');
}
export interface Command {
name: string;
docs: string;
}
================================================
FILE: docs/.vitepress/theme/custom.css
================================================
/* Colors */
:root {
--wxt-c-green-1: #0b8a00;
--wxt-c-green-2: #096600;
--wxt-c-green-3: #096600;
--wxt-c-green-soft: rgba(11, 138, 0, 0.14);
}
.dark {
--wxt-c-green-1: #67d45e;
--wxt-c-green-2: #329929;
--wxt-c-green-3: #21651b;
--wxt-c-green-soft: rgba(103, 212, 94, 0.14);
}
/* https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css */
:root {
--vp-c-brand-1: var(--wxt-c-green-1);
--vp-c-brand-2: var(--wxt-c-green-2);
--vp-c-brand-3: var(--wxt-c-green-3);
--vp-c-brand-soft: var(--wxt-c-green-soft);
}
/* Customize Individual Components */
.vp-doc .no-vertical-dividers th,
.vp-doc .no-vertical-dividers td {
border: none;
}
.vp-doc .no-vertical-dividers tr {
border: 1px solid var(--vp-c-divider);
}
body {
overflow-y: scroll;
}
.VPSidebar {
user-select: none;
}
.VPSidebarItem .badge {
display: inline-block;
min-width: 1.6em;
padding: 0.3em 0.4em 0.2em;
border-radius: 1rem;
font-size: 0.75em;
line-height: 1;
margin-left: 0.5rem;
text-align: center;
vertical-align: middle;
background-color: var(--vp-c-default-2);
}
.light-netlify {
display: inline;
}
.dark .light-netlify {
display: none;
}
.dark-netlify {
display: none;
}
.dark .dark-netlify {
display: inline;
}
================================================
FILE: docs/.vitepress/theme/index.ts
================================================
import DefaultTheme from 'vitepress/theme';
import Icon from '../components/Icon.vue';
import EntrypointPatterns from '../components/EntrypointPatterns.vue';
import UsingWxtSection from '../components/UsingWxtSection.vue';
import ExampleSearch from '../components/ExampleSearch.vue';
import BlogLayout from '../components/BlogLayout.vue';
import './custom.css';
import 'virtual:group-icons.css';
export default {
extends: DefaultTheme,
enhanceApp(ctx) {
ctx.app
.component('Icon', Icon)
.component('EntrypointPatterns', EntrypointPatterns)
.component('UsingWxtSection', UsingWxtSection)
.component('ExampleSearch', ExampleSearch)
.component('blog', BlogLayout);
},
};
================================================
FILE: docs/.vitepress/utils/head.ts
================================================
import { HeadConfig } from 'vitepress/types/shared';
export function meta(
property: string,
content: string,
options?: { useName: boolean },
): HeadConfig {
return [
'meta',
{
[options?.useName ? 'name' : 'property']: property,
content,
},
];
}
export function script(
src: string,
props: Record<string, string> = {},
): HeadConfig {
return [
'script',
{
...props,
src,
},
];
}
================================================
FILE: docs/.vitepress/utils/menus.ts
================================================
import { DefaultTheme } from 'vitepress';
type SidebarItem = DefaultTheme.SidebarItem;
type NavItem = DefaultTheme.NavItem;
type NavItemWithLink = DefaultTheme.NavItemWithLink;
type NavItemWithChildren = DefaultTheme.NavItemWithChildren;
type NavItemChildren = DefaultTheme.NavItemChildren;
export function navItem(text: string): NavItemChildren;
export function navItem(text: string, link: string): NavItemChildren;
export function navItem(text: string, items: any[]): NavItemWithChildren;
export function navItem(text: string, arg2?: unknown): any {
if (typeof arg2 === 'string') {
return { text, link: arg2 };
} else if (Array.isArray(arg2)) {
return { text, items: arg2 };
}
return { text };
}
export function menuRoot(items: SidebarItem[]) {
return items.map((item, index) => {
// item.collapsed = false; // uncomment to expand all level-0 items
return item;
});
}
export function menuGroup(
text: string,
items: SidebarItem[],
collapsible?: boolean,
): SidebarItem;
export function menuGroup(
text: string,
base: string,
items: SidebarItem[],
collapsible?: boolean,
): SidebarItem;
export function menuGroup(
text: string,
a: string | SidebarItem[],
b?: SidebarItem[] | boolean,
c?: boolean,
): SidebarItem {
if (typeof a === 'string' && Array.isArray(b)) {
return {
text,
base: a,
items: b,
collapsed: c,
};
}
if (typeof a !== 'string' && !Array.isArray(b))
return {
text,
items: a,
collapsed: b,
};
throw Error('Unknown overload');
}
export function menuItems(items: SidebarItem[]) {
return {
items,
};
}
export function menuItem(
text: string,
link: string,
items?: SidebarItem[],
): SidebarItem {
if (items) {
return { text, link, items };
}
return { text, link };
}
/** Clean up and add badges to typedoc leaf sections */
export function prepareTypedocSidebar(items: SidebarItem[]) {
// skip contents file
const filtered = items.slice(1);
// remove Typedoc's collapse: true from text nodes
const prepareItems = (items: DefaultTheme.SidebarItem[], depth = 0) => {
for (const item of items) {
if (item.items) {
prepareItems(item.items, depth + 1);
const hasLeaves = item.items.some((item) => !item.items);
if (hasLeaves) {
item.text += ` <span class="badge">${item.items.length}</span>`;
}
} else {
delete item.collapsed;
}
}
};
// process
prepareItems(filtered);
// return
return filtered;
}
================================================
FILE: docs/.vitepress/utils/types.ts
================================================
export interface Example {
name: string;
description?: string;
url: string;
searchText: string;
apis: string[];
permissions: string[];
packages: string[];
}
export type ExamplesMetadata = {
examples: Example[];
allApis: string[];
allPermissions: string[];
allPackages: string[];
};
export type KeySelectedObject = Record<string, boolean | undefined>;
================================================
FILE: docs/analytics.md
================================================
<!--@include: ../packages/analytics/README.md-->
================================================
FILE: docs/api/cli/wxt-build.md
================================================
# `wxt build`
<script setup>
import { data } from '../../.vitepress/loaders/cli.data.ts'
</script>
<div class="language-sh vp-adaptive-theme active"><pre class="shiki shiki-themes github-light github-dark vp-code"><code>{{ data.build }}</code></pre></div>
================================================
FILE: docs/api/cli/wxt-clean.md
================================================
# `wxt clean`
<script setup>
import { data } from '../../.vitepress/loaders/cli.data.ts'
</script>
<div class="language-sh vp-adaptive-theme active"><pre class="shiki shiki-themes github-light github-dark vp-code"><code>{{ data.clean }}</code></pre></div>
================================================
FILE: docs/api/cli/wxt-init.md
================================================
# `wxt init`
<script setup>
import { data } from '../../.vitepress/loaders/cli.data.ts'
</script>
<div class="language-sh vp-adaptive-theme active"><pre class="shiki shiki-themes github-light github-dark vp-code"><code>{{ data.init }}</code></pre></div>
================================================
FILE: docs/api/cli/wxt-prepare.md
================================================
# `wxt prepare`
<script setup>
import { data } from '../../.vitepress/loaders/cli.data.ts'
</script>
<div class="language-sh vp-adaptive-theme active"><pre class="shiki shiki-themes github-light github-dark vp-code"><code>{{ data.prepare }}</code></pre></div>
================================================
FILE: docs/api/cli/wxt-submit-init.md
================================================
# `wxt submit init`
> Alias for [`publish-browser-extension`](https://www.npmjs.com/package/publish-browser-extension)
<script setup>
import { data } from '../../.vitepress/loaders/cli.data.ts'
</script>
<div class="language-sh vp-adaptive-theme active"><pre class="shiki shiki-themes github-light github-dark vp-code"><code>{{ data.submitInit }}</code></pre></div>
================================================
FILE: docs/api/cli/wxt-submit.md
================================================
# `wxt submit`
> Alias for [`publish-browser-extension`](https://www.npmjs.com/package/publish-browser-extension)
<script setup>
import { data } from '../../.vitepress/loaders/cli.data.ts'
</script>
<div class="language-sh vp-adaptive-theme active"><pre class="shiki shiki-themes github-light github-dark vp-code"><code>{{ data.submit }}</code></pre></div>
================================================
FILE: docs/api/cli/wxt-zip.md
================================================
# `wxt zip`
<script setup>
import { data } from '../../.vitepress/loaders/cli.data.ts'
</script>
<div class="language-sh vp-adaptive-theme active"><pre class="shiki shiki-themes github-light github-dark vp-code"><code>{{ data.zip }}</code></pre></div>
================================================
FILE: docs/api/cli/wxt.md
================================================
# `wxt`
<script setup>
import { data } from '../../.vitepress/loaders/cli.data.ts'
</script>
<div class="language-sh vp-adaptive-theme active"><pre class="shiki shiki-themes github-light github-dark vp-code"><code>{{ data.wxt }}</code></pre></div>
================================================
FILE: docs/auto-icons.md
================================================
<!--@include: ../packages/auto-icons/README.md-->
================================================
FILE: docs/blog/.drafts/2024-10-19-real-world-messaging.md
================================================
---
layout: blog
title: Real World Messaging
description: |
The extension messaging APIs are difficult to learn. Let's go beyond the simple examples from Chrome and Firefox's documentation to build our own simple messaging system from scratch.
authors:
- name: Aaron Klinker
github: aklinker1
date: 2024-10-20T04:54:23.601Z
---
Test content **bold** _italic_
================================================
FILE: docs/blog/2024-12-06-using-imports-module.md
================================================
---
layout: blog
title: Introducing <code>#imports</code>
description: Learn how WXT's new <code>#imports</code> module works and how to use it.
authors:
- name: Aaron Klinker
github: aklinker1
date: 2024-12-06T14:39:00.000Z
---
WXT v0.20 introduced a new way of manually importing its APIs: **the `#imports` module**. This module was introduced to simplify import statements and provide more visibility into all the APIs WXT provides.
<!-- prettier-ignore -->
```ts
import { browser } from 'wxt/browser'; // [!code --]
import { createShadowRootUi } from 'wxt/utils/content-script-ui/shadow-root'; // [!code --]
import { defineContentScript } from 'wxt/utils/define-content-script'; // [!code --]
import { injectScript } from 'wxt/utils/inject-script'; // [!code --]
import { // [!code ++]
browser, createShadowRootUi, defineContentScript, injectScript // [!code ++]
} from '#imports'; // [!code ++]
```
The `#imports` module is considered a "virtual module", because the file doesn't actually exist. At build-time, imports are split into individual statements for each API:
:::code-group
```ts [What you write]
import { defineContentScript, injectScript } from '#imports';
```
```ts [What the bundler sees]
import { defineContentScript } from 'wxt/utils/define-content-script';
import { injectScript } from 'wxt/utils/inject-script';
```
:::
Think of `#imports` as a convenient way to access all of WXT's APIs from one place, without impacting performance or bundle size.
This enables better tree-shaking compared to v0.19 and below.
:::tip Need to lookup the full import path of an API?
Open up your project's `.wxt/types/imports-module.d.ts` file.
:::
## Mocking
When writing tests, you might need to mock APIs from the `#imports` module. While mocking these APIs is very easy, it may not be immediately clear how to accomplish it.
Let's look at an example using Vitest. When [configured with `wxt/testing`](/guide/essentials/unit-testing#vitest), Vitest sees the same transformed code as the bundler. That means to mock an API from `#imports`, you need to call `vi.mock` with the real import path, not `#imports`:
```ts
import { injectScript } from '#imports';
import { vi } from 'vitest';
vi.mock('wxt/utils/inject-script')
const injectScriptMock = vi.mocked(injectScript);
injectScriptMock.mockReturnValueOnce(...);
```
## Conclusion
You don't have to use `#imports` if you don't like - you can continue importing APIs from their submodules. However, using `#imports` is the recommended approach moving forwards.
- As more APIs are added, you won't have to memorize additional import paths.
- If breaking changes are made to import paths in future major versions, `#imports` won't break.
Happy Coding 😄
> P.S. Yes, this is exactly how [Nuxt's `#imports`](https://nuxt.com/docs/guide/concepts/auto-imports#explicit-imports) works! We use the exact same library, [`unimport`](https://github.com/unjs/unimport).
---
[Discuss this blog post on Github](https://github.com/wxt-dev/wxt/discussions/1543).
================================================
FILE: docs/blog.md
================================================
---
layout: page
---
<script lang="ts" setup>
import BlogHome from './.vitepress/components/BlogHome.vue';
</script>
<BlogHome />
================================================
FILE: docs/examples.md
================================================
---
layout: page
---
<style>
.examples-container {
padding: 32px;
}
</style>
<div class="examples-container">
<div class="vp-doc">
<h1>Examples</h1>
</div>
<br />
<ExampleSearch />
</div>
================================================
FILE: docs/guide/essentials/assets.md
================================================
# Assets
## `/assets` Directory
Any assets imported or referenced inside the `<srcDir>/assets/` directory will be processed by WXT's bundler.
Here's how you access them:
:::code-group
```ts [JS]
import imageUrl from '~/assets/image.png';
const img = document.createElement('img');
img.src = imageUrl;
```
```html [HTML]
<!-- In HTML tags, you must use the relative path --->
<img src="../assets/image.png" />
```
```css [CSS]
.bg-image {
background-image: url(~/assets/image.png);
}
```
```vue [Vue]
<script>
import image from '~/assets/image.png';
</script>
<template>
<img :src="image" />
</template>
```
```jsx [JSX]
import image from '~/assets/image.png';
<img src={image} />;
```
:::
## `/public` Directory
Files inside `<rootDir>/public/` are copied into the output folder as-is, without being processed by WXT's bundler.
Here's how you access them:
:::code-group
```ts [JS]
import imageUrl from '/image.png';
const img = document.createElement('img');
img.src = imageUrl;
```
```html [HTML]
<img src="/image.png" />
```
```css [CSS]
.bg-image {
background-image: url(/image.png);
}
```
```vue [Vue]
<template>
<img src="/image.png" />
</template>
```
```jsx [JSX]
<img src="/image.png" />
```
:::
:::warning
Assets in the `public/` directory are **_not_** accessible in content scripts by default. To use a public asset in a content script, you must add it to your manifest's [`web_accessible_resources` array](/api/reference/wxt/type-aliases/UserManifest#web-accessible-resources).
:::
## Inside Content Scripts
Assets inside content scripts are a little different. By default, when you import an asset, it returns just the path to the asset. This is because Vite assumes you're loading assets from the same hostname.
But, inside content scripts, the hostname is whatever the tab is set to. So if you try to fetch the asset, manually or as an `<img>`'s `src`, it will be loaded from the tab's website, not your extension.
To fix this, you need to convert the image to a full URL using `browser.runtime.getURL`:
```ts [entrypoints/content.ts]
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://<id>/icon/128.png"
},
});
```
## WASM
How a `.wasm` file is loaded varies greatly between packages, but most follow a basic setup: Use a JS API to load and execute the `.wasm` file.
For an extension, that means two things:
1. The `.wasm` file needs to be present in output folder so it can be loaded.
2. You must import the JS API to load and initialize the `.wasm` file, usually provided by the NPM package.
For an example, let's say you have a content script needs to parse TS code into AST. We'll use [`@oxc-parser/wasm`](https://www.npmjs.com/package/@oxc-parser/wasm) to do it!
First, we need to copy the `.wasm` file to the output directory. We'll do it with a [WXT module](/guide/essentials/wxt-modules):
```ts
// modules/oxc-parser-wasm.ts
import { resolve } from 'node:path';
export default defineWxtModule((wxt) => {
wxt.hook('build:publicAssets', (_, assets) => {
assets.push({
absoluteSrc: resolve(
'node_modules/@oxc-parser/wasm/web/oxc_parser_wasm_bg.wasm',
),
relativeDest: 'oxc_parser_wasm_bg.wasm',
});
});
});
```
Run `wxt build`, and you should see the WASM file copied into your `.output/chrome-mv3` folder!
Next, since this is in a content script and we'll be fetching the WASM file over the network to load it, we need to add the file to the `web_accessible_resources`:
```ts [wxt.config.ts]
export default defineConfig({
manifest: {
web_accessible_resources: [
{
// We'll use this matches in the content script as well
matches: ['*://*.github.com/*'],
// Use the same path as `relativeDest` from the WXT module
resources: ['/oxc_parser_wasm_bg.wasm'],
},
],
},
});
```
And finally, we need to load and initialize the `.wasm` file inside the content script to use it:
```ts [entrypoints/content.ts]
import initWasm, { parseSync } from '@oxc-parser/wasm';
export default defineContentScript({
matches: '*://*.github.com/*',
async main(ctx) {
if (!location.pathname.endsWith('.ts')) return;
// Get text from GitHub
const code = document.getElementById(
'read-only-cursor-text-area',
)?.textContent;
if (!code) return;
const sourceFilename = document.getElementById('file-name-id')?.textContent;
if (!sourceFilename) return;
// Load the WASM file:
await initWasm({
module_or_path: browser.runtime.getURL('/oxc_parser_wasm_bg.wasm'),
});
// Once loaded, we can use `parseSync`!
const ast = parseSync(code, { sourceFilename });
console.log(ast);
},
});
```
This code is taken directly from `@oxc-parser/wasm` docs with one exception: We manually pass in a file path. In a standard NodeJS or web project, the default path works just fine so you don't have to pass anything in. However, extensions are different. You should always explicitly pass in the full URL to the WASM file in your output directory, which is what `browser.runtime.getURL` returns.
Run your extension, and you should see OXC parse the TS file!
================================================
FILE: docs/guide/essentials/config/auto-imports.md
================================================
# Auto-imports
WXT uses [`unimport`](https://www.npmjs.com/package/unimport), the same tool as Nuxt, to setup auto-imports.
```ts
export default defineConfig({
// See https://www.npmjs.com/package/unimport#configurations
imports: {
// ...
},
});
```
By default, WXT automatically sets up auto-imports for all of it's own APIs and some of your project directories:
- `<srcDir>/components/*`
- `<srcDir>/composables/*`
- `<srcDir>/hooks/*`
- `<srcDir>/utils/*`
All named and default exports from files in these directories are available everywhere else in your project without having to import them.
To see the complete list of auto-imported APIs, run [`wxt prepare`](/api/cli/wxt-prepare) and look at your project's `.wxt/types/imports-module.d.ts` file.
## TypeScript
For TypeScript and your editor to recognize auto-imported variables, you need to run the [`wxt prepare` command](/api/cli/wxt-prepare).
Add this command to your `postinstall` script so your editor has everything it needs to report type errors after installing dependencies:
```jsonc
// package.json
{
"scripts": {
"postinstall": "wxt prepare", // [!code ++]
},
}
```
## ESLint
ESLint doesn't know about the auto-imported variables unless they are explicitly defined in the ESLint's `globals`. By default, WXT will generate the config if it detects ESLint is installed in your project. If the config isn't generated automatically, you can manually tell WXT to generate it.
:::code-group
```ts [ESLint 9]
export default defineConfig({
imports: {
eslintrc: {
enabled: 9,
},
},
});
```
```ts [ESLint 8]
export default defineConfig({
imports: {
eslintrc: {
enabled: 8,
},
},
});
```
:::
Then in your ESLint config, import and use the generated file:
:::code-group
```js [ESLint 9]
// eslint.config.mjs
import autoImports from './.wxt/eslint-auto-imports.mjs';
export default [
autoImports,
{
// The rest of your config...
},
];
```
```js [ESLint 8]
// .eslintrc.mjs
export default {
extends: ['./.wxt/eslintrc-auto-import.json'],
// The rest of your config...
};
```
:::
## Disabling Auto-imports
Not all developers like auto-imports. To disable them, set `imports` to `false`.
```ts
export default defineConfig({
imports: false, // [!code ++]
});
```
## Explicit Imports (`#imports`)
You can manually import all of WXT's APIs via the `#imports` module:
```ts
import {
createShadowRootUi,
ContentScriptContext,
MatchPattern,
} from '#imports';
```
To learn more about how the `#imports` module works, read the [related blog post](/blog/2024-12-06-using-imports-module).
If you've disabled auto-imports, you should still use `#imports` to import all of WXT's APIs from a single place.
================================================
FILE: docs/guide/essentials/config/browser-startup.md
================================================
---
outline: deep
---
# Browser Startup
> See the [API Reference](/api/reference/wxt/interfaces/WebExtConfig) for a full list of config.
During development, WXT uses [`web-ext` by Mozilla](https://www.npmjs.com/package/web-ext) to automatically open a browser window with your extension installed.
## Config Files
You can configure browser startup in 3 places:
1. `<rootDir>/web-ext.config.ts`: Ignored from version control, this file lets you configure your own options for a specific project without affecting other developers
```ts [web-ext.config.ts]
import { defineWebExtConfig } from 'wxt';
export default defineWebExtConfig({
// ...
});
```
2. `<rootDir>/wxt.config.ts`: Via the [`webExt` config](/api/reference/wxt/interfaces/InlineConfig#webext), included in version control
3. `$HOME/web-ext.config.ts`: Provide default values for all WXT projects on your computer
## Recipes
### Set Browser Binaries
To set or customize the browser opened during development:
```ts [web-ext.config.ts]
import { defineWebExtConfig } from 'wxt';
export default defineWebExtConfig({
binaries: {
chrome: '/path/to/chrome-beta', // Use Chrome Beta instead of regular Chrome
firefox: 'firefoxdeveloperedition', // Use Firefox Developer Edition instead of regular Firefox
edge: '/path/to/edge', // Open MS Edge when running "wxt -b edge"
},
});
```
```ts [wxt.config.ts]
export default defineConfig({
webExt: {
binaries: {
chrome: '/path/to/chrome-beta', // Use Chrome Beta instead of regular Chrome
firefox: 'firefoxdeveloperedition', // Use Firefox Developer Edition instead of regular Firefox
edge: '/path/to/edge', // Open MS Edge when running "wxt -b edge"
},
},
});
```
By default, WXT will try to automatically discover where Chrome/Firefox are installed. However, if you have chrome installed in a non-standard location, you need to set it manually as shown above.
### Persist Data
By default, to keep from modifying your browser's existing profiles, `web-ext` creates a brand new profile every time you run the `dev` script.
Right now, Chromium based browsers are the only browsers that support overriding this behavior and persisting data when running the `dev` script multiple times.
To persist data, set the `--user-data-dir` flag in any of the config files mentioned above:
:::code-group
```ts [Mac/Linux]
import { defineWebExtConfig } from 'wxt';
export default defineWebExtConfig({
chromiumArgs: ['--user-data-dir=./.wxt/chrome-data'],
});
```
```ts [Windows]
import { resolve } from 'node:path';
import { defineWebExtConfig } from 'wxt';
export default defineWebExtConfig({
// On Windows, the path must be absolute
chromiumProfile: resolve('.wxt/chrome-data'),
keepProfileChanges: true,
});
```
:::
Now, next time you run the `dev` script, a persistent profile will be created in `.wxt/chrome-data/{profile-name}`. With a persistent profile, you can install devtools extensions to help with development, allow the browser to remember logins, etc, without worrying about the profile being reset the next time you run the `dev` script.
:::tip
You can use any directory you'd like for `--user-data-dir`, the examples above create a persistent profile for each WXT project. To create a profile for all WXT projects, you can put the `chrome-data` directory inside your user's home directory.
:::
### Disable Opening Browser
If you prefer to load the extension into your browser manually, you can disable the auto-open behavior:
```ts [web-ext.config.ts]
import { defineWebExtConfig } from 'wxt';
export default defineWebExtConfig({
disabled: true,
});
```
### Enabling Chrome Features
Some APIs are disabled in Chrome during development because of the default flags `web-ext` uses to launch Chrome, like the [Prompt API](https://developer.chrome.com/docs/ai/prompt-api).
If your extension depends on new features or services, you can enable them via `chromiumArgs`:
```ts
import { defineWebExtConfig } from 'wxt';
export default defineWebExtConfig({
chromiumArgs: [
// For example, this flag enables the Prompt API
'--disable-features=DisableLoadExtensionCommandLineSwitch',
],
});
```
There is no comprehensive list of what feature flags enable what APIs and services.
Alternatively, if you can't find a flag that enables a feature you're looking for, [disable the opening the browser during development](#disable-opening-browser) and use your regular chrome profile for development.
================================================
FILE: docs/guide/essentials/config/build-mode.md
================================================
# Build Modes
Because WXT is powered by Vite, it supports [modes](https://vite.dev/guide/env-and-mode.html#modes) in the same way.
When running any dev or build commands, pass the `--mode` flag:
```sh
wxt --mode production
wxt build --mode development
wxt zip --mode testing
```
By default, `--mode` is `development` for the dev command and `production` for all other commands (build, zip, etc).
## Get Mode at Runtime
You can access the current mode in your extension using `import.meta.env.MODE`:
```ts
switch (import.meta.env.MODE) {
case 'development': // ...
case 'production': // ...
// Custom modes specified with --mode
case 'testing': // ...
case 'staging': // ...
// ...
}
```
================================================
FILE: docs/guide/essentials/config/entrypoint-loaders.md
================================================
# Entrypoint Loaders
To generate the manifest and other files at build-time, WXT must import each entrypoint to get their options, like content script `matches`. For HTML files, this is easy. For JS/TS entrypoints, the process is more complicated.
When loading your JS/TS entrypoints, they are imported into a NodeJS environment, not the `browser` environment that they normally run in. This can lead to issues commonly seen when running browser-only code in a NodeJS environment, like missing global variables.
WXT does several pre-processing steps to try and prevent errors during this process:
1. Use `linkedom` to make a small set of browser globals (`window`, `document`, etc) available.
2. Use `@webext-core/fake-browser` to create a fake version of the `chrome` and `browser` globals expected by extensions.
3. Pre-process the JS/TS code, stripping out the `main` function then tree-shaking unused code from the file
However, this process is not perfect. It doesn't setup all the globals found in the browser and the APIs may behave differently. As such, **_you should avoid using browser or extension APIs outside the `main` function of your entrypoints!_** See [Entrypoint Limitations](/guide/essentials/extension-apis#entrypoint-limitations) for more details.
:::tip
If you're running into errors while importing entrypoints, run `wxt prepare --debug` to see more details about this process. When debugging, WXT will print out the pre-processed code to help you identify issues.
:::
Once the environment has been polyfilled and your code pre-processed, it's up the entrypoint loader to import your code, extracting the options from the default export.
================================================
FILE: docs/guide/essentials/config/environment-variables.md
================================================
# Environment Variables
## Dotenv Files
WXT supports [dotenv files the same way as Vite](https://vite.dev/guide/env-and-mode.html#env-files). Create any of the following files:
```plaintext
.env
.env.local
.env.[mode]
.env.[mode].local
.env.[browser]
.env.[browser].local
.env.[mode].[browser]
.env.[mode].[browser].local
```
And any environment variables listed inside them will be available at runtime:
```sh
# .env
WXT_API_KEY=...
```
```ts
await fetch(`/some-api?apiKey=${import.meta.env.WXT_API_KEY}`);
```
Remember to prefix any environment variables with `WXT_` or `VITE_`, otherwise they won't be available at runtime, as per [Vite's convention](https://vite.dev/guide/env-and-mode.html#env-files).
## Built-in Environment Variables
WXT provides some custom environment variables based on the current command:
| Usage | Type | Description |
| ---------------------------------- | --------- | ----------------------------------------------------- |
| `import.meta.env.MANIFEST_VERSION` | `2 │ 3` | The target manifest version |
| `import.meta.env.BROWSER` | `string` | The target browser |
| `import.meta.env.CHROME` | `boolean` | Equivalent to `import.meta.env.BROWSER === "chrome"` |
| `import.meta.env.FIREFOX` | `boolean` | Equivalent to `import.meta.env.BROWSER === "firefox"` |
| `import.meta.env.SAFARI` | `boolean` | Equivalent to `import.meta.env.BROWSER === "safari"` |
| `import.meta.env.EDGE` | `boolean` | Equivalent to `import.meta.env.BROWSER === "edge"` |
| `import.meta.env.OPERA` | `boolean` | Equivalent to `import.meta.env.BROWSER === "opera"` |
You can set the [`targetBrowsers`](/api/reference/wxt/interfaces/InlineConfig#targetbrowsers) option to make the `BROWSER` variable a more specific type, like `"chrome" | "firefox"`.
You can also access all of [Vite's environment variables](https://vite.dev/guide/env-and-mode.html#env-variables):
| Usage | Type | Description |
| ---------------------- | --------- | --------------------------------------------------------------------------- |
| `import.meta.env.MODE` | `string` | The [mode](/guide/essentials/config/build-mode) the extension is running in |
| `import.meta.env.PROD` | `boolean` | When `NODE_ENV='production'` |
| `import.meta.env.DEV` | `boolean` | Opposite of `import.meta.env.PROD` |
:::details Other Vite Environment Variables
Vite provides two other environment variables, but they aren't useful in WXT projects:
- `import.meta.env.BASE_URL`: Use `browser.runtime.getURL` instead.
- `import.meta.env.SSR`: Always `false`.
:::
## Manifest
To use environment variables in the manifest, you need to use the function syntax:
```ts
export default defineConfig({
modules: ['@wxt-dev/module-vue'],
manifest: { // [!code --]
oauth2: { // [!code --]
client_id: import.meta.env.WXT_APP_CLIENT_ID // [!code --]
} // [!code --]
} // [!code --]
manifest: () => ({ // [!code ++]
oauth2: { // [!code ++]
client_id: import.meta.env.WXT_APP_CLIENT_ID // [!code ++]
} // [!code ++]
}), // [!code ++]
});
```
WXT can't load your `.env` files until after the config file has been loaded. So by using the function syntax for `manifest`, it defers creating the object until after the `.env` files are loaded into the process.
Note that Vite's runtime environment variables, like `import.meta.env.DEV`, will not be defined. Instead, access the `mode` like this:
```ts
export default defineConfig({
manifest: ({ mode }) => {
const isDev = mode === 'development';
console.log('Is development mode:', isDev);
// ...
},
});
```
================================================
FILE: docs/guide/essentials/config/hooks.md
================================================
# Hooks
WXT includes a system that lets you hook into the build process and make changes.
## Adding Hooks
The easiest way to add a hook is via the `wxt.config.ts`. Here's an example hook that modifies the `manifest.json` file before it is written to the output directory:
```ts [wxt.config.ts]
export default defineConfig({
hooks: {
'build:manifestGenerated': (wxt, manifest) => {
if (wxt.config.mode === 'development') {
manifest.name += ' (DEV)';
}
},
},
});
```
Most hooks provide the `wxt` object as the first argument. It contains the resolved config and other info about the current build. The other arguments can be modified by reference to change different parts of the build system.
You can find the [list of all available hooks](/api/reference/wxt/interfaces/WxtHooks) in the API reference.
Putting one-off hooks like this in your config file is simple, but if you find yourself writing lots of hooks, you should extract them into [WXT Modules](/guide/essentials/wxt-modules) instead.
## Execution Order
Because hooks can be defined in multiple places, including [WXT Modules](/guide/essentials/wxt-modules), the order which they're executed can matter. Hooks are executed in the following order:
1. NPM modules in the order listed in the [`modules` config](/api/reference/wxt/interfaces/InlineConfig#modules)
2. User modules in [`/modules` folder](/guide/essentials/project-structure), loaded alphabetically
3. Hooks listed in your `wxt.config.ts`
To see the order for your project, run `wxt prepare --debug` flag and search for the "Hook execution order":
```plaintext
⚙ Hook execution order:
⚙ 1. wxt:built-in:unimport
⚙ 2. src/modules/auto-icons.ts
⚙ 3. src/modules/example.ts
⚙ 4. src/modules/i18n.ts
⚙ 5. wxt.config.ts > hooks
```
Changing execution order is simple:
- Prefix your user modules with a number (lower numbers are loaded first):
<!-- prettier-ignore -->
```html
📁 modules/
📄 0.my-module.ts
📄 1.another-module.ts
```
- If you need to run an NPM module after user modules, just make it a user module and prefix the filename with a number!
```ts
// modules/2.i18n.ts
export { default } from '@wxt-dev/i18n/module';
```
================================================
FILE: docs/guide/essentials/config/manifest.md
================================================
# Manifest
In WXT, there is no `manifest.json` file in your source code. Instead, WXT generates the manifest from multiple sources:
- Global options [defined in your `wxt.config.ts` file](#global-options)
- Entrypoint-specific options [defined in your entrypoints](/guide/essentials/entrypoints#defining-manifest-options)
- [WXT Modules](/guide/essentials/wxt-modules) added to your project can modify your manifest
- [Hooks](/guide/essentials/config/hooks) defined in your project can modify your manifest
Your extension's `manifest.json` will be output to `.output/{target}/manifest.json` when running `wxt build`.
## Global Options
To add a property to your manifest, use the `manifest` config inside your `wxt.config.ts`:
```ts
export default defineConfig({
manifest: {
// Put manual changes here
},
});
```
You can also define the manifest as a function, and use JS to generate it based on the target browser, mode, and more.
```ts
export default defineConfig({
manifest: ({ browser, manifestVersion, mode, command }) => {
return {
// ...
};
},
});
```
### MV2 and MV3 Compatibility
When adding properties to the manifest, always define the property in it's MV3 format when possible. When targeting MV2, WXT will automatically convert these properties to their MV2 format.
For example, for this config:
```ts
export default defineConfig({
manifest: {
action: {
default_title: 'Some Title',
},
web_accessible_resources: [
{
matches: ['*://*.google.com/*'],
resources: ['icon/*.png'],
},
],
},
});
```
WXT will generate the following manifests:
:::code-group
```json [MV2]
{
"manifest_version": 2,
// ...
"browser_action": {
"default_title": "Some Title"
},
"web_accessible_resources": ["icon/*.png"]
}
```
```json [MV3]
{
"manifest_version": 3,
// ...
"action": {
"default_title": "Some Title"
},
"web_accessible_resources": [
{
"matches": ["*://*.google.com/*"],
"resources": ["icon/*.png"]
}
]
}
```
:::
You can also specify properties specific to a single manifest version, and they will be stripped out when targeting the other manifest version.
## Name
> [Chrome Docs](https://developer.chrome.com/docs/extensions/mv3/manifest/name/)
If not provided via the `manifest` config, the manifest's `name` property defaults to your `package.json`'s `name` property.
## Version and Version Name
> [Chrome Docs](https://developer.chrome.com/docs/extensions/mv3/manifest/version/)
Your extension's `version` and `version_name` is based on the `version` from your `package.json`.
- `version_name` is the exact string listed
- `version` is the string cleaned up, with any invalid suffixes removed
Example:
```json
// package.json
{
"version": "1.3.0-alpha2"
}
```
```json
// .output/<target>/manifest.json
{
"version": "1.3.0",
"version_name": "1.3.0-alpha2"
}
```
If a version is not present in your `package.json`, it defaults to `"0.0.0"`.
## Icons
WXT automatically discovers your extension's icon by looking at files in the `public/` directory:
```plaintext
public/
├─ icon-16.png
├─ icon-24.png
├─ icon-48.png
├─ icon-96.png
└─ icon-128.png
```
Specifically, an icon must match one of these regex to be discovered:
<<< @/../packages/wxt/src/core/utils/manifest.ts#snippet
If you don't like these filename or you're migrating to WXT and don't want to rename the files, you can manually specify an `icon` in your manifest:
```ts
export default defineConfig({
manifest: {
icons: {
16: '/extension-icon-16.png',
24: '/extension-icon-24.png',
48: '/extension-icon-48.png',
96: '/extension-icon-96.png',
128: '/extension-icon-128.png',
},
},
});
```
Alternatively, you can use [`@wxt-dev/auto-icons`](https://www.npmjs.com/package/@wxt-dev/auto-icons) to let WXT generate your icon at the required sizes.
## Permissions
> [Chrome docs](https://developer.chrome.com/docs/extensions/reference/permissions/)
Most of the time, you need to manually add permissions to your manifest. Only in a few specific situations are permissions added automatically:
- During development: the `tabs` and `scripting` permissions will be added to enable hot reloading.
- When a `sidepanel` entrypoint is present: The `sidepanel` permission is added.
```ts
export default defineConfig({
manifest: {
permissions: ['storage', 'tabs'],
},
});
```
## Host Permissions
> [Chrome docs](https://developer.chrome.com/docs/extensions/develop/concepts/declare-permissions#host-permissions)
```ts
export default defineConfig({
manifest: {
host_permissions: ['https://www.google.com/*'],
},
});
```
:::warning
If you use host permissions and target both MV2 and MV3, make sure to only include the required host permissions for each version:
```ts
export default defineConfig({
manifest: ({ manifestVersion }) => ({
host_permissions: manifestVersion === 2 ? [...] : [...],
}),
});
```
:::
## Default Locale
```ts
export default defineConfig({
manifest: {
name: '__MSG_extName__',
description: '__MSG_extDescription__',
default_locale: 'en',
},
});
```
> See [I18n docs](/guide/essentials/i18n) for a full guide on internationalizing your extension.
## Actions
In MV2, you have two options: [`browser_action`](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/browser_action) and [`page_action`](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/page_action). In MV3, they were merged into a single [`action`](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/action) API.
By default, whenever an `action` is generated, WXT falls back to `browser_action` when targeting MV2.
### Action With Popup
To generate a manifest where a UI appears after clicking the icon, just create a [Popup entrypoint](/guide/essentials/entrypoints#popup). If you want to use a `page_action` for MV2, add the following meta tag to the HTML document's head:
```html
<meta name="manifest.type" content="page_action" />
```
### Action Without Popup
If you want to use the `activeTab` permission or the `browser.action.onClicked` event, but don't want to show a popup:
1. Delete the [Popup entrypoint](/guide/essentials/entrypoints#popup) if it exists
2. Add the `action` key to your manifest:
```ts
export default defineConfig({
manifest: {
action: {},
},
});
```
Same as an action with a popup, WXT will fallback on using `browser_action` for MV2. To use a `page_action` instead, add that key as well:
```ts
export default defineConfig({
manifest: {
action: {},
page_action: {},
},
});
```
================================================
FILE: docs/guide/essentials/config/runtime.md
================================================
# Runtime Config
> This API is still a WIP, with more features coming soon!
Define runtime configuration in a single place, `<srcDir>/app.config.ts`:
```ts
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',
});
```
:::warning
This file is committed to the repo, so don't put any secrets here. Instead, use [Environment Variables](/guide/essentials/config/environment-variables)
:::
To access runtime config, WXT provides the `getAppConfig` function:
```ts
import { getAppConfig } from '#imports';
console.log(getAppConfig()); // { theme: "dark" }
```
## Environment Variables in App Config
You can use environment variables in the `app.config.ts` file.
```ts
declare module 'wxt/utils/define-app-config' {
export interface WxtAppConfig {
apiKey?: string;
skipWelcome: boolean;
}
}
export default defineAppConfig({
apiKey: import.meta.env.WXT_API_KEY,
skipWelcome: import.meta.env.WXT_SKIP_WELCOME === 'true',
});
```
This has several advantages:
- Define all expected environment variables in a single file
- Convert strings to other types, like booleans or arrays
- Provide default values if an environment variable is not provided
================================================
FILE: docs/guide/essentials/config/typescript.md
================================================
# TypeScript Configuration
When you run [`wxt prepare`](/api/cli/wxt-prepare), WXT generates a base TSConfig file for your project at `<rootDir>/.wxt/tsconfig.json`.
At a minimum, you need to create a TSConfig in your root directory that looks like this:
```jsonc
// <rootDir>/tsconfig.json
{
"extends": ".wxt/tsconfig.json",
}
```
Or if you're in a monorepo, you may not want to extend the config. If you don't extend it, you need to add `.wxt/wxt.d.ts` to the TypeScript project:
```ts
/// <reference path="./.wxt/wxt.d.ts" />
```
## Compiler Options
To specify custom compiler options, add them in `<rootDir>/tsconfig.json`:
```jsonc
// <rootDir>/tsconfig.json
{
"extends": ".wxt/tsconfig.json",
"compilerOptions": {
"jsx": "preserve",
},
}
```
## TSConfig Paths
WXT provides a default set of path aliases.
| Alias | To | Example |
| ----- | ------------- | ----------------------------------------------- |
| `~~` | `<rootDir>/*` | `import "~~/scripts"` |
| `@@` | `<rootDir>/*` | `import "@@/scripts"` |
| `~` | `<srcDir>/*` | `import { toLowerCase } from "~/utils/strings"` |
| `@` | `<srcDir>/*` | `import { toLowerCase } from "@/utils/strings"` |
To add your own, DO NOT add them to your `tsconfig.json`! Instead, use the [`alias` option](/api/reference/wxt/interfaces/InlineConfig#alias) in `wxt.config.ts`.
This will add your custom aliases to `<rootDir>/.wxt/tsconfig.json` next time you run `wxt prepare`. It also adds your alias to the bundler so it can resolve imports.
```ts
import { resolve } from 'node:path';
export default defineConfig({
alias: {
// Directory:
testing: resolve('utils/testing'),
// File:
strings: resolve('utils/strings.ts'),
},
});
```
```ts
import { fakeTab } from 'testing/fake-objects';
import { toLowerCase } from 'strings';
```
================================================
FILE: docs/guide/essentials/config/vite.md
================================================
# Vite
WXT uses [Vite](https://vitejs.dev/) under the hood to bundle your extension.
This page explains how to customize your project's Vite config. Refer to [Vite's documentation](https://vite.dev/config/) to learn more about configuring the bundler.
:::tip
In most cases, you shouldn't change Vite's build settings. WXT provides sensible defaults that output a valid extension accepted by all stores when publishing.
:::
## Change Vite Config
You can change Vite's config via the `wxt.config.ts` file:
```ts [wxt.config.ts]
import { defineConfig } from 'wxt';
export default defineConfig({
vite: () => ({
// Override config here, same as `defineConfig({ ... })`
// inside vite.config.ts files
}),
});
```
## Add Vite Plugins
To add a plugin, install the NPM package and add it to the Vite config:
```ts [wxt.config.ts]
import { defineConfig } from 'wxt';
import VueRouter from 'unplugin-vue-router/vite';
export default defineConfig({
vite: () => ({
plugins: [
VueRouter({
/* ... */
}),
],
}),
});
```
:::warning
Due to the way WXT orchestrates Vite builds, some plugins may not work as expected. For example, `vite-plugin-remove-console` normally only runs when you build for production (`vite build`). However, WXT uses a combination of dev server and builds during development, so you need to manually tell it when to run:
```ts [wxt.config.ts]
import { defineConfig } from 'wxt';
import removeConsole from 'vite-plugin-remove-console';
export default defineConfig({
vite: (configEnv) => ({
plugins:
configEnv.mode === 'production'
? [removeConsole({ includes: ['log'] })]
: [],
}),
});
```
Search [GitHub issues](https://github.com/wxt-dev/wxt/issues?q=is%3Aissue+label%3A%22vite+plugin%22) if you run into issues with a specific plugin.
If an issue doesn't exist for your plugin, [open a new one](https://github.com/wxt-dev/wxt/issues/new/choose).
:::
================================================
FILE: docs/guide/essentials/content-scripts.md
================================================
---
outline: deep
---
# Content Scripts
> To create a content script, see [Entrypoint Types](/guide/essentials/entrypoints#content-scripts).
## Context
The first argument to a content script's `main` function is its "context".
```ts
// entrypoints/example.content.ts
export default defineContentScript({
main(ctx) {},
});
```
This object is responsible for tracking whether or not the content script's context is "invalidated". Most browsers, by default, do not stop content scripts if the extension is uninstalled, updated, or disabled. When this happens, content scripts start reporting this error:
```plaintext
Error: Extension context invalidated.
```
The `ctx` object provides several helpers to stop asynchronous code from running once the context is invalidated:
```ts
ctx.addEventListener(...);
ctx.setTimeout(...);
ctx.setInterval(...);
ctx.requestAnimationFrame(...);
// and more
```
You can also check if the context is invalidated manually:
```ts
if (ctx.isValid) {
// do something
}
// OR
if (ctx.isInvalid) {
// do something
}
```
## CSS
In regular web extensions, CSS for content scripts is usually a separate CSS file, that is added to a CSS array in the manifest:
```json
{
"content_scripts": [
{
"css": ["content/style.css"],
"js": ["content/index.js"],
"matches": ["*://*/*"]
}
]
}
```
In WXT, to add CSS to a content script, simply import the CSS file into your JS entrypoint, and WXT will automatically add the bundled CSS output to the `css` array.
```ts
// entrypoints/example.content/index.ts
import './style.css';
export default defineContentScript({
// ...
});
```
To create a standalone content script that only includes a CSS file:
1. Create the CSS file: `entrypoints/example.content.css`
2. Use the `build:manifestGenerated` hook to add the content script to the manifest:
```ts [wxt.config.ts]
export default defineConfig({
hooks: {
'build:manifestGenerated': (wxt, manifest) => {
manifest.content_scripts ??= [];
manifest.content_scripts.push({
// Build extension once to see where your CSS get's written to
css: ['content-scripts/example.css'],
matches: ['*://*/*'],
});
},
},
});
```
## UI
WXT provides 3 built-in utilities for adding UIs to a page from a content script:
- [Integrated](#integrated) - `createIntegratedUi`
- [Shadow Root](#shadow-root) -`createShadowRootUi`
- [IFrame](#iframe) - `createIframeUi`
Each has their own set of advantages and disadvantages.
| Method | Isolated Styles | Isolated Events | HMR | Use page's context |
| ----------- | :-------------: | :-----------------: | :-: | :----------------: |
| Integrated | ❌ | ❌ | ❌ | ✅ |
| Shadow Root | ✅ | ✅ (off by default) | ❌ | ✅ |
| IFrame | ✅ | ✅ | ✅ | ❌ |
### Integrated
Integrated content script UIs are injected alongside the content of a page. This means that they are affected by CSS on that page.
:::code-group
```ts [Vanilla]
// entrypoints/example-ui.content.ts
export default defineContentScript({
matches: ['<all_urls>'],
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();
},
});
```
```ts [Vue]
// entrypoints/example-ui.content/index.ts
import { createApp } from 'vue';
import App from './App.vue';
export default defineContentScript({
matches: ['<all_urls>'],
main(ctx) {
const ui = createIntegratedUi(ctx, {
position: 'inline',
anchor: 'body',
onMount: (container) => {
// Create the app and mount it to the UI container
const app = createApp(App);
app.mount(container);
return app;
},
onRemove: (app) => {
// Unmount the app when the UI is removed
app.unmount();
},
});
// Call mount to add the UI to the DOM
ui.mount();
},
});
```
```tsx [React]
// entrypoints/example-ui.content/index.tsx
import ReactDOM from 'react-dom/client';
import App from './App.tsx';
export default defineContentScript({
matches: ['<all_urls>'],
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(<App />);
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();
},
});
```
```ts [Svelte]
// entrypoints/example-ui.content/index.ts
import App from './App.svelte';
import { mount, unmount } from 'svelte';
export default defineContentScript({
matches: ['<all_urls>'],
main(ctx) {
const ui = createIntegratedUi(ctx, {
position: 'inline',
anchor: 'body',
onMount: (container) => {
// Create the Svelte app inside the UI container
return mount(App, { target: container });
},
onRemove: (app) => {
// Destroy the app when the UI is removed
unmount(app);
},
});
// Call mount to add the UI to the DOM
ui.mount();
},
});
```
```tsx [Solid]
// entrypoints/example-ui.content/index.ts
import { render } from 'solid-js/web';
export default defineContentScript({
matches: ['<all_urls>'],
main(ctx) {
const ui = createIntegratedUi(ctx, {
position: 'inline',
anchor: 'body',
onMount: (container) => {
// Render your app to the UI container
const unmount = render(() => <div>...</div>, 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();
},
});
```
:::
See the [API Reference](/api/reference/wxt/utils/content-script-ui/integrated/functions/createIntegratedUi) for the complete list of options.
### Shadow Root
Often in web extensions, you don't want your content script's CSS affecting the page, or vise-versa. The [`ShadowRoot`](https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot) API is ideal for this.
WXT's [`createShadowRootUi`](/api/reference/wxt/utils/content-script-ui/shadow-root/functions/createShadowRootUi) abstracts all the `ShadowRoot` setup away, making it easy to create UIs whose styles are isolated from the page. It also supports an optional `isolateEvents` parameter to further isolate user interactions.
To use `createShadowRootUi`, follow these steps:
1. Import your CSS file at the top of your content script
2. Set [`cssInjectionMode: "ui"`](/api/reference/wxt/interfaces/BaseContentScriptEntrypointOptions#cssinjectionmode) inside `defineContentScript`
3. Define your UI with `createShadowRootUi()`
4. Mount the UI so it is visible to users
:::code-group
```ts [Vanilla]
// 1. Import the style
import './style.css';
export default defineContentScript({
matches: ['<all_urls>'],
// 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();
},
});
```
```ts [Vue]
// 1. Import the style
import './style.css';
import { createApp } from 'vue';
import App from './App.vue';
export default defineContentScript({
matches: ['<all_urls>'],
// 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();
},
});
```
```tsx [React]
// 1. Import the style
import './style.css';
import ReactDOM from 'react-dom/client';
import App from './App.tsx';
export default defineContentScript({
matches: ['<all_urls>'],
// 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(<App />);
return root;
},
onRemove: (root) => {
// Unmount the root when the UI is removed
root?.unmount();
},
});
// 4. Mount the UI
ui.mount();
},
});
```
```ts [Svelte]
// 1. Import the style
import './style.css';
import App from './App.svelte';
import { mount, unmount } from 'svelte';
export default defineContentScript({
matches: ['<all_urls>'],
// 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) => {
// Create the Svelte app inside the UI container
return mount(App, { target: container });
},
onRemove: (app) => {
// Destroy the app when the UI is removed
unmount(app);
},
});
// 4. Mount the UI
ui.mount();
},
});
```
```tsx [Solid]
// 1. Import the style
import './style.css';
import { render } from 'solid-js/web';
export default defineContentScript({
matches: ['<all_urls>'],
// 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(() => <div>...</div>, container);
},
onRemove: (unmount) => {
// Unmount the app when the UI is removed
unmount?.();
},
});
// 4. Mount the UI
ui.mount();
},
});
```
:::
See the [API Reference](/api/reference/wxt/utils/content-script-ui/shadow-root/functions/createShadowRootUi) for the complete list of options.
Full examples:
- [react-content-script-ui](https://github.com/wxt-dev/examples/tree/main/examples/react-content-script-ui)
- [tailwindcss](https://github.com/wxt-dev/examples/tree/main/examples/tailwindcss)
### IFrame
If you don't need to run your UI in the same frame as the content script, you can use an IFrame to host your UI instead. Since an IFrame just hosts an HTML page, **_HMR is supported_**.
WXT provides a helper function, [`createIframeUi`](/api/reference/wxt/utils/content-script-ui/iframe/functions/createIframeUi), which simplifies setting up the IFrame.
1. Create an HTML page that will be loaded into your IFrame:
```html
<!-- entrypoints/example-iframe.html -->
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Your Content Script IFrame</title>
</head>
<body>
<!-- ... -->
</body>
</html>
```
1. Add the page to the manifest's `web_accessible_resources`:
```ts [wxt.config.ts]
export default defineConfig({
manifest: {
web_accessible_resources: [
{
resources: ['example-iframe.html'],
matches: [...],
},
],
},
});
```
1. Create and mount the IFrame:
```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();
},
});
```
See the [API Reference](/api/reference/wxt/utils/content-script-ui/iframe/functions/createIframeUi) for the complete list of options.
## Isolated World vs Main World
By default, all content scripts run in an isolated context where only the DOM is shared with the webpage it is running on - an "isolated world". In MV3, Chromium introduced the ability to run content scripts in the "main" world - where everything, not just the DOM, is available to the content script, just like if the script were loaded by the webpage.
You can enable this for a content script by setting the `world` option:
```ts
export default defineContentScript({
world: 'MAIN',
});
```
However, this approach has several notable drawbacks:
- Doesn't support MV2
- `world: "MAIN"` is only supported by Chromium browsers
- Main world content scripts don't have access to the extension API
Instead, WXT recommends injecting a script into the main world manually using it's `injectScript` function. This will address the drawbacks mentioned before.
- `injectScript` supports both MV2 and MV3
- `injectScript` supports all browsers
- Having a "parent" content script means you can send messages back and forth, making it possible to access the extension API
To use `injectScript`, we need two entrypoints, one content script and one unlisted script:
<!-- prettier-ignore -->
```html
📂 entrypoints/
📄 example.content.ts
📄 example-main-world.ts
```
```ts
// entrypoints/example-main-world.ts
export default defineUnlistedScript(() => {
console.log('Hello from the main world');
});
```
```ts
// entrypoints/example.content.ts
export default defineContentScript({
matches: ['*://*/*'],
async main() {
console.log('Injecting script...');
await injectScript('/example-main-world.js', {
keepInDom: true,
});
console.log('Done!');
},
});
```
```json
export default defineConfig({
manifest: {
// ...
web_accessible_resources: [
{
resources: ["example-main-world.js"],
matches: ["*://*/*"],
}
]
}
});
```
`injectScript` works by creating a `script` element on the page pointing to your script. This loads the script into the page's context so it runs in the main world.
`injectScript` returns a promise, that when resolved, means the script has been evaluated by the browser and you can start communicating with it.
:::warning Warning: `run_at` Caveat
For MV3, `injectScript` is synchronous and the injected script will be evaluated at the same time as your the content script's `run_at`.
However for MV2, `injectScript` has to `fetch` the script's text content and create an inline `<script>` block. This means for MV2, your script is injected asynchronously and it will not be evaluated at the same time as your content script's `run_at`.
:::
The `script` element can be modified just before it is added to the DOM by using the `modifyScript` option. This can be used to e.g. modify `script.async`/`script.defer`, add event listeners to the element, or pass data to the script via `script.dataset`. An example:
```ts
// entrypoints/example.content.ts
export default defineContentScript({
matches: ['*://*/*'],
async main() {
await injectScript('/example-main-world.js', {
modifyScript(script) {
script.dataset['greeting'] = 'Hello there';
},
});
},
});
```
```ts
// entrypoints/example-main-world.ts
export default defineUnlistedScript(() => {
console.log(document.currentScript?.dataset['greeting']);
});
```
`injectScript` returns the created script element. It can be used to e.g. send messages to the script in the form of custom events. The script can add an event listener for them via `document.currentScript`. An example of bidirectional communication:
```ts
// entrypoints/example.content.ts
export default defineContentScript({
matches: ['*://*/*'],
async main() {
const { script } = await injectScript('/example-main-world.js', {
modifyScript(script) {
// Add a listener before the injected script is loaded.
script.addEventListener('from-injected-script', (event) => {
if (event instanceof CustomEvent) {
console.log(`${event.type}:`, event.detail);
}
});
},
});
// Send an event after the injected script is loaded.
script.dispatchEvent(
new CustomEvent('from-content-script', {
detail: 'General Kenobi',
}),
);
},
});
```
```ts
// entrypoints/example-main-world.ts
export default defineUnlistedScript(() => {
const script = document.currentScript;
script?.addEventListener('from-content-script', (event) => {
if (event instanceof CustomEvent) {
console.log(`${event.type}:`, event.detail);
}
});
script?.dispatchEvent(
new CustomEvent('from-injected-script', {
detail: 'Hello there',
}),
);
});
```
## Mounting UI to dynamic element
In many cases, you may need to mount a UI to a DOM element that does not exist at the time the web page is initially loaded. To handle this, use the `autoMount` API to automatically mount the UI when the target element appears dynamically and unmount it when the element disappears. In WXT, the `anchor` option is used to target the element, enabling automatic mounting and unmounting based on its appearance and removal.
```ts
export default defineContentScript({
matches: ['<all_urls>'],
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();
},
});
```
:::tip
When the `ui.remove` is called, `autoMount` also stops.
:::
See the [API Reference](/api/reference/wxt/utils/content-script-ui/types/interfaces/ContentScriptUi#automount) for the complete list of options.
## Dealing with SPAs
It is difficult to write content scripts for SPAs (single page applications) and websites using HTML5 history mode for navigation because content scripts are only ran on full page reloads. SPAs and websites that take advantage of HTML5 history mode **_do not perform a full reload when changing paths_**, and thus your content script isn't going to be ran when you expect it to be.
Let's look at an example. Say you want to add a UI to YouTube when watching a video:
```ts
export default defineContentScript({
matches: ['*://*.youtube.com/watch*'],
main(ctx) {
console.log('YouTube content script loaded');
mountUi(ctx);
},
});
function mountUi(ctx: ContentScriptContext): void {
// ...
}
```
You're only going to see "YouTube content script loaded" when reloading the watch page or when navigating directly to it from another website.
To get around this, you'll need to manually listen for the path to change and run your content script when the URL matches what you expect it to match.
```ts
const watchPattern = new MatchPattern('*://*.youtube.com/watch*');
export default defineContentScript({
matches: ['*://*.youtube.com/*'],
main(ctx) {
ctx.addEventListener(window, 'wxt:locationchange', ({ newUrl }) => {
if (watchPattern.includes(newUrl)) mainWatch(ctx);
});
},
});
function mainWatch(ctx: ContentScriptContext) {
mountUi(ctx);
}
```
================================================
FILE: docs/guide/essentials/e2e-testing.md
================================================
# E2E Testing
## Playwright
[Playwright](https://playwright.dev) is the only good option for writing Chrome Extension end-to-end tests.
To add E2E tests to your project, follow Playwright's [Chrome Extension docs](https://playwright.dev/docs/chrome-extensions). When you have to pass the path to your extension, pass the output directory, `/path/to/project/.output/chrome-mv3`.
For a complete example, see the [WXT's Playwright Example](https://github.com/wxt-dev/examples/tree/main/examples/playwright-e2e-testing).
================================================
FILE: docs/guide/essentials/entrypoints.md
================================================
---
outline: deep
---
# Entrypoints
WXT uses the files inside the `entrypoints/` directory as inputs when bundling your extension. They can be HTML, JS, CSS, or any variant of those file types supported by Vite (TS, JSX, SCSS, etc).
## Folder Structure
Inside the `entrypoints/` directory, an entrypoint is defined as a single file or directory (with an `index` file) inside it.
:::code-group
<!-- prettier-ignore -->
```html [Single File]
📂 entrypoints/
📄 {name}.{ext}
```
<!-- prettier-ignore -->
```html [Directory]
📂 entrypoints/
📂 {name}/
📄 index.{ext}
```
:::
The entrypoint's `name` dictates the type of entrypoint. For example, to add a ["Background" entrypoint](#background), either of these files would work:
:::code-group
<!-- prettier-ignore -->
```html [Single File]
📂 entrypoints/
📄 background.ts
```
<!-- prettier-ignore -->
```html [Directory]
📂 entrypoints/
📂 background/
📄 index.ts
```
:::
Refer to the [Entrypoint Types](#entrypoint-types) section for the full list of listed entrypoints and their filename patterns.
### Including Other Files
When using an entrypoint directory, `entrypoints/{name}/index.{ext}`, you can add related files next to the `index` file.
<!-- prettier-ignore -->
```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
```
:::danger
**DO NOT** put files related to an entrypoint directly inside the `entrypoints/` directory. WXT will treat them as entrypoints and try to build them, usually resulting in an error.
Instead, use a directory for that entrypoint:
<!-- prettier-ignore -->
```html
📂 entrypoints/
📄 popup.html <!-- [!code --] -->
📄 popup.ts <!-- [!code --] -->
📄 popup.css <!-- [!code --] -->
📂 popup/ <!-- [!code ++] -->
📄 index.html <!-- [!code ++] -->
📄 main.ts <!-- [!code ++] -->
📄 style.css <!-- [!code ++] -->
```
:::
### Deeply Nested Entrypoints
While the `entrypoints/` directory might resemble the `pages/` directory of other web frameworks, like Nuxt or Next.js, **it does not support deeply nesting entrypoints** in the same way.
Entrypoints must be zero or one levels deep for WXT to discover and build them:
<!-- prettier-ignore -->
```html
📂 entrypoints/
📂 youtube/ <!-- [!code --] -->
📂 content/ <!-- [!code --] -->
📄 index.ts <!-- [!code --] -->
📄 ... <!-- [!code --] -->
📂 injected/ <!-- [!code --] -->
📄 index.ts <!-- [!code --] -->
📄 ... <!-- [!code --] -->
📂 youtube.content/ <!-- [!code ++] -->
📄 index.ts <!-- [!code ++] -->
📄 ... <!-- [!code ++] -->
📂 youtube-injected/ <!-- [!code ++] -->
📄 index.ts <!-- [!code ++] -->
📄 ... <!-- [!code ++] -->
```
## Unlisted Entrypoints
In web extensions, there are two types of entrypoints:
1. **Listed**: Referenced in the `manifest.json`
2. **Unlisted**: Not referenced in the `manifest.json`
Throughout the rest of WXT's documentation, listed entrypoints are referred to by name. For example:
- Popup
- Options
- Background
- Content Script
However, not all entrypoints in web extensions are listed in the manifest. Some are not listed in the manifest, but are still used by extensions. For example:
- A welcome page shown in a new tab when the extension is installed
- JS files injected by content scripts into the main world
For more details on how to add unlisted entrypoints, see:
- [Unlisted Pages](#unlisted-pages)
- [Unlisted Scripts](#unlisted-scripts)
- [Unlisted CSS](#unlisted-css)
## Defining Manifest Options
Most listed entrypoints have options that need to be added to the `manifest.json`. However with WXT, instead of defining the options in a separate file, _you define these options inside the entrypoint file itself_.
For example, here's how to define `matches` for content scripts:
```ts [entrypoints/content.ts]
export default defineContentScript({
matches: ['*://*.wxt.dev/*'],
main() {
// ...
},
});
```
For HTML entrypoints, options are configured as `<meta>` tags. For example, to use a `page_action` for your MV2 popup:
```html
<!doctype html>
<html lang="en">
<head>
<meta name="manifest.type" content="page_action" />
</head>
</html>
```
> Refer to the [Entrypoint Types](#entrypoint-types) sections for a list of options configurable inside each entrypoint, and how to define them.
When building your extension, WXT will look at the options defined in your entrypoints, and generate the manifest accordingly.
## Entrypoint Types
### Background
[Chrome Docs](https://developer.chrome.com/docs/extensions/mv3/manifest/background/) • [Firefox Docs](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/background)
<EntrypointPatterns
:patterns="[
['background.[jt]s', 'background.js'],
['background/index.[jt]s', 'background.js'],
]"
/>
:::code-group
```ts [Minimal]
export default defineBackground(() => {
// Executed when background is loaded
});
```
```ts [With Manifest Options]
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
},
});
```
:::
For MV2, the background is added as a script to the background page. For MV3, the background becomes a service worker.
When defining your background entrypoint, keep in mind that WXT will import this file in a NodeJS environment during the build process. That means you cannot place any runtime code outside the `main` function.
<!-- prettier-ignore -->
```ts
browser.action.onClicked.addListener(() => { // [!code --]
// ... // [!code --]
}); // [!code --]
export default defineBackground(() => {
browser.action.onClicked.addListener(() => { // [!code ++]
// ... // [!code ++]
}); // [!code ++]
});
```
Refer to the [Entrypoint Loaders](/guide/essentials/config/entrypoint-loaders) documentation for more details.
### Bookmarks
[Chrome Docs](https://developer.chrome.com/docs/extensions/mv3/override/) • [Firefox Docs](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/chrome_url_overrides)
<EntrypointPatterns
:patterns="[
['bookmarks.html', 'bookmarks.html'],
['bookmarks/index.html', 'bookmarks.html'],
]"
/>
```html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Title</title>
<!-- Set include/exclude if the page should be removed from some builds -->
<meta name="manifest.include" content="['chrome', ...]" />
<meta name="manifest.exclude" content="['chrome', ...]" />
</head>
<body>
<!-- ... -->
</body>
</html>
```
When you define a Bookmarks entrypoint, WXT will automatically update the manifest to override the browser's bookmarks page with your own HTML page.
### Content Scripts
[Chrome Docs](https://developer.chrome.com/docs/extensions/mv3/content_scripts/) • [Firefox Docs](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_scripts)
<EntrypointPatterns
:patterns="[
['content.[jt]sx?', 'content-scripts/content.js'],
['content/index.[jt]sx?', 'content-scripts/content.js'],
['{name}.content.[jt]sx?', 'content-scripts/{name}.js'],
['{name}.content/index.[jt]sx?', 'content-scripts/{name}.js'],
]"
/>
```ts
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
},
});
```
When defining content script entrypoints, keep in mind that WXT will import this file in a NodeJS environment during the build process. That means you cannot place any runtime code outside the `main` function.
<!-- prettier-ignore -->
```ts
const container = document.createElement('div'); // [!code --]
document.body.append(container); // [!code --]
export default defineContentScript({
main: function () {
const container = document.createElement('div'); // [!code ++]
document.body.append(container); // [!code ++]
},
});
```
Refer to the [Entrypoint Loaders](/guide/essentials/config/entrypoint-loaders) documentation for more details.
See [Content Script UI](/guide/essentials/content-scripts) for more info on creating UIs and including CSS in content scripts.
### Devtools
[Chrome Docs](https://developer.chrome.com/docs/extensions/mv3/devtools/) • [Firefox Docs](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/devtools_page)
<EntrypointPatterns
:patterns="[
['devtools.html', 'devtools.html'],
['devtools/index.html', 'devtools.html'],
]"
/>
```html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- Set include/exclude if the page should be removed from some builds -->
<meta name="manifest.include" content="['chrome', ...]" />
<meta name="manifest.exclude" content="['chrome', ...]" />
</head>
<body>
<!-- ... -->
</body>
</html>
```
Follow the [Devtools Example](https://github.com/wxt-dev/examples/tree/main/examples/devtools-extension#readme) to add different panels and panes.
### History
[Chrome Docs](https://developer.chrome.com/docs/extensions/mv3/override/) • [Firefox Docs](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/chrome_url_overrides)
<EntrypointPatterns
:patterns="[
['history.html', 'history.html'],
['history/index.html', 'history.html'],
]"
/>
```html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Title</title>
<!-- Set include/exclude if the page should be removed from some builds -->
<meta name="manifest.include" content="['chrome', ...]" />
<meta name="manifest.exclude" content="['chrome', ...]" />
</head>
<body>
<!-- ... -->
</body>
</html>
```
When you define a History entrypoint, WXT will automatically update the manifest to override the browser's history page with your own HTML page.
### Newtab
[Chrome Docs](https://developer.chrome.com/docs/extensions/mv3/override/) • [Firefox Docs](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/chrome_url_overrides)
<EntrypointPatterns
:patterns="[
['newtab.html', 'newtab.html'],
['newtab/index.html', 'newtab.html'],
]"
/>
```html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Title</title>
<!-- Set include/exclude if the page should be removed from some builds -->
<meta name="manifest.include" content="['chrome', ...]" />
<meta name="manifest.exclude" content="['chrome', ...]" />
</head>
<body>
<!-- ... -->
</body>
</html>
```
When you define a Newtab entrypoint, WXT will automatically update the manifest to override the browser's new tab page with your own HTML page.
### Options
[Chrome Docs](https://developer.chrome.com/docs/extensions/mv3/options/) • [Firefox Docs](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/options_ui)
<EntrypointPatterns
:patterns="[
['options.html', 'options.html'],
['options/index.html', 'options.html'],
]"
/>
```html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Options Title</title>
<!-- Customize the manifest options -->
<meta name="manifest.open_in_tab" content="true|false" />
<meta name="manifest.chrome_style" content="true|false" />
<meta name="manifest.browser_style" content="true|false" />
<!-- Set include/exclude if the page should be removed from some builds -->
<meta name="manifest.include" content="['chrome', ...]" />
<meta name="manifest.exclude" content="['chrome', ...]" />
</head>
<body>
<!-- ... -->
</body>
</html>
```
### Popup
[Chrome Docs](https://developer.chrome.com/docs/extensions/reference/action/) • [Firefox Docs](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/action)
<EntrypointPatterns
:patterns="[
['popup.html', 'popup.html'],
['popup/index.html', 'popup.html'],
]"
/>
```html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- Set the `action.default_title` in the manifest -->
<title>Default Popup Title</title>
<!-- Customize the manifest options -->
<meta
name="manifest.default_icon"
content="{
16: '/icon-16.png',
24: '/icon-24.png',
...
}"
/>
<meta name="manifest.type" content="page_action|browser_action" />
<meta name="manifest.browser_style" content="true|false" />
<!-- Firefox only: where to place the action button -->
<meta
name="manifest.default_area"
content="navbar|menupanel|tabstrip|personaltoolbar"
/>
<!-- Firefox only: icons for light/dark themes -->
<meta
name="manifest.theme_icons"
content="[
{ light: '/icon-light-16.png', dark: '/icon-dark-16.png', size: 16 },
{ light: '/icon-light-32.png', dark: '/icon-dark-32.png', size: 32 }
]"
/>
<!-- Set include/exclude if the page should be removed from some builds -->
<meta name="manifest.include" content="['chrome', ...]" />
<meta name="manifest.exclude" content="['chrome', ...]" />
</head>
<body>
<!-- ... -->
</body>
</html>
```
### Sandbox
[Chrome Docs](https://developer.chrome.com/docs/extensions/mv3/manifest/sandbox/)
:::warning Chromium Only
Firefox does not support sandboxed pages.
:::
<EntrypointPatterns
:patterns="[
['sandbox.html', 'sandbox.html'],
['sandbox/index.html', 'sandbox.html'],
['{name}.sandbox.html', '{name}.html'],
['{name}.sandbox/index.html', '{name}.html'],
]"
/>
```html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Title</title>
<!-- Set include/exclude if the page should be removed from some builds -->
<meta name="manifest.include" content="['chrome', ...]" />
<meta name="manifest.exclude" content="['chrome', ...]" />
</head>
<body>
<!-- ... -->
</body>
</html>
```
### Side Panel
[Chrome Docs](https://developer.chrome.com/docs/extensions/reference/sidePanel/) • [Firefox Docs](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/user_interface/Sidebars)
<EntrypointPatterns
:patterns="[
['sidepanel.html', 'sidepanel.html'],
['sidepanel/index.html', 'sidepanel.html'],
['{name}.sidepanel.html', '{name}.html` '],
['{name}.sidepanel/index.html', '{name}.html` '],
]"
/>
```html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Default Side Panel Title</title>
<!-- Customize the manifest options -->
<meta
name="manifest.default_icon"
content="{
16: '/icon-16.png',
24: '/icon-24.png',
...
}"
/>
<meta name="manifest.open_at_install" content="true|false" />
<meta name="manifest.browser_style" content="true|false" />
<!-- Set include/exclude if the page should be removed from some builds -->
<meta name="manifest.include" content="['chrome', ...]" />
<meta name="manifest.exclude" content="['chrome', ...]" />
</head>
<body>
<!-- ... -->
</body>
</html>
```
In Chrome, side panels use the `side_panel` API, while Firefox uses the `sidebar_action` API.
### Unlisted CSS
<EntrypointPatterns
:patterns="[
['{name}.(css|scss|sass|less|styl|stylus)', '{name}.css'],
['{name}/index.(css|scss|sass|less|styl|stylus)', '{name}.css'],
['content.(css|scss|sass|less|styl|stylus)', 'content-scripts/content.css'],
['content/index.(css|scss|sass|less|styl|stylus)', 'content-scripts/content.css'],
['{name}.content.(css|scss|sass|less|styl|stylus)', 'content-scripts/{name}.css'],
['{name}.content/index.(css|scss|sass|less|styl|stylus)', 'content-scripts/{name}.css'],
]"
/>
```css
body {
/* ... */
}
```
Follow Vite's guide to setup your preprocessor of choice: <https://vitejs.dev/guide/features.html#css-pre-processors>
CSS entrypoints are always unlisted. To add CSS to a content script, see the [Content Script](/guide/essentials/content-scripts#css) docs.
### Unlisted Pages
<EntrypointPatterns
:patterns="[
['{name}.html', '{name}.html'],
['{name}/index.html', '{name}.html'],
]"
/>
```html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Title</title>
<!-- Set include/exclude if the page should be removed from some builds -->
<meta name="manifest.include" content="['chrome', ...]" />
<meta name="manifest.exclude" content="['chrome', ...]" />
</head>
<body>
<!-- ... -->
</body>
</html>
```
At runtime, unlisted pages are accessible at `/{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
```
### Unlisted Scripts
<EntrypointPatterns
:patterns="[
['{name}.[jt]sx?', '{name}.js'],
['{name}/index.[jt]sx?', '{name}.js'],
]"
/>
:::code-group
```ts [Minimal]
export default defineUnlistedScript(() => {
// Executed when script is loaded
});
```
```ts [With Options]
export default defineUnlistedScript({
// Set include/exclude if the script should be removed from some builds
include: undefined | string[],
exclude: undefined | string[],
main() {
// Executed when script is loaded
},
});
```
:::
At runtime, unlisted scripts are accessible from `/{name}.js`:
```ts
const url = browser.runtime.getURL('/{name}.js');
console.log(url); // "chrome-extension://{id}/{name}.js"
```
You are responsible for loading/running these scripts where needed. If necessary, don't forget to add the script and/or any related assets to [`web_accessible_resources`](https://developer.chrome.com/docs/extensions/reference/manifest/web-accessible-resources).
When defining an unlisted script, keep in mind that WXT will import this file in a NodeJS environment during the build process. That means you cannot place any runtime code outside the `main` function.
<!-- prettier-ignore -->
```ts
document.querySelectorAll('a').forEach((anchor) => { // [!code --]
// ... // [!code --]
}); // [!code --]
export default defineUnlistedScript(() => {
document.querySelectorAll('a').forEach((anchor) => { // [!code ++]
// ... // [!code ++]
}); // [!code ++]
});
```
Refer to the [Entrypoint Loaders](/guide/essentials/config/entrypoint-loaders) documentation for more details.
================================================
FILE: docs/guide/essentials/es-modules.md
================================================
# ES Modules
Your source code should always be written as ESM. However, you have some control whether an entrypoint is bundled as ESM.
## HTML Pages <Badge type="warning" text="≥0.0.1" />
Vite only supports bundling JS from HTML pages as ESM. Ensure you have added `type="module"` to your `<script>` tags:
<!-- prettier-ignore -->
```html
<script src="./main.ts"></script> <!-- [!code --] -->
<script src="./main.ts" type="module"></script> <!-- [!code ++] -->
```
## Background <Badge type="warning" text="≥0.16.0" />
By default, your background will be bundled into a single file as IIFE. You can change this by setting `type: "module"` in your background entrypoint:
```ts
export default defineBackground({
type: 'module', // [!code ++]
main() {
// ...
},
});
```
This will change the output format to ESM, enable code-spliting between your background script and HTML pages, and set `"type": "module"` in your manifest.
:::warning
Only MV3 supports ESM background scripts/service workers. When targeting MV2, the `type` option is ignored and the background is always bundled into a single file as IIFE.
:::
## Content Scripts
WXT does not yet include built-in support for bundling content scripts as ESM. The plan is to add support for chunking to reduce bundle size, but not support HMR for now. There are several technical issues that make implementing a generic solution for HMR impossible. See [Content Script ESM Support #357](https://github.com/wxt-dev/wxt/issues/357) for details.
If you can't wait, and need ESM support right now, you can implement ESM support manually. See the [ESM Content Script UI](https://github.com/wxt-dev/examples/tree/main/examples/esm-content-script-ui) example to learn how.
================================================
FILE: docs/guide/essentials/extension-apis.md
================================================
# Extension APIs
[Chrome Docs](https://developer.chrome.com/docs/extensions/reference/api) • [Firefox Docs](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Browser_support_for_JavaScript_APIs)
Different browsers provide different global variables for accessing the extension APIs (chrome provides `chrome`, firefox provides `browser`, etc).
WXT merges these two into a unified API accessed through the `browser` variable.
```ts
import { browser } from 'wxt/browser';
browser.action.onClicked.addListener(() => {
// ...
});
```
:::tip
With auto-imports enabled, you don't even need to import this variable from `wxt/browser`!
:::
The `browser` variable WXT provides is a simple export of the `browser` or `chrome` globals provided by the browser at runtime:
<<< @/../packages/browser/src/index.mjs#snippet
This means you can use the promise-style API for both MV2 and MV3, and it will work across all browsers (Chromium, Firefox, Safari, etc).
## Accessing Types
All types can be accessed via WXT's `Browser` namespace:
```ts
import { type Browser } from 'wxt/browser';
function handleMessage(message: any, sender: Browser.runtime.MessageSender) {
// ...
}
```
## Using `webextension-polyfill`
If you want to use the `webextension-polyfill` when importing `browser`, you can do so by installing the `@wxt-dev/webextension-polyfill` package.
See it's [Installation Guide](https://github.com/wxt-dev/wxt/blob/main/packages/webextension-polyfill/README.md) to get started.
## Feature Detection
Depending on the manifest version, browser, and permissions, some APIs are not available at runtime. If an API is not available, it will be `undefined`.
:::warning
Types will not help you here. The types WXT provides for `browser` assume all APIs exist. You are responsible for knowing whether an API is available or not.
:::
To check if an API is available, use feature detection:
```ts
if (browser.runtime.onSuspend != null) {
browser.runtime.onSuspend.addListener(() => {
// ...
});
}
```
Here, [optional chaining](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining) is your best friend:
```ts
browser.runtime.onSuspend?.addListener(() => {
// ...
});
```
Alternatively, if you're trying to use similar APIs under different names (to support MV2 and MV3), you can do something like this:
```ts
(browser.action ?? browser.browser_action).onClicked.addListener(() => {
//
});
```
### Augmenting the Browser Type
WXT's `browser` types are based on the `@types/chrome` package. That means some Firefox-specific APIs may not be typed, like `browser.sidebarAction`. If you want to add types for these APIs, you can augment the browser type to add them yourself:
```ts
// <srcDir>/browser-types.d.ts
import '@wxt-dev/browser';
import type { SidebarAction } from 'webextension-polyfill';
declare module '@wxt-dev/browser' {
namespace Browser {
export const sidebarAction: SidebarAction.Static;
}
}
```
> For this to work, you may need to install `@wxt-dev/browser` as a direct dependency.
>
> ```sh
> pnpm add @wxt-dev/browser
> ```
## Entrypoint Limitations
Because WXT imports your entrypoint files into a NodeJS, non-extension environment, the `chrome`/`browser` variables provided to extensions by the browser **will not be available**.
To prevent some basic errors, WXT polyfills these globals with the same in-memory, fake implementation it uses for testing: [`@webext-core/fake-browser`](https://webext-core.aklinker1.io/fake-browser/installation/). However, not all the APIs have been implemented.
So it is extremely important to NEVER use `browser.*` extension APIs outside the main function of any JS/TS entrypoints (background, content scripts, and unlisted scripts). If you do, you'll see an error like this:
```plaintext
✖ Command failed after 440 ms
ERROR Browser.action.onClicked.addListener not implemented.
```
The fix is simple, just move your API usage into the entrypoint's main function:
:::code-group
```ts [background.ts]
browser.action.onClicked.addListener(() => {
/* ... */
}); // [!code --]
export default defineBackground(() => {
browser.action.onClicked.addListener(() => {
/* ... */
}); // [!code ++]
});
```
```ts [content.ts]
browser.runtime.onMessage.addListener(() => {
/* ... */
}); // [!code --]
export default defineContentScript({
main() {
browser.runtime.onMessage.addListener(() => {
/* ... */
}); // [!code ++]
},
});
```
```ts [unlisted.ts]
browser.runtime.onMessage.addListener(() => {
/* ... */
}); // [!code --]
export default defineUnlistedScript(() => {
browser.runtime.onMessage.addListener(() => {
/* ... */
}); // [!code ++]
});
```
:::
Read [Entrypoint Loaders](/guide/essentials/config/entrypoint-loaders) for more technical details about this limitation.
================================================
FILE: docs/guide/essentials/frontend-frameworks.md
================================================
# Frontend Frameworks
## Built-in Modules
WXT has preconfigured modules for the most popular frontend frameworks:
- [`@wxt-dev/module-react`](https://github.com/wxt-dev/wxt/tree/main/packages/module-react)
- [`@wxt-dev/module-vue`](https://github.com/wxt-dev/wxt/tree/main/packages/module-vue)
- [`@wxt-dev/module-svelte`](https://github.com/wxt-dev/wxt/tree/main/packages/module-svelte)
- [`@wxt-dev/module-solid`](https://github.com/wxt-dev/wxt/tree/main/packages/module-solid)
Install the module for your framework, then add it to your config:
:::code-group
```ts [React]
import { defineConfig } from 'wxt';
export default defineConfig({
modules: ['@wxt-dev/module-react'],
});
```
```ts [Vue]
import { defineConfig } from 'wxt';
export default defineConfig({
modules: ['@wxt-dev/module-vue'],
});
```
```ts [Svelte]
import { defineConfig } from 'wxt';
export default defineConfig({
modules: ['@wxt-dev/module-svelte'],
});
```
```ts [Solid]
import { defineConfig } from 'wxt';
export default defineConfig({
modules: ['@wxt-dev/module-solid'],
});
```
:::
## Adding Vite Plugins
If your framework doesn't have an official WXT module, no worries! WXT supports any framework with a Vite plugin.
Just add the Vite plugin to your config and you're good to go! Use the framework in HTML pages or content scripts and it will just work 👍
```ts
import { defineConfig } from 'wxt';
import react from '@vitejs/plugin-react';
export default defineConfig({
vite: () => ({
plugins: [react()],
}),
});
```
> The WXT modules just simplify the configuration and add auto-imports. They're not much different than the above.
## Multiple Apps
Since web extensions usually contain multiple UIs across multiple entrypoints (popup, options, changelog, side panel, content scripts, etc), you'll need to create individual app instances, one per entrypoint.
Usually, this means each entrypoint should be a directory with it's own files inside it. Here's the recommended folder structure:
<!-- prettier-ignore -->
```html
📂 {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
```
## Configuring Routers
All frameworks come with routers for building a multi-page app using the URL's path... But web extensions don't work like this. Since HTML files are static, `chrome-extension://{id}/popup.html`, there's no way to change the entire path for routing.
Instead, you need to configure the router to run in "hash" mode, where the routing information is a part of the URL's hash, not the path (ie: `popup.html#/` and `popup.html#/account/settings`).
Refer to your router's docs for information about hash mode and how to enable it. Here's a non-extensive list of a few popular routers:
- [`react-router`](https://reactrouter.com/en/main/routers/create-hash-router)
- [`vue-router`](https://router.vuejs.org/guide/essentials/history-mode.html#Hash-Mode)
- [`svelte-spa-router`](https://www.npmjs.com/package/svelte-spa-router#hash-based-routing)
- [`solid-router`](https://github.com/solidjs/solid-router?tab=readme-ov-file#hash-mode-router)
================================================
FILE: docs/guide/essentials/i18n.md
================================================
# I18n
[Chrome Docs](https://developer.chrome.com/docs/extensions/reference/api/i18n) • [Firefox Docs](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/i18n)
This page discusses how to setup internationalization using the vanilla `browser.i18n` APIs and mentions some alternatives if you want to use something else.
[[toc]]
## Usage
1. Add `default_locale` to your manifest:
```ts
export default defineConfig({
manifest: {
default_locale: 'en',
},
});
```
2. Create `messages.json` files in the `public/` directory:
<!-- prettier-ignore -->
```html
📂 {rootDir}/
📂 public/
📂 _locales/
📂 en/
📄 messages.json
📂 de/
📄 messages.json
📂 ko/
📄 messages.json
```
```jsonc
// public/_locales/en/messages.json
{
"helloWorld": {
"message": "Hello world!",
},
}
```
3. Get the translation:
```ts
browser.i18n.getMessage('helloWorld');
```
4. _Optional_: Add translations for extension name and description:
```json
{
"extName": {
"message": "..."
},
"extDescription": {
"message": "..."
},
"helloWorld": {
"message": "Hello world!"
}
}
```
```ts
export default defineConfig({
manifest: {
name: '__MSG_extName__',
description: '__MSG_extDescription__',
default_locale: 'en',
},
});
```
## Alternatives
The vanilla API has very few features, which is why you may want to consider using third-party NPM packages like `i18next`, `react-i18n`, `vue-i18n`, etc.
However, it is recommended you stick with the vanilla API (or a package based on top of the vanilla API, like [`@wxt-dev/i18n`](/i18n)), because:
- They can localize text in your manifest and CSS files
- Translations are loaded synchronously
- Translations are not bundled multiple times, keeping your extension small
- Zero configuration
However, there is one major downside to the vanilla API and any packages built on top of it:
- Language cannot be changed without changing your browser/system language
Here are some examples of how to setup a third party i18n library:
- [vue-i18n](https://github.com/wxt-dev/wxt-examples/tree/main/examples/vue-i18n)
================================================
FILE: docs/guide/essentials/messaging.md
================================================
# Messaging
[Chrome Docs](https://developer.chrome.com/docs/extensions/develop/concepts/messaging) • [Firefox Docs](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_scripts#communicating_with_background_scripts)
Read the docs linked above to learn more about using the vanilla messaging APIs.
## Alternatives
The vanilla APIs are difficult to use and are a pain point to many new extension developers. For this reason, WXT recommends installing an NPM package that wraps around the vanilla APIs.
Here are some popular messaging libraries that support all browsers and work with WXT:
- [`trpc-chrome`](https://www.npmjs.com/package/trpc-chrome) - [tRPC](https://trpc.io/) adapter for Web Extensions.
- [`webext-bridge`](https://www.npmjs.com/package/webext-bridge) - Messaging in WebExtensions made super easy. Out of the box.
- [`@webext-core/messaging`](https://www.npmjs.com/package/@webext-core/messaging) - Light weight, type-safe wrapper around the web extension messaging APIs
- [`@webext-core/proxy-service`](https://www.npmjs.com/package/@webext-core/proxy-service) - A type-safe wrapper around the web extension messaging APIs that lets you call a function from anywhere, but execute it in the background.
- [`Comctx`](https://github.com/molvqingtai/comctx) - Cross-context RPC solution with type safety and flexible adapters.
================================================
FILE: docs/guide/essentials/project-structure.md
================================================
# Project Structure
WXT follows a strict project structure. By default, it's a flat folder structure that looks like this:
<!-- prettier-ignore -->
```html
📂 {rootDir}/
📁 .output/
📁 .wxt/
📁 assets/
📁 components/
📁 composables/
📁 entrypoints/
📁 hook
gitextract_x35r4j0y/ ├── .codecov.yml ├── .commitlintrc.yml ├── .gitattributes ├── .github/ │ ├── CODEOWNERS │ ├── FUNDING.yml │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.yml │ │ ├── config.yml │ │ └── feature_request.md │ ├── actions/ │ │ └── setup/ │ │ └── action.yml │ ├── dependabot.yml │ ├── pull_request_template.md │ └── workflows/ │ ├── auto-label.yml │ ├── notify-unreleased-commits.yml │ ├── pkg.pr.new.yml │ ├── pr-closed.yml │ ├── pr-title.yml │ ├── publish-docs.yml │ ├── release.yml │ ├── sync-releases.yml │ ├── update-browser-package.yml │ ├── validate.yml │ └── vhs.yml ├── .gitignore ├── .markdownlint.json ├── .markdownlintignore ├── .prettierignore ├── .prettierrc.yml ├── .vscode/ │ ├── extensions.json │ └── settings.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── MAINTAINERS.md ├── README.md ├── SECURITY.md ├── docs/ │ ├── .vitepress/ │ │ ├── Dockerfile │ │ ├── components/ │ │ │ ├── BlogHome.vue │ │ │ ├── BlogLayout.vue │ │ │ ├── BlogPostPreview.vue │ │ │ ├── EntrypointPatterns.vue │ │ │ ├── ExampleSearch.vue │ │ │ ├── ExampleSearchFilterByItem.vue │ │ │ ├── ExampleSearchResult.vue │ │ │ ├── Icon.vue │ │ │ └── UsingWxtSection.vue │ │ ├── composables/ │ │ │ ├── useBlogDate.ts │ │ │ └── useListExtensionDetails.ts │ │ ├── config.ts │ │ ├── loaders/ │ │ │ ├── blog.data.ts │ │ │ └── cli.data.ts │ │ ├── theme/ │ │ │ ├── custom.css │ │ │ └── index.ts │ │ └── utils/ │ │ ├── head.ts │ │ ├── menus.ts │ │ └── types.ts │ ├── analytics.md │ ├── api/ │ │ └── cli/ │ │ ├── wxt-build.md │ │ ├── wxt-clean.md │ │ ├── wxt-init.md │ │ ├── wxt-prepare.md │ │ ├── wxt-submit-init.md │ │ ├── wxt-submit.md │ │ ├── wxt-zip.md │ │ └── wxt.md │ ├── auto-icons.md │ ├── blog/ │ │ ├── .drafts/ │ │ │ └── 2024-10-19-real-world-messaging.md │ │ └── 2024-12-06-using-imports-module.md │ ├── blog.md │ ├── examples.md │ ├── guide/ │ │ ├── essentials/ │ │ │ ├── assets.md │ │ │ ├── config/ │ │ │ │ ├── auto-imports.md │ │ │ │ ├── browser-startup.md │ │ │ │ ├── build-mode.md │ │ │ │ ├── entrypoint-loaders.md │ │ │ │ ├── environment-variables.md │ │ │ │ ├── hooks.md │ │ │ │ ├── manifest.md │ │ │ │ ├── runtime.md │ │ │ │ ├── typescript.md │ │ │ │ └── vite.md │ │ │ ├── content-scripts.md │ │ │ ├── e2e-testing.md │ │ │ ├── entrypoints.md │ │ │ ├── es-modules.md │ │ │ ├── extension-apis.md │ │ │ ├── frontend-frameworks.md │ │ │ ├── i18n.md │ │ │ ├── messaging.md │ │ │ ├── project-structure.md │ │ │ ├── publishing.md │ │ │ ├── remote-code.md │ │ │ ├── scripting.md │ │ │ ├── storage.md │ │ │ ├── target-different-browsers.md │ │ │ ├── testing-updates.md │ │ │ ├── unit-testing.md │ │ │ └── wxt-modules.md │ │ ├── installation.md │ │ ├── introduction.md │ │ └── resources/ │ │ ├── community.md │ │ ├── compare.md │ │ ├── faq.md │ │ ├── how-wxt-works.md │ │ ├── migrate.md │ │ └── upgrading.md │ ├── i18n.md │ ├── index.md │ ├── is-background.md │ ├── public/ │ │ ├── _redirects │ │ └── robots.txt │ ├── runner.md │ ├── storage.md │ ├── tapes/ │ │ └── init-demo.tape │ ├── typedoc.json │ └── unocss.md ├── package.json ├── packages/ │ ├── analytics/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── app.config.ts │ │ ├── entrypoints/ │ │ │ └── popup/ │ │ │ ├── index.html │ │ │ └── main.ts │ │ ├── modules/ │ │ │ └── analytics/ │ │ │ ├── background-plugin.ts │ │ │ ├── client.ts │ │ │ ├── index.ts │ │ │ ├── providers/ │ │ │ │ ├── google-analytics-4.ts │ │ │ │ └── umami.ts │ │ │ └── types.ts │ │ ├── package.json │ │ ├── public/ │ │ │ └── .keep │ │ ├── tsconfig.json │ │ ├── tsdown.config.ts │ │ └── wxt.config.ts │ ├── auto-icons/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── package.json │ │ ├── src/ │ │ │ ├── __test__/ │ │ │ │ └── index.test.ts │ │ │ └── index.ts │ │ ├── tsconfig.json │ │ └── vitest.config.ts │ ├── browser/ │ │ ├── README.md │ │ ├── package.json │ │ ├── scripts/ │ │ │ └── generate.ts │ │ ├── src/ │ │ │ ├── __tests__/ │ │ │ │ └── index.test.ts │ │ │ ├── gen/ │ │ │ │ ├── chrome-cast/ │ │ │ │ │ └── index.d.ts │ │ │ │ ├── har-format/ │ │ │ │ │ └── index.d.ts │ │ │ │ └── index.d.ts │ │ │ ├── index.d.ts │ │ │ └── index.mjs │ │ ├── templates/ │ │ │ └── package.json │ │ └── tsconfig.json │ ├── i18n/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── package.json │ │ ├── src/ │ │ │ ├── __tests__/ │ │ │ │ ├── build.test.ts │ │ │ │ ├── index.test.ts │ │ │ │ ├── types.test.ts │ │ │ │ └── utils.test.ts │ │ │ ├── build.ts │ │ │ ├── index.ts │ │ │ ├── module.ts │ │ │ ├── supported-locales.ts │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ ├── tsconfig.json │ │ ├── tsdown.config.ts │ │ └── vitest.config.ts │ ├── is-background/ │ │ ├── README.md │ │ ├── package.json │ │ ├── src/ │ │ │ ├── __tests__/ │ │ │ │ └── getter.test.ts │ │ │ ├── getter.ts │ │ │ └── index.ts │ │ └── tsconfig.json │ ├── module-react/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── components/ │ │ │ └── App.tsx │ │ ├── entrypoints/ │ │ │ ├── content/ │ │ │ │ └── index.tsx │ │ │ └── popup/ │ │ │ ├── index.html │ │ │ └── main.tsx │ │ ├── modules/ │ │ │ └── react.ts │ │ ├── package.json │ │ ├── public/ │ │ │ └── .keep │ │ ├── tsconfig.json │ │ └── tsdown.config.ts │ ├── module-solid/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── components/ │ │ │ └── App.tsx │ │ ├── entrypoints/ │ │ │ ├── content/ │ │ │ │ └── index.tsx │ │ │ └── popup/ │ │ │ ├── index.html │ │ │ └── main.tsx │ │ ├── modules/ │ │ │ └── solid.ts │ │ ├── package.json │ │ ├── public/ │ │ │ └── .keep │ │ ├── tsconfig.json │ │ └── tsdown.config.ts │ ├── module-svelte/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── package.json │ │ ├── src/ │ │ │ └── index.ts │ │ ├── tsconfig.json │ │ └── tsdown.config.ts │ ├── module-vue/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── package.json │ │ ├── src/ │ │ │ └── index.ts │ │ ├── tsconfig.json │ │ └── tsdown.config.ts │ ├── runner/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── demo-extension/ │ │ │ ├── background.js │ │ │ └── manifest.json │ │ ├── dev.ts │ │ ├── package.json │ │ ├── src/ │ │ │ ├── __tests__/ │ │ │ │ ├── install.test.ts │ │ │ │ └── options.test.ts │ │ │ ├── bidi.ts │ │ │ ├── browser-paths.ts │ │ │ ├── cdp.ts │ │ │ ├── debug.ts │ │ │ ├── index.ts │ │ │ ├── install.ts │ │ │ ├── options.ts │ │ │ ├── promises.ts │ │ │ ├── run.ts │ │ │ └── web-socket.ts │ │ ├── tsconfig.json │ │ └── vitest.config.ts │ ├── storage/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── package.json │ │ ├── src/ │ │ │ ├── __tests__/ │ │ │ │ └── index.test.ts │ │ │ └── index.ts │ │ ├── tsconfig.json │ │ ├── vitest.config.ts │ │ └── vitest.setup.ts │ ├── unocss/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── package.json │ │ ├── src/ │ │ │ └── index.ts │ │ └── tsconfig.json │ ├── webextension-polyfill/ │ │ ├── README.md │ │ ├── entrypoints/ │ │ │ ├── content/ │ │ │ │ └── index.ts │ │ │ └── popup/ │ │ │ ├── index.html │ │ │ └── main.ts │ │ ├── modules/ │ │ │ └── webextension-polyfill/ │ │ │ ├── browser.ts │ │ │ └── index.ts │ │ ├── package.json │ │ ├── public/ │ │ │ └── .keep │ │ ├── tsconfig.json │ │ └── tsdown.config.ts │ ├── wxt/ │ │ ├── .oxlintignore │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── bin/ │ │ │ ├── wxt-publish-extension.mjs │ │ │ └── wxt.mjs │ │ ├── e2e/ │ │ │ ├── tests/ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── auto-imports.test.ts.snap │ │ │ │ ├── analysis.test.ts │ │ │ │ ├── auto-imports.test.ts │ │ │ │ ├── dev.test.ts │ │ │ │ ├── encoding.test.ts │ │ │ │ ├── hooks.test.ts │ │ │ │ ├── init.test.ts │ │ │ │ ├── manifest-content.test.ts │ │ │ │ ├── modules.test.ts │ │ │ │ ├── npm-packages.test.ts │ │ │ │ ├── output-structure.test.ts │ │ │ │ ├── react.test.ts │ │ │ │ ├── remote-code.test.ts │ │ │ │ ├── typescript-project.test.ts │ │ │ │ ├── user-config.test.ts │ │ │ │ └── zip.test.ts │ │ │ └── utils.ts │ │ ├── globals.d.ts │ │ ├── package.json │ │ ├── src/ │ │ │ ├── @types/ │ │ │ │ ├── globals.d.ts │ │ │ │ ├── modules.d.ts │ │ │ │ └── project-types.d.ts │ │ │ ├── __tests__/ │ │ │ │ └── modules.test.ts │ │ │ ├── browser.ts │ │ │ ├── builtin-modules/ │ │ │ │ ├── index.ts │ │ │ │ └── unimport.ts │ │ │ ├── cli/ │ │ │ │ ├── __tests__/ │ │ │ │ │ └── index.test.ts │ │ │ │ ├── cli-utils.ts │ │ │ │ ├── commands.ts │ │ │ │ └── index.ts │ │ │ ├── core/ │ │ │ │ ├── build.ts │ │ │ │ ├── builders/ │ │ │ │ │ └── vite/ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ └── fixtures/ │ │ │ │ │ │ ├── module.ts │ │ │ │ │ │ └── test.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── plugins/ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ ├── devHtmlPrerender.test.ts │ │ │ │ │ │ └── iifeFooter.test.ts │ │ │ │ │ ├── bundleAnalysis.ts │ │ │ │ │ ├── cssEntrypoints.ts │ │ │ │ │ ├── defineImportMeta.ts │ │ │ │ │ ├── devHtmlPrerender.ts │ │ │ │ │ ├── devServerGlobals.ts │ │ │ │ │ ├── download.ts │ │ │ │ │ ├── entrypointGroupGlobals.ts │ │ │ │ │ ├── extensionApiMock.ts │ │ │ │ │ ├── globals.ts │ │ │ │ │ ├── iifeAnonymous.ts │ │ │ │ │ ├── iifeFooter.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── noopBackground.ts │ │ │ │ │ ├── removeEntrypointMainFunction.ts │ │ │ │ │ ├── resolveAppConfig.ts │ │ │ │ │ ├── resolveVirtualModules.ts │ │ │ │ │ ├── tsconfigPaths.ts │ │ │ │ │ └── wxtPluginLoader.ts │ │ │ │ ├── clean.ts │ │ │ │ ├── create-server.ts │ │ │ │ ├── define-config.ts │ │ │ │ ├── define-web-ext-config.ts │ │ │ │ ├── generate-wxt-dir.ts │ │ │ │ ├── index.ts │ │ │ │ ├── initialize.ts │ │ │ │ ├── keyboard-shortcuts.ts │ │ │ │ ├── package-managers/ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ ├── bun.test.ts │ │ │ │ │ │ ├── fixtures/ │ │ │ │ │ │ │ ├── simple-bun-project/ │ │ │ │ │ │ │ │ ├── bun.lockb │ │ │ │ │ │ │ │ └── package.json │ │ │ │ │ │ │ ├── simple-npm-project/ │ │ │ │ │ │ │ │ └── package.json │ │ │ │ │ │ │ ├── simple-pnpm-project/ │ │ │ │ │ │ │ │ └── package.json │ │ │ │ │ │ │ └── simple-yarn-project/ │ │ │ │ │ │ │ └── package.json │ │ │ │ │ │ ├── npm.test.ts │ │ │ │ │ │ ├── pnpm.test.ts │ │ │ │ │ │ └── yarn.test.ts │ │ │ │ │ ├── bun.ts │ │ │ │ │ ├── deno.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── npm.ts │ │ │ │ │ ├── pnpm.ts │ │ │ │ │ ├── types.ts │ │ │ │ │ └── yarn.ts │ │ │ │ ├── prepare.ts │ │ │ │ ├── resolve-config.ts │ │ │ │ ├── runners/ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ └── index.test.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── manual.ts │ │ │ │ │ ├── safari.ts │ │ │ │ │ ├── web-ext.ts │ │ │ │ │ └── wsl.ts │ │ │ │ ├── utils/ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ ├── arrays.test.ts │ │ │ │ │ │ ├── content-scripts.test.ts │ │ │ │ │ │ ├── content-security-policy.test.ts │ │ │ │ │ │ ├── entrypoints.test.ts │ │ │ │ │ │ ├── manifest.test.ts │ │ │ │ │ │ ├── network.test.ts │ │ │ │ │ │ ├── number.test.ts │ │ │ │ │ │ ├── package.test.ts │ │ │ │ │ │ ├── paths.test.ts │ │ │ │ │ │ ├── picomatch-multiple.test.ts │ │ │ │ │ │ ├── strings.test.ts │ │ │ │ │ │ ├── transform.test.ts │ │ │ │ │ │ ├── validation.test.ts │ │ │ │ │ │ └── virtual-modules.test.ts │ │ │ │ │ ├── arrays.ts │ │ │ │ │ ├── building/ │ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ │ ├── detect-dev-changes.test.ts │ │ │ │ │ │ │ ├── find-entrypoints.test.ts │ │ │ │ │ │ │ ├── group-entrypoints.test.ts │ │ │ │ │ │ │ └── test-entrypoints/ │ │ │ │ │ │ │ ├── background.ts │ │ │ │ │ │ │ ├── content.ts │ │ │ │ │ │ │ ├── imported-option.ts │ │ │ │ │ │ │ ├── no-default-export.ts │ │ │ │ │ │ │ ├── react.tsx │ │ │ │ │ │ │ ├── unlisted.ts │ │ │ │ │ │ │ └── with-named.ts │ │ │ │ │ │ ├── build-entrypoints.ts │ │ │ │ │ │ ├── detect-dev-changes.ts │ │ │ │ │ │ ├── find-entrypoints.ts │ │ │ │ │ │ ├── group-entrypoints.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── internal-build.ts │ │ │ │ │ │ └── rebuild.ts │ │ │ │ │ ├── cache.ts │ │ │ │ │ ├── cli.ts │ │ │ │ │ ├── constants.ts │ │ │ │ │ ├── content-scripts.ts │ │ │ │ │ ├── content-security-policy.ts │ │ │ │ │ ├── entrypoints.ts │ │ │ │ │ ├── env.ts │ │ │ │ │ ├── environments/ │ │ │ │ │ │ ├── browser-environment.ts │ │ │ │ │ │ ├── environment.ts │ │ │ │ │ │ ├── extension-environment.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── eslint.ts │ │ │ │ │ ├── fs.ts │ │ │ │ │ ├── globals.ts │ │ │ │ │ ├── i18n.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── log/ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── printBuildSummary.ts │ │ │ │ │ │ ├── printFileList.ts │ │ │ │ │ │ ├── printHeader.ts │ │ │ │ │ │ └── printTable.ts │ │ │ │ │ ├── manifest.ts │ │ │ │ │ ├── network.ts │ │ │ │ │ ├── number.ts │ │ │ │ │ ├── package.ts │ │ │ │ │ ├── paths.ts │ │ │ │ │ ├── picomatch-multiple.ts │ │ │ │ │ ├── strings.ts │ │ │ │ │ ├── syntax-errors.ts │ │ │ │ │ ├── testing/ │ │ │ │ │ │ └── fake-objects.ts │ │ │ │ │ ├── time.ts │ │ │ │ │ ├── transform.ts │ │ │ │ │ ├── types.ts │ │ │ │ │ ├── validation.ts │ │ │ │ │ ├── virtual-modules.ts │ │ │ │ │ └── wsl.ts │ │ │ │ ├── wxt.ts │ │ │ │ └── zip.ts │ │ │ ├── index.ts │ │ │ ├── modules.ts │ │ │ ├── testing/ │ │ │ │ ├── fake-browser.ts │ │ │ │ ├── index.ts │ │ │ │ └── wxt-vitest-plugin.ts │ │ │ ├── types.ts │ │ │ ├── utils/ │ │ │ │ ├── README.md │ │ │ │ ├── __tests__/ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── split-shadow-root-css.test.ts.snap │ │ │ │ │ ├── content-script-context.test.ts │ │ │ │ │ ├── define-background.test.ts │ │ │ │ │ ├── define-content-script.test.ts │ │ │ │ │ ├── define-unlisted-script.test.ts │ │ │ │ │ └── split-shadow-root-css.test.ts │ │ │ │ ├── app-config.ts │ │ │ │ ├── content-script-context.ts │ │ │ │ ├── content-script-ui/ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ └── index.test.ts │ │ │ │ │ ├── iframe.ts │ │ │ │ │ ├── integrated.ts │ │ │ │ │ ├── shadow-root.ts │ │ │ │ │ ├── shared.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── define-app-config.ts │ │ │ │ ├── define-background.ts │ │ │ │ ├── define-content-script.ts │ │ │ │ ├── define-unlisted-script.ts │ │ │ │ ├── define-wxt-plugin.ts │ │ │ │ ├── inject-script.ts │ │ │ │ ├── internal/ │ │ │ │ │ ├── custom-events.ts │ │ │ │ │ ├── dev-server-websocket.ts │ │ │ │ │ ├── location-watcher.ts │ │ │ │ │ └── logger.ts │ │ │ │ ├── match-patterns.ts │ │ │ │ ├── split-shadow-root-css.ts │ │ │ │ └── storage.ts │ │ │ ├── version.ts │ │ │ ├── virtual/ │ │ │ │ ├── README.md │ │ │ │ ├── background-entrypoint.ts │ │ │ │ ├── content-script-isolated-world-entrypoint.ts │ │ │ │ ├── content-script-main-world-entrypoint.ts │ │ │ │ ├── mock-browser.ts │ │ │ │ ├── reload-html.ts │ │ │ │ ├── tsconfig.json │ │ │ │ ├── unlisted-script-entrypoint.ts │ │ │ │ ├── utils/ │ │ │ │ │ ├── keep-service-worker-alive.ts │ │ │ │ │ └── reload-content-scripts.ts │ │ │ │ └── virtual-module-globals.d.ts │ │ │ └── vite-builder-env.d.ts │ │ ├── tsconfig.json │ │ ├── tsdown.config.ts │ │ ├── typedoc.json │ │ ├── vitest.config.ts │ │ ├── vitest.globalSetup.ts │ │ └── vitest.setup.ts │ └── wxt-demo/ │ ├── eslint.config.js │ ├── modules/ │ │ ├── auto-icons.ts │ │ ├── example.ts │ │ ├── i18n.ts │ │ └── unocss.ts │ ├── package.json │ ├── src/ │ │ ├── app.config.ts │ │ ├── entrypoints/ │ │ │ ├── __tests__/ │ │ │ │ └── background.test.ts │ │ │ ├── automount.content/ │ │ │ │ ├── index.ts │ │ │ │ └── style.css │ │ │ ├── background.ts │ │ │ ├── example-2.scss │ │ │ ├── example-tsx.content.tsx │ │ │ ├── example.sandbox/ │ │ │ │ └── index.html │ │ │ ├── iframe-src/ │ │ │ │ ├── index.html │ │ │ │ └── main.ts │ │ │ ├── iframe.content.ts │ │ │ ├── injected.content/ │ │ │ │ └── index.css │ │ │ ├── location-change.content.ts │ │ │ ├── main-world.content.ts │ │ │ ├── options/ │ │ │ │ ├── index.html │ │ │ │ ├── main.ts │ │ │ │ └── style.css │ │ │ ├── popup.html │ │ │ ├── sandbox.html │ │ │ ├── sidepanel.html │ │ │ ├── ui.content/ │ │ │ │ ├── index.ts │ │ │ │ ├── manual-style.css │ │ │ │ └── style.css │ │ │ └── unlisted.ts │ │ ├── locales/ │ │ │ └── en.yml │ │ └── utils/ │ │ └── logger.ts │ ├── tsconfig.json │ ├── vitest.config.ts │ └── wxt.config.ts ├── patches/ │ ├── markdown-it-footnote.md │ └── markdown-it-footnote.patch ├── pnpm-workspace.yaml ├── scripts/ │ ├── benchmarks/ │ │ ├── browser-startup.patch │ │ └── browser-startup.sh │ ├── bump-package-version.ts │ ├── create-github-release.ts │ ├── generate-readmes.sh │ ├── git.ts │ ├── list-unreleased-commits.sh │ ├── sync-releases.ts │ └── upgrade-deps.ts ├── templates/ │ ├── react/ │ │ ├── README.md │ │ ├── _gitignore │ │ ├── entrypoints/ │ │ │ ├── background.ts │ │ │ ├── content.ts │ │ │ └── popup/ │ │ │ ├── App.css │ │ │ ├── App.tsx │ │ │ ├── index.html │ │ │ ├── main.tsx │ │ │ └── style.css │ │ ├── package.json │ │ ├── tsconfig.json │ │ └── wxt.config.ts │ ├── solid/ │ │ ├── README.md │ │ ├── _gitignore │ │ ├── entrypoints/ │ │ │ ├── background.ts │ │ │ ├── content.ts │ │ │ └── popup/ │ │ │ ├── App.css │ │ │ ├── App.tsx │ │ │ ├── index.html │ │ │ ├── main.tsx │ │ │ └── style.css │ │ ├── package.json │ │ ├── tsconfig.json │ │ └── wxt.config.ts │ ├── svelte/ │ │ ├── .vscode/ │ │ │ └── extensions.json │ │ ├── README.md │ │ ├── _gitignore │ │ ├── package.json │ │ ├── src/ │ │ │ ├── entrypoints/ │ │ │ │ ├── background.ts │ │ │ │ ├── content.ts │ │ │ │ └── popup/ │ │ │ │ ├── App.svelte │ │ │ │ ├── app.css │ │ │ │ ├── index.html │ │ │ │ └── main.ts │ │ │ └── lib/ │ │ │ └── Counter.svelte │ │ ├── tsconfig.json │ │ ├── wxt-env.d.ts │ │ └── wxt.config.ts │ ├── vanilla/ │ │ ├── _gitignore │ │ ├── components/ │ │ │ └── counter.ts │ │ ├── entrypoints/ │ │ │ ├── background.ts │ │ │ ├── content.ts │ │ │ └── popup/ │ │ │ ├── index.html │ │ │ ├── main.ts │ │ │ └── style.css │ │ ├── package.json │ │ ├── tsconfig.json │ │ └── wxt.config.ts │ └── vue/ │ ├── .vscode/ │ │ └── extensions.json │ ├── README.md │ ├── _gitignore │ ├── components/ │ │ └── HelloWorld.vue │ ├── entrypoints/ │ │ ├── background.ts │ │ ├── content.ts │ │ └── popup/ │ │ ├── App.vue │ │ ├── index.html │ │ ├── main.ts │ │ └── style.css │ ├── package.json │ ├── tsconfig.json │ └── wxt.config.ts ├── tsconfig.base.json └── tsconfig.json
SYMBOL INDEX (1402 symbols across 196 files)
FILE: docs/.vitepress/composables/useBlogDate.ts
constant MONTH_FORMATTER (line 3) | const MONTH_FORMATTER = new Intl.DateTimeFormat(
FILE: docs/.vitepress/composables/useListExtensionDetails.ts
type ChromeExtension (line 3) | interface ChromeExtension {
FILE: docs/.vitepress/config.ts
method buildEnd (line 93) | async buildEnd(site) {
FILE: docs/.vitepress/loaders/cli.data.ts
method load (line 10) | async load() {
function getHelp (line 39) | async function getHelp(command: string): Promise<string> {
function getWxtHelp (line 47) | function getWxtHelp(command: string): Promise<string> {
function getPublishExtensionHelp (line 51) | async function getPublishExtensionHelp(command: string): Promise<string> {
type Command (line 58) | interface Command {
FILE: docs/.vitepress/theme/index.ts
method enhanceApp (line 12) | enhanceApp(ctx) {
FILE: docs/.vitepress/utils/head.ts
function meta (line 3) | function meta(
function script (line 17) | function script(
FILE: docs/.vitepress/utils/menus.ts
type SidebarItem (line 3) | type SidebarItem = DefaultTheme.SidebarItem;
type NavItem (line 4) | type NavItem = DefaultTheme.NavItem;
type NavItemWithLink (line 5) | type NavItemWithLink = DefaultTheme.NavItemWithLink;
type NavItemWithChildren (line 6) | type NavItemWithChildren = DefaultTheme.NavItemWithChildren;
type NavItemChildren (line 7) | type NavItemChildren = DefaultTheme.NavItemChildren;
function navItem (line 12) | function navItem(text: string, arg2?: unknown): any {
function menuRoot (line 21) | function menuRoot(items: SidebarItem[]) {
function menuGroup (line 39) | function menuGroup(
function menuItems (line 63) | function menuItems(items: SidebarItem[]) {
function menuItem (line 69) | function menuItem(
function prepareTypedocSidebar (line 81) | function prepareTypedocSidebar(items: SidebarItem[]) {
FILE: docs/.vitepress/utils/types.ts
type Example (line 1) | interface Example {
type ExamplesMetadata (line 11) | type ExamplesMetadata = {
type KeySelectedObject (line 18) | type KeySelectedObject = Record<string, boolean | undefined>;
FILE: packages/analytics/modules/analytics/client.ts
type AnalyticsMessage (line 15) | type AnalyticsMessage = {
type AnalyticsMethod (line 22) | type AnalyticsMethod =
type MethodForwarder (line 26) | type MethodForwarder = <K extends keyof Analytics>(
constant ANALYTICS_PORT (line 30) | const ANALYTICS_PORT = '@wxt-dev/analytics';
constant INTERACTIVE_TAGS (line 32) | const INTERACTIVE_TAGS = new Set([
constant INTERACTIVE_ROLES (line 39) | const INTERACTIVE_ROLES = new Set([
function createAnalytics (line 48) | function createAnalytics(config?: AnalyticsConfig): Analytics {
function createBackgroundAnalytics (line 68) | function createBackgroundAnalytics(
function createFrontendAnalytics (line 224) | function createFrontendAnalytics(): Analytics {
function defineStorageItem (line 280) | function defineStorageItem(
function defineAnalyticsProvider (line 292) | function defineAnalyticsProvider<T = never>(
FILE: packages/analytics/modules/analytics/index.ts
type WxtAppConfig (line 14) | interface WxtAppConfig {
method setup (line 22) | setup(wxt) {
FILE: packages/analytics/modules/analytics/providers/google-analytics-4.ts
constant DEFAULT_ENGAGEMENT_TIME_IN_MSEC (line 4) | const DEFAULT_ENGAGEMENT_TIME_IN_MSEC = 100;
type GoogleAnalytics4ProviderOptions (line 6) | interface GoogleAnalytics4ProviderOptions {
FILE: packages/analytics/modules/analytics/providers/umami.ts
type UmamiProviderOptions (line 3) | interface UmamiProviderOptions {
type UmamiPayload (line 60) | interface UmamiPayload {
FILE: packages/analytics/modules/analytics/types.ts
type Analytics (line 1) | interface Analytics {
type AnalyticsConfig (line 20) | interface AnalyticsConfig {
type AnalyticsStorageItem (line 48) | interface AnalyticsStorageItem<T> {
type AnalyticsProvider (line 53) | type AnalyticsProvider = (
type BaseAnalyticsEvent (line 65) | interface BaseAnalyticsEvent {
type AnalyticsEventMetadata (line 73) | interface AnalyticsEventMetadata {
type AnalyticsPageInfo (line 90) | interface AnalyticsPageInfo {
type AnalyticsPageViewEvent (line 96) | interface AnalyticsPageViewEvent extends BaseAnalyticsEvent {
type AnalyticsTrackEvent (line 100) | interface AnalyticsTrackEvent extends BaseAnalyticsEvent {
FILE: packages/auto-icons/src/__test__/index.test.ts
type MockWxt (line 22) | interface MockWxt {
type PublicAsset (line 36) | interface PublicAsset {
type BuildOutput (line 41) | interface BuildOutput {
FILE: packages/auto-icons/src/index.ts
method setup (line 11) | async setup(wxt, options) {
type AutoIconsOptions (line 117) | interface AutoIconsOptions {
type InlineConfig (line 158) | interface InlineConfig {
FILE: packages/browser/scripts/generate.ts
function transformFile (line 67) | function transformFile(file: string, content: string): string {
FILE: packages/browser/src/gen/chrome-cast/index.d.ts
type AutoJoinPolicy (line 13) | enum AutoJoinPolicy {
type DefaultActionPolicy (line 23) | enum DefaultActionPolicy {
type Capability (line 31) | enum Capability {
type ErrorCode (line 42) | enum ErrorCode {
type ReceiverAvailability (line 58) | enum ReceiverAvailability {
type SenderPlatform (line 66) | enum SenderPlatform {
type ReceiverType (line 75) | enum ReceiverType {
type ReceiverAction (line 85) | enum ReceiverAction {
type SessionStatus (line 93) | enum SessionStatus {
class ApiConfig (line 185) | class ApiConfig {
class Error (line 209) | class Error {
class Image (line 223) | class Image {
class SenderApplication (line 235) | class SenderApplication {
class SessionRequest (line 247) | class SessionRequest {
class Session (line 262) | class Session {
class Receiver (line 393) | class Receiver {
class ReceiverDisplayStatus (line 416) | class ReceiverDisplayStatus {
class Volume (line 428) | class Volume {
type MediaCommand (line 447) | enum MediaCommand {
type MetadataType (line 457) | enum MetadataType {
type PlayerState (line 468) | enum PlayerState {
type ResumeState (line 478) | enum ResumeState {
type StreamType (line 486) | enum StreamType {
type IdleReason (line 495) | enum IdleReason {
type RepeatMode (line 505) | enum RepeatMode {
class QueueItem (line 512) | class QueueItem {
class QueueLoadRequest (line 528) | class QueueLoadRequest {
class QueueInsertItemsRequest (line 541) | class QueueInsertItemsRequest {
class QueueRemoveItemsRequest (line 553) | class QueueRemoveItemsRequest {
class QueueReorderItemsRequest (line 564) | class QueueReorderItemsRequest {
class QueueUpdateItemsRequest (line 576) | class QueueUpdateItemsRequest {
type TrackType (line 590) | enum TrackType {
type TextTrackType (line 599) | enum TextTrackType {
type TextTrackEdgeType (line 610) | enum TextTrackEdgeType {
type TextTrackWindowType (line 621) | enum TextTrackWindowType {
type TextTrackFontGenericFamily (line 630) | enum TextTrackFontGenericFamily {
type TextTrackFontStyle (line 643) | enum TextTrackFontStyle {
class GetStatusRequest (line 650) | class GetStatusRequest {
class PauseRequest (line 659) | class PauseRequest {
class PlayRequest (line 668) | class PlayRequest {
class SeekRequest (line 677) | class SeekRequest {
class StopRequest (line 688) | class StopRequest {
class VolumeRequest (line 697) | class VolumeRequest {
class LoadRequest (line 708) | class LoadRequest {
class EditTracksInfoRequest (line 723) | class EditTracksInfoRequest {
class GenericMediaMetadata (line 735) | class GenericMediaMetadata {
class MovieMediaMetadata (line 747) | class MovieMediaMetadata {
class TvShowMediaMetadata (line 765) | class TvShowMediaMetadata {
class MusicTrackMediaMetadata (line 791) | class MusicTrackMediaMetadata {
class PhotoMediaMetadata (line 817) | class PhotoMediaMetadata {
class MediaInfo (line 838) | class MediaInfo {
class Media (line 856) | class Media {
class Track (line 1086) | class Track {
class TextTrackStyle (line 1104) | class TextTrackStyle {
class LiveSeekableRange (line 1124) | class LiveSeekableRange {
FILE: packages/browser/src/gen/har-format/index.d.ts
type HARFormatEntry (line 6) | type HARFormatEntry = Entry;
type HARFormatLog (line 7) | type HARFormatLog = Log;
FILE: packages/browser/src/gen/index.d.ts
type SetRequired (line 8) | type SetRequired<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;
type SetPartial (line 9) | type SetPartial<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
type Window (line 14) | interface Window {
type BadgeColorDetails (line 156) | interface BadgeColorDetails {
type BadgeTextDetails (line 163) | interface BadgeTextDetails {
type TitleDetails (line 170) | interface TitleDetails {
type PopupDetails (line 177) | interface PopupDetails {
type TabIconDetails (line 184) | interface TabIconDetails {
type OpenPopupOptions (line 194) | interface OpenPopupOptions {
type TabDetails (line 199) | interface TabDetails {
type UserSettings (line 208) | interface UserSettings {
type UserSettingsChange (line 214) | interface UserSettingsChange {
type AlarmCreateInfo (line 385) | interface AlarmCreateInfo {
type Alarm (line 394) | interface Alarm {
type AudioDeviceInfo (line 469) | interface AudioDeviceInfo {
type DeviceFilter (line 488) | interface DeviceFilter {
type DeviceIdLists (line 495) | interface DeviceIdLists {
type DeviceProperties (line 508) | interface DeviceProperties {
type DeviceType (line 518) | enum DeviceType {
type LevelChangedEvent (line 537) | interface LevelChangedEvent {
type MuteChangedEvent (line 544) | interface MuteChangedEvent {
type StreamType (line 552) | enum StreamType {
type BookmarkTreeNode (line 620) | interface BookmarkTreeNode {
type BookmarkTreeNodeUnmodifiable (line 666) | enum BookmarkTreeNodeUnmodifiable {
type CreateDetails (line 671) | interface CreateDetails {
type FolderType (line 684) | enum FolderType {
type MoveDestination (line 761) | interface MoveDestination {
type SearchQuery (line 794) | interface SearchQuery {
type UpdateChanges (line 812) | interface UpdateChanges {
type BadgeBackgroundColorDetails (line 878) | interface BadgeBackgroundColorDetails {
type BadgeTextDetails (line 885) | interface BadgeTextDetails {
type TitleDetails (line 892) | interface TitleDetails {
type TabDetails (line 899) | interface TabDetails {
type TabIconDetails (line 904) | type TabIconDetails =
type PopupDetails (line 924) | interface PopupDetails {
type OriginTypes (line 1004) | interface OriginTypes {
type RemovalOptions (line 1014) | interface RemovalOptions {
type DataTypeSet (line 1032) | interface DataTypeSet {
type SettingsResult (line 1074) | interface SettingsResult {
type Algorithm (line 1227) | enum Algorithm {
type CertificateInfo (line 1249) | interface CertificateInfo {
type CertificatesUpdateRequest (line 1257) | interface CertificatesUpdateRequest {
type ClientCertificateInfo (line 1263) | interface ClientCertificateInfo {
type Error (line 1278) | enum Error {
type Hash (line 1283) | enum Hash {
type PinRequestErrorType (line 1300) | enum PinRequestErrorType {
type PinRequestType (line 1315) | enum PinRequestType {
type PinResponseDetails (line 1323) | interface PinResponseDetails {
type ReportSignatureDetails (line 1329) | interface ReportSignatureDetails {
type RequestPinDetails (line 1339) | interface RequestPinDetails {
type SetCertificatesDetails (line 1351) | interface SetCertificatesDetails {
type SignatureRequest (line 1361) | interface SignatureRequest {
type SignRequest (line 1372) | interface SignRequest {
type StopPinRequestDetails (line 1387) | interface StopPinRequestDetails {
type Command (line 1464) | interface Command {
type AutoVerifyContentSetting (line 1495) | enum AutoVerifyContentSetting {
type CameraContentSetting (line 1501) | enum CameraContentSetting {
type ClipboardContentSetting (line 1508) | enum ClipboardContentSetting {
type ContentSettingClearParams (line 1514) | interface ContentSettingClearParams {
type ContentSettingGetParams (line 1519) | interface ContentSettingGetParams {
type ContentSettingGetResult (line 1530) | interface ContentSettingGetResult<T> {
type ContentSettingSetParams (line 1535) | interface ContentSettingSetParams<T> {
type ContentSetting (line 1548) | interface ContentSetting<T extends string> {
type CookiesContentSetting (line 1579) | enum CookiesContentSetting {
type FullscreenContentSetting (line 1586) | enum FullscreenContentSetting {
type ImagesContentSetting (line 1591) | enum ImagesContentSetting {
type JavascriptContentSetting (line 1597) | enum JavascriptContentSetting {
type LocationContentSetting (line 1603) | enum LocationContentSetting {
type MicrophoneContentSetting (line 1610) | enum MicrophoneContentSetting {
type MouselockContentSetting (line 1617) | enum MouselockContentSetting {
type MultipleAutomaticDownloadsContentSetting (line 1622) | enum MultipleAutomaticDownloadsContentSetting {
type NotificationsContentSetting (line 1629) | enum NotificationsContentSetting {
type PluginsContentSetting (line 1636) | enum PluginsContentSetting {
type PopupsContentSetting (line 1641) | enum PopupsContentSetting {
type PpapiBrokerContentSetting (line 1647) | enum PpapiBrokerContentSetting {
type ResourceIdentifier (line 1652) | interface ResourceIdentifier {
type Scope (line 1667) | enum Scope {
type SoundContentSetting (line 1673) | enum SoundContentSetting {
type ContextType (line 1865) | enum ContextType {
type CreateProperties (line 1885) | interface CreateProperties {
type ItemType (line 1921) | enum ItemType {
type OnClickData (line 1929) | interface OnClickData {
type SameSiteStatus (line 2015) | enum SameSiteStatus {
type Cookie (line 2023) | interface Cookie {
type CookiePartitionKey (line 2060) | interface CookiePartitionKey {
type CookieStore (line 2071) | interface CookieStore {
type GetAllDetails (line 2078) | interface GetAllDetails {
type SetDetails (line 2100) | interface SetDetails {
type CookieDetails (line 2135) | interface CookieDetails {
type CookieChangeInfo (line 2149) | interface CookieChangeInfo {
type FrameDetails (line 2162) | interface FrameDetails {
type OnChangedCause (line 2175) | enum OnChangedCause {
type Debuggee (line 2251) | interface Debuggee {
type DebuggerSession (line 2264) | interface DebuggerSession {
type DetachReason (line 2279) | enum DetachReason {
type TargetInfo (line 2285) | interface TargetInfo {
type TargetInfoType (line 2308) | enum TargetInfoType {
type PageStateMatcherProperties (line 2379) | interface PageStateMatcherProperties {
class PageStateMatcher (line 2392) | class PageStateMatcher {
type RequestContentScriptProperties (line 2396) | interface RequestContentScriptProperties {
class RequestContentScript (line 2411) | class RequestContentScript {
class ShowAction (line 2421) | class ShowAction {}
class ShowPageAction (line 2430) | class ShowPageAction {}
class SetIcon (line 2437) | class SetIcon {
type HeaderFilter (line 2458) | interface HeaderFilter {
type AddResponseHeader (line 2478) | interface AddResponseHeader {
type RemoveResponseCookie (line 2486) | interface RemoveResponseCookie {
type RemoveResponseHeader (line 2492) | interface RemoveResponseHeader {
type RequestMatcher (line 2500) | interface RequestMatcher {
type IgnoreRules (line 2532) | interface IgnoreRules {
type RedirectToEmptyDocument (line 2541) | interface RedirectToEmptyDocument {}
type RedirectRequest (line 2544) | interface RedirectRequest {
type ResponseCookie (line 2550) | interface ResponseCookie {
type AddResponseCookie (line 2570) | interface AddResponseCookie {
type EditResponseCookie (line 2575) | interface EditResponseCookie {
type CancelRequest (line 2584) | interface CancelRequest {}
type RemoveRequestHeader (line 2587) | interface RemoveRequestHeader {
type EditRequestCookie (line 2593) | interface EditRequestCookie {
type FilterResponseCookie (line 2601) | interface FilterResponseCookie {
type SetRequestHeader (line 2627) | interface SetRequestHeader {
type RequestCookie (line 2635) | interface RequestCookie {
type RedirectByRegEx (line 2643) | interface RedirectByRegEx {
type RedirectToTransparentImage (line 2652) | interface RedirectToTransparentImage {}
type AddRequestCookie (line 2655) | interface AddRequestCookie {
type RemoveRequestCookie (line 2660) | interface RemoveRequestCookie {
type Stage (line 2665) | enum Stage {
type MessageDetails (line 2672) | interface MessageDetails {
type SendMessageToExtension (line 2702) | interface SendMessageToExtension {
type DesktopCaptureSourceType (line 2724) | enum DesktopCaptureSourceType {
type StreamOptions (line 2735) | interface StreamOptions {
type Resource (line 2773) | interface Resource {
type ReloadOptions (line 2800) | interface ReloadOptions {
type EvaluationExceptionInfo (line 2809) | interface EvaluationExceptionInfo {
type EvalOptions (line 2856) | interface EvalOptions {
type Request (line 2879) | interface Request extends HARFormatEntry {
type ExtensionPanel (line 2930) | interface ExtensionPanel {
type Button (line 2952) | interface Button {
type ElementsPanel (line 2965) | interface ElementsPanel {
type SourcesPanel (line 2982) | interface SourcesPanel {
type ExtensionSidebarPane (line 2999) | interface ExtensionSidebarPane {
type Theme (line 3038) | type Theme = "default" | "dark";
type RecorderExtensionPlugin (line 3108) | interface RecorderExtensionPlugin {
type RecorderView (line 3134) | interface RecorderView {
type CancelScanResponse (line 3177) | interface CancelScanResponse<T> {
type CloseScannerResponse (line 3185) | interface CloseScannerResponse<T> {
type Configurability (line 3196) | enum Configurability {
type ConnectionType (line 3209) | enum ConnectionType {
type ConstraintType (line 3219) | enum ConstraintType {
type DeviceFilter (line 3233) | interface DeviceFilter {
type GetOptionGroupsResponse (line 3241) | interface GetOptionGroupsResponse<T> {
type GetScannerListResponse (line 3251) | interface GetScannerListResponse {
type OpenScannerResponse (line 3259) | interface OpenScannerResponse<T> {
type OperationResult (line 3274) | enum OperationResult {
type OptionConstraint (line 3312) | interface OptionConstraint {
type OptionGroup (line 3321) | interface OptionGroup {
type OptionSetting (line 3329) | interface OptionSetting {
type OptionType (line 3342) | enum OptionType {
type OptionUnit (line 3363) | enum OptionUnit {
type ReadScanDataResponse (line 3381) | interface ReadScanDataResponse<T> {
type ScannerInfo (line 3393) | interface ScannerInfo {
type ScannerOption (line 3415) | interface ScannerOption {
type ScanOptions (line 3444) | interface ScanOptions {
type ScanResults (line 3451) | interface ScanResults {
type SetOptionResult (line 3459) | interface SetOptionResult {
type SetOptionsResponse (line 3467) | interface SetOptionsResponse<T> {
type StartScanOptions (line 3481) | interface StartScanOptions {
type StartScanResponse (line 3489) | interface StartScanResponse<T> {
type HeaderNameValuePair (line 3627) | interface HeaderNameValuePair {
type FilenameConflictAction (line 3634) | enum FilenameConflictAction {
type HttpMethod (line 3643) | enum HttpMethod {
type DownloadOptions (line 3648) | interface DownloadOptions {
type DownloadDelta (line 3665) | interface DownloadDelta {
type BooleanDelta (line 3701) | interface BooleanDelta {
type DoubleDelta (line 3706) | interface DoubleDelta {
type StringDelta (line 3711) | interface StringDelta {
type InterruptReason (line 3716) | enum InterruptReason {
type State (line 3748) | enum State {
type DangerType (line 3757) | enum DangerType {
type DownloadItem (line 3795) | interface DownloadItem {
type GetFileIconOptions (line 3843) | interface GetFileIconOptions {
type DownloadQuery (line 3848) | interface DownloadQuery {
type FilenameSuggestion (line 3911) | interface FilenameSuggestion {
type UiOptions (line 3919) | interface UiOptions {
type Token (line 4071) | interface Token {
type ChallengeKeyOptions (line 4097) | interface ChallengeKeyOptions {
type RegisterKeyOptions (line 4116) | interface RegisterKeyOptions {
type Algorithm (line 4127) | enum Algorithm {
type Scope (line 4136) | enum Scope {
type HardwarePlatformInfo (line 4315) | interface HardwarePlatformInfo {
type NetworkDetails (line 4359) | interface NetworkDetails {
type UrlFilter (line 4383) | interface UrlFilter {
type Event (line 4431) | interface Event<T extends (...args: any) => void> {
type Rule (line 4487) | interface Rule {
type ViewType (line 4512) | enum ViewType {
type FetchProperties (line 4517) | interface FetchProperties {
type ColorArray (line 4624) | type ColorArray = [number, number, number, number];
type CSSOrigin (line 4630) | type CSSOrigin = "author" | "user";
type DocumentLifecycle (line 4636) | type DocumentLifecycle = "prerender" | "active" | "cached" | "pending_de...
type FrameType (line 4642) | type FrameType = "outermost_frame" | "fenced_frame" | "sub_frame";
type ImageDetails (line 4645) | interface ImageDetails {
type ImageFormat (line 4656) | type ImageFormat = "jpeg" | "png";
type InjectDetails (line 4659) | interface InjectDetails {
type RunAt (line 4696) | type RunAt = "document_start" | "document_end" | "document_idle";
type FileHandlerExecuteEventDetails (line 4710) | interface FileHandlerExecuteEventDetails {
type AbortRequestedOptions (line 4731) | interface AbortRequestedOptions {
type Action (line 4741) | interface Action {
type AddWatcherRequestedOptions (line 4748) | interface AddWatcherRequestedOptions {
type Change (line 4759) | interface Change {
type ChangeType (line 4772) | enum ChangeType {
type CloseFileRequestedOptions (line 4777) | interface CloseFileRequestedOptions {
type CloudFileInfo (line 4787) | interface CloudFileInfo {
type CloudIdentifier (line 4793) | interface CloudIdentifier {
type CommonActionId (line 4804) | enum CommonActionId {
type ConfigureRequestedOptions (line 4811) | interface ConfigureRequestedOptions {
type CopyEntryRequestedOptions (line 4818) | interface CopyEntryRequestedOptions {
type CreateDirectoryRequestedOptions (line 4829) | interface CreateDirectoryRequestedOptions {
type CreateFileRequestedOptions (line 4840) | interface CreateFileRequestedOptions {
type DeleteEntryRequestedOptions (line 4849) | interface DeleteEntryRequestedOptions {
type EntryMetadata (line 4860) | interface EntryMetadata {
type ExecuteActionRequestedOptions (line 4886) | interface ExecuteActionRequestedOptions {
type FileSystemInfo (line 4900) | interface FileSystemInfo {
type GetActionsRequestedOptions (line 4924) | interface GetActionsRequestedOptions {
type GetMetadataRequestedOptions (line 4936) | interface GetMetadataRequestedOptions {
type MountOptions (line 4982) | interface MountOptions {
type MoveEntryRequestedOptions (line 5003) | interface MoveEntryRequestedOptions {
type NotifyOptions (line 5014) | interface NotifyOptions {
type OpenedFile (line 5029) | interface OpenedFile {
type OpenFileMode (line 5039) | enum OpenFileMode {
type OpenFileRequestedOptions (line 5044) | interface OpenFileRequestedOptions {
type ProviderError (line 5056) | enum ProviderError {
type ReadDirectoryRequestedOptions (line 5076) | interface ReadDirectoryRequestedOptions {
type ReadFileRequestedOptions (line 5115) | interface ReadFileRequestedOptions {
type RemoveWatcherRequestedOptions (line 5128) | interface RemoveWatcherRequestedOptions {
type TruncateRequestedOptions (line 5139) | interface TruncateRequestedOptions {
type UnmountOptions (line 5150) | interface UnmountOptions {
type UnmountRequestedOptions (line 5155) | interface UnmountRequestedOptions {
type Watcher (line 5162) | interface Watcher {
type WriteFileRequestedOptions (line 5171) | interface WriteFileRequestedOptions {
type FontName (line 5494) | interface FontName {
type GenericFamily (line 5502) | enum GenericFamily {
type LevelOfControl (line 5512) | enum LevelOfControl {
type ScriptCode (line 5524) | enum ScriptCode {
type ClearFontDetails (line 5679) | interface ClearFontDetails {
type GetFontDetails (line 5686) | interface GetFontDetails {
type SetFontDetails (line 5693) | interface SetFontDetails {
type FontChangedResult (line 5702) | interface FontChangedResult {
type FontResult (line 5713) | interface FontResult {
type FontSizeResult (line 5720) | interface FontSizeResult {
type FontSizeDetails (line 5727) | interface FontSizeDetails {
type OutgoingMessage (line 5888) | interface OutgoingMessage {
type VisitItem (line 5966) | interface VisitItem {
type HistoryItem (line 5985) | interface HistoryItem {
type TransitionType (line 6004) | enum TransitionType {
type HistoryQuery (line 6029) | interface HistoryQuery {
type UrlDetails (line 6041) | interface UrlDetails {
type Range (line 6046) | interface Range {
type RemovedResult (line 6053) | interface RemovedResult {
type DetectedLanguage (line 6123) | interface DetectedLanguage {
type LanguageDetectionResult (line 6130) | interface LanguageDetectionResult {
type GetMessageOptions (line 6138) | interface GetMessageOptions {
type AccountInfo (line 6185) | interface AccountInfo {
type AccountStatus (line 6191) | enum AccountStatus {
type ProfileDetails (line 6199) | interface ProfileDetails {
type TokenDetails (line 6204) | interface TokenDetails {
type ProfileUserInfo (line 6222) | interface ProfileUserInfo {
type InvalidTokenDetails (line 6229) | interface InvalidTokenDetails {
type WebAuthFlowDetails (line 6234) | interface WebAuthFlowDetails {
type GetAuthTokenResult (line 6263) | interface GetAuthTokenResult {
type IdleState (line 6368) | enum IdleState {
type KeyboardEvent (line 6417) | interface KeyboardEvent {
type KeyboardEventType (line 6449) | enum KeyboardEventType {
type AutoCapitalizeType (line 6458) | enum AutoCapitalizeType {
type InputContextType (line 6468) | enum InputContextType {
type InputContext (line 6480) | interface InputContext {
type MenuItem (line 6504) | interface MenuItem {
type MenuItemStyle (line 6523) | enum MenuItemStyle {
type CommitTextParameters (line 6529) | interface CommitTextParameters {
type CandidateUsage (line 6536) | interface CandidateUsage {
type CandidateTemplate (line 6543) | interface CandidateTemplate {
type CandidatesParameters (line 6558) | interface CandidatesParameters {
type CompositionParameterSegment (line 6565) | interface CompositionParameterSegment {
type CompositionParameters (line 6574) | interface CompositionParameters {
type MenuParameters (line 6590) | interface MenuParameters {
type MouseButton (line 6601) | enum MouseButton {
type ScreenType (line 6611) | enum ScreenType {
type UnderlineStyle (line 6622) | enum UnderlineStyle {
type WindowPosition (line 6632) | enum WindowPosition {
type AssistiveWindowType (line 6638) | enum AssistiveWindowType {
type AssistiveWindowButton (line 6646) | enum AssistiveWindowButton {
type AssistiveWindowProperties (line 6655) | interface AssistiveWindowProperties {
type CandidateWindowParameterProperties (line 6663) | interface CandidateWindowParameterProperties {
type CandidateWindowParameter (line 6690) | interface CandidateWindowParameter {
type ClearCompositionParameters (line 6696) | interface ClearCompositionParameters {
type CursorPositionParameters (line 6701) | interface CursorPositionParameters {
type SendKeyEventParameters (line 6708) | interface SendKeyEventParameters {
type DeleteSurroundingTextParameters (line 6715) | interface DeleteSurroundingTextParameters {
type AssistiveWindowButtonHighlightedParameters (line 6726) | interface AssistiveWindowButtonHighlightedParameters {
type AssistiveWindowPropertiesParameters (line 6739) | interface AssistiveWindowPropertiesParameters {
type SurroundingTextInfo (line 6746) | interface SurroundingTextInfo {
type AssistiveWindowButtonClickedDetails (line 6760) | interface AssistiveWindowButtonClickedDetails {
type DeleteTokenParams (line 6956) | interface DeleteTokenParams {
type GetTokenParams (line 7000) | interface GetTokenParams {
type ProfileType (line 7040) | enum ProfileType {
type SessionState (line 7049) | enum SessionState {
type ExtensionDisabledReason (line 7097) | enum ExtensionDisabledReason {
type ExtensionInfo (line 7103) | interface ExtensionInfo {
type ExtensionInstallType (line 7165) | enum ExtensionInstallType {
type ExtensionType (line 7182) | enum ExtensionType {
type IconInfo (line 7192) | interface IconInfo {
type LaunchType (line 7200) | enum LaunchType {
type UninstallOptions (line 7211) | interface UninstallOptions {
type NotificationButton (line 7360) | interface NotificationButton {
type NotificationItem (line 7366) | interface NotificationItem {
type NotificationOptions (line 7373) | interface NotificationOptions {
type NotificationCreateOptions (line 7437) | type NotificationCreateOptions = SetRequired<NotificationOptions, "type"...
type PermissionLevel (line 7439) | enum PermissionLevel {
type TemplateType (line 7446) | enum TemplateType {
type Reason (line 7544) | enum Reason {
type CreateParameters (line 7577) | interface CreateParameters {
type SuggestResult (line 7622) | interface SuggestResult {
type DefaultSuggestResult (line 7635) | interface DefaultSuggestResult {
type DescriptionStyleType (line 7644) | enum DescriptionStyleType {
type OnInputEnteredDisposition (line 7654) | enum OnInputEnteredDisposition {
type TitleDetails (line 7701) | interface TitleDetails {
type TabDetails (line 7708) | interface TabDetails {
type PopupDetails (line 7713) | interface PopupDetails {
type IconDetails (line 7720) | type IconDetails =
type SaveDetails (line 7790) | interface SaveDetails {
type Permissions (line 7811) | interface Permissions {
type AddHostAccessRequest (line 7818) | interface AddHostAccessRequest {
type RemoveHostAccessRequest (line 7866) | interface RemoveHostAccessRequest {
type Match (line 7900) | interface Match {
type ClientCertificateRequest (line 7907) | interface ClientCertificateRequest {
type ClientCertificateType (line 7914) | enum ClientCertificateType {
type SelectDetails (line 7919) | interface SelectDetails {
type VerificationDetails (line 7928) | interface VerificationDetails {
type VerificationResult (line 7935) | interface VerificationResult {
type Level (line 8009) | enum Level {
type PrinterInfo (line 8042) | interface PrinterInfo {
type PrintError (line 8052) | enum PrintError {
type PrinterCapabilities (line 8063) | interface PrinterCapabilities {
type PrintJob (line 8068) | interface PrintJob {
type Device (line 8082) | interface Device {
type GetPrinterInfoResponse (line 8148) | interface GetPrinterInfoResponse {
type JobStatus (line 8156) | enum JobStatus {
type Printer (line 8169) | interface Printer {
type PrinterSource (line 8193) | enum PrinterSource {
type PrinterStatus (line 8201) | enum PrinterStatus {
type SubmitJobRequest (line 8226) | interface SubmitJobRequest {
type SubmitJobResponse (line 8235) | interface SubmitJobResponse {
type SubmitJobStatus (line 8243) | enum SubmitJobStatus {
type ColorMode (line 8310) | enum ColorMode {
type DuplexMode (line 8317) | enum DuplexMode {
type MediaSize (line 8326) | interface MediaSize {
type Printer (line 8338) | interface Printer {
type PrinterSource (line 8348) | enum PrinterSource {
type PrintJobInfo (line 8355) | interface PrintJobInfo {
type PrintJobSource (line 8384) | enum PrintJobSource {
type PrintJobStatus (line 8396) | enum PrintJobStatus {
type PrintSettings (line 8405) | interface PrintSettings {
type IPHandlingPolicy (line 8441) | enum IPHandlingPolicy {
type Mode (line 8605) | enum Mode {
type PacScript (line 8619) | interface PacScript {
type ProxyConfig (line 8629) | interface ProxyConfig {
type ProxyServer (line 8638) | interface ProxyServer {
type ProxyRules (line 8648) | interface ProxyRules {
type Scheme (line 8664) | enum Scheme {
type ErrorDetails (line 8672) | interface ErrorDetails {
type AddEntryOptions (line 8698) | interface AddEntryOptions {
type QueryInfo (line 8707) | interface QueryInfo {
type ReadingListEntry (line 8716) | interface ReadingListEntry {
type RemoveOptions (line 8729) | interface RemoveOptions {
type UpdateEntryOptions (line 8734) | interface UpdateEntryOptions {
type Disposition (line 8799) | enum Disposition {
type QueryInfo (line 8808) | type QueryInfo =
type LastError (line 8844) | interface LastError {
type PlatformOs (line 8859) | enum PlatformOs {
type PlatformArch (line 8880) | enum PlatformArch {
type PlatformNaclArch (line 8901) | enum PlatformNaclArch {
type ContextType (line 8915) | enum ContextType {
type OnInstalledReason (line 8934) | enum OnInstalledReason {
type OnRestartRequiredReason (line 8949) | enum OnRestartRequiredReason {
type ContextFilter (line 8962) | interface ContextFilter {
type ConnectInfo (line 8974) | interface ConnectInfo {
type InstalledDetails (line 8981) | interface InstalledDetails {
type ExtensionContext (line 8994) | interface ExtensionContext {
type MessageOptions (line 9015) | interface MessageOptions {
type MessageSender (line 9021) | interface MessageSender {
type PlatformInfo (line 9055) | interface PlatformInfo {
type Port (line 9065) | interface Port {
type UpdateAvailableDetails (line 9080) | interface UpdateAvailableDetails {
type UpdateCheckDetails (line 9085) | interface UpdateCheckDetails {
type RequestUpdateCheckStatus (line 9094) | enum RequestUpdateCheckStatus {
type RequestUpdateCheckResult (line 9103) | interface RequestUpdateCheckResult {
type ManifestIcons (line 9110) | interface ManifestIcons {
type ManifestAction (line 9114) | interface ManifestAction {
type ManifestPermission (line 9121) | type ManifestPermission =
type ManifestPermissions (line 9208) | type ManifestPermissions = ManifestPermission;
type ManifestOptionalPermission (line 9211) | type ManifestOptionalPermission = Exclude<
type ManifestOptionalPermissions (line 9230) | type ManifestOptionalPermissions = ManifestOptionalPermission;
type SearchProvider (line 9232) | interface SearchProvider {
type ManifestBase (line 9250) | interface ManifestBase {
type ManifestV2 (line 9434) | interface ManifestV2 extends ManifestBase {
type ManifestV3 (line 9456) | interface ManifestV3 extends ManifestBase {
type Manifest (line 9504) | type Manifest = ManifestV2 | ManifestV3;
type StyleOrigin (line 9746) | enum StyleOrigin {
type ExecutionWorld (line 9755) | enum ExecutionWorld {
type InjectionResult (line 9762) | interface InjectionResult<T extends any = any> {
type InjectionTarget (line 9777) | type InjectionTarget =
type CSSInjection (line 9818) | type CSSInjection =
type ScriptInjection (line 9840) | type ScriptInjection<Args extends any[], Result> =
type Awaited (line 9874) | type Awaited<T> = T extends PromiseLike<infer U> ? U : T;
type RegisteredContentScript (line 9877) | type RegisteredContentScript =
type ContentScriptFilter (line 9915) | interface ContentScriptFilter {
type Filter (line 9998) | interface Filter {
type Session (line 10003) | interface Session {
type Device (line 10012) | interface Device {
type NoInferX (line 10064) | type NoInferX<T> = T[][T extends any ? 0 : never];
type StorageArea (line 10068) | interface StorageArea {
type StorageChange (line 10146) | interface StorageChange {
type LocalStorageArea (line 10153) | interface LocalStorageArea extends StorageArea {
type SyncStorageArea (line 10158) | interface SyncStorageArea extends StorageArea {
type SessionStorageArea (line 10181) | interface SessionStorageArea extends StorageArea {
type AreaName (line 10186) | type AreaName = "sync" | "local" | "managed" | "session";
type AccessLevel (line 10192) | enum AccessLevel {
type CpuTime (line 10229) | interface CpuTime {
type ProcessorUsage (line 10242) | interface ProcessorUsage extends CpuTime {}
type ProcessorInfo (line 10244) | interface ProcessorInfo {
type CpuInfo (line 10249) | interface CpuInfo {
type MemoryInfo (line 10288) | interface MemoryInfo {
type EjectDeviceResultCode (line 10313) | enum EjectDeviceResultCode {
type StorageUnitInfo (line 10324) | interface StorageUnitInfo {
type StorageUnitType (line 10335) | enum StorageUnitType {
type StorageAvailableCapacityInfo (line 10344) | interface StorageAvailableCapacityInfo {
type LayoutPosition (line 10392) | enum LayoutPosition {
type MirrorMode (line 10403) | enum MirrorMode {
type Bounds (line 10415) | interface Bounds {
type Insets (line 10426) | interface Insets {
type Point (line 10438) | interface Point {
type TouchCalibrationPair (line 10446) | interface TouchCalibrationPair {
type DisplayMode (line 10454) | interface DisplayMode {
type DisplayLayout (line 10487) | interface DisplayLayout {
type TouchCalibrationPairQuad (line 10502) | interface TouchCalibrationPairQuad {
type DisplayProperties (line 10513) | interface DisplayProperties {
type GetInfoFlags (line 10585) | interface GetInfoFlags {
type ActiveState (line 10599) | enum ActiveState {
type DisplayUnitInfo (line 10604) | interface DisplayUnitInfo {
type Edid (line 10694) | interface Edid {
type MirrorModeInfo (line 10703) | interface MirrorModeInfo {
type MirrorModeInfoMixed (line 10708) | interface MirrorModeInfoMixed extends MirrorModeInfo {
type MessageOptions (line 10874) | interface MessageOptions {
type CaptureInfo (line 10895) | interface CaptureInfo {
type MediaStreamConstraint (line 10904) | interface MediaStreamConstraint {
type CaptureOptions (line 10909) | interface CaptureOptions {
type GetMediaStreamOptions (line 10917) | interface GetMediaStreamOptions {
type TabCaptureState (line 10924) | enum TabCaptureState {
type MutedInfo (line 10974) | interface MutedInfo {
type MutedInfoReason (line 10987) | enum MutedInfoReason {
type Tab (line 10996) | interface Tab {
type TabStatus (line 11080) | enum TabStatus {
type WindowType (line 11087) | enum WindowType {
type ZoomSettings (line 11096) | interface ZoomSettings {
type ZoomSettingsMode (line 11112) | enum ZoomSettingsMode {
type ZoomSettingsScope (line 11125) | enum ZoomSettingsScope {
type CreateProperties (line 11156) | interface CreateProperties {
type MoveProperties (line 11176) | interface MoveProperties {
type UpdateProperties (line 11183) | interface UpdateProperties {
type ReloadProperties (line 11211) | interface ReloadProperties {
type ConnectInfo (line 11216) | interface ConnectInfo {
type MessageSendOptions (line 11228) | interface MessageSendOptions {
type GroupOptions (line 11238) | interface GroupOptions {
type HighlightInfo (line 11250) | interface HighlightInfo {
type QueryInfo (line 11257) | interface QueryInfo {
type OnHighlightedInfo (line 11317) | interface OnHighlightedInfo {
type OnRemovedInfo (line 11324) | interface OnRemovedInfo {
type OnUpdatedInfo (line 11331) | interface OnUpdatedInfo {
type OnAttachedInfo (line 11379) | interface OnAttachedInfo {
type OnMovedInfo (line 11384) | interface OnMovedInfo {
type OnDetachedInfo (line 11390) | interface OnDetachedInfo {
type OnActivatedInfo (line 11395) | interface OnActivatedInfo {
type OnSelectionChangedInfo (line 11402) | interface OnSelectionChangedInfo {
type OnActiveChangedInfo (line 11407) | interface OnActiveChangedInfo {
type OnHighlightChangedInfo (line 11412) | interface OnHighlightChangedInfo {
type OnZoomChangeInfo (line 11419) | interface OnZoomChangeInfo {
type Color (line 11867) | enum Color {
type TabGroup (line 11879) | interface TabGroup {
type MoveProperties (line 11897) | interface MoveProperties {
type QueryInfo (line 11904) | interface QueryInfo {
type UpdateProperties (line 11920) | interface UpdateProperties {
type MostVisitedURL (line 11991) | interface MostVisitedURL {
type EventType (line 12017) | enum EventType {
type TtsEvent (line 12031) | interface TtsEvent {
type TtsOptions (line 12049) | interface TtsOptions {
type TtsVoice (line 12083) | interface TtsVoice {
type VoiceGender (line 12102) | enum VoiceGender {
type AudioBuffer (line 12163) | interface AudioBuffer {
type AudioStreamOptions (line 12175) | interface AudioStreamOptions {
type LanguageInstallStatus (line 12186) | enum LanguageInstallStatus {
type LanguageStatus (line 12197) | interface LanguageStatus {
type LanguageUninstallOptions (line 12210) | interface LanguageUninstallOptions {
type SpeakOptions (line 12219) | interface SpeakOptions {
type TtsClient (line 12241) | interface TtsClient {
type TtsClientSource (line 12252) | enum TtsClientSource {
type VoiceGender (line 12261) | enum VoiceGender {
type ChromeSettingScope (line 12343) | type ChromeSettingScope = "regular" | "regular_only" | "incognito_persis...
type LevelOfControl (line 12353) | type LevelOfControl =
type ChromeSettingSetDetails (line 12360) | interface ChromeSettingSetDetails<T> {
type ChromeSettingGetDetails (line 12371) | interface ChromeSettingGetDetails {
type ChromeSettingGetResult (line 12377) | interface ChromeSettingGetResult<T> {
type ChromeSettingClearDetails (line 12390) | interface ChromeSettingClearDetails {
type ChromeSettingOnChangeDetails (line 12396) | interface ChromeSettingOnChangeDetails<T> {
type ChromeSetting (line 12409) | interface ChromeSetting<T> {
type Parameters (line 12450) | interface Parameters {
type VpnSessionParameters (line 12478) | interface VpnSessionParameters extends Parameters {}
type PlatformMessage (line 12481) | enum PlatformMessage {
type UIEvent (line 12501) | enum UIEvent {
type VpnConnectionState (line 12509) | enum VpnConnectionState {
type WallpaperLayout (line 12596) | enum WallpaperLayout {
type WallpaperDetails (line 12602) | interface WallpaperDetails {
type CreateRequest (line 12634) | interface CreateRequest {
type CreateResponseDetails (line 12641) | interface CreateResponseDetails {
type DOMExceptionDetails (line 12650) | interface DOMExceptionDetails {
type GetRequest (line 12655) | interface GetRequest {
type GetResponseDetails (line 12662) | interface GetResponseDetails {
type IsUvpaaRequest (line 12671) | interface IsUvpaaRequest {
type IsUvpaaResponseDetails (line 12676) | interface IsUvpaaResponseDetails {
type TransitionQualifier (line 12751) | enum TransitionQualifier {
type TransitionType (line 12762) | enum TransitionType {
type GetFrameDetails (line 12776) | type GetFrameDetails =
type GetFrameResultDetails (line 12808) | interface GetFrameResultDetails {
type GetAllFrameDetails (line 12831) | interface GetAllFrameDetails {
type GetAllFrameResultDetails (line 12837) | interface GetAllFrameResultDetails extends GetFrameResultDetails {
type WebNavigationReplacementCallbackDetails (line 12844) | interface WebNavigationReplacementCallbackDetails {
type WebNavigationBaseCallbackDetails (line 12853) | interface WebNavigationBaseCallbackDetails {
type WebNavigationFramedCallbackDetails (line 12873) | interface WebNavigationFramedCallbackDetails extends WebNavigationBaseCa...
type WebNavigationFramedErrorCallbackDetails (line 12881) | interface WebNavigationFramedErrorCallbackDetails extends WebNavigationB...
type WebNavigationSourceCallbackDetails (line 12891) | interface WebNavigationSourceCallbackDetails {
type WebNavigationTransitionCallbackDetails (line 12906) | interface WebNavigationTransitionCallbackDetails extends WebNavigationBa...
type WebNavigationEventFilter (line 12918) | interface WebNavigationEventFilter {
type WebNavigationEvent (line 12923) | interface WebNavigationEvent<T extends (...args: any) => void>
type WebRequestEvent (line 13002) | interface WebRequestEvent<T extends (...args: any) => void, U extends st...
type AuthCredentials (line 13008) | interface AuthCredentials {
type HttpHeader (line 13014) | interface HttpHeader {
type BlockingResponse (line 13024) | interface BlockingResponse {
type FormDataItem (line 13041) | type FormDataItem = string | ArrayBuffer;
type IgnoredActionType (line 13044) | enum IgnoredActionType {
type OnAuthRequiredOptions (line 13052) | enum OnAuthRequiredOptions {
type OnBeforeRedirectOptions (line 13064) | enum OnBeforeRedirectOptions {
type OnBeforeRequestOptions (line 13072) | enum OnBeforeRequestOptions {
type OnBeforeSendHeadersOptions (line 13082) | enum OnBeforeSendHeadersOptions {
type OnCompletedOptions (line 13092) | enum OnCompletedOptions {
type OnErrorOccurredOptions (line 13100) | enum OnErrorOccurredOptions {
type OnHeadersReceivedOptions (line 13106) | enum OnHeadersReceivedOptions {
type OnResponseStartedOptions (line 13120) | enum OnResponseStartedOptions {
type OnSendHeadersOptions (line 13128) | enum OnSendHeadersOptions {
type RequestFilter (line 13136) | interface RequestFilter {
type ResourceType (line 13146) | enum ResourceType {
type SecurityInfo (line 13178) | interface SecurityInfo {
type UploadData (line 13195) | interface UploadData {
type WebRequestDetails (line 13206) | interface WebRequestDetails {
type OnAuthRequiredDetails (line 13249) | interface OnAuthRequiredDetails extends WebRequestDetails {
type OnBeforeRedirectDetails (line 13272) | interface OnBeforeRedirectDetails extends WebRequestDetails {
type OnBeforeRequestDetails (line 13287) | interface OnBeforeRequestDetails
type OnBeforeSendHeadersDetails (line 13301) | interface OnBeforeSendHeadersDetails extends WebRequestDetails {
type OnCompletedDetails (line 13306) | interface OnCompletedDetails extends WebRequestDetails {
type OnErrorOccurredDetails (line 13319) | interface OnErrorOccurredDetails extends WebRequestDetails {
type OnHeadersReceivedDetails (line 13328) | interface OnHeadersReceivedDetails extends WebRequestDetails {
type OnResponseStartedDetails (line 13342) | interface OnResponseStartedDetails extends WebRequestDetails {
type OnSendHeadersDetails (line 13355) | interface OnSendHeadersDetails extends WebRequestDetails {
type WindowsEvent (line 13453) | interface WindowsEvent<T extends (...args: any) => void> extends Omit<Br...
type Window (line 13459) | interface Window {
type QueryOptions (line 13487) | interface QueryOptions {
type CreateData (line 13494) | interface CreateData {
type UpdateInfo (line 13525) | interface UpdateInfo {
type CreateType (line 13547) | enum CreateType {
type WindowState (line 13560) | enum WindowState {
type WindowType (line 13577) | enum WindowType {
type RequestMethod (line 13761) | enum RequestMethod {
type ResourceType (line 13774) | enum ResourceType {
type RuleActionType (line 13793) | enum RuleActionType {
type UnsupportedRegexReason (line 13812) | enum UnsupportedRegexReason {
type DomainType (line 13823) | enum DomainType {
type HeaderOperation (line 13834) | enum HeaderOperation {
type RequestDetails (line 13843) | interface RequestDetails {
type Rule (line 13882) | interface Rule {
type RuleAction (line 13893) | interface RuleAction {
type RuleCondition (line 13910) | interface RuleCondition {
type RuleConditionKeys (line 14110) | enum RuleConditionKeys {
type MatchedRule (line 14133) | interface MatchedRule {
type MatchedRuleInfo (line 14140) | interface MatchedRuleInfo {
type MatchedRulesFilter (line 14148) | interface MatchedRulesFilter {
type HeaderInfo (line 14156) | interface HeaderInfo {
type ModifyHeaderInfo (line 14174) | interface ModifyHeaderInfo {
type QueryKeyValue (line 14183) | interface QueryKeyValue {
type QueryTransform (line 14193) | interface QueryTransform {
type URLTransform (line 14200) | interface URLTransform {
type RegexOptions (line 14222) | interface RegexOptions {
type IsRegexSupportedResult (line 14232) | interface IsRegexSupportedResult {
type TabActionCountUpdate (line 14239) | interface TabActionCountUpdate {
type ExtensionActionOptions (line 14247) | interface ExtensionActionOptions {
type GetDisabledRuleIdsOptions (line 14258) | interface GetDisabledRuleIdsOptions {
type GetRulesFilter (line 14264) | interface GetRulesFilter {
type Redirect (line 14269) | interface Redirect {
type UpdateRuleOptions (line 14286) | interface UpdateRuleOptions {
type UpdateStaticRulesOptions (line 14297) | interface UpdateStaticRulesOptions {
type UpdateRulesetOptions (line 14307) | interface UpdateRulesetOptions {
type MatchedRuleInfoDebug (line 14314) | interface MatchedRuleInfoDebug {
type Ruleset (line 14320) | interface Ruleset {
type RulesMatchedDetails (line 14329) | interface RulesMatchedDetails {
type TestMatchOutcomeResult (line 14335) | interface TestMatchOutcomeResult {
type TestMatchRequestDetails (line 14341) | interface TestMatchRequestDetails {
type CloseOptions (line 14521) | type CloseOptions =
type GetPanelOptions (line 14535) | interface GetPanelOptions {
type OpenOptions (line 14544) | type OpenOptions =
type PanelBehavior (line 14567) | interface PanelBehavior {
type PanelClosedInfo (line 14573) | interface PanelClosedInfo {
type PanelLayout (line 14583) | interface PanelLayout {
type PanelOpenedInfo (line 14588) | interface PanelOpenedInfo {
type PanelOptions (line 14597) | interface PanelOptions {
type Side (line 14614) | enum Side {
type SidePanel (line 14619) | interface SidePanel {
type ExecutionWorld (line 14708) | enum ExecutionWorld {
type InjectionResult (line 14716) | type InjectionResult<T = unknown> =
type WorldProperties (line 14738) | interface WorldProperties {
type UserScriptFilter (line 14750) | interface UserScriptFilter {
type InjectionTarget (line 14756) | type InjectionTarget =
type RegisteredUserScript (line 14788) | interface RegisteredUserScript {
type UserScriptInjection (line 14815) | interface UserScriptInjection {
type ScriptSource (line 14828) | type ScriptSource = {
FILE: packages/i18n/src/build.ts
type SimpleMessage (line 19) | type SimpleMessage = string;
type PluralMessage (line 21) | type PluralMessage = Record<'n' | number, string>;
type ChromeMessage (line 23) | interface ChromeMessage {
type Message (line 29) | type Message =
type MessagesObject (line 36) | type MessagesObject = Record<string, Message>;
type ParsedBaseMessage (line 38) | interface ParsedBaseMessage {
type ParsedChromeMessage (line 43) | interface ParsedChromeMessage extends ParsedBaseMessage, ChromeMessage {
type ParsedSimpleMessage (line 46) | interface ParsedSimpleMessage extends ParsedBaseMessage {
type ParsedPluralMessage (line 50) | interface ParsedPluralMessage extends ParsedBaseMessage {
type ParsedMessage (line 55) | type ParsedMessage =
type MessageFormat (line 60) | type MessageFormat = 'JSON5' | 'YAML' | 'TOML';
constant PREDEFINED_MESSAGES (line 70) | const PREDEFINED_MESSAGES: Record<string, ChromeMessage> = {
constant EXT_FORMATS_MAP (line 102) | const EXT_FORMATS_MAP: Record<string, MessageFormat> = {
constant PARSERS (line 111) | const PARSERS: Record<MessageFormat, (text: string) => MessagesObject> = {
constant ALLOWED_CHROME_MESSAGE_KEYS (line 117) | const ALLOWED_CHROME_MESSAGE_KEYS: Set<string> = new Set<keyof ChromeMes...
function parseMessagesFile (line 128) | async function parseMessagesFile(
function parseMessagesText (line 138) | function parseMessagesText(
function parseMessagesObject (line 146) | function parseMessagesObject(object: MessagesObject): ParsedMessage[] {
function _parseMessagesObject (line 157) | function _parseMessagesObject(
function isPluralMessage (line 225) | function isPluralMessage(object: Message): object is PluralMessage {
function isChromeMessage (line 231) | function isChromeMessage(object: Message): object is ChromeMessage {
function generateTypeText (line 241) | function generateTypeText(messages: ParsedMessage[]): string {
function generateTypeFile (line 259) | async function generateTypeFile(
function generateChromeMessages (line 268) | function generateChromeMessages(
function generateChromeMessagesText (line 300) | function generateChromeMessagesText(messages: ParsedMessage[]): string {
function generateChromeMessagesFile (line 305) | async function generateChromeMessagesFile(
FILE: packages/i18n/src/index.ts
function createI18n (line 10) | function createI18n<
FILE: packages/i18n/src/module.ts
method setup (line 32) | setup(wxt, options) {
type I18nOptions (line 185) | interface I18nOptions {
type InlineConfig (line 195) | interface InlineConfig {
FILE: packages/i18n/src/supported-locales.ts
constant SUPPORTED_LOCALES (line 2) | const SUPPORTED_LOCALES = new Set([
FILE: packages/i18n/src/types.ts
type I18nFeatures (line 1) | interface I18nFeatures {
type I18nStructure (line 6) | type I18nStructure = {
type DefaultI18nStructure (line 10) | type DefaultI18nStructure = {
type SubstitutionTuple (line 15) | type SubstitutionTuple<T extends SubstitutionCount> =
type TFunction (line 27) | type TFunction<T extends I18nStructure> = {
type I18n (line 69) | interface I18n<T extends DefaultI18nStructure> {
type Substitution (line 73) | type Substitution = string | number;
type SubstitutionCount (line 75) | type SubstitutionCount = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
FILE: packages/i18n/src/utils.ts
function applyChromeMessagePlaceholders (line 3) | function applyChromeMessagePlaceholders(message: ChromeMessage): string {
function getSubstitutionCount (line 14) | function getSubstitutionCount(message: string): number {
constant MAX_SUBSTITUTIONS (line 23) | const MAX_SUBSTITUTIONS = 9;
function standardizeLocale (line 26) | function standardizeLocale(locale: string): string {
FILE: packages/is-background/src/__tests__/getter.test.ts
method browser (line 6) | get browser() {
function setupEnv (line 14) | function setupEnv(options: {
FILE: packages/is-background/src/getter.ts
class ServiceWorkerGlobalScope (line 3) | class ServiceWorkerGlobalScope {}
function getIsBackground (line 5) | function getIsBackground(): boolean {
FILE: packages/is-background/src/index.ts
function isBackground (line 28) | function isBackground(): boolean {
FILE: packages/module-react/entrypoints/content/index.tsx
method main (line 12) | async main(ctx) {
function createUi (line 18) | function createUi(ctx: ContentScriptContext) {
FILE: packages/module-react/modules/react.ts
method setup (line 9) | setup(wxt, options) {
type ReactModuleOptions (line 32) | interface ReactModuleOptions {
type InlineConfig (line 43) | interface InlineConfig {
FILE: packages/module-solid/entrypoints/content/index.tsx
method main (line 11) | async main(ctx) {
function createUi (line 17) | function createUi(ctx: ContentScriptContext) {
FILE: packages/module-solid/modules/solid.ts
method setup (line 8) | setup(wxt, options) {
type SolidModuleOptions (line 34) | interface SolidModuleOptions {
type InlineConfig (line 39) | interface InlineConfig {
FILE: packages/module-svelte/src/index.ts
method setup (line 12) | setup(wxt, options) {
type SvelteModuleOptions (line 33) | interface SvelteModuleOptions {
type InlineConfig (line 38) | interface InlineConfig {
FILE: packages/module-vue/src/index.ts
method setup (line 8) | setup(wxt, options) {
type VueModuleOptions (line 39) | interface VueModuleOptions {
type InlineConfig (line 44) | interface InlineConfig {
FILE: packages/runner/src/bidi.ts
type BidiConnection (line 6) | interface BidiConnection extends Disposable {
function createBidiConnection (line 11) | async function createBidiConnection(
FILE: packages/runner/src/browser-paths.ts
type BrowserPlatform (line 1) | type BrowserPlatform = 'windows' | 'mac' | 'linux';
type KnownTarget (line 3) | type KnownTarget =
constant KNOWN_BROWSER_PATHS (line 20) | const KNOWN_BROWSER_PATHS: Record<
constant FALLBACK_TARGETS (line 130) | const FALLBACK_TARGETS: Partial<Record<KnownTarget, KnownTarget[]>> = {
FILE: packages/runner/src/cdp.ts
type CDPConnection (line 7) | interface CDPConnection extends Disposable {
function createCdpConnection (line 12) | function createCdpConnection(
FILE: packages/runner/src/debug.ts
type Debug (line 1) | interface Debug {
function createDebug (line 6) | function createDebug(scopes: string[]): Debug {
FILE: packages/runner/src/install.ts
function installFirefox (line 13) | async function installFirefox(
type BidiWebExtensionInstallResponse (line 34) | type BidiWebExtensionInstallResponse = {
function installChromium (line 48) | async function installChromium(
type CdpExtensionsLoadUnpackedResponse (line 61) | type CdpExtensionsLoadUnpackedResponse = {
FILE: packages/runner/src/options.ts
type UnknownTarget (line 14) | type UnknownTarget = string & {};
type Target (line 15) | type Target = KnownTarget | UnknownTarget;
type RunOptions (line 17) | type RunOptions = {
type ResolvedRunOptions (line 63) | type ResolvedRunOptions = {
function resolveRunOptions (line 78) | async function resolveRunOptions(
function findBrowserBinary (line 132) | async function findBrowserBinary(target: string): Promise<string | undef...
function getPlatform (line 147) | function getPlatform(): BrowserPlatform {
function resolveChromiumArgs (line 158) | function resolveChromiumArgs(
function resolveFirefoxArgs (line 184) | function resolveFirefoxArgs(
function deduplicateArgs (line 211) | function deduplicateArgs(
function pathExists (line 235) | async function pathExists(path: string): Promise<boolean> {
constant CHROME_LAUNCHER_DEFAULT_FLAGS (line 251) | const CHROME_LAUNCHER_DEFAULT_FLAGS = [
FILE: packages/runner/src/promises.ts
function promiseWithResolvers (line 1) | function promiseWithResolvers<T>(): {
FILE: packages/runner/src/run.ts
type Runner (line 14) | interface Runner {
function run (line 18) | async function run(options: RunOptions): Promise<Runner> {
function runFirefox (line 31) | async function runFirefox(options: ResolvedRunOptions): Promise<Runner> {
function runChromium (line 73) | async function runChromium(options: ResolvedRunOptions): Promise<Runner> {
FILE: packages/runner/src/web-socket.ts
function openWebSocket (line 1) | function openWebSocket(url: string): Promise<WebSocket> {
FILE: packages/storage/src/__tests__/index.test.ts
function waitForMigrations (line 10) | async function waitForMigrations() {
function waitForInit (line 18) | async function waitForInit() {
FILE: packages/storage/src/index.ts
function createStorage (line 15) | function createStorage(): WxtStorage {
function createDriver (line 583) | function createDriver(storageArea: StorageArea): WxtStorageDriver {
type WxtStorage (line 689) | interface WxtStorage {
type WxtStorageDriver (line 873) | interface WxtStorageDriver {
type WxtStorageItem (line 887) | interface WxtStorageItem<
type StorageArea (line 931) | type StorageArea = 'local' | 'session' | 'sync' | 'managed';
type StorageItemKey (line 932) | type StorageItemKey = `${StorageArea}:${string}`;
type GetItemOptions (line 934) | interface GetItemOptions<T> {
type RemoveItemOptions (line 942) | interface RemoveItemOptions {
type SnapshotOptions (line 951) | interface SnapshotOptions {
type WxtStorageItemOptions (line 959) | interface WxtStorageItemOptions<T> {
type StorageAreaChanges (line 998) | type StorageAreaChanges = {
type NullablePartial (line 1006) | type NullablePartial<T> = {
type WatchCallback (line 1011) | type WatchCallback<T> = (newValue: T, oldValue: T) => void;
type Unwatch (line 1014) | type Unwatch = () => void;
class MigrationError (line 1016) | class MigrationError extends Error {
method constructor (line 1017) | constructor(
FILE: packages/unocss/src/index.ts
method setup (line 9) | async setup(wxt, options) {
type UnoCSSOptions (line 42) | interface UnoCSSOptions<Theme extends object = object> {
type InlineConfig (line 69) | interface InlineConfig {
FILE: packages/webextension-polyfill/entrypoints/content/index.ts
method main (line 3) | async main() {
FILE: packages/webextension-polyfill/modules/webextension-polyfill/index.ts
method setup (line 7) | setup(wxt) {
FILE: packages/wxt-demo/modules/example.ts
type ExampleModuleOptions (line 4) | interface ExampleModuleOptions {
type InlineConfig (line 9) | interface InlineConfig {
method setup (line 16) | setup(wxt, options) {
FILE: packages/wxt-demo/src/app.config.ts
type WxtAppConfig (line 4) | interface WxtAppConfig {
FILE: packages/wxt-demo/src/entrypoints/automount.content/index.ts
method main (line 8) | async main(ctx) {
FILE: packages/wxt-demo/src/entrypoints/background.ts
method main (line 4) | main() {
function _otherTypeChecksNotEvaluated (line 47) | function _otherTypeChecksNotEvaluated() {
FILE: packages/wxt-demo/src/entrypoints/example-tsx.content.tsx
method main (line 5) | async main(ctx) {
function SomeComponent (line 27) | function SomeComponent() {
FILE: packages/wxt-demo/src/entrypoints/iframe.content.ts
method main (line 4) | main(ctx) {
FILE: packages/wxt-demo/src/entrypoints/location-change.content.ts
method main (line 5) | main(ctx) {
FILE: packages/wxt-demo/src/entrypoints/main-world.content.ts
method main (line 5) | main() {
FILE: packages/wxt-demo/src/entrypoints/ui.content/index.ts
method main (line 9) | async main(ctx) {
FILE: packages/wxt-demo/src/utils/logger.ts
function logId (line 3) | function logId() {
FILE: packages/wxt/e2e/tests/auto-imports.test.ts
function runEslint (line 310) | async function runEslint(
FILE: packages/wxt/e2e/tests/hooks.test.ts
function expectHooksToBeCalled (line 30) | function expectHooksToBeCalled(
FILE: packages/wxt/e2e/tests/modules.test.ts
function addPluginModule (line 163) | function addPluginModule(project: TestProject) {
FILE: packages/wxt/e2e/tests/npm-packages.test.ts
function iterateDependencies (line 27) | function iterateDependencies(
FILE: packages/wxt/e2e/utils.ts
constant WXT_PACKAGE_DIR (line 20) | const WXT_PACKAGE_DIR = resolve(__dirname, '..');
constant E2E_DIR (line 22) | const E2E_DIR = resolve(WXT_PACKAGE_DIR, 'e2e');
class TestProject (line 24) | class TestProject {
method constructor (line 30) | constructor(packageJson: any = {}) {
method setConfigFileConfig (line 64) | setConfigFileConfig(config: UserConfig = {}) {
method addFile (line 83) | addFile(filename: string, content?: string) {
method prepare (line 89) | async prepare(config: InlineConfig = {}) {
method build (line 94) | async build(config: InlineConfig = {}) {
method zip (line 99) | async zip(config: InlineConfig = {}) {
method startServer (line 104) | async startServer(config: InlineConfig = {}) {
method resolvePath (line 112) | resolvePath(...path: string[]): string {
method writeProjectToDisk (line 116) | private async writeProjectToDisk() {
method serializeOutput (line 147) | serializeOutput(ignoreContentsOfFilenames?: string[]): Promise<string> {
method serializeDir (line 157) | private async serializeDir(
method serializeFile (line 183) | async serializeFile(path: string, ignoreContents?: boolean): Promise<s...
method pathExists (line 193) | pathExists(...path: string[]): Promise<boolean> {
method getOutputManifest (line 197) | getOutputManifest(
FILE: packages/wxt/src/@types/globals.d.ts
type ImportMetaEnv (line 4) | interface ImportMetaEnv {
FILE: packages/wxt/src/@types/modules.d.ts
type WebExtRunInstance (line 4) | interface WebExtRunInstance {
type IConsoleStream (line 19) | interface IConsoleStream {
type Packet (line 25) | interface Packet {
class ConsoleStream (line 30) | class ConsoleStream implements IConsoleStream {
FILE: packages/wxt/src/@types/project-types.d.ts
type PublicPath (line 3) | type PublicPath = string;
FILE: packages/wxt/src/browser.ts
type WxtRuntime (line 24) | interface WxtRuntime {}
type WxtI18n (line 32) | interface WxtI18n {}
type ScriptInjection (line 34) | type ScriptInjection<Args extends any[], Result> =
type InjectionResult (line 40) | type InjectionResult<Result> = Array<
type WxtScripting (line 44) | interface WxtScripting {
type WxtBrowser (line 57) | type WxtBrowser = Omit<
FILE: packages/wxt/src/builtin-modules/unimport.ts
method setup (line 14) | setup(wxt) {
function getImportsDeclarationEntry (line 71) | async function getImportsDeclarationEntry(
function getImportsModuleEntry (line 85) | async function getImportsModuleEntry(
function getEslintConfigEntry (line 104) | async function getEslintConfigEntry(
function getEslint8ConfigEntry (line 122) | function getEslint8ConfigEntry(
function getEslint9ConfigEntry (line 132) | function getEslint9ConfigEntry(
FILE: packages/wxt/src/cli/__tests__/index.test.ts
function mockArgv (line 35) | function mockArgv(...args: string[]) {
function importCli (line 39) | async function importCli() {
FILE: packages/wxt/src/cli/cli-utils.ts
function wrapAction (line 14) | function wrapAction(
function getArrayFromFlags (line 61) | function getArrayFromFlags<T>(
function createAliasedCommand (line 78) | function createAliasedCommand(
function isAliasedCommand (line 105) | function isAliasedCommand(command: Command | undefined): boolean {
FILE: packages/wxt/src/core/build.ts
function build (line 19) | async function build(config?: InlineConfig): Promise<BuildOutput> {
FILE: packages/wxt/src/core/builders/vite/__tests__/fixtures/module.ts
function defineSomething (line 3) | function defineSomething<T>(config: T): T {
FILE: packages/wxt/src/core/builders/vite/index.ts
function createViteBuilder (line 32) | async function createViteBuilder(
function getBuildOutputChunks (line 389) | function getBuildOutputChunks(
function getRollupEntry (line 401) | function getRollupEntry(entrypoint: Entrypoint): string {
function moveHtmlFiles (line 436) | async function moveHtmlFiles(
function removeEmptyDirs (line 479) | async function removeEmptyDirs(dir: string): Promise<void> {
FILE: packages/wxt/src/core/builders/vite/plugins/__tests__/iifeFooter.test.ts
type OutputChunk (line 4) | interface OutputChunk {
type OutputAsset (line 10) | interface OutputAsset {
type OutputBundle (line 15) | type OutputBundle = Record<string, OutputChunk | OutputAsset>;
function dedent (line 17) | function dedent(code: string) {
function createBundle (line 22) | function createBundle(code: string): OutputBundle {
function getCode (line 32) | function getCode(bundle: OutputBundle): string {
function runPlugin (line 42) | function runPlugin(name: string, bundle: OutputBundle) {
FILE: packages/wxt/src/core/builders/vite/plugins/bundleAnalysis.ts
function bundleAnalysis (line 8) | function bundleAnalysis(config: ResolvedConfig): vite.Plugin {
function resetBundleIncrement (line 19) | function resetBundleIncrement() {
FILE: packages/wxt/src/core/builders/vite/plugins/cssEntrypoints.ts
function cssEntrypoints (line 17) | function cssEntrypoints(
FILE: packages/wxt/src/core/builders/vite/plugins/defineImportMeta.ts
function defineImportMeta (line 7) | function defineImportMeta() {
FILE: packages/wxt/src/core/builders/vite/plugins/devHtmlPrerender.ts
function devHtmlPrerender (line 16) | function devHtmlPrerender(
function pointToDevServer (line 153) | function pointToDevServer(
function isUrl (line 211) | function isUrl(str: string): boolean {
FILE: packages/wxt/src/core/builders/vite/plugins/devServerGlobals.ts
function devServerGlobals (line 8) | function devServerGlobals(
FILE: packages/wxt/src/core/builders/vite/plugins/download.ts
function download (line 13) | function download(config: ResolvedConfig): Plugin {
FILE: packages/wxt/src/core/builders/vite/plugins/entrypointGroupGlobals.ts
function entrypointGroupGlobals (line 6) | function entrypointGroupGlobals(
FILE: packages/wxt/src/core/builders/vite/plugins/extensionApiMock.ts
function extensionApiMock (line 9) | function extensionApiMock(config: ResolvedConfig): vite.PluginOption {
FILE: packages/wxt/src/core/builders/vite/plugins/globals.ts
function globals (line 5) | function globals(config: ResolvedConfig): vite.PluginOption {
FILE: packages/wxt/src/core/builders/vite/plugins/iifeAnonymous.ts
function iifeAnonymous (line 3) | function iifeAnonymous(iifeReturnValueName: string): Plugin {
FILE: packages/wxt/src/core/builders/vite/plugins/iifeFooter.ts
function iifeFooter (line 10) | function iifeFooter(iifeReturnValueName: string): Plugin {
FILE: packages/wxt/src/core/builders/vite/plugins/noopBackground.ts
function noopBackground (line 9) | function noopBackground(): Plugin {
FILE: packages/wxt/src/core/builders/vite/plugins/removeEntrypointMainFunction.ts
function removeEntrypointMainFunction (line 11) | function removeEntrypointMainFunction(
FILE: packages/wxt/src/core/builders/vite/plugins/resolveAppConfig.ts
function resolveAppConfig (line 10) | function resolveAppConfig(config: ResolvedConfig): vite.Plugin {
FILE: packages/wxt/src/core/builders/vite/plugins/resolveVirtualModules.ts
function resolveVirtualModules (line 15) | function resolveVirtualModules(config: ResolvedConfig): Plugin[] {
FILE: packages/wxt/src/core/builders/vite/plugins/tsconfigPaths.ts
function tsconfigPaths (line 4) | function tsconfigPaths(config: ResolvedConfig): vite.Plugin {
FILE: packages/wxt/src/core/builders/vite/plugins/wxtPluginLoader.ts
function wxtPluginLoader (line 11) | function wxtPluginLoader(config: ResolvedConfig): vite.Plugin {
FILE: packages/wxt/src/core/clean.ts
function clean (line 29) | async function clean(config?: string | InlineConfig) {
FILE: packages/wxt/src/core/create-server.ts
function createServer (line 44) | async function createServer(
function createServerInternal (line 54) | async function createServerInternal(): Promise<WxtDevServer> {
function createFileReloader (line 206) | function createFileReloader(server: WxtDevServer) {
function reloadContentScripts (line 302) | function reloadContentScripts(steps: BuildStepOutput[], server: WxtDevSe...
function reloadHtmlPages (line 328) | function reloadHtmlPages(
function getFilenameList (line 345) | function getFilenameList(names: string[]): string {
function getExternalOutputDependencies (line 359) | function getExternalOutputDependencies(server: WxtDevServer) {
FILE: packages/wxt/src/core/define-config.ts
function defineConfig (line 3) | function defineConfig(config: UserConfig): UserConfig {
FILE: packages/wxt/src/core/define-web-ext-config.ts
function defineRunnerConfig (line 5) | function defineRunnerConfig(config: WebExtConfig): WebExtConfig {
function defineWebExtConfig (line 16) | function defineWebExtConfig(config: WebExtConfig): WebExtConfig {
FILE: packages/wxt/src/core/generate-wxt-dir.ts
function generateWxtDir (line 16) | async function generateWxtDir(entrypoints: Entrypoint[]): Promise<void> {
function getPathsDeclarationEntry (line 66) | async function getPathsDeclarationEntry(
function getEntrypointPublicExt (line 111) | function getEntrypointPublicExt(entry: Entrypoint): '.html' | '.js' | '....
function getI18nDeclarationEntry (line 123) | async function getI18nDeclarationEntry(): Promise<WxtDirFileEntry> {
function getGlobalsDeclarationEntry (line 206) | async function getGlobalsDeclarationEntry(): Promise<WxtDirFileEntry> {
function getMainDeclarationEntry (line 224) | function getMainDeclarationEntry(references: WxtDirEntry[]): WxtDirFileE...
function getTsConfigEntry (line 241) | async function getTsConfigEntry(): Promise<WxtDirFileEntry> {
FILE: packages/wxt/src/core/initialize.ts
function initialize (line 10) | async function initialize(options: {
type Template (line 90) | interface Template {
function listTemplates (line 97) | async function listTemplates(): Promise<Template[]> {
function listTemplatesUngh (line 111) | async function listTemplatesUngh(): Promise<Template[]> {
function listTemplatesGithub (line 135) | async function listTemplatesGithub(): Promise<Template[]> {
function cloneProject (line 154) | async function cloneProject({
constant TEMPLATE_COLORS (line 185) | const TEMPLATE_COLORS: Record<string, Formatter> = {
constant TEMPLATE_SORT_WEIGHT (line 193) | const TEMPLATE_SORT_WEIGHT: Record<string, number> = {
constant REPO (line 199) | const REPO = 'wxt-dev/wxt';
FILE: packages/wxt/src/core/keyboard-shortcuts.ts
type KeyboardShortcutWatcher (line 6) | interface KeyboardShortcutWatcher {
function createKeyboardShortcuts (line 13) | function createKeyboardShortcuts(
FILE: packages/wxt/src/core/package-managers/bun.ts
method downloadDependency (line 7) | downloadDependency(...args) {
method listDependencies (line 10) | async listDependencies(options) {
FILE: packages/wxt/src/core/package-managers/deno.ts
method downloadDependency (line 5) | downloadDependency() {
method listDependencies (line 8) | listDependencies() {
FILE: packages/wxt/src/core/package-managers/index.ts
function createWxtPackageManager (line 19) | async function createWxtPackageManager(
FILE: packages/wxt/src/core/package-managers/npm.ts
method downloadDependency (line 9) | async downloadDependency(id, downloadDir) {
method listDependencies (line 17) | async listDependencies(options) {
function flattenNpmListOutput (line 29) | function flattenNpmListOutput(projects: NpmListProject[]): Dependency[] {
function dedupeDependencies (line 52) | function dedupeDependencies(dependencies: Dependency[]): Dependency[] {
type NpmListProject (line 65) | interface NpmListProject {
type NpmListDependency (line 71) | interface NpmListDependency {
type PackedDependency (line 79) | interface PackedDependency {
FILE: packages/wxt/src/core/package-managers/pnpm.ts
method downloadDependency (line 7) | downloadDependency(...args) {
method listDependencies (line 10) | async listDependencies(options) {
FILE: packages/wxt/src/core/package-managers/types.ts
type WxtPackageManagerImpl (line 3) | type WxtPackageManagerImpl = Pick<
FILE: packages/wxt/src/core/package-managers/yarn.ts
method downloadDependency (line 8) | downloadDependency(...args) {
method listDependencies (line 11) | async listDependencies(options) {
type JsonLine (line 42) | type JsonLine =
type JsonLineTree (line 46) | interface JsonLineTree {
type Tree (line 51) | interface Tree {
FILE: packages/wxt/src/core/prepare.ts
function prepare (line 6) | async function prepare(config: InlineConfig) {
FILE: packages/wxt/src/core/resolve-config.ts
function resolveConfig (line 41) | async function resolveConfig(
function resolveManifestConfig (line 243) | async function resolveManifestConfig(
function mergeInlineConfig (line 256) | async function mergeInlineConfig(
function resolveZipConfig (line 293) | function resolveZipConfig(
function resolveAnalysisConfig (line 330) | function resolveAnalysisConfig(
function getUnimportOptions (line 352) | async function getUnimportOptions(
function getUnimportEslintOptions (line 498) | async function getUnimportEslintOptions(
function resolveWxtModuleDir (line 534) | function resolveWxtModuleDir() {
function isDirMissing (line 545) | async function isDirMissing(dir: string) {
function logMissingDir (line 549) | function logMissingDir(logger: Logger, name: string, expected: string) {
constant COMMAND_MODES (line 558) | const COMMAND_MODES: Record<WxtCommand, string> = {
function mergeBuilderConfig (line 563) | async function mergeBuilderConfig(
function resolveWxtUserModules (line 584) | async function resolveWxtUserModules(
FILE: packages/wxt/src/core/runners/index.ts
function createExtensionRunner (line 9) | async function createExtensionRunner(): Promise<ExtensionRunner> {
FILE: packages/wxt/src/core/runners/manual.ts
function createManualRunner (line 6) | function createManualRunner(): ExtensionRunner {
FILE: packages/wxt/src/core/runners/safari.ts
function createSafariRunner (line 9) | function createSafariRunner(): ExtensionRunner {
FILE: packages/wxt/src/core/runners/web-ext.ts
function createWebExtRunner (line 8) | function createWebExtRunner(): ExtensionRunner {
constant WARN_LOG_LEVEL (line 86) | const WARN_LOG_LEVEL = 40;
constant ERROR_LOG_LEVEL (line 87) | const ERROR_LOG_LEVEL = 50;
constant DEFAULT_CHROMIUM_PREFS (line 89) | const DEFAULT_CHROMIUM_PREFS = {
FILE: packages/wxt/src/core/runners/wsl.ts
function createWslRunner (line 9) | function createWslRunner(): ExtensionRunner {
FILE: packages/wxt/src/core/utils/__tests__/manifest.test.ts
type ActionType (line 36) | type ActionType = 'browser_action' | 'page_action';
FILE: packages/wxt/src/core/utils/__tests__/network.test.ts
type DnsCallback (line 6) | type DnsCallback = (err: NodeJS.ErrnoException | null) => void;
type MockedFetch (line 7) | type MockedFetch = ReturnType<typeof vi.fn>;
FILE: packages/wxt/src/core/utils/arrays.ts
function every (line 2) | function every<T>(
function some (line 12) | function some<T>(
function toArray (line 22) | function toArray<T>(a: T | T[]): T[] {
function filterTruthy (line 26) | function filterTruthy<T>(array: Array<T | undefined>): T[] {
FILE: packages/wxt/src/core/utils/building/__tests__/test-entrypoints/background.ts
method main (line 4) | main() {}
FILE: packages/wxt/src/core/utils/building/__tests__/test-entrypoints/content.ts
method main (line 5) | main() {}
FILE: packages/wxt/src/core/utils/building/__tests__/test-entrypoints/imported-option.ts
method main (line 6) | main() {}
FILE: packages/wxt/src/core/utils/building/build-entrypoints.ts
function buildEntrypoints (line 15) | async function buildEntrypoints(
function copyPublicDirectory (line 41) | async function copyPublicDirectory(): Promise<BuildOutput['publicAssets'...
FILE: packages/wxt/src/core/utils/building/detect-dev-changes.ts
function detectDevChanges (line 44) | function detectDevChanges(
function findEffectedSteps (line 141) | function findEffectedSteps(
type DevModeChange (line 181) | type DevModeChange =
type NoChange (line 189) | interface NoChange {
type RebuildChange (line 193) | interface RebuildChange {
type FullRestart (line 200) | interface FullRestart {
type BrowserRestart (line 204) | interface BrowserRestart {
type HtmlReload (line 208) | interface HtmlReload extends RebuildChange {
type ExtensionReload (line 212) | interface ExtensionReload extends RebuildChange {
type ContentScriptReload (line 216) | interface ContentScriptReload extends RebuildChange {
FILE: packages/wxt/src/core/utils/building/find-entrypoints.ts
function findEntrypoints (line 36) | async function findEntrypoints(): Promise<Entrypoint[]> {
function importEntrypoints (line 174) | async function importEntrypoints(infos: EntrypointInfo[]) {
function importHtmlEntrypoint (line 204) | async function importHtmlEntrypoint(
function preventDuplicateEntrypointNames (line 237) | function preventDuplicateEntrypointNames(files: EntrypointInfo[]) {
function preventNoEntrypoints (line 266) | function preventNoEntrypoints(files: EntrypointInfo[]) {
function getPopupEntrypoint (line 272) | async function getPopupEntrypoint(
function getOptionsEntrypoint (line 299) | async function getOptionsEntrypoint(
function getUnlistedPageEntrypoint (line 312) | async function getUnlistedPageEntrypoint(
function getUnlistedScriptEntrypoint (line 325) | async function getUnlistedScriptEntrypoint(
function getBackgroundEntrypoint (line 338) | async function getBackgroundEntrypoint(
function getContentScriptEntrypoint (line 358) | async function getContentScriptEntrypoint(
function getSidepanelEntrypoint (line 376) | async function getSidepanelEntrypoint(
function isEntrypointSkipped (line 398) | function isEntrypointSkipped(entry: Omit<Entrypoint, 'skipped'>): boolean {
constant PATH_GLOB_TO_TYPE_MAP (line 421) | const PATH_GLOB_TO_TYPE_MAP: Record<string, Entrypoint['type']> = {
constant CONTENT_SCRIPT_OUT_DIR (line 471) | const CONTENT_SCRIPT_OUT_DIR = 'content-scripts';
FILE: packages/wxt/src/core/utils/building/group-entrypoints.ts
function groupEntrypoints (line 9) | function groupEntrypoints(entrypoints: Entrypoint[]): EntrypointGroup[] {
constant ENTRY_TYPE_TO_GROUP_MAP (line 35) | const ENTRY_TYPE_TO_GROUP_MAP: Record<Entrypoint['type'], Group> = {
type Group (line 54) | type Group = 'esm' | 'sandboxed-esm' | 'individual';
FILE: packages/wxt/src/core/utils/building/internal-build.ts
function internalBuild (line 33) | async function internalBuild(): Promise<BuildOutput> {
function combineAnalysisStats (line 99) | async function combineAnalysisStats(): Promise<void> {
function printValidationResults (line 120) | function printValidationResults({
FILE: packages/wxt/src/core/utils/building/rebuild.ts
function rebuild (line 27) | async function rebuild(
FILE: packages/wxt/src/core/utils/cache.ts
function createFsCache (line 12) | function createFsCache(wxtDir: string): FsCache {
FILE: packages/wxt/src/core/utils/cli.ts
function defineCommand (line 5) | function defineCommand<TArgs extends any[]>(
FILE: packages/wxt/src/core/utils/constants.ts
constant VIRTUAL_NOOP_BACKGROUND_MODULE_ID (line 5) | const VIRTUAL_NOOP_BACKGROUND_MODULE_ID = 'virtual:user-background';
FILE: packages/wxt/src/core/utils/content-scripts.ts
function hashContentScriptOptions (line 12) | function hashContentScriptOptions(
function mapWxtOptionsToContentScript (line 51) | function mapWxtOptionsToContentScript(
function mapWxtOptionsToRegisteredContentScript (line 72) | function mapWxtOptionsToRegisteredContentScript(
function getContentScriptJs (line 88) | function getContentScriptJs(
FILE: packages/wxt/src/core/utils/content-security-policy.ts
type CspDirective (line 5) | type CspDirective = 'default-src' | 'script-src' | 'object-src';
class ContentSecurityPolicy (line 7) | class ContentSecurityPolicy {
method constructor (line 16) | constructor(csp?: string) {
method add (line 30) | add(directive: CspDirective, ...newValues: string[]): ContentSecurityP...
method toString (line 39) | toString(): string {
FILE: packages/wxt/src/core/utils/entrypoints.ts
function getEntrypointName (line 10) | function getEntrypointName(
function getEntrypointOutputFile (line 22) | function getEntrypointOutputFile(
function getEntrypointBundlePath (line 33) | function getEntrypointBundlePath(
function resolvePerBrowserOption (line 44) | function resolvePerBrowserOption<T>(
function resolvePerBrowserOptions (line 59) | function resolvePerBrowserOptions<
function isHtmlEntrypoint (line 77) | function isHtmlEntrypoint(
function isJsEntrypoint (line 89) | function isJsEntrypoint(
FILE: packages/wxt/src/core/utils/env.ts
function loadEnv (line 7) | function loadEnv(mode: string, browser: TargetBrowser) {
FILE: packages/wxt/src/core/utils/environments/browser-environment.ts
function createBrowserEnvironment (line 4) | function createBrowserEnvironment(): Environment {
function getBrowserEnvironmentGlobals (line 8) | function getBrowserEnvironmentGlobals(): EnvGlobals {
FILE: packages/wxt/src/core/utils/environments/environment.ts
type Environment (line 1) | interface Environment {
function createEnvironment (line 6) | function createEnvironment(getGlobals: () => EnvGlobals): Environment {
type EnvGlobals (line 30) | type EnvGlobals = Record<string, any>;
function getOgGlobals (line 32) | function getOgGlobals(envGlobals: EnvGlobals): EnvGlobals {
function applyGlobals (line 40) | function applyGlobals(globals: EnvGlobals): void {
FILE: packages/wxt/src/core/utils/environments/extension-environment.ts
function createExtensionEnvironment (line 5) | function createExtensionEnvironment(): Environment {
function getExtensionEnvironmentGlobals (line 9) | function getExtensionEnvironmentGlobals() {
FILE: packages/wxt/src/core/utils/eslint.ts
function getEslintVersion (line 1) | async function getEslintVersion(): Promise<string[]> {
FILE: packages/wxt/src/core/utils/fs.ts
function pathExists (line 6) | async function pathExists(path: string): Promise<boolean> {
function readJson (line 15) | async function readJson<T = any>(path: string): Promise<T> {
function writeFileIfDifferent (line 27) | async function writeFileIfDifferent(
function getPublicFiles (line 38) | async function getPublicFiles(): Promise<string[]> {
FILE: packages/wxt/src/core/utils/globals.ts
function getGlobals (line 3) | function getGlobals(
function getEntrypointGlobals (line 53) | function getEntrypointGlobals(entrypointName: string) {
FILE: packages/wxt/src/core/utils/i18n.ts
type Message (line 1) | interface Message {
function parseI18nMessages (line 44) | function parseI18nMessages(messagesJson: object): Message[] {
FILE: packages/wxt/src/core/utils/log/printBuildSummary.ts
function printBuildSummary (line 6) | async function printBuildSummary(
constant DEFAULT_SORT_WEIGHT (line 28) | const DEFAULT_SORT_WEIGHT = 100;
constant CHUNK_SORT_WEIGHTS (line 29) | const CHUNK_SORT_WEIGHTS: Record<string, number> = {
function getChunkSortWeight (line 36) | function getChunkSortWeight(filename: string) {
FILE: packages/wxt/src/core/utils/log/printFileList.ts
function printFileList (line 7) | async function printFileList(
constant DEFAULT_COLOR (line 38) | const DEFAULT_COLOR = pc.blue;
constant CHUNK_COLORS (line 39) | const CHUNK_COLORS: Record<string, (text: string) => string> = {
function getChunkColor (line 50) | function getChunkColor(filename: string) {
FILE: packages/wxt/src/core/utils/log/printHeader.ts
function printHeader (line 5) | function printHeader() {
FILE: packages/wxt/src/core/utils/log/printTable.ts
function printTable (line 1) | function printTable(
FILE: packages/wxt/src/core/utils/manifest.ts
function writeManifest (line 27) | async function writeManifest(
function generateManifest (line 46) | async function generateManifest(
function simplifyVersion (line 158) | function simplifyVersion(versionName: string): string {
function addEntrypoints (line 172) | function addEntrypoints(
function discoverIcons (line 430) | function discoverIcons(
function addDevModeCsp (line 464) | function addDevModeCsp(manifest: Browser.runtime.Manifest): void {
function addDevModePermissions (line 505) | function addDevModePermissions(manifest: Browser.runtime.Manifest) {
function getContentScriptCssFiles (line 517) | function getContentScriptCssFiles(
function getContentScriptCssWebAccessibleResources (line 545) | function getContentScriptCssWebAccessibleResources(
function getContentScriptsCssMap (line 574) | function getContentScriptsCssMap(
function addPermission (line 589) | function addPermission(
function addHostPermission (line 600) | function addHostPermission(
function stripPathFromMatchPattern (line 613) | function stripPathFromMatchPattern(pattern: string) {
function convertWebAccessibleResourcesToMv2 (line 627) | function convertWebAccessibleResourcesToMv2(
function moveHostPermissionsToPermissions (line 642) | function moveHostPermissionsToPermissions(
function convertActionToMv2 (line 653) | function convertActionToMv2(manifest: Browser.runtime.Manifest): void {
function convertCspToMv2 (line 664) | function convertCspToMv2(manifest: Browser.runtime.Manifest): void {
function validateMv3WebAccessibleResources (line 676) | function validateMv3WebAccessibleResources(
function stripKeys (line 694) | function stripKeys(manifest: Browser.runtime.Manifest): void {
constant DEFAULT_MV3_EXTENSION_PAGES_CSP (line 737) | const DEFAULT_MV3_EXTENSION_PAGES_CSP =
constant DEFAULT_MV3_SANDBOX_CSP (line 739) | const DEFAULT_MV3_SANDBOX_CSP =
constant DEFAULT_MV2_CSP (line 741) | const DEFAULT_MV2_CSP = "script-src 'self'; object-src 'self';";
FILE: packages/wxt/src/core/utils/network.ts
function isOffline (line 6) | async function isOffline(): Promise<boolean> {
function isOnline (line 18) | async function isOnline(): Promise<boolean> {
function fetchCached (line 27) | async function fetchCached(
FILE: packages/wxt/src/core/utils/number.ts
function safeStringToNumber (line 1) | function safeStringToNumber(str: string | undefined): number | null {
FILE: packages/wxt/src/core/utils/package.ts
function getPackageJson (line 10) | async function getPackageJson(): Promise<
FILE: packages/wxt/src/core/utils/paths.ts
function normalizePath (line 8) | function normalizePath(path: string): string {
function unnormalizePath (line 16) | function unnormalizePath(path: string): string {
constant CSS_EXTENSIONS (line 20) | const CSS_EXTENSIONS = ['css', 'scss', 'sass', 'less', 'styl', 'stylus'];
constant CSS_EXTENSIONS_PATTERN (line 23) | const CSS_EXTENSIONS_PATTERN = `+(${CSS_EXTENSIONS.join('|')})`;
FILE: packages/wxt/src/core/utils/picomatch-multiple.ts
function picomatchMultiple (line 16) | function picomatchMultiple(
FILE: packages/wxt/src/core/utils/strings.ts
function kebabCaseAlphanumeric (line 3) | function kebabCaseAlphanumeric(str: string): string {
function safeVarName (line 11) | function safeVarName(str: string): string {
function safeFilename (line 22) | function safeFilename(str: string): string {
function removeImportStatements (line 30) | function removeImportStatements(text: string): string {
FILE: packages/wxt/src/core/utils/syntax-errors.ts
type BabelSyntaxError (line 5) | interface BabelSyntaxError extends SyntaxError {
function isBabelSyntaxError (line 12) | function isBabelSyntaxError(error: unknown): error is BabelSyntaxError {
function logBabelSyntaxError (line 19) | function logBabelSyntaxError(error: BabelSyntaxError) {
FILE: packages/wxt/src/core/utils/testing/fake-objects.ts
type DeepPartial (line 31) | type DeepPartial<T> = T extends object
function fakeObjectCreator (line 36) | function fakeObjectCreator<T>(base: () => T) {
function fakeFileName (line 40) | function fakeFileName(): string {
function fakeFile (line 44) | function fakeFile(root = process.cwd()): string {
function fakeDir (line 48) | function fakeDir(root = process.cwd()): string {
function fakeArray (line 219) | function fakeArray<T>(createItem: () => T, count = 3): T[] {
function setFakeWxt (line 336) | function setFakeWxt(overrides?: DeepPartial<Wxt>) {
FILE: packages/wxt/src/core/utils/time.ts
function formatDuration (line 1) | function formatDuration(duration: number): string {
function withTimeout (line 9) | function withTimeout<T>(
function sleep (line 28) | function sleep(ms: number): Promise<void> {
FILE: packages/wxt/src/core/utils/transform.ts
function removeMainFunctionCode (line 13) | function removeMainFunctionCode(code: string): {
function emptyMainFunction (line 32) | function emptyMainFunction(mod: ProxifiedModule): void {
function removeUnusedTopLevelVariables (line 50) | function removeUnusedTopLevelVariables(mod: ProxifiedModule): number {
function removeUnusedTopLevelFunctions (line 136) | function removeUnusedTopLevelFunctions(mod: ProxifiedModule): number {
function removeUnusedImports (line 154) | function removeUnusedImports(mod: ProxifiedModule): number {
function findUsedIdentifiers (line 171) | function findUsedIdentifiers(simpleAst: any) {
function deleteImportAst (line 202) | function deleteImportAst(
function removeSideEffectImports (line 217) | function removeSideEffectImports(mod: ProxifiedModule): void {
function getSimpleAstJson (line 225) | function getSimpleAstJson(ast: any): any {
FILE: packages/wxt/src/core/utils/types.ts
type NullablyRequired (line 10) | type NullablyRequired<T> = { [K in keyof Required<T>]: T[K] };
type ManifestContentScript (line 12) | type ManifestContentScript = NonNullable<
type ManifestV3WebAccessibleResource (line 16) | type ManifestV3WebAccessibleResource = NonNullable<
FILE: packages/wxt/src/core/utils/validation.ts
function validateEntrypoints (line 3) | function validateEntrypoints(
function validateContentScriptEntrypoint (line 29) | function validateContentScriptEntrypoint(
function validateBaseEntrypoint (line 47) | function validateBaseEntrypoint(definition: Entrypoint): ValidationResul...
type ValidationResult (line 76) | interface ValidationResult {
type ValidationResults (line 83) | interface ValidationResults {
class ValidationError (line 89) | class ValidationError extends Error {}
FILE: packages/wxt/src/core/utils/virtual-modules.ts
type VirtualEntrypointType (line 7) | type VirtualEntrypointType = (typeof virtualEntrypointTypes)[0];
type VirtualEntrypointModuleName (line 20) | type VirtualEntrypointModuleName =
type VirtualModuleName (line 36) | type VirtualModuleName = (typeof virtualModuleNames)[0];
type VirtualModuleId (line 39) | type VirtualModuleId = `virtual:wxt-${VirtualModuleName}`;
FILE: packages/wxt/src/core/utils/wsl.ts
function isWsl (line 5) | function isWsl(): boolean {
FILE: packages/wxt/src/core/wxt.ts
function registerWxt (line 20) | async function registerWxt(
function initWxtModules (line 63) | async function initWxtModules() {
function initWxtModule (line 90) | async function initWxtModule(module: WxtModule<any>): Promise<void> {
function deinitWxtModules (line 100) | function deinitWxtModules(): void {
function setWxtForTesting (line 112) | function setWxtForTesting(testInstance: Wxt) {
FILE: packages/wxt/src/core/zip.ts
function zip (line 22) | async function zip(config?: InlineConfig): Promise<string[]> {
function zipDir (line 102) | async function zipDir(
function downloadPrivatePackages (line 170) | async function downloadPrivatePackages() {
function addOverridesToPackageJson (line 199) | function addOverridesToPackageJson(
FILE: packages/wxt/src/modules.ts
function defineWxtModule (line 22) | function defineWxtModule<TOptions extends WxtModuleOptions>(
function addEntrypoint (line 56) | function addEntrypoint(wxt: Wxt, entrypoint: Entrypoint): void {
function addPublicAssets (line 75) | function addPublicAssets(wxt: Wxt, dir: string): void {
function addViteConfig (line 109) | function addViteConfig(
function addWxtPlugin (line 139) | function addWxtPlugin(wxt: Wxt, plugin: string): void {
function addImportPreset (line 175) | function addImportPreset(
function addAlias (line 215) | function addAlias(wxt: Wxt, alias: string, path: string) {
FILE: packages/wxt/src/testing/wxt-vitest-plugin.ts
function WxtVitest (line 37) | async function WxtVitest(
FILE: packages/wxt/src/types.ts
type InlineConfig (line 12) | interface InlineConfig {
type InlineConfig (line 405) | interface InlineConfig {
type ResolvedConfig (line 421) | interface ResolvedConfig {
type WxtViteConfig (line 426) | type WxtViteConfig = Omit<
type WxtHooks (line 432) | interface WxtHooks {
type BuildOutput (line 455) | interface BuildOutput {
type OutputFile (line 461) | type OutputFile = OutputChunk | OutputAsset;
type OutputChunk (line 463) | interface OutputChunk {
type OutputAsset (line 475) | interface OutputAsset {
type BuildStepOutput (line 485) | interface BuildStepOutput {
type WxtDevServer (line 490) | interface WxtDevServer
type ReloadContentScriptPayload (line 534) | interface ReloadContentScriptPayload {
type TargetBrowser (line 539) | type TargetBrowser = string;
type TargetManifestVersion (line 540) | type TargetManifestVersion = 2 | 3;
type UserConfig (line 542) | type UserConfig = Omit<InlineConfig, 'configFile'>;
type Logger (line 544) | interface Logger {
type BaseEntrypointOptions (line 555) | interface BaseEntrypointOptions {
type BackgroundEntrypointOptions (line 573) | interface BackgroundEntrypointOptions extends BaseEntrypointOptions {
type BaseScriptEntrypointOptions (line 587) | interface BaseScriptEntrypointOptions extends BaseEntrypointOptions {
type BaseContentScriptEntrypointOptions (line 613) | interface BaseContentScriptEntrypointOptions extends BaseScriptEntrypoin...
type MainWorldContentScriptEntrypointOptions (line 691) | interface MainWorldContentScriptEntrypointOptions extends BaseContentScr...
type IsolatedWorldContentScriptEntrypointOptions (line 699) | interface IsolatedWorldContentScriptEntrypointOptions extends BaseConten...
type ThemeIcon (line 714) | interface ThemeIcon {
type PopupEntrypointOptions (line 723) | interface PopupEntrypointOptions extends BaseEntrypointOptions {
type OptionsEntrypointOptions (line 746) | interface OptionsEntrypointOptions extends BaseEntrypointOptions {
type SidepanelEntrypointOptions (line 753) | interface SidepanelEntrypointOptions extends BaseEntrypointOptions {
type BaseEntrypoint (line 770) | interface BaseEntrypoint {
type GenericEntrypoint (line 808) | interface GenericEntrypoint extends BaseEntrypoint {
type UnlistedScriptEntrypoint (line 821) | interface UnlistedScriptEntrypoint extends BaseEntrypoint {
type BackgroundEntrypoint (line 826) | interface BackgroundEntrypoint extends BaseEntrypoint {
type ContentScriptEntrypoint (line 831) | interface ContentScriptEntrypoint extends BaseEntrypoint {
type PopupEntrypoint (line 839) | interface PopupEntrypoint extends BaseEntrypoint {
type OptionsEntrypoint (line 844) | interface OptionsEntrypoint extends BaseEntrypoint {
type SidepanelEntrypoint (line 849) | interface SidepanelEntrypoint extends BaseEntrypoint {
type Entrypoint (line 854) | type Entrypoint =
type EntrypointInfo (line 863) | interface EntrypointInfo {
type EntrypointGroup (line 870) | type EntrypointGroup = Entrypoint | Entrypoint[];
type OnContentScriptStopped (line 872) | type OnContentScriptStopped = (cb: () => void) => void;
type IsolatedWorldContentScriptDefinition (line 874) | interface IsolatedWorldContentScriptDefinition extends IsolatedWorldCont...
type MainWorldContentScriptDefinition (line 885) | interface MainWorldContentScriptDefinition extends MainWorldContentScrip...
type ContentScriptDefinition (line 896) | type ContentScriptDefinition =
type BackgroundDefinition (line 900) | interface BackgroundDefinition extends BackgroundEntrypointOptions {
type UnlistedScriptDefinition (line 908) | interface UnlistedScriptDefinition extends BaseScriptEntrypointOptions {
type PerBrowserOption (line 923) | type PerBrowserOption<T> = T | PerBrowserMap<T>;
type PerBrowserMap (line 924) | type PerBrowserMap<T> = { [browser: TargetBrowser]: T };
type ResolvedPerBrowserOptions (line 933) | type ResolvedPerBrowserOptions<T, TOmitted extends keyof T = never> = {
type UserManifest (line 943) | type UserManifest = {
type UserManifestFn (line 993) | type UserManifestFn = (
type ConfigEnv (line 997) | interface ConfigEnv {
type WxtCommand (line 1022) | type WxtCommand = 'build' | 'serve';
type ExtensionRunnerConfig (line 1025) | type ExtensionRunnerConfig = WebExtConfig;
type WebExtConfig (line 1031) | interface WebExtConfig {
type WxtBuilder (line 1100) | interface WxtBuilder {
type WxtBuilderServer (line 1121) | interface WxtBuilderServer {
type ServerInfo (line 1150) | interface ServerInfo {
type HookResult (line 1159) | type HookResult = Promise<void> | void;
type WxtHooks (line 1161) | interface WxtHooks {
type Wxt (line 1337) | interface Wxt {
type ResolvedConfig (line 1354) | interface ResolvedConfig {
type FsCache (line 1471) | interface FsCache {
type ExtensionRunner (line 1476) | interface ExtensionRunner {
type EslintGlobalsPropValue (line 1485) | type EslintGlobalsPropValue =
type Eslintrc (line 1492) | interface Eslintrc {
type ResolvedEslintrc (line 1520) | interface ResolvedEslintrc {
type WxtUnimportOptions (line 1528) | type WxtUnimportOptions = Partial<UnimportOptions> & {
type WxtResolvedUnimportOptions (line 1540) | type WxtResolvedUnimportOptions = Partial<UnimportOptions> & {
type WxtPackageManager (line 1557) | interface WxtPackageManager extends Nypm.PackageManager {
type Dependency (line 1588) | interface Dependency {
type WxtModuleOptions (line 1593) | type WxtModuleOptions = Record<string, any>;
type WxtModuleSetup (line 1595) | type WxtModuleSetup<TOptions extends WxtModuleOptions> = (
type WxtModule (line 1600) | interface WxtModule<TOptions extends WxtModuleOptions> {
type WxtModuleWithMetadata (line 1621) | interface WxtModuleWithMetadata<
type ResolvedPublicFile (line 1628) | type ResolvedPublicFile = CopiedPublicFile | GeneratedPublicFile;
type ResolvedBasePublicFile (line 1630) | interface ResolvedBasePublicFile {
type CopiedPublicFile (line 1640) | interface CopiedPublicFile extends ResolvedBasePublicFile {
type GeneratedPublicFile (line 1650) | interface GeneratedPublicFile extends ResolvedBasePublicFile {
type WxtPlugin (line 1655) | type WxtPlugin = () => void;
type WxtDirEntry (line 1657) | type WxtDirEntry = WxtDirTypeReferenceEntry | WxtDirFileEntry;
type WxtDirTypeReferenceEntry (line 1663) | interface WxtDirTypeReferenceEntry {
type WxtDirFileEntry (line 1673) | interface WxtDirFileEntry {
FILE: packages/wxt/src/utils/__tests__/content-script-context.test.ts
function waitForEventsToFire (line 12) | function waitForEventsToFire() {
FILE: packages/wxt/src/utils/app-config.ts
function getAppConfig (line 11) | function getAppConfig(): WxtAppConfig {
function useAppConfig (line 20) | function useAppConfig(): WxtAppConfig {
FILE: packages/wxt/src/utils/content-script-context.ts
class ContentScriptContext (line 43) | class ContentScriptContext implements AbortController {
method constructor (line 52) | constructor(
method signal (line 63) | get signal() {
method abort (line 67) | abort(reason?: any): void {
method isInvalid (line 71) | get isInvalid(): boolean {
method isValid (line 78) | get isValid(): boolean {
method onInvalidated (line 96) | onInvalidated(cb: () => void): () => void {
method block (line 112) | block<T>(): Promise<T> {
method setInterval (line 124) | setInterval(handler: () => void, timeout?: number): number {
method setTimeout (line 138) | setTimeout(handler: () => void, timeout?: number): number {
method requestAnimationFrame (line 153) | requestAnimationFrame(callback: FrameRequestCallback): number {
method requestIdleCallback (line 169) | requestIdleCallback(
method addEventListener (line 219) | addEventListener(
method notifyInvalidated (line 244) | notifyInvalidated() {
method stopOldScripts (line 251) | stopOldScripts() {
method verifyScriptStartedEvent (line 273) | verifyScriptStartedEvent(event: CustomEvent) {
method listenForNewerScripts (line 281) | listenForNewerScripts() {
type WxtWindowEventMap (line 305) | interface WxtWindowEventMap extends WindowEventMap {
FILE: packages/wxt/src/utils/content-script-ui/__tests__/index.test.ts
function runMicrotasks (line 10) | async function runMicrotasks() {
function appendTestApp (line 14) | function appendTestApp(container: HTMLElement) {
function appendTestElement (line 18) | function appendTestElement({
method onMount (line 99) | onMount(uiContainer) {
FILE: packages/wxt/src/utils/content-script-ui/iframe.ts
function createIframeUi (line 12) | function createIframeUi<TMounted>(
type IframeContentScriptUi (line 49) | interface IframeContentScriptUi<
type IframeContentScriptUiOptions (line 58) | type IframeContentScriptUiOptions<TMounted> =
FILE: packages/wxt/src/utils/content-script-ui/integrated.ts
function createIntegratedUi (line 11) | function createIntegratedUi<TMounted>(
type IntegratedContentScriptUi (line 54) | interface IntegratedContentScriptUi<
type IntegratedContentScriptUiOptions (line 61) | type IntegratedContentScriptUiOptions<TMounted> =
FILE: packages/wxt/src/utils/content-script-ui/shadow-root.ts
function createShadowRootUi (line 18) | async function createShadowRootUi<TMounted>(
function loadCss (line 120) | async function loadCss(): Promise<string> {
type ShadowRootContentScriptUi (line 136) | interface ShadowRootContentScriptUi<
type ShadowRootContentScriptUiOptions (line 154) | type ShadowRootContentScriptUiOptions<TMounted> =
FILE: packages/wxt/src/utils/content-script-ui/shared.ts
function applyPosition (line 17) | function applyPosition(
function getAnchor (line 53) | function getAnchor(
function mountUi (line 82) | function mountUi(
function createMountFunctions (line 114) | function createMountFunctions<TMounted>(
function autoMountUi (line 156) | function autoMountUi(
FILE: packages/wxt/src/utils/content-script-ui/types.ts
type ContentScriptUi (line 3) | interface ContentScriptUi<TMounted> extends MountFunctions {
type ContentScriptUiOptions (line 7) | type ContentScriptUiOptions<TMounted> = ContentScriptPositioningOptions &
type ContentScriptOverlayAlignment (line 20) | type ContentScriptOverlayAlignment =
type ContentScriptAppendMode (line 30) | type ContentScriptAppendMode =
type ContentScriptInlinePositioningOptions (line 38) | interface ContentScriptInlinePositioningOptions {
type ContentScriptOverlayPositioningOptions (line 42) | interface ContentScriptOverlayPositioningOptions {
type ContentScriptModalPositioningOptions (line 61) | interface ContentScriptModalPositioningOptions {
type ContentScriptPositioningOptions (line 76) | type ContentScriptPositioningOptions =
type ContentScriptAnchoredOptions (line 81) | interface ContentScriptAnchoredOptions {
type BaseMountFunctions (line 107) | interface BaseMountFunctions {
type MountFunctions (line 115) | interface MountFunctions extends BaseMountFunctions {
type AutoMountOptions (line 123) | type AutoMountOptions = {
type StopAutoMount (line 129) | type StopAutoMount = () => void;
type AutoMount (line 130) | interface AutoMount {
FILE: packages/wxt/src/utils/define-app-config.ts
type WxtAppConfig (line 2) | interface WxtAppConfig {}
function defineAppConfig (line 21) | function defineAppConfig(config: WxtAppConfig): WxtAppConfig {
FILE: packages/wxt/src/utils/define-background.ts
function defineBackground (line 8) | function defineBackground(
FILE: packages/wxt/src/utils/define-content-script.ts
function defineContentScript (line 4) | function defineContentScript(
FILE: packages/wxt/src/utils/define-unlisted-script.ts
function defineUnlistedScript (line 10) | function defineUnlistedScript(
FILE: packages/wxt/src/utils/define-wxt-plugin.ts
function defineWxtPlugin (line 4) | function defineWxtPlugin(plugin: WxtPlugin): WxtPlugin {
FILE: packages/wxt/src/utils/inject-script.ts
type ScriptPublicPath (line 4) | type ScriptPublicPath = Extract<
function injectScript (line 21) | async function injectScript(
function makeLoadedPromise (line 54) | function makeLoadedPromise(script: HTMLScriptElement): Promise<void> {
type InjectScriptOptions (line 76) | interface InjectScriptOptions {
type InjectScriptResult (line 92) | interface InjectScriptResult {
FILE: packages/wxt/src/utils/internal/custom-events.ts
class WxtLocationChangeEvent (line 3) | class WxtLocationChangeEvent extends Event {
method constructor (line 6) | constructor(
function getUniqueEventName (line 18) | function getUniqueEventName(eventName: string): string {
FILE: packages/wxt/src/utils/internal/dev-server-websocket.ts
type WebSocketMessage (line 3) | interface WebSocketMessage {
type WxtWebSocket (line 9) | interface WxtWebSocket extends WebSocket {
function getDevServerWebSocket (line 31) | function getDevServerWebSocket(): WxtWebSocket {
type ReloadContentScriptPayload (line 73) | interface ReloadContentScriptPayload {
FILE: packages/wxt/src/utils/internal/location-watcher.ts
function createLocationWatcher (line 12) | function createLocationWatcher(ctx: ContentScriptContext) {
FILE: packages/wxt/src/utils/internal/logger.ts
function print (line 3) | function print(method: (...args: any[]) => void, ...args: any[]) {
FILE: packages/wxt/src/utils/split-shadow-root-css.ts
constant AT_RULE_BLOCKS (line 3) | const AT_RULE_BLOCKS = /(\s*@(property|font-face)[\s\S]*?{[\s\S]*?})/gm;
function splitShadowRootCss (line 15) | function splitShadowRootCss(css: string): {
FILE: packages/wxt/src/virtual/utils/keep-service-worker-alive.ts
function keepServiceWorkerAlive (line 4) | function keepServiceWorkerAlive() {
FILE: packages/wxt/src/virtual/utils/reload-content-scripts.ts
function reloadContentScript (line 6) | function reloadContentScript(payload: ReloadContentScriptPayload) {
function reloadContentScriptMv3 (line 15) | async function reloadContentScriptMv3({
type ContentScript (line 26) | type ContentScript = ReloadContentScriptPayload['contentScript'];
function reloadManifestContentScriptMv3 (line 28) | async function reloadManifestContentScriptMv3(
function reloadRuntimeContentScriptMv3 (line 61) | async function reloadRuntimeContentScriptMv3(
function reloadTabsForContentScript (line 86) | async function reloadTabsForContentScript(contentScript: ContentScript) {
function reloadContentScriptMv2 (line 107) | async function reloadContentScriptMv2(
FILE: packages/wxt/tsdown.config.ts
function replaceVars (line 53) | async function replaceVars(
FILE: packages/wxt/vitest.globalSetup.ts
function setup (line 5) | async function setup() {
FILE: scripts/git.ts
function grabPackageDetails (line 5) | async function grabPackageDetails(pkg: string) {
function getPkgTag (line 21) | function getPkgTag(pkg: string, version: string | undefined) {
function listCommitsInDir (line 25) | async function listCommitsInDir(
FILE: scripts/upgrade-deps.ts
constant HELP_MESSAGE (line 9) | const HELP_MESSAGE = `
constant IGNORED_PACKAGES (line 23) | const IGNORED_PACKAGES = [
function main (line 38) | async function main(): Promise<never> {
type DependencyVersionsMap (line 84) | type DependencyVersionsMap = Record<string, Set<string>>;
type PackageJsonData (line 85) | type PackageJsonData = {
function getPackageJsonDependencies (line 91) | async function getPackageJsonDependencies(
type DependencyVersionMap (line 138) | type DependencyVersionMap = Record<string, string>;
function validateNoMultipleVersions (line 140) | function validateNoMultipleVersions(
function fetchPackageInfo (line 173) | async function fetchPackageInfo(name: string): Promise<PackageInfo> {
type PackageInfo (line 179) | type PackageInfo = {
type DependencyInfo (line 193) | type DependencyInfo = {
function fetchAllPackageInfos (line 199) | async function fetchAllPackageInfos(
type UpgradeDetails (line 213) | type UpgradeDetails = {
function detectUpgrades (line 227) | async function detectUpgrades(
function printUpgrades (line 302) | function printUpgrades(upgrades: UpgradeDetails[]): void {
function writeUpgrades (line 339) | async function writeUpgrades(
FILE: templates/react/entrypoints/content.ts
method main (line 3) | main() {
FILE: templates/react/entrypoints/popup/App.tsx
function App (line 6) | function App() {
FILE: templates/solid/entrypoints/content.ts
method main (line 3) | main() {
FILE: templates/solid/entrypoints/popup/App.tsx
function App (line 6) | function App() {
FILE: templates/svelte/src/entrypoints/content.ts
method main (line 3) | main() {
FILE: templates/vanilla/components/counter.ts
function setupCounter (line 1) | function setupCounter(element: HTMLButtonElement) {
FILE: templates/vanilla/entrypoints/content.ts
method main (line 3) | main() {
FILE: templates/vue/entrypoints/content.ts
method main (line 3) | main() {
Condensed preview — 573 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,399K chars).
[
{
"path": ".codecov.yml",
"chars": 130,
"preview": "coverage:\n status:\n project:\n default:\n informational: true\n patch:\n default:\n informatio"
},
{
"path": ".commitlintrc.yml",
"chars": 171,
"preview": "extends:\n - '@commitlint/config-conventional'\nrules:\n subject-case:\n - 0\n - always\n - - sentence-case\n -"
},
{
"path": ".gitattributes",
"chars": 503,
"preview": "# See https://git-scm.com/docs/gitattributes#_pattern_format for more about `.gitattributes`.\n\n# Normalize EOL for all f"
},
{
"path": ".github/CODEOWNERS",
"chars": 163,
"preview": "# Set default\n* @aklinker1\n\n# Secure Directories\n/.github/ @aklinker1\n\n# Creator of specific wxt modules\n/packages/auto-"
},
{
"path": ".github/FUNDING.yml",
"chars": 202,
"preview": "# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/di"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.yml",
"chars": 3247,
"preview": "name: \"\\U0001F41E Bug report\"\ndescription: Report an issue with WXT\nlabels: [pending-triage]\ntype: Bug\nbody:\n - type: m"
},
{
"path": ".github/ISSUE_TEMPLATE/config.yml",
"chars": 348,
"preview": "blank_issues_enabled: false\ncontact_links:\n - name: Discord Chat\n url: https://discord.gg/ZFsZqGery9\n about: Ask "
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.md",
"chars": 558,
"preview": "---\nname: Feature request\nabout: Suggest an idea for WXT\ntitle: ''\ntype: Feature\nassignees: ''\n---\n\n### Feature Request\n"
},
{
"path": ".github/actions/setup/action.yml",
"chars": 710,
"preview": "name: Basic Setup\ndescription: Install PNPM, Node, and dependencies\n\ninputs:\n install:\n default: 'true'\n descript"
},
{
"path": ".github/dependabot.yml",
"chars": 526,
"preview": "# To get started with Dependabot version updates, you'll need to specify which\n# package ecosystems to update and where "
},
{
"path": ".github/pull_request_template.md",
"chars": 285,
"preview": "### Overview\n\n<!-- Describe your changes and why you made them -->\n\n### Manual Testing\n\n<!-- Describe how to test your c"
},
{
"path": ".github/workflows/auto-label.yml",
"chars": 4174,
"preview": "name: ✨ Auto-label PR\n\non:\n pull_request_target:\n types: [opened, synchronized, reopened]\n\njobs:\n update-pr:\n na"
},
{
"path": ".github/workflows/notify-unreleased-commits.yml",
"chars": 1285,
"preview": "name: 🔔 Notify Unreleased Commits\non:\n workflow_dispatch:\n schedule:\n - cron: '0 20 * * 1' # Weekly at 8 PM UTC (3 "
},
{
"path": ".github/workflows/pkg.pr.new.yml",
"chars": 585,
"preview": "name: ✨ pkg.pr.new\non:\n push:\n branches:\n - main\n pull_request:\n branches:\n - main\n\npermissions:\n con"
},
{
"path": ".github/workflows/pr-closed.yml",
"chars": 691,
"preview": "name: 🎉 PR closed\n\non:\n pull_request_target:\n types:\n - closed\n\npermissions:\n contents: read\n pull-requests: "
},
{
"path": ".github/workflows/pr-title.yml",
"chars": 800,
"preview": "name: 🛡️ Check PR Title\n\non:\n pull_request:\n types: [opened, edited]\n\njobs:\n lint-pr-title:\n runs-on: ubuntu-lat"
},
{
"path": ".github/workflows/publish-docs.yml",
"chars": 1357,
"preview": "name: 📝 Publish Docs\non:\n push:\n branches:\n - main\n workflow_dispatch:\n inputs:\n tag:\n descript"
},
{
"path": ".github/workflows/release.yml",
"chars": 1872,
"preview": "name: 🚀 Release\non:\n workflow_dispatch:\n inputs:\n package:\n description: Package to release\n defa"
},
{
"path": ".github/workflows/sync-releases.yml",
"chars": 972,
"preview": "name: 🔄 Sync Releases\non:\n workflow_dispatch:\n inputs:\n package:\n description: Package to sync\n d"
},
{
"path": ".github/workflows/update-browser-package.yml",
"chars": 1434,
"preview": "name: 🔄 Update @wxt-dev/browser\non:\n workflow_dispatch:\n schedule:\n - cron: '0 0 * * *' # Every day at midnight\n\npe"
},
{
"path": ".github/workflows/validate.yml",
"chars": 3314,
"preview": "name: 🛡️ Validate\non:\n workflow_call:\n pull_request:\n push:\n branches:\n - main\n\npermissions:\n contents: read"
},
{
"path": ".github/workflows/vhs.yml",
"chars": 1658,
"preview": "name: 📼 VHS\non:\n push:\n paths:\n - 'docs/tapes/*.tape'\n workflow_dispatch:\n\npermissions:\n contents: read\n\njobs"
},
{
"path": ".gitignore",
"chars": 329,
"preview": ".DS_Store\n.env\n.env.*\n.idea\n.output\n.webextrc\n.wxt\n.wxt-runner\n*.log\n/docs/.vitepress/cache\ndocs/.vitepress/.temp\ncovera"
},
{
"path": ".markdownlint.json",
"chars": 214,
"preview": "{\n \"$schema\": \"https://raw.githubusercontent.com/DavidAnson/markdownlint/refs/heads/main/schema/markdownlint-config-sch"
},
{
"path": ".markdownlintignore",
"chars": 106,
"preview": "node_modules\n.git\n.output\ndist\n\n# Generated files\npackages/wxt/README.md\npackages/*/CHANGELOG.md\ndocs/api\n"
},
{
"path": ".prettierignore",
"chars": 102,
"preview": ".output\ncoverage\ndist\n.wxt\ndocs/.vitepress/cache\npnpm-lock.yaml\nCHANGELOG.md\npackages/browser/src/gen\n"
},
{
"path": ".prettierrc.yml",
"chars": 67,
"preview": "singleQuote: true\nendOfLine: lf\nplugins:\n - prettier-plugin-jsdoc\n"
},
{
"path": ".vscode/extensions.json",
"chars": 134,
"preview": "{\n \"recommendations\": [\n \"davidanson.vscode-markdownlint\",\n \"esbenp.prettier-vscode\",\n \"github.vscode-github-a"
},
{
"path": ".vscode/settings.json",
"chars": 528,
"preview": "{\n // Set default formatter\n \"editor.defaultFormatter\": \"esbenp.prettier-vscode\",\n\n \"[json]\": { \"editor.defaultFormat"
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 5232,
"preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participa"
},
{
"path": "CONTRIBUTING.md",
"chars": 7924,
"preview": "# Contributing\n\nEveryone is welcome to contribute to **WXT**!\n\nIf you are changing the docs or fixing a bug, feel free t"
},
{
"path": "LICENSE",
"chars": 1062,
"preview": "MIT License\n\nCopyright (c) 2023 Aaron\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof t"
},
{
"path": "MAINTAINERS.md",
"chars": 4461,
"preview": "# Maintainers\n\nA couple of things for you to consider before merging a PR or giving the go-ahead on a feature proposal.\n"
},
{
"path": "README.md",
"chars": 2783,
"preview": "<div align=\"center\">\n\n# <img align=\"top\" width=\"44\" src=\"https://raw.githubusercontent.com/wxt-dev/wxt/HEAD/docs/public/"
},
{
"path": "SECURITY.md",
"chars": 564,
"preview": "# Security Policy\n\nWhile WXT is in prerelease, only the latest version will receive security updates. The latest version"
},
{
"path": "docs/.vitepress/Dockerfile",
"chars": 55,
"preview": "FROM lipanski/docker-static-website:latest\nCOPY dist .\n"
},
{
"path": "docs/.vitepress/components/BlogHome.vue",
"chars": 1240,
"preview": "<script lang=\"ts\" setup>\nimport { computed } from 'vue';\n// @ts-expect-error: Vitepress data-loader magic, this import i"
},
{
"path": "docs/.vitepress/components/BlogLayout.vue",
"chars": 1454,
"preview": "<script lang=\"ts\" setup>\nimport useBlogDate from '../composables/useBlogDate';\nimport { useData } from 'vitepress';\n\ncon"
},
{
"path": "docs/.vitepress/components/BlogPostPreview.vue",
"chars": 1253,
"preview": "<script lang=\"ts\" setup>\nimport useBlogDate from '../composables/useBlogDate';\n\nconst props = defineProps<{\n post: {\n "
},
{
"path": "docs/.vitepress/components/EntrypointPatterns.vue",
"chars": 1040,
"preview": "<script lang=\"ts\" setup>\nconst props = defineProps<{\n patterns: Array<[intput: string, output: string]>;\n}>();\n</script"
},
{
"path": "docs/.vitepress/components/ExampleSearch.vue",
"chars": 5075,
"preview": "<script lang=\"ts\" setup>\nimport { ref, onMounted, computed, toRaw, Ref } from 'vue';\nimport ExampleSearchFilterByItem fr"
},
{
"path": "docs/.vitepress/components/ExampleSearchFilterByItem.vue",
"chars": 1868,
"preview": "<script lang=\"ts\" setup>\nimport { computed, toRaw } from 'vue';\nimport { KeySelectedObject } from '../utils/types';\n\ncon"
},
{
"path": "docs/.vitepress/components/ExampleSearchResult.vue",
"chars": 1242,
"preview": "<script lang=\"ts\" setup>\nimport { Example } from '../utils/types';\n\nconst props = defineProps<{\n example: Example;\n}>()"
},
{
"path": "docs/.vitepress/components/Icon.vue",
"chars": 513,
"preview": "<script lang=\"ts\" setup>\nimport { computed } from 'vue';\n\nconst props = defineProps<{\n name: string;\n icon?: string;\n}"
},
{
"path": "docs/.vitepress/components/UsingWxtSection.vue",
"chars": 13186,
"preview": "<script lang=\"ts\" setup>\nimport { computed } from 'vue';\nimport useListExtensionDetails, {\n ChromeExtension,\n} from '.."
},
{
"path": "docs/.vitepress/composables/useBlogDate.ts",
"chars": 393,
"preview": "import { computed, toValue, MaybeRefOrGetter } from 'vue';\n\nconst MONTH_FORMATTER = new Intl.DateTimeFormat(\n globalThi"
},
{
"path": "docs/.vitepress/composables/useListExtensionDetails.ts",
"chars": 1230,
"preview": "import { ref } from 'vue';\n\nexport interface ChromeExtension {\n id: string;\n name: string;\n iconUrl: string;\n weekly"
},
{
"path": "docs/.vitepress/config.ts",
"chars": 8999,
"preview": "import { DefaultTheme, defineConfig } from 'vitepress';\nimport typedocSidebar from '../api/reference/typedoc-sidebar.jso"
},
{
"path": "docs/.vitepress/loaders/blog.data.ts",
"chars": 99,
"preview": "import { createContentLoader } from 'vitepress';\n\nexport default createContentLoader('blog/*.md');\n"
},
{
"path": "docs/.vitepress/loaders/cli.data.ts",
"chars": 1459,
"preview": "import { resolve } from 'node:path';\nimport consola from 'consola';\nimport spawn from 'nano-spawn';\n\nconst cliDir = reso"
},
{
"path": "docs/.vitepress/theme/custom.css",
"chars": 1278,
"preview": "/* Colors */\n:root {\n --wxt-c-green-1: #0b8a00;\n --wxt-c-green-2: #096600;\n --wxt-c-green-3: #096600;\n --wxt-c-green"
},
{
"path": "docs/.vitepress/theme/index.ts",
"chars": 709,
"preview": "import DefaultTheme from 'vitepress/theme';\nimport Icon from '../components/Icon.vue';\nimport EntrypointPatterns from '."
},
{
"path": "docs/.vitepress/utils/head.ts",
"chars": 447,
"preview": "import { HeadConfig } from 'vitepress/types/shared';\n\nexport function meta(\n property: string,\n content: string,\n opt"
},
{
"path": "docs/.vitepress/utils/menus.ts",
"chars": 2547,
"preview": "import { DefaultTheme } from 'vitepress';\n\ntype SidebarItem = DefaultTheme.SidebarItem;\ntype NavItem = DefaultTheme.NavI"
},
{
"path": "docs/.vitepress/utils/types.ts",
"chars": 375,
"preview": "export interface Example {\n name: string;\n description?: string;\n url: string;\n searchText: string;\n apis: string[]"
},
{
"path": "docs/analytics.md",
"chars": 49,
"preview": "<!--@include: ../packages/analytics/README.md-->\n"
},
{
"path": "docs/api/cli/wxt-build.md",
"chars": 258,
"preview": "# `wxt build`\n\n<script setup>\nimport { data } from '../../.vitepress/loaders/cli.data.ts'\n</script>\n\n<div class=\"languag"
},
{
"path": "docs/api/cli/wxt-clean.md",
"chars": 258,
"preview": "# `wxt clean`\n\n<script setup>\nimport { data } from '../../.vitepress/loaders/cli.data.ts'\n</script>\n\n<div class=\"languag"
},
{
"path": "docs/api/cli/wxt-init.md",
"chars": 256,
"preview": "# `wxt init`\n\n<script setup>\nimport { data } from '../../.vitepress/loaders/cli.data.ts'\n</script>\n\n<div class=\"language"
},
{
"path": "docs/api/cli/wxt-prepare.md",
"chars": 262,
"preview": "# `wxt prepare`\n\n<script setup>\nimport { data } from '../../.vitepress/loaders/cli.data.ts'\n</script>\n\n<div class=\"langu"
},
{
"path": "docs/api/cli/wxt-submit-init.md",
"chars": 369,
"preview": "# `wxt submit init`\n\n> Alias for [`publish-browser-extension`](https://www.npmjs.com/package/publish-browser-extension)\n"
},
{
"path": "docs/api/cli/wxt-submit.md",
"chars": 360,
"preview": "# `wxt submit`\n\n> Alias for [`publish-browser-extension`](https://www.npmjs.com/package/publish-browser-extension)\n\n<scr"
},
{
"path": "docs/api/cli/wxt-zip.md",
"chars": 254,
"preview": "# `wxt zip`\n\n<script setup>\nimport { data } from '../../.vitepress/loaders/cli.data.ts'\n</script>\n\n<div class=\"language-"
},
{
"path": "docs/api/cli/wxt.md",
"chars": 250,
"preview": "# `wxt`\n\n<script setup>\nimport { data } from '../../.vitepress/loaders/cli.data.ts'\n</script>\n\n<div class=\"language-sh v"
},
{
"path": "docs/auto-icons.md",
"chars": 50,
"preview": "<!--@include: ../packages/auto-icons/README.md-->\n"
},
{
"path": "docs/blog/.drafts/2024-10-19-real-world-messaging.md",
"chars": 368,
"preview": "---\nlayout: blog\ntitle: Real World Messaging\ndescription: |\n The extension messaging APIs are difficult to learn. Let's"
},
{
"path": "docs/blog/2024-12-06-using-imports-module.md",
"chars": 3035,
"preview": "---\nlayout: blog\ntitle: Introducing <code>#imports</code>\ndescription: Learn how WXT's new <code>#imports</code> module "
},
{
"path": "docs/blog.md",
"chars": 132,
"preview": "---\nlayout: page\n---\n\n<script lang=\"ts\" setup>\nimport BlogHome from './.vitepress/components/BlogHome.vue';\n</script>\n\n<"
},
{
"path": "docs/examples.md",
"chars": 206,
"preview": "---\nlayout: page\n---\n\n<style>\n.examples-container {\n padding: 32px;\n}\n</style>\n\n<div class=\"examples-container\">\n <div"
},
{
"path": "docs/guide/essentials/assets.md",
"chars": 5343,
"preview": "# Assets\n\n## `/assets` Directory\n\nAny assets imported or referenced inside the `<srcDir>/assets/` directory will be proc"
},
{
"path": "docs/guide/essentials/config/auto-imports.md",
"chars": 2753,
"preview": "# Auto-imports\n\nWXT uses [`unimport`](https://www.npmjs.com/package/unimport), the same tool as Nuxt, to setup auto-impo"
},
{
"path": "docs/guide/essentials/config/browser-startup.md",
"chars": 4510,
"preview": "---\noutline: deep\n---\n\n# Browser Startup\n\n> See the [API Reference](/api/reference/wxt/interfaces/WebExtConfig) for a fu"
},
{
"path": "docs/guide/essentials/config/build-mode.md",
"chars": 707,
"preview": "# Build Modes\n\nBecause WXT is powered by Vite, it supports [modes](https://vite.dev/guide/env-and-mode.html#modes) in th"
},
{
"path": "docs/guide/essentials/config/entrypoint-loaders.md",
"chars": 1669,
"preview": "# Entrypoint Loaders\n\nTo generate the manifest and other files at build-time, WXT must import each entrypoint to get the"
},
{
"path": "docs/guide/essentials/config/environment-variables.md",
"chars": 3961,
"preview": "# Environment Variables\n\n## Dotenv Files\n\nWXT supports [dotenv files the same way as Vite](https://vite.dev/guide/env-an"
},
{
"path": "docs/guide/essentials/config/hooks.md",
"chars": 2229,
"preview": "# Hooks\n\nWXT includes a system that lets you hook into the build process and make changes.\n\n## Adding Hooks\n\nThe easiest"
},
{
"path": "docs/guide/essentials/config/manifest.md",
"chars": 6755,
"preview": "# Manifest\n\nIn WXT, there is no `manifest.json` file in your source code. Instead, WXT generates the manifest from multi"
},
{
"path": "docs/guide/essentials/config/runtime.md",
"chars": 1356,
"preview": "# Runtime Config\n\n> This API is still a WIP, with more features coming soon!\n\nDefine runtime configuration in a single p"
},
{
"path": "docs/guide/essentials/config/typescript.md",
"chars": 1929,
"preview": "# TypeScript Configuration\n\nWhen you run [`wxt prepare`](/api/cli/wxt-prepare), WXT generates a base TSConfig file for y"
},
{
"path": "docs/guide/essentials/config/vite.md",
"chars": 1949,
"preview": "# Vite\n\nWXT uses [Vite](https://vitejs.dev/) under the hood to bundle your extension.\n\nThis page explains how to customi"
},
{
"path": "docs/guide/essentials/content-scripts.md",
"chars": 20592,
"preview": "---\noutline: deep\n---\n\n# Content Scripts\n\n> To create a content script, see [Entrypoint Types](/guide/essentials/entrypo"
},
{
"path": "docs/guide/essentials/e2e-testing.md",
"chars": 521,
"preview": "# E2E Testing\n\n## Playwright\n\n[Playwright](https://playwright.dev) is the only good option for writing Chrome Extension "
},
{
"path": "docs/guide/essentials/entrypoints.md",
"chars": 20356,
"preview": "---\noutline: deep\n---\n\n# Entrypoints\n\nWXT uses the files inside the `entrypoints/` directory as inputs when bundling you"
},
{
"path": "docs/guide/essentials/es-modules.md",
"chars": 1736,
"preview": "# ES Modules\n\nYour source code should always be written as ESM. However, you have some control whether an entrypoint is "
},
{
"path": "docs/guide/essentials/extension-apis.md",
"chars": 4871,
"preview": "# Extension APIs\n\n[Chrome Docs](https://developer.chrome.com/docs/extensions/reference/api) • [Firefox Docs](https://dev"
},
{
"path": "docs/guide/essentials/frontend-frameworks.md",
"chars": 3503,
"preview": "# Frontend Frameworks\n\n## Built-in Modules\n\nWXT has preconfigured modules for the most popular frontend frameworks:\n\n- ["
},
{
"path": "docs/guide/essentials/i18n.md",
"chars": 2265,
"preview": "# I18n\n\n[Chrome Docs](https://developer.chrome.com/docs/extensions/reference/api/i18n) • [Firefox Docs](https://develope"
},
{
"path": "docs/guide/essentials/messaging.md",
"chars": 1372,
"preview": "# Messaging\n\n[Chrome Docs](https://developer.chrome.com/docs/extensions/develop/concepts/messaging) • [Firefox Docs](htt"
},
{
"path": "docs/guide/essentials/project-structure.md",
"chars": 3082,
"preview": "# Project Structure\n\nWXT follows a strict project structure. By default, it's a flat folder structure that looks like th"
},
{
"path": "docs/guide/essentials/publishing.md",
"chars": 9317,
"preview": "---\noutline: deep\n---\n\n# Publishing\n\nWXT can ZIP your extension and submit it to various stores for review or for self-h"
},
{
"path": "docs/guide/essentials/remote-code.md",
"chars": 846,
"preview": "# Remote Code\n\nWXT will automatically download and bundle imports with the `url:` prefix so the extension does not depen"
},
{
"path": "docs/guide/essentials/scripting.md",
"chars": 865,
"preview": "# Scripting\n\n[Chrome Docs](https://developer.chrome.com/docs/extensions/reference/api/scripting) • [Firefox Docs](https:"
},
{
"path": "docs/guide/essentials/storage.md",
"chars": 1188,
"preview": "# Storage\n\n[Chrome Docs](https://developer.chrome.com/docs/extensions/reference/api/storage) • [Firefox Docs](https://de"
},
{
"path": "docs/guide/essentials/target-different-browsers.md",
"chars": 2502,
"preview": "# Targeting Different Browsers\n\nWhen building an extension with WXT, you can create multiple builds of your extension ta"
},
{
"path": "docs/guide/essentials/testing-updates.md",
"chars": 1211,
"preview": "# Testing Updates\n\n## Testing Permission Changes\n\nWhen `permissions`/`host_permissions` change during an update, dependi"
},
{
"path": "docs/guide/essentials/unit-testing.md",
"chars": 3858,
"preview": "# Unit Testing\n\n[[toc]]\n\n## Vitest\n\nWXT provides first class support for Vitest for unit testing:\n\n```ts\n// vitest.confi"
},
{
"path": "docs/guide/essentials/wxt-modules.md",
"chars": 9175,
"preview": "---\noutline: deep\n---\n\n# WXT Modules\n\nWXT provides a \"module system\" that let's you run code at different steps in the b"
},
{
"path": "docs/guide/installation.md",
"chars": 3251,
"preview": "# Installation\n\nBootstrap a new project, start from scratch, or [migrate an existing project](/guide/resources/migrate)."
},
{
"path": "docs/guide/introduction.md",
"chars": 1379,
"preview": "# Welcome to WXT\n\nWXT is a modern, open-source framework for building web extensions. Inspired by Nuxt, its goals are to"
},
{
"path": "docs/guide/resources/community.md",
"chars": 995,
"preview": "# Community\n\nThis page is dedicated to all the awesome people how have made something for WXT or that works with WXT. Bl"
},
{
"path": "docs/guide/resources/compare.md",
"chars": 4133,
"preview": "# Compare\n\nLets compare the features of WXT vs [Plasmo](https://docs.plasmo.com/framework) (another framework) and [CRXJ"
},
{
"path": "docs/guide/resources/faq.md",
"chars": 8446,
"preview": "---\noutline: false\n---\n\n# FAQ\n\nCommonly asked questions about how to use WXT or why it behaves the way it does.\n\n[[toc]]"
},
{
"path": "docs/guide/resources/how-wxt-works.md",
"chars": 85,
"preview": "# How WXT Works\n\n:::warning 🚧 Under construction\nThese docs will be coming soon!\n:::\n"
},
{
"path": "docs/guide/resources/migrate.md",
"chars": 6275,
"preview": "---\noutline: deep\n---\n\n# Migrate to WXT\n\n> If you have problems migrating to WXT, feel free to ask for help in GitHub by"
},
{
"path": "docs/guide/resources/upgrading.md",
"chars": 21660,
"preview": "---\noutline: deep\n---\n\n# Upgrading WXT\n\n## Overview\n\nTo upgrade WXT to the latest major version:\n\n1. Install it, skippin"
},
{
"path": "docs/i18n.md",
"chars": 67,
"preview": "---\noutline: deep\n---\n\n<!--@include: ../packages/i18n/README.md-->\n"
},
{
"path": "docs/index.md",
"chars": 3839,
"preview": "---\n# https://vitepress.dev/reference/default-theme-home-page\nlayout: home\ntitle: Next-gen Web Extension Framework\n\nhero"
},
{
"path": "docs/is-background.md",
"chars": 53,
"preview": "<!--@include: ../packages/is-background/README.md-->\n"
},
{
"path": "docs/public/_redirects",
"chars": 8649,
"preview": "# Netlify Redirects File\n# https://docs.netlify.com/routing/redirects/\n\n# Old URLs -> New URLs\n\n# OLD\n/config.html "
},
{
"path": "docs/public/robots.txt",
"chars": 95,
"preview": "User-agent: *\nDisallow: /api.html\nDisallow: /config.html\n\nSitemap: https://wxt.dev/sitemap.xml\n"
},
{
"path": "docs/runner.md",
"chars": 46,
"preview": "<!--@include: ../packages/runner/README.md-->\n"
},
{
"path": "docs/storage.md",
"chars": 10429,
"preview": "---\noutline: deep\n---\n\n# WXT Storage\n\n[Changelog](https://github.com/wxt-dev/wxt/blob/main/packages/wxt/CHANGELOG.md) &b"
},
{
"path": "docs/tapes/init-demo.tape",
"chars": 1727,
"preview": "# VHS documentation\n#\n# You can view all VHS documentation on the command line with `vhs manual`.\n# Or see https://githu"
},
{
"path": "docs/typedoc.json",
"chars": 445,
"preview": "{\n \"$schema\": \"https://typedoc.org/schema.json\",\n \"entryPointStrategy\": \"packages\",\n \"entryPoints\": [\"../packages/wxt"
},
{
"path": "docs/unocss.md",
"chars": 46,
"preview": "<!--@include: ../packages/unocss/README.md-->\n"
},
{
"path": "package.json",
"chars": 1935,
"preview": "{\n \"private\": true,\n \"type\": \"module\",\n \"packageManager\": \"pnpm@10.29.2+sha512.bef43fa759d91fd2da4b319a5a0d13ef7a45bb"
},
{
"path": "packages/analytics/CHANGELOG.md",
"chars": 3837,
"preview": "# Changelog\n\n## v0.5.4\n\n[compare changes](https://github.com/wxt-dev/wxt/compare/analytics-v0.5.3...analytics-v0.5.4)\n\n#"
},
{
"path": "packages/analytics/README.md",
"chars": 6708,
"preview": "# WXT Analytics\n\nReport analytics events from your web extension extension.\n\n## Supported Analytics Providers\n\n- [Google"
},
{
"path": "packages/analytics/app.config.ts",
"chars": 569,
"preview": "import { defineAppConfig } from 'wxt/utils/define-app-config';\nimport { googleAnalytics4 } from './modules/analytics/pro"
},
{
"path": "packages/analytics/entrypoints/popup/index.html",
"chars": 463,
"preview": "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-w"
},
{
"path": "packages/analytics/entrypoints/popup/main.ts",
"chars": 214,
"preview": "import { analytics } from '#analytics';\n\ndeclare const enabledCheckbox: HTMLInputElement;\n\nanalytics.autoTrack(document)"
},
{
"path": "packages/analytics/modules/analytics/background-plugin.ts",
"chars": 47,
"preview": "import '#analytics';\n\nexport default () => {};\n"
},
{
"path": "packages/analytics/modules/analytics/client.ts",
"chars": 9204,
"preview": "import { UAParser } from 'ua-parser-js';\nimport type {\n Analytics,\n AnalyticsConfig,\n AnalyticsEventMetadata,\n Analy"
},
{
"path": "packages/analytics/modules/analytics/index.ts",
"chars": 2863,
"preview": "import 'wxt';\nimport 'wxt/utils/define-app-config';\nimport {\n addAlias,\n addViteConfig,\n addWxtPlugin,\n defineWxtMod"
},
{
"path": "packages/analytics/modules/analytics/providers/google-analytics-4.ts",
"chars": 2386,
"preview": "import { defineAnalyticsProvider } from '../client';\nimport type { BaseAnalyticsEvent } from '../types';\n\nconst DEFAULT_"
},
{
"path": "packages/analytics/modules/analytics/providers/umami.ts",
"chars": 1960,
"preview": "import { defineAnalyticsProvider } from '../client';\n\nexport interface UmamiProviderOptions {\n apiUrl: string;\n websit"
},
{
"path": "packages/analytics/modules/analytics/types.ts",
"chars": 3027,
"preview": "export interface Analytics {\n /** Report a page change. */\n page: (url: string) => void;\n /** Report a custom event. "
},
{
"path": "packages/analytics/package.json",
"chars": 1672,
"preview": "{\n \"name\": \"@wxt-dev/analytics\",\n \"version\": \"0.5.4\",\n \"description\": \"Add analytics to your web extension\",\n \"type\""
},
{
"path": "packages/analytics/public/.keep",
"chars": 0,
"preview": ""
},
{
"path": "packages/analytics/tsconfig.json",
"chars": 208,
"preview": "{\n \"extends\": [\"../../tsconfig.base.json\", \"./.wxt/tsconfig.json\"],\n \"compilerOptions\": {\n \"paths\": {\n \"#analy"
},
{
"path": "packages/analytics/tsdown.config.ts",
"chars": 528,
"preview": "import { defineConfig } from 'tsdown';\n\nexport default defineConfig({\n entry: {\n index: './modules/analytics/client."
},
{
"path": "packages/analytics/wxt.config.ts",
"chars": 285,
"preview": "import { defineConfig } from 'wxt';\n\nexport default defineConfig({\n // Unimport doesn't look for imports in node_module"
},
{
"path": "packages/auto-icons/CHANGELOG.md",
"chars": 3772,
"preview": "# Changelog\n\n## v1.1.1\n\n[compare changes](https://github.com/wxt-dev/wxt/compare/auto-icons-v1.1.0...auto-icons-v1.1.1)\n"
},
{
"path": "packages/auto-icons/README.md",
"chars": 990,
"preview": "# WXT Auto Icons\n\n[Changelog](https://github.com/wxt-dev/wxt/blob/main/packages/auto-icons/CHANGELOG.md)\n\n## Features\n\n-"
},
{
"path": "packages/auto-icons/package.json",
"chars": 1322,
"preview": "{\n \"name\": \"@wxt-dev/auto-icons\",\n \"description\": \"WXT module for automatically generating extension icons in differen"
},
{
"path": "packages/auto-icons/src/__test__/index.test.ts",
"chars": 18669,
"preview": "import { describe, it, expect, vi, beforeEach, Mock } from 'vitest';\nimport { resolve } from 'node:path';\nimport * as fs"
},
{
"path": "packages/auto-icons/src/index.ts",
"chars": 5245,
"preview": "import 'wxt';\nimport { defineWxtModule } from 'wxt/modules';\nimport { resolve, relative } from 'node:path';\nimport defu "
},
{
"path": "packages/auto-icons/tsconfig.json",
"chars": 89,
"preview": "{\n \"extends\": \"../../tsconfig.base.json\",\n \"exclude\": [\"node_modules/**\", \"dist/**\"]\n}\n"
},
{
"path": "packages/auto-icons/vitest.config.ts",
"chars": 141,
"preview": "import { defineConfig } from 'vitest/config';\n\nexport default defineConfig({\n test: {\n mockReset: true,\n restoreM"
},
{
"path": "packages/browser/README.md",
"chars": 1862,
"preview": "# `@wxt-dev/browser`\n\nProvides access to the `browser` or `chrome` extension APIs and related types.\n\n```ts\nimport { bro"
},
{
"path": "packages/browser/package.json",
"chars": 867,
"preview": "{\n \"name\": \"@wxt-dev/browser\",\n \"description\": \"Provides a cross-browser API for using extension APIs and types based "
},
{
"path": "packages/browser/scripts/generate.ts",
"chars": 2824,
"preview": "import spawn from 'nano-spawn';\nimport { mkdir, readdir, readFile, writeFile } from 'node:fs/promises';\nimport { fileURL"
},
{
"path": "packages/browser/src/__tests__/index.test.ts",
"chars": 956,
"preview": "/// <reference types=\"chrome\" />\nimport { describe, expectTypeOf, it } from 'vitest';\nimport { browser, type Browser } f"
},
{
"path": "packages/browser/src/gen/chrome-cast/index.d.ts",
"chars": 39211,
"preview": "/* DO NOT EDIT - generated by scripts/generate.ts */\n\n/* eslint-disable @typescript-eslint/no-wrapper-object-types */\nex"
},
{
"path": "packages/browser/src/gen/har-format/index.d.ts",
"chars": 192,
"preview": "/* DO NOT EDIT - generated by scripts/generate.ts */\n\nimport { Entry, Log } from \"har-format\";\n\ndeclare global {\n exp"
},
{
"path": "packages/browser/src/gen/index.d.ts",
"chars": 761674,
"preview": "/* DO NOT EDIT - generated by scripts/generate.ts */\n\n/// <reference types=\"filesystem\" />\n/// <reference path=\"./har-fo"
},
{
"path": "packages/browser/src/index.d.ts",
"chars": 92,
"preview": "import { Browser } from './gen';\n\nexport const browser: typeof Browser;\nexport { Browser };\n"
},
{
"path": "packages/browser/src/index.mjs",
"chars": 142,
"preview": "// #region snippet\nexport const browser = globalThis.browser?.runtime?.id\n ? globalThis.browser\n : globalThis.chrome;\n"
},
{
"path": "packages/browser/templates/package.json",
"chars": 789,
"preview": "{\n \"name\": \"@wxt-dev/browser\",\n \"description\": \"Provides a cross-browser API for using extension APIs and types based "
},
{
"path": "packages/browser/tsconfig.json",
"chars": 69,
"preview": "{\n \"extends\": \"../../tsconfig.base.json\",\n \"compilerOptions\": {}\n}\n"
},
{
"path": "packages/i18n/CHANGELOG.md",
"chars": 5202,
"preview": "# Changelog\n\n## v0.2.5\n\n[compare changes](https://github.com/wxt-dev/wxt/compare/i18n-v0.2.4...i18n-v0.2.5)\n\n### 🩹 Fixes"
},
{
"path": "packages/i18n/README.md",
"chars": 10124,
"preview": "# `@wxt-dev/i18n`\n\n[Changelog](https://github.com/wxt-dev/wxt/blob/main/packages/i18n/CHANGELOG.md)\n\n`@wxt-dev/i18n` is "
},
{
"path": "packages/i18n/package.json",
"chars": 2082,
"preview": "{\n \"name\": \"@wxt-dev/i18n\",\n \"description\": \"Type-safe wrapper around browser.i18n.getMessage with additional features"
},
{
"path": "packages/i18n/src/__tests__/build.test.ts",
"chars": 5478,
"preview": "import { describe, it, expect, vi } from 'vitest';\nimport {\n parseMessagesFile,\n generateChromeMessagesFile,\n generat"
},
{
"path": "packages/i18n/src/__tests__/index.test.ts",
"chars": 2085,
"preview": "import { describe, it, expect, vi, beforeEach } from 'vitest';\nimport { createI18n } from '../index';\nimport { browser }"
},
{
"path": "packages/i18n/src/__tests__/types.test.ts",
"chars": 3230,
"preview": "import { beforeEach, describe, it, vi } from 'vitest';\nimport { createI18n } from '..';\nimport { browser } from '@wxt-de"
},
{
"path": "packages/i18n/src/__tests__/utils.test.ts",
"chars": 3242,
"preview": "import { describe, it, expect } from 'vitest';\nimport { ChromeMessage } from '../build';\nimport {\n applyChromeMessagePl"
},
{
"path": "packages/i18n/src/build.ts",
"chars": 8141,
"preview": "/**\n * This module contains utils for generating types and `messages.json` files\n * based on the custom messages file fo"
},
{
"path": "packages/i18n/src/index.ts",
"chars": 1840,
"preview": "/** @module @wxt-dev/i18n */\nimport {\n I18nStructure,\n DefaultI18nStructure,\n I18n,\n Substitution,\n} from './types';"
},
{
"path": "packages/i18n/src/module.ts",
"chars": 5889,
"preview": "/**\n * The WXT Module to integrate `@wxt-dev/i18n` into your project.\n *\n * ```ts\n * export default defineConfig({\n * "
},
{
"path": "packages/i18n/src/supported-locales.ts",
"chars": 597,
"preview": "/** From https://developer.chrome.com/docs/extensions/reference/api/i18n#locales */\nexport const SUPPORTED_LOCALES = new"
},
{
"path": "packages/i18n/src/types.ts",
"chars": 2856,
"preview": "export interface I18nFeatures {\n plural: boolean;\n substitutions: SubstitutionCount;\n}\n\nexport type I18nStructure = {\n"
},
{
"path": "packages/i18n/src/utils.ts",
"chars": 1020,
"preview": "import { ChromeMessage } from './build';\n\nexport function applyChromeMessagePlaceholders(message: ChromeMessage): string"
},
{
"path": "packages/i18n/tsconfig.json",
"chars": 139,
"preview": "{\n \"extends\": \"../../tsconfig.base.json\",\n \"compilerOptions\": {\n \"types\": [\"node\"]\n },\n \"exclude\": [\"node_modules"
},
{
"path": "packages/i18n/tsdown.config.ts",
"chars": 199,
"preview": "import { defineConfig } from 'tsdown';\n\nconst entry = ['src/index.ts', 'src/build.ts', 'src/module.ts'];\n\nexport default"
},
{
"path": "packages/i18n/vitest.config.ts",
"chars": 222,
"preview": "import { defineProject } from 'vitest/config';\nimport RandomSeed from 'vitest-plugin-random-seed';\n\nexport default defin"
},
{
"path": "packages/is-background/README.md",
"chars": 279,
"preview": "# `@wxt-dev/is-background`\n\nExports a getter to determine if the current JS context is the background or not.\n\n## Instal"
},
{
"path": "packages/is-background/package.json",
"chars": 1220,
"preview": "{\n \"name\": \"@wxt-dev/is-background\",\n \"type\": \"module\",\n \"version\": \"1.0.0\",\n \"description\": \"Check if the current c"
},
{
"path": "packages/is-background/src/__tests__/getter.test.ts",
"chars": 3582,
"preview": "import { describe, it, vi, expect } from 'vitest';\nimport { getIsBackground } from '../getter';\n\nlet mockBrowser: any;\nv"
},
{
"path": "packages/is-background/src/getter.ts",
"chars": 859,
"preview": "import { browser } from '@wxt-dev/browser';\n\ndeclare class ServiceWorkerGlobalScope {}\n\nexport function getIsBackground("
},
{
"path": "packages/is-background/src/index.ts",
"chars": 897,
"preview": "/**\n * This module uses a lazy getter function so the logic isn't ran until it's\n * needed.\n *\n * This has a few benefit"
},
{
"path": "packages/is-background/tsconfig.json",
"chars": 89,
"preview": "{\n \"extends\": \"../../tsconfig.base.json\",\n \"exclude\": [\"node_modules/**\", \"dist/**\"]\n}\n"
},
{
"path": "packages/module-react/CHANGELOG.md",
"chars": 5192,
"preview": "# Changelog\n\n## v1.2.2\n\n[compare changes](https://github.com/wxt-dev/wxt/compare/module-react-v1.2.1...module-react-v1.2"
},
{
"path": "packages/module-react/README.md",
"chars": 635,
"preview": "# `@wxt-dev/module-react`\n\nEnables the use of [React](https://react.dev/) in your web extension, in HTML pages and conte"
},
{
"path": "packages/module-react/components/App.tsx",
"chars": 192,
"preview": "export default function () {\n const [count, setCount] = useState(0);\n const increment = () => setCount((count) => coun"
},
{
"path": "packages/module-react/entrypoints/content/index.tsx",
"chars": 722,
"preview": "import {\n defineContentScript,\n ContentScriptContext,\n createShadowRootUi,\n} from '#imports';\nimport React from 'reac"
},
{
"path": "packages/module-react/entrypoints/popup/index.html",
"chars": 291,
"preview": "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-w"
},
{
"path": "packages/module-react/entrypoints/popup/main.tsx",
"chars": 209,
"preview": "import React from 'react';\nimport ReactDOM from 'react-dom/client';\n\nconst root = document.getElementById('app')!;\n\nReac"
},
{
"path": "packages/module-react/modules/react.ts",
"chars": 1315,
"preview": "import 'wxt';\nimport { addImportPreset, addViteConfig, defineWxtModule } from 'wxt/modules';\nimport react, { Options as "
},
{
"path": "packages/module-react/package.json",
"chars": 1575,
"preview": "{\n \"name\": \"@wxt-dev/module-react\",\n \"description\": \"WXT module to enable React support\",\n \"repository\": {\n \"type\""
},
{
"path": "packages/module-react/public/.keep",
"chars": 0,
"preview": ""
},
{
"path": "packages/module-react/tsconfig.json",
"chars": 206,
"preview": "{\n \"extends\": [\"../../tsconfig.base.json\", \"./.wxt/tsconfig.json\"],\n \"compilerOptions\": {\n \"allowImportingTsExtensi"
},
{
"path": "packages/module-react/tsdown.config.ts",
"chars": 184,
"preview": "import { defineConfig } from 'tsdown';\n\nconst entry = {\n index: './modules/react.ts',\n};\n\nexport default defineConfig(["
},
{
"path": "packages/module-solid/CHANGELOG.md",
"chars": 3655,
"preview": "# Changelog\n\n## v1.1.4\n\n[compare changes](https://github.com/wxt-dev/wxt/compare/module-solid-v1.1.3...module-solid-v1.1"
},
{
"path": "packages/module-solid/README.md",
"chars": 682,
"preview": "# `@wxt-dev/module-solid`\n\nEnables the use of [SolidJS](https://www.solidjs.com/) in your web extension, in HTML pages a"
},
{
"path": "packages/module-solid/components/App.tsx",
"chars": 247,
"preview": "import { Component } from 'solid-js';\n\nexport const App: Component = () => {\n const [count, setCount] = createSignal(0)"
},
{
"path": "packages/module-solid/entrypoints/content/index.tsx",
"chars": 567,
"preview": "import {\n defineContentScript,\n ContentScriptContext,\n createShadowRootUi,\n} from '#imports';\nimport { render } from "
},
{
"path": "packages/module-solid/entrypoints/popup/index.html",
"chars": 291,
"preview": "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-w"
},
{
"path": "packages/module-solid/entrypoints/popup/main.tsx",
"chars": 116,
"preview": "import { render } from 'solid-js/web';\n\nconst root = document.getElementById('app')!;\n\nrender(() => <App />, root);\n"
},
{
"path": "packages/module-solid/modules/solid.ts",
"chars": 1059,
"preview": "import 'wxt';\nimport { addImportPreset, addViteConfig, defineWxtModule } from 'wxt/modules';\nimport solid, { Options as "
},
{
"path": "packages/module-solid/package.json",
"chars": 1389,
"preview": "{\n \"name\": \"@wxt-dev/module-solid\",\n \"description\": \"WXT module to enable SolidJS support\",\n \"repository\": {\n \"typ"
},
{
"path": "packages/module-solid/public/.keep",
"chars": 0,
"preview": ""
},
{
"path": "packages/module-solid/tsconfig.json",
"chars": 200,
"preview": "{\n \"extends\": [\"../../tsconfig.base.json\", \"./.wxt/tsconfig.json\"],\n \"compilerOptions\": {\n \"jsx\": \"preserve\",\n \""
},
{
"path": "packages/module-solid/tsdown.config.ts",
"chars": 184,
"preview": "import { defineConfig } from 'tsdown';\n\nconst entry = {\n index: './modules/solid.ts',\n};\n\nexport default defineConfig(["
},
{
"path": "packages/module-svelte/CHANGELOG.md",
"chars": 4846,
"preview": "# Changelog\n\n## v2.0.5\n\n[compare changes](https://github.com/wxt-dev/wxt/compare/module-svelte-v2.0.4...module-svelte-v2"
},
{
"path": "packages/module-svelte/README.md",
"chars": 642,
"preview": "# `@wxt-dev/module-svelte`\n\nEnables the use of [Svelte](https://svelte.dev/) in your web extension, in HTML pages and co"
},
{
"path": "packages/module-svelte/package.json",
"chars": 1319,
"preview": "{\n \"name\": \"@wxt-dev/module-svelte\",\n \"description\": \"WXT module to enable Svelte support\",\n \"repository\": {\n \"typ"
},
{
"path": "packages/module-svelte/src/index.ts",
"chars": 943,
"preview": "import 'wxt';\nimport { addImportPreset, addViteConfig, defineWxtModule } from 'wxt/modules';\nimport {\n svelte,\n vitePr"
},
{
"path": "packages/module-svelte/tsconfig.json",
"chars": 89,
"preview": "{\n \"extends\": \"../../tsconfig.base.json\",\n \"exclude\": [\"node_modules/**\", \"dist/**\"]\n}\n"
},
{
"path": "packages/module-svelte/tsdown.config.ts",
"chars": 180,
"preview": "import { defineConfig } from 'tsdown';\n\nconst entry = {\n index: './src/index.ts',\n};\n\nexport default defineConfig([\n {"
}
]
// ... and 373 more files (download for full content)
About this extraction
This page contains the full source code of the wxt-dev/wxt GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 573 files (2.2 MB), approximately 601.8k tokens, and a symbol index with 1402 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.