Compare commits

...

293 Commits

Author SHA1 Message Date
GitHub Actions 763dbd5ee8 chore(release): wxt v0.19.7 2024-08-19 15:40:58 +00:00
Aaron 5821ae0e8c feat: New @wxt-dev/i18n package (#758) 2024-08-19 09:18:01 -05:00
Aaron 751706d2ae docs: Fix module name for wxt/browser/chrome 2024-08-19 09:08:53 -05:00
Aaron cf8554718d feat(modules): Add addAlias helper (#928) 2024-08-18 15:20:12 -05:00
Aaron 5f653b3ff9 fix: Ensure TSConfig paths start with ../ or ./ so they are valid (#927) 2024-08-18 15:18:23 -05:00
Aaron 5f2e1c38a7 chore: Remove warning log for missing public directory 2024-08-18 15:10:07 -05:00
Aaron 8a9d8be8a4 feat(testing): Run WXT modules when setting up test environment (#926) 2024-08-18 15:08:45 -05:00
Aaron 067b2eccf3 fix(testing): Stub chrome and browser globals with fakeBrowser automatically (#925) 2024-08-18 14:56:15 -05:00
Aaron 2e1bd6ec93 chore: Update demo package cache behavior 2024-08-18 14:49:29 -05:00
Aaron b463cef1c2 Update changelog 2024-08-16 15:59:58 -05:00
GitHub Actions adf9d39d69 chore(release): wxt v0.19.6 2024-08-16 20:16:57 +00:00
1natsu b1699592e4 perf: Ignore non-source code from the file watcher (#919) 2024-08-16 15:01:18 -05:00
Aaron 8675abfced docs: Update ESM content script docs with example 2024-08-16 09:34:32 -05:00
Aaron a1fc19e47c chore(bench): Setup benchmark script for testing browser open timing (#917) 2024-08-15 16:51:06 -05:00
Aaron 8235de04d2 chore: Add profiling docs to CONTRIBUTING.md 2024-08-15 16:50:42 -05:00
Aaron 46a324adc2 fix(types): Don't report type errors when using string templates with browser.i18n.getMessage (#916) 2024-08-14 23:44:11 -05:00
Aaron c0af62316d fix: Typo in sidepanel options (browse_stylebrowser_style) (#914) 2024-08-14 07:46:42 -05:00
GitHub Actions 2fd3503694 chore(release): wxt v0.19.5 2024-08-12 15:36:58 +00:00
Aaron e6529e6e41 fix: Update chromium setting for enabling content script sourcemaps 2024-08-12 10:32:25 -05:00
1natsu 72673ca366 fix: #907 move wxt devDeps execa to dependencies (#908) 2024-08-10 12:01:44 -05:00
Florian Metz cbda49ba7b feat: allow excluding files when zipping (#906) 2024-08-07 20:15:33 -05:00
hikiko4ern 0ab32e5afa feat: allow zipping hidden files by listing them explicitly in includeSources (#902) 2024-08-07 20:13:33 -05:00
GitHub Actions 36cfcd0acb chore(release): @wxt-dev/module-solid v1.1.2 2024-08-06 13:07:15 +00:00
GitHub Actions f746d46247 chore(release): @wxt-dev/module-svelte v1.0.1 2024-08-06 12:29:43 +00:00
GitHub Actions a2de6cbe44 chore(release): @wxt-dev/module-vue v1.0.1 2024-08-06 04:23:00 +00:00
GitHub Actions e632a2964a chore(release): @wxt-dev/module-react v1.1.1 2024-08-06 01:55:29 +00:00
GitHub Actions f736a14651 chore(release): @wxt-dev/auto-icons v1.0.2 2024-08-05 23:52:51 +00:00
uncenter a8b0d40959 docs(auto-icons): fix configuration example typo (#905) 2024-08-05 18:48:54 -05:00
Aaron 4c5504d139 Update changelog 2024-08-04 10:18:02 -05:00
GitHub Actions fb86deb388 chore(release): wxt v0.19.4 2024-08-04 14:31:30 +00:00
Aaron 3a8e6135ac fix: Fix createIframeUi page option types 2024-08-04 09:27:46 -05:00
Aaron a38de0c03f feat: Add injectScript helper (#900) 2024-08-04 09:16:46 -05:00
Aaron ea97410fb4 fix(types): PublicPath type resolution with extensionApi: "chrome" (#901) 2024-08-04 08:59:45 -05:00
hikiko4ern e36549ddce fix: do not clear .wxt/tsconfig.json in findEntrypoints if it exists (#898) 2024-08-03 21:59:12 -05:00
KnightYoshi 10851ae01c docs: add missing extension-apis segment (#896) 2024-08-03 19:28:53 -05:00
GitHub Actions d553ef6b29 chore(release): wxt v0.19.3 2024-08-02 21:48:05 +00:00
Aaron 15bf0da82e fix(content-script-context): Fix initialization logic for Firefox (#895) 2024-08-02 16:43:40 -05:00
hikiko4ern fc246ffaac fix: add consola to wxt dependencies (#892) 2024-08-01 19:05:28 -05:00
Florian Metz 9785eff21e chore: add more metadata for npm (#885) 2024-08-01 18:00:00 -05:00
Himanshu Patil 52fbd2c99e docs: Improve prepare:types hook JSDoc (#886) 2024-08-01 17:11:20 -05:00
GitHub Actions 648ae4fb8d chore(release): @wxt-dev/auto-icons v1.0.1 2024-07-30 18:23:12 +00:00
Aaron Klinker bbeeabc9ea Revert version change for auto-icons module 2024-07-30 13:18:35 -05:00
web-dahuyou 35cf6e7bc0 docs: Add "NiceTab" to homepage (#882) 2024-07-30 13:12:00 -05:00
Florian Metz 78822acdac fix(auto-icons): path option (#880)
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2024-07-30 13:06:41 -05:00
不游 aea123890f docs: Add "1Proompt" to homepage (#879) 2024-07-29 07:50:28 -05:00
Matt Strayer c369f4a955 docs: Add "mindful" to homepage (#878) 2024-07-28 16:33:58 -05:00
GitHub Actions 16d8240406 chore(release): wxt v0.19.2 2024-07-28 15:49:52 +00:00
Aaron 24cd01dd31 fix: Don't default to dev mode for production builds when using vite-node loader (#877) 2024-07-28 10:45:32 -05:00
Aaron fb22beadb8 fix: Remove unused top-level functions and variables when loading entrypoints with the vite-node loader (#875) 2024-07-28 09:27:29 -05:00
Aaron Klinker fa85177648 docs(modules): Adjust wording 2024-07-27 17:04:36 -05:00
Aaron Klinker ed07a49dd2 docs: Update README and homepage features with WXT modules 2024-07-27 16:57:33 -05:00
Aaron 09c9de0a60 docs: Fix environment variable reference (#870) 2024-07-27 16:15:28 -05:00
Aaron 523296b29a chore(deps): Upgrade all dependencies (#869) 2024-07-27 16:07:50 -05:00
Aaron Klinker ef67ef47aa chore: Update template package names 2024-07-27 15:37:48 -05:00
Aaron Klinker cb5eb68d62 Fix changelog 2024-07-27 15:11:27 -05:00
GitHub Actions 2e9ab75e2b chore(release): wxt v0.19.1 2024-07-27 20:09:05 +00:00
Aaron 0c2d795800 pref: Tree-shake unrelated code inside vite-node entrypoint loader (#867) 2024-07-27 15:03:23 -05:00
Aaron 97aa173f7e fix: Define web globals when importing entrypoints (#865) 2024-07-27 14:48:55 -05:00
Aaron 9eb64d94d6 docs: Add README for auto-icons module 2024-07-26 14:00:37 -05:00
Florian Metz a0971cab52 feat: Auto Icons Module (#851)
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2024-07-25 23:41:53 -05:00
Aaron 127562e9d0 ci: Fix breaking changes link generation in changelog 2024-07-25 22:48:05 -05:00
Aaron 038e7450e0 Fix diff 2024-07-25 22:40:33 -05:00
Aaron 6c00763187 docs: Add missing ssr.noExternal docs to vite-node loader 2024-07-25 22:38:21 -05:00
Aaron 2da0f3d686 Fix changelog 2024-07-25 22:14:06 -05:00
GitHub Actions 742d2f1536 chore(release): wxt v0.19.0 2024-07-26 01:03:48 +00:00
Aaron b4b69783d5 docs: Add upgrade guide and breaking changes (#860) 2024-07-25 19:59:15 -05:00
Aaron c8ddc66cfa feat!: Use vite-node to load entrypoints by default (#859)
BREAKING CHANGE: Switch from using `jiti` to import entrypoints during the build process by default to `vite-node`.

To continue using `jiti`, add the following to your `wxt.config.ts` file:

```ts
export default defineConfig({
  entrypointLoader: "jiti",
})
```

NOTE: "jiti" is deprecated and will be removed in the next major version, `v0.20.0`.
2024-07-25 17:25:46 -05:00
Aaron 2b6ff8d30f docs: Update labels in content script UI positioning screenshot 2024-07-25 11:45:49 -05:00
Aaron d79d7ed778 feat(hooks): Add prepare:publicPaths hook (#858) 2024-07-25 11:32:16 -05:00
Aaron Klinker ab234c0f45 docs: Review full docs, fix typos, re-order sections 2024-07-25 00:10:04 -05:00
Aaron Klinker eeb43c6bf4 docs: Fix typo 2024-07-24 23:22:14 -05:00
Aaron 17bda1eb34 feat(storage): init option and rename defaultValue to fallback (#827) 2024-07-24 23:18:16 -05:00
Aaron 96e28c415c docs: Extract comparison comments to footnotes (#853) 2024-07-24 23:17:01 -05:00
Florian Metz 1f9f6d9681 chore: update readme (#852) 2024-07-24 21:11:28 -05:00
Aaron f1bb7cb0c2 feat(experimental): First-class support for excluding webextension-polyfill (#847) 2024-07-24 17:09:56 -05:00
Aaron 5eb5be7123 perf(size)!: Switch from tsup to unbuild for building WXT (#848) 2024-07-24 08:48:48 -05:00
Florian Metz 886b2081c2 fix: wrong module hook type (#849) 2024-07-23 20:02:26 -05:00
Radek Grebski c69e51ce50 docs: Added "RespondEasy" to homepage (#844)
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2024-07-23 09:14:59 -05:00
Hagatopaxi 861efa3415 docs: fix typo (#845) 2024-07-22 23:53:00 -05:00
Aaron 792b57542d updtae lockfile 2024-07-21 11:53:34 -05:00
Aaron 97e6678e5b Upgrade vitest's listed version 2024-07-21 11:46:23 -05:00
Aaron 66c4ec3f99 chore(dev-deps): Upgrade happy-dom from 13 to 14 (#843) 2024-07-21 11:44:52 -05:00
Aaron 8988d6a241 chore(deps): Upgrade minimatch from 9 to 10 (#840) 2024-07-21 11:42:33 -05:00
Aaron b52856bea4 chore(deps): Upgrade webextension-polyfill from 0.10 to 0.12 (#842) 2024-07-21 11:39:40 -05:00
Aaron 16fee19b85 chore(deps): Upgrade ora from 7 to 8 (#841) 2024-07-21 11:39:03 -05:00
Aaron 14011c19cb chore(deps): Upgrade vite-node from 1.6 to 2.0 (#839) 2024-07-21 11:36:02 -05:00
Aaron 005a9dff16 chore(deps): Upgrade esbuild from 0.19.12 to 0.23.0 (#838) 2024-07-21 11:33:39 -05:00
Aaron 3109bbadbe chore(deps): Upgrade async-mutex from 0.4.1 to 0.5.0 (#837) 2024-07-21 11:31:35 -05:00
Aaron 34ae689569 chore(dev-deps): Upgrade vitest from 1.6 to 2.0 (#836) 2024-07-21 11:24:23 -05:00
Aaron 1f216dd57b chore(deps): Bump all non-major dependencies (#834) 2024-07-21 10:01:51 -05:00
GitHub Actions a7963e23db chore(release): wxt v0.18.15 2024-07-21 13:43:02 +00:00
Aaron 069bd6c435 fix: Externalize app config during dependency optimization (#833) 2024-07-21 08:37:09 -05:00
Aaron 88a1244ca9 fix: Build latest version of package before packing 2024-07-21 08:36:45 -05:00
Aaron 7ee391f688 fix: Don't throw error if localization file is missing (#832) 2024-07-21 07:53:38 -05:00
Aaron 2b3eab9c2a docs: Add link to google's update testing tool in migration guide and improve host permission docs 2024-07-20 11:33:17 -05:00
eetann a3fc9e1e18 docs: fix link to unimport (#826) 2024-07-17 07:40:34 -05:00
Aaron 559d32e6eb Update README.md 2024-07-12 08:19:59 -05:00
Aaron f904b79367 Update README.md 2024-07-12 08:19:33 -05:00
eetann 9cd7cca81c docs: fix links to Guide pages (#821) 2024-07-12 07:25:11 -05:00
GitHub Actions 3366c1e35f chore(release): wxt v0.18.14 2024-07-09 16:03:18 +00:00
Aaron 82be31a408 fix(modules): Add types from all wxt node_modules, not just ones with config (#817) 2024-07-09 10:58:41 -05:00
GitHub Actions d767f3f598 chore(release): wxt v0.18.13 2024-07-09 15:07:38 +00:00
Ayub Kokabi 48967c7c5f feat: add XPath support to getAnchor() (#813)
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2024-07-09 10:02:00 -05:00
Aaron 6c4da7225d fix: Add debug logs for vite builder (#816) 2024-07-09 09:58:59 -05:00
多吃点 e9025fb13e docs: Update manifest.md (#815) 2024-07-09 08:12:38 -05:00
jy00566722 8db6b3187b docs: Add "Exchange Rate Converter" extensions to homepage (#808) 2024-07-07 14:41:48 -05:00
Aaron a19f9e12c4 feat(config): dev.server.hostname (#807) 2024-07-07 09:31:38 -05:00
Farzad Soltani a82eb46511 docs: fix grammar (#806) 2024-07-07 09:16:03 -05:00
GitHub Actions e50f2b047a chore(release): wxt v0.18.12 2024-07-07 14:10:47 +00:00
Aaron 1b41cd26ee chore(deps): Upgrade web-ext-run (0.2.0 to 0.2.1) (#804) 2024-07-07 08:57:29 -05:00
Aaron e32fbed1b7 docs: Update README (#802) 2024-07-06 08:29:23 -05:00
sacrosanctic f8acdd6352 doc: detail issues with vite plugins (#799)
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2024-07-06 08:01:22 -05:00
ntnyq 9ea89c6340 fix: Add missing name to ESLint v9 autoImports config (#801) 2024-07-06 08:01:10 -05:00
Margarita Balkheeva a521a80d43 docs: Add "MaxFocus" extension to homepage (#795)
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2024-07-04 14:38:44 -05:00
sacrosanctic 4c6a57dd33 docs: rephrase a paragraph (#797) 2024-07-03 16:16:41 -05:00
Florian Metz 3ce8c8b1f4 perf: create zip using streams (#793) 2024-07-03 01:37:58 -05:00
deyu 4ee8f7837e docs: Add "Vanilla Pudding" extension to homepage (#794) 2024-07-03 01:36:32 -05:00
Aaron 1e8e5488af feat: Support runtime config in app.config.ts (#792) 2024-07-02 17:19:54 -05:00
GitHub Actions 5704765cc4 chore(release): wxt v0.18.11 2024-07-02 16:40:05 +00:00
GitHub Actions 8c7adbf463 chore(release): @wxt-dev/module-react v1.1.0 2024-07-02 16:34:30 +00:00
Aaron 8c4436efe8 Update solid template to @wxt-dev/module-solid v1.1.1 (#789) 2024-07-02 11:29:53 -05:00
GitHub Actions 5e361c0085 chore(release): @wxt-dev/module-solid v1.1.1 2024-07-02 16:23:54 +00:00
Aaron ccfc207e92 fix: Use prepare instead of postinstall for local dev setup (#788) 2024-07-02 11:18:44 -05:00
GitHub Actions 36be4ce771 chore(release): @wxt-dev/module-solid v1.1.0 2024-07-02 15:37:46 +00:00
KnightYoshi 18f8a387b0 feat: add eslint 9 config support (#762)
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2024-07-02 10:32:32 -05:00
C.C 48c2c07557 docs: Fix manifest typo (#787) 2024-07-02 07:09:07 -05:00
Aaron 61548a9478 fix(dev): Catch error when attempting to reload a tab in a saved tab group (#786) 2024-07-01 16:11:00 -05:00
dependabot[bot] fd678e9572 chore(deps): bump oven-sh/setup-bun from 1 to 2 (#785)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-01 15:40:10 -05:00
Aaron 63fb913f76 docs: New example search (#751) 2024-06-30 09:01:42 -05:00
Aaron faffe20a62 chore(deps): Upgrade non-major deps (#778) 2024-06-29 15:00:15 -05:00
Aaron 3ed8bd10fd chore: Upgrade buildc to v1.0.10 (#780) 2024-06-29 14:09:56 -05:00
Asakura Mizu 6f3f270573 fix: Respect custom outDir when cleaning and zipping (#774) 2024-06-28 09:05:40 -05:00
Aaron 5347cb4626 chore: Replace consola with wxt.logger (#776) 2024-06-28 09:04:21 -05:00
Aaron d6b4d2d1f6 chore(dev-deps): Upgrade buildc to v1.0.9 2024-06-27 16:47:35 -05:00
Aaron 0d7ae287da chore(dev-deps): Upgrade buildc to v1.0.8 2024-06-27 16:38:40 -05:00
Aaron 90cb3bd3bf feat: Enable auto-imports for JSX/TSX files (#773) 2024-06-27 00:05:45 -05:00
Prakhar 🔱 Man of Creativity 60eb97c4b2 docs: Update examples URL (#768)
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2024-06-26 13:52:10 -05:00
Aaron 0ffc6eae3e Fix comment typo 2024-06-25 15:12:59 -05:00
GitHub Actions 06a8c5fb0e chore(release): wxt v0.18.10 2024-06-25 20:03:59 +00:00
Aaron eb86413f35 chore: Consolidate unimport code into a built-in module (#771) 2024-06-25 14:59:28 -05:00
Aaron b29d49cbf1 fix: Await prepare:types hook 2024-06-24 10:04:44 -05:00
Aaron c0a0edb30c feat(modules): Allow adding generated public files (#769) 2024-06-24 08:46:45 -05:00
Aaron b15a933c75 feat: Add prepare:types hook to extend .wxt/ directory generation (#767) 2024-06-23 15:12:28 -05:00
Malix 1851be22a7 docs: Update CRXJS Firefox Compatibility (#764)
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2024-06-23 10:32:09 -05:00
Aaron 39f6c29e4f chore: Refactor package manager test fixtures 2024-06-21 09:10:22 -05:00
GitHub Actions 936e89fbfb chore(release): wxt v0.18.9 2024-06-20 15:34:16 +00:00
Aaron ad365ecde4 feat(experimental): Replace viteRuntime option with entrypointImporter option, and implement vite-node importer (#761) 2024-06-20 10:27:19 -05:00
GitHub Actions b4283e37bd chore(release): wxt v0.18.8 2024-06-20 14:03:16 +00:00
Aaron b467ad760a fix(modules): addViteConfig ignored user vite config (#760) 2024-06-20 08:59:46 -05:00
Aaron 9fc6408ef9 chore: Add E2E test for addImportPreset 2024-06-20 08:52:45 -05:00
Aaron 394cb1a520 docs: Add 'WorkFlowy MultiFlow' to homepage 2024-06-19 14:16:58 -05:00
Aaron ffec88549b fix: Ignore .wxt file changes in dev (#755) 2024-06-19 08:33:52 -05:00
Ziheng Xun 4758bea187 docs: update sandbox.md (#754) 2024-06-19 08:06:08 -05:00
Aaron 6671471f75 feat(dev): Reload extension when public files change (#752) 2024-06-19 08:05:56 -05:00
Aaron ae78dc7fb3 chore: Refactor client web socket util (#753) 2024-06-18 22:47:30 -05:00
Aaron b62af3d007 chore(dev-deps): Upgrade @aklinker1/buildc to 1.0.7 (#748) 2024-06-18 00:11:14 -05:00
Aaron 43ae44ecd5 fix: Don't load plugins twice in HTML pages (#746) 2024-06-17 23:41:39 -05:00
Aaron 5bab9d2f59 chore: Fix build script flags (#745) 2024-06-17 23:41:10 -05:00
Aaron 7edf1c8103 fix: Upgrade wxt peer to >= 0.18.6
This closes https://github.com/wxt-dev/wxt/issues/743
2024-06-17 14:42:24 -05:00
Aaron 53b4eac955 docs: Update wxt init command for bun 2024-06-17 14:39:41 -05:00
GitHub Actions f9a10c2c52 chore(release): wxt v0.18.7 2024-06-17 16:17:42 +00:00
Aaron 8206ca9164 fix(zip): Revert dotfile changes from #674 (#742) 2024-06-17 11:10:06 -05:00
Aaron 1a823cc008 chore: Extract build cache script to NPM package (#737) 2024-06-17 11:09:18 -05:00
Aaron efc011eb81 ci: Fix release 422 failure 2024-06-14 00:36:03 -05:00
GitHub Actions 35f6d28977 chore(release): @wxt-dev/module-solid v1.0.1 2024-06-14 05:29:40 +00:00
Aaron 43fcbec0eb fix: Add target: esnext by default (#733) 2024-06-14 00:25:11 -05:00
Aaron a0d56b4d27 chore: Update templates to use new modules (#732) 2024-06-14 00:19:13 -05:00
Aaron 38ccb6ace6 docs: Update frontend framework docs with new modules (#731) 2024-06-14 00:06:23 -05:00
Aaron aaf75f1de1 ci: Only mark wxt releases as latest 2024-06-14 00:02:41 -05:00
Aaron 21e8ca0a2c chore: Add changelog 2024-06-13 23:52:58 -05:00
Aaron 55444858bc ci: Add new modules as release targets 2024-06-13 23:44:28 -05:00
Aaron 771ea03069 feat: Add @wxt-dev/module-solid package (#730) 2024-06-13 23:23:32 -05:00
Aaron 38b71d1350 chore: Remove extra dependencies 2024-06-13 23:08:17 -05:00
Aaron cb781aceb5 chore: Remove extra dependencies 2024-06-13 23:05:48 -05:00
Aaron d53c792218 chore: Remove dependencies from vue module 2024-06-13 23:03:16 -05:00
Aaron 907f4d3672 feat: Add @wxt-dev/module-react package (#729) 2024-06-13 22:53:40 -05:00
Aaron 8432d73a6b fix: Generalize react-refresh preamble logic to virtualize all inline scripts (#728) 2024-06-13 19:17:23 -05:00
Aaron 94a5435089 docs: Add missing vue install step 2024-06-13 16:39:09 -05:00
Aaron edf3cf3f17 feat: Add @wxt-dev/module-vue package (#726) 2024-06-13 16:36:37 -05:00
Aaron 48783baec3 chore(deps): Upgrade and sync all dependencies (#725) 2024-06-13 15:44:00 -05:00
Aaron c70f047696 chore: Add taze to project (#724) 2024-06-13 15:17:21 -05:00
Aaron e6e0c713bc feat: Add @wxt-dev/module-vue package (#716) 2024-06-13 15:16:45 -05:00
Aaron 3691554a73 docs: Update contributor docs with release steps 2024-06-13 14:58:57 -05:00
Aaron 1a3436606b fix(dev): Fix CSP error loading HTML plugins (#723) 2024-06-13 14:49:50 -05:00
GitHub Actions 2c9e7750ec chore(release): wxt v0.18.6 2024-06-13 17:28:34 +00:00
Aaron fa67910007 fix(modules): Add modules to TS project so type augmentation works (#722) 2024-06-13 12:25:18 -05:00
Aaron c77773eb20 feat(modules): Add new addImportPreset helper function (#720) 2024-06-13 12:20:09 -05:00
Aaron 148f3d53a6 fix(modules): Re-export WxtModule type from wxt/modules to prevent TS2742 (#721) 2024-06-13 12:19:15 -05:00
Aaron c7af789173 fix(types): Module options param is optional, but types did not reflect that (#719) 2024-06-13 11:20:59 -05:00
Aaron 274d39b9a4 chore(dev-deps): Upgrade typescript to 5.4 (#718) 2024-06-13 00:38:11 -05:00
Aaron d1edb2da0e chore: Cache workspace dependency builds (#715) 2024-06-12 22:34:08 -05:00
Aaron ed860027ef ci: Fix sync-releases script 2024-06-12 00:51:11 -05:00
Aaron 488fa6e773 ci: Fix sync-releases workflow 2024-06-12 00:48:40 -05:00
Aaron ea51cc04a9 Fix changelog 2024-06-12 00:46:23 -05:00
Aaron 6d1761533f ci: Fix compare url generation 2024-06-12 00:45:39 -05:00
GitHub Actions e35b540a3b chore(release): wxt v0.18.5 2024-06-12 05:42:26 +00:00
Aaron 7080b36173 ci: Add support for managing multiple changelogs (#712) 2024-06-12 00:36:28 -05:00
Aaron 4437dc404b chore(deps): Upgrade braces to 3.0.3 (#711) 2024-06-11 19:45:07 -05:00
Aaron b3ddab7bcb feat: Module system (#672) 2024-06-11 17:45:34 -05:00
Aaron Klinker eb3b9bc334 chore: Remove log in tests 2024-06-11 17:43:21 -05:00
Dave Stewart 34ea23030b docs: Simplify menu configuration (#709)
Co-authored-by: Dave Stewart <dev@davestewart.co.uk>
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2024-06-10 16:10:27 -05:00
Aaron a25721708f chore: Fix flakey TS config 2024-06-09 10:00:45 -05:00
Aaron 6427e74edb chore: Fix engine requirements for PNPM 2024-06-09 10:00:31 -05:00
TheOnlyTails 15395a8c46 fix(storage): Add storage area typing for storage keys (#708)
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2024-06-09 09:20:32 -05:00
Aaron 454b076eaf docs: Add eslintrc info to auto-imports page 2024-06-08 13:40:14 -05:00
Aaron 00597f6790 docs: Fill out web-ext.config.ts docs 2024-06-08 08:20:38 -05:00
rxliuli ca29feaecf fix: To fix the issue with Entrypoint Side Effects link errors (#705) 2024-06-05 19:24:58 -07:00
Aaron f6420e5fdf docs: Fix more homepage links 2024-06-04 12:12:25 -05:00
Aaron 78e0646043 docs: Fix home page links and redirects 2024-06-04 08:41:04 -05:00
dependabot[bot] c15e75e6ab chore(deps): bump pnpm/action-setup from 3 to 4 (#689)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2024-06-03 23:06:38 -05:00
Aaron 863a006ee7 docs: Restructure wxt.dev (#701) 2024-06-03 18:43:25 -05:00
dependabot[bot] 9fd54cfa73 chore(deps-dev): bump execa from 8.0.1 to 9.1.0 (#691)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-02 22:35:29 -07:00
Durgaprasad 3535fb77fa docs: Add SmartEReply to homepage (#697) 2024-06-02 22:25:24 -07:00
dependabot[bot] be22fc43cb chore(deps-dev): bump prettier from 3.1.1 to 3.3.0 (#693)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-02 22:25:07 -07:00
dependabot[bot] 3fd09edd25 chore(deps-dev): bump tsx from 4.7.0 to 4.11.2 (#699)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-02 22:23:40 -07:00
dependabot[bot] d36007b453 chore(deps): bump nypm from 0.3.6 to 0.3.8 (#692)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-02 22:14:05 -07:00
dependabot[bot] 9eda887fd8 chore(deps): bump linkedom from 0.16.8 to 0.18.2 (#690)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-02 22:13:21 -07:00
John Wheeler b79220dbd1 docs: Adds demo.fun to homepage (#688)
Co-authored-by: John Wheeler <jwheeler@dinesh.local>
2024-05-31 11:31:44 -07:00
Aaron 927d29535f fix: Previous version of WXT printed on startup 2024-05-31 08:33:48 -05:00
GitHub Actions 12805e9862 chore(release): v0.18.4 2024-05-31 13:27:34 +00:00
hujiulong d889a21465 fix: Properly invalidate content script context (#683) 2024-05-31 08:24:12 -05:00
Aaron 8125d74057 docs: Update contributing guidelines 2024-05-31 01:32:16 -05:00
Aaron c39087a81a Migrate bug report to a GitHub form template 2024-05-31 01:28:45 -05:00
Aaron 7b849b80cb fix: Allow zipping hidden files in sources by listing them explicitly in includeSources (#674) 2024-05-25 16:43:51 -05:00
GitHub Actions b98a5c378e chore(release): v0.18.3 2024-05-24 10:51:34 +00:00
Aaron 215def7e15 fix(security): Upgrade tar to 6.2.1 2024-05-24 05:46:11 -05:00
Aaron 3b954cc6fb chore: Upgrade templates to v0.18 2024-05-24 05:40:07 -05:00
Aaron 20bdd8ad2f fix: Remove import * as imports from entrypoints during build (#671) 2024-05-24 05:38:53 -05:00
Edoan cb9a9c0530 docs: Add YTBlock to homepage (#666) 2024-05-21 12:01:55 -05:00
Aaron 48d8d236c0 fix: Automatically add dev server to sandbox CSP (#663) 2024-05-20 23:41:11 -05:00
Aaron 87d9511b31 chore: Add missing tests for dev mode CSP (#662) 2024-05-20 23:35:21 -05:00
Aaron 5d8efef02f ci: Fix sync-releases workflow trigger 2024-05-08 11:04:58 -05:00
Aaron c9008cd835 Update changelog 2024-05-08 11:03:17 -05:00
GitHub Actions 203a9cc234 chore(release): v0.18.2 2024-05-08 15:50:03 +00:00
Aaron 5fcaf7c68b fix: Automatically detect and add "sidePanel" permission 2024-05-08 10:42:07 -05:00
Aaron c74e530d4a docs: Fix iframe typos 2024-05-08 10:34:34 -05:00
Edoan 3f78be0c95 feat(runner): Add keepProfileChanges option (#655) 2024-05-07 22:20:51 -05:00
Linus Norton 2a3d52045d docs: Correct event handler name in handling-updates.md (#653) 2024-05-07 04:31:28 -05:00
Jeffrey Zang ea5b81d25e docs: Fix spelling mistake in remote-code.md (#652) 2024-05-06 21:58:36 -05:00
Emmanuel Ferdman cec9d7103a docs: Fix wxt-vitest-plugin reference (#650)
Signed-off-by: Emmanuel Ferdman <emmanuelferdman@gmail.com>
2024-05-05 08:30:40 -05:00
GitHub Actions 34dd2c1487 chore(release): v0.18.1 2024-05-04 16:42:09 +00:00
Aaron a5667f85d0 fix: _background is not defined (#649) 2024-05-04 11:39:29 -05:00
Aaron ec3dd52f83 chore: Add root README back 2024-05-04 11:03:55 -05:00
Aaron 87ebde3abb Fix sync releases workflow 2024-05-04 11:01:08 -05:00
Aaron dc5b55bffb ci: Fix sync releases workflow 2024-05-04 10:59:40 -05:00
Aaron df20993917 Fix changelog generation 2024-05-04 10:57:23 -05:00
Aaron caa0fb31e6 Add breaking change message to changelog 2024-05-04 10:53:35 -05:00
GitHub Actions 95da4fb054 chore(release): v0.18.0 2024-05-04 15:51:44 +00:00
Aaron a917f32a0e feat(experimental): Load entrypoint options with Vite Runtime API (#648) 2024-05-04 10:46:31 -05:00
Aaron 6ca376749c chore: Fix formatting after monorepo refactor 2024-05-04 09:44:07 -05:00
Aaron 792e3032b9 feat: Support returning values from scripts executed with the scripting API (#624) 2024-05-03 17:32:42 -05:00
alegal200 38a5a2c440 docs: Document required permission for storage API (#632)
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2024-05-03 17:28:52 -05:00
yacine-bens 21106ce188 docs: Add MS Edge TTS to homepage (#647) 2024-05-03 17:26:34 -05:00
Aaron ec7263e7de chore: Refactor repo to a standard monorepo (#646) 2024-05-03 17:16:33 -05:00
dependabot[bot] e7c3fc2a5e chore(deps-dev): bump simple-git-hooks from 2.9.0 to 2.11.1 (#640)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-02 08:14:03 -05:00
dependabot[bot] f808cb7526 chore(deps-dev): bump publint from 0.2.6 to 0.2.7 (#639)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-02 08:13:15 -05:00
dependabot[bot] c4795e7479 chore(deps): bump react and @types/react (#638)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-02 08:13:02 -05:00
dependabot[bot] b44a96ab81 chore(deps-dev): bump lint-staged from 15.2.1 to 15.2.2 (#637)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-02 08:12:45 -05:00
evsamson 3bfdc5c755 FIX: Chromium window-size example format (#630)
Co-authored-by: smsnbv <active.sock7816@fastmail.com>
2024-04-22 07:12:30 -05:00
Aaron acb75543ff docs: Add docs about handling updates
Related to #620
2024-04-20 00:04:05 -05:00
Aaron 25b45b9c09 fix(dep): Upgrade @webext-core/isolated-element to v1.1.2 (#625) 2024-04-19 22:09:16 -05:00
Aaron efd5c40043 fix!: Automatically move host_permissions to permissions for MV2 (#626)
BREAKING CHANGE: Out of an abundance of caution, I've marked this as a breaking change because permission generation has changed. ***If you list `host_permissions` in your `wxt.config.ts`'s manifest and have released your extension***, double check that your `permissions` and `host_permissions` have not changed for all browsers you target. Permission changes can cause the extension to be disabled on update, and can cause a drop in users, so be sure to double check for differences compared to the previous manifest version.
2024-04-19 22:08:52 -05:00
Aaron e47519fb76 docs: Update content script registration JSDoc
See https://github.com/wxt-dev/wxt/discussions/623
2024-04-19 15:59:14 -05:00
Ayden 171e32c272 docs: Add ElemSnap to homepage (#621) 2024-04-19 08:00:41 -05:00
wuzequanyouzi 54e5ed0bb4 chore: Update vue template config (#607)
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2024-04-15 12:43:43 -05:00
Aaron a94d673f31 docs: Fix typo in assets page 2024-04-15 12:17:02 -05:00
yacine-bens b7f7222c26 docs: Add Facebook Video Controls to homepage (#615) 2024-04-15 12:13:06 -05:00
Can Rau aa5a9d4fa9 docs: Tix typo in entrypoints.md (#614) 2024-04-14 17:21:12 -05:00
日高 凌 77da2d6ade docs: Fix typo on example for wxt.config.ts. (#609) 2024-04-12 09:00:15 -05:00
Bas van Zanten 3119c04e10 feat: Add zip compression settings (#605) 2024-04-12 08:59:54 -05:00
couriourc c09994263e doc: Fix bad extension API examples (#608) 2024-04-12 01:01:07 -05:00
ThinkStu 2a4fa9ae5c docs: Add Fluent Read to homepage (#600)
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2024-04-07 09:01:02 -05:00
Aaron c833d3b15b Update test snapshot after vite upgrade 2024-04-07 08:53:15 -05:00
Aaron d6e095bfce Fix type error 2024-04-07 08:47:52 -05:00
Aaron 825160a3cc chore(deps): Upgrade vite 2024-04-03 14:16:51 -05:00
Aaron e29ca33f82 Add missing cleanup from PR 2024-04-03 14:15:55 -05:00
GitHub Actions ca5a52c6f1 chore(release): v0.17.12 2024-04-03 19:04:03 +00:00
Aaron 982c69f8ae feat: Add hooks for extending vite config (#599) 2024-04-03 14:00:48 -05:00
Aaron 6fc7d9254a fix(content-script-ui): Properly assign and unassign mounted value (#598) 2024-04-03 12:38:46 -05:00
dependabot[bot] 2e0e104d48 chore(deps): bump c12 from 1.5.1 to 1.10.0 (#592)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-01 23:23:11 -05:00
dependabot[bot] 02430fd7b8 chore(deps-dev): bump sass from 1.69.5 to 1.72.0 (#591)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-01 23:23:01 -05:00
dependabot[bot] 2e6d35d193 chore(deps-dev): bump vue from 3.3.10 to 3.4.21 (#589)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-01 23:08:37 -05:00
dependabot[bot] 7cf412ac1f chore(deps): bump vitest from 1.2.2 to 1.4.0 (#590)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-01 22:15:44 -05:00
Aaron 9398cbb596 docs: Add discord server link (#593) 2024-04-01 19:13:12 -05:00
dependabot[bot] ca9b96142e chore(deps-dev): bump @aklinker1/check from 1.1.1 to 1.2.0 (#588)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-01 18:10:28 -05:00
Aaron db57c8e079 chore: Remove unnecssary 'Omit' types 2024-03-31 08:40:21 -05:00
GitHub Actions 7e37e11caf chore(release): v0.17.11 2024-03-31 13:22:25 +00:00
Aaron bb90029c54 fix: Resolve absolute paths from the public directory properly (#583) 2024-03-31 08:19:06 -05:00
Aaron d3b14afbce chore: Extract helper function 2024-03-30 14:49:10 -05:00
Aaron ba2197a609 chore: Add some array utils (#582) 2024-03-30 13:30:45 -05:00
Aaron 4c558d3eb6 chore: Simplify virtual module setup (#581) 2024-03-30 12:44:27 -05:00
Qiwei Yang dcd175444a docs: Add "GitHub Custom Notifier" to homepage (#580) 2024-03-30 08:37:26 -05:00
Aaron 16fc58404a docs: Fix zip.includeSources example 2024-03-30 08:37:00 -05:00
445 changed files with 18951 additions and 7208 deletions
-50
View File
@@ -1,50 +0,0 @@
---
name: Bug report
about: Report an issue with WXT
title: ''
labels: triage
assignees: ''
---
### Describe the bug
A clear and concise description of what the bug is.
### To Reproduce
Share minimal reproduction. Examples of a minimal reproduction:
- PR with a failing test case
- ZIP file containing a minimal WXT project (be sure to include your lockfile!!)
> **_⚠️ If you don't upload a minimal reproduction, your issue will be closed until a reproduction is added._**
>
> Why? https://antfu.me/posts/why-reproductions-are-required
Steps to reproduce the bug using the reproduction:
1. Install dependencies: `pnpm i`
2. Start dev mode: `pnpm dev`
3. Click this...
4. Do that...
5. Etc...
### Expected behavior
A clear and concise description of what you expected to happen.
### Screenshots
If applicable, add screenshots to help explain your problem.
### Environment
<!--- Run `npx envinfo --system --browsers --binaries --npmPackages wxt,vite` and paste the output below -->
```
Paste output here
```
### Additional context
Add any other context about the problem here, otherwise you can delete this section.
+74
View File
@@ -0,0 +1,74 @@
name: "\U0001F41E Bug report"
description: Report an issue with WXT
labels: [pending-triage]
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
+8
View File
@@ -0,0 +1,8 @@
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.
+1 -3
View File
@@ -4,9 +4,7 @@ runs:
using: composite
steps:
- name: Setup PNPM
uses: pnpm/action-setup@v3
with:
version: 8
uses: pnpm/action-setup@v4
- name: Setup NodeJS
uses: actions/setup-node@v4
with:
+19 -2
View File
@@ -1,6 +1,19 @@
name: Release
on:
workflow_dispatch:
inputs:
package:
description: Package to release
default: wxt
type: choice
options:
- auto-icons
- i18n
- module-react
- module-solid
- module-svelte
- module-vue
- wxt
jobs:
validate:
@@ -22,14 +35,18 @@ jobs:
run: |
git config user.email "github-actions@users.noreply.github.com"
git config user.name "GitHub Actions"
pnpx changelogen@latest --release
pnpm tsx scripts/bump-package-version.ts ${{ inputs.package }}
git push
git push --tags
- name: NPM
run: |
echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_AUTH_TOKEN }}" > ~/.npmrc
pnpm build
pnpm publish
working-directory: packages/${{ inputs.package }}
- name: GitHub Release
run: pnpx changelogen@latest gh release --token ${{ secrets.GITHUB_TOKEN }}
run: pnpm tsx scripts/create-github-release.ts ${{ inputs.package }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+15 -13
View File
@@ -1,22 +1,24 @@
name: Sync Releases
on:
workflow_dispatch:
push:
branches:
- main
paths:
- CHANGELOG.md
inputs:
package:
description: Package to sync
default: wxt
type: choice
options:
- wxt
- module-react
- module-vue
- module-svelte
- module-solid
jobs:
sync:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v3
with:
version: 8
- uses: actions/setup-node@v4
with:
node-version: 18
cache: pnpm
- run: pnpm sync-releases all --token ${{ secrets.GITHUB_TOKEN }}
- uses: ./.github/actions/setup
- run: pnpm tsx scripts/sync-releases.ts ${{ inputs.package }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+15 -11
View File
@@ -13,27 +13,29 @@ jobs:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup
- run: pnpm check
validate-demo:
builds:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup
- run: pnpm buildc all
build-demo:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup
- run: pnpm tsc --noEmit
working-directory: demo
- run: pnpm build:all
working-directory: demo
working-directory: packages/wxt-demo
- run: pnpm wxt zip
working-directory: demo
- run: pnpm vitest run
working-directory: demo
working-directory: packages/wxt-demo
tests:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup
- uses: oven-sh/setup-bun@v1
- uses: oven-sh/setup-bun@v2
- name: pnpm test:coverage
run: pnpm test:coverage --reporter=default --reporter=hanging-process
run: pnpm test:coverage -- --reporter=default --reporter=hanging-process
- uses: codecov/codecov-action@v4
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
@@ -42,10 +44,11 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup
- run: pnpm test run
- run: pnpm test
template:
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
template:
- react
@@ -57,9 +60,10 @@ jobs:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup
- run: pnpm pack
working-directory: packages/wxt
- run: npm i
working-directory: templates/${{ matrix.template }}
- run: npm i -D ../../wxt-*.tgz
- run: npm i -D ../../packages/wxt/wxt-*.tgz
working-directory: templates/${{ matrix.template }}
- run: pnpm compile
if: matrix.template != 'svelte'
+3 -1
View File
@@ -17,6 +17,8 @@ web-ext.config.ts
templates/*/pnpm-lock.yaml
templates/*/yarn.lock
templates/*/package-lock.json
docs/api
docs/api/reference
stats.html
.tool-versions
.cache
*-stats.txt
-1
View File
@@ -1 +0,0 @@
ignore-workspace-root-check=true
+36 -4
View File
@@ -37,13 +37,13 @@ pnpm build
```sh
# Build WXT package, then build demo extension
cd demo
cd packages/wxt-demo
pnpm build
```
```sh
# Build WXT package, then start the demo extension in dev mode
cd demo
cd packages/wxt-demo
pnpm dev
```
@@ -57,6 +57,21 @@ pnpm test
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.
@@ -75,7 +90,7 @@ To run tests for a specific file, add the filename at the end of the test comman
pnpm test manifest-contents
```
Unit and E2E tests are ran together via [Vitest workspaces](https://vitest.dev/guide/#workspaces-support).
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.
@@ -90,7 +105,7 @@ 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 changes against the templates, but if you want to manually do it, update the package.json dependency:
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": {
@@ -112,3 +127,20 @@ 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.
## Releasing 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.
## Upgrading Dependencies
Use [`taze`](https://www.npmjs.com/package/taze) to upgrade dependencies throughout the entire monorepo.
```ts
pnpm dlx taze -r
```
Configuration is in [`taze.config.ts`](./taze.config.ts).
+9 -6
View File
@@ -1,5 +1,5 @@
<h1 align="center">
<img style="vertical-align:middle" width="44" src="./docs/public/hero-logo.svg" alt="WXT Logo">
<img style="vertical-align:middle" width="44" src="https://raw.githubusercontent.com/wxt-dev/wxt/HEAD/docs/public/hero-logo.svg" alt="WXT Logo">
<span>WXT</span>
</h1>
@@ -18,20 +18,22 @@
<br/>
<span>⚡</span>
<br/>
<q><i>It's like Nuxt, but for Chrome Extensions</i></q>
<q><i>It's like Nuxt, but for Web Extensions</i></q>
</p>
<p align="center">
<a href="https://wxt.dev" target="_blank">Get Started</a>
&bull;
<a href="https://wxt.dev/guide/installation.html" target="_blank">Installation</a>
<a href="https://wxt.dev/guide/installation.html" target="_blank">Get Started</a>
&bull;
<a href="https://wxt.dev/api/config.html" target="_blank">Configuration</a>
&bull;
<a href="https://wxt.dev/examples.html" target="_blank">Examples</a>
&bull;
<a href="https://github.com/wxt-dev/wxt/blob/main/packages/wxt/CHANGELOG.md" target="_blank">Changelog</a>
&bull;
<a href="https://discord.gg/ZFsZqGery9" target="_blank">Discord</a>
</p>
![Example CLI Output](./docs/assets/cli-output.png)
![Example CLI Output](https://raw.githubusercontent.com/wxt-dev/wxt/HEAD/docs/assets/cli-output.png)
## Demo
@@ -57,6 +59,7 @@ Or see the [installation guide](https://wxt.dev/guide/installation.html) to get
- 🦾 Auto-imports
- 🤖 Automated publishing
- 🎨 Frontend framework agnostic: works with Vue, React, Svelte, etc
- 📦 Modular architecture with [WXT modules](https://wxt.dev/guide/go-further/reusable-modules.html#overview)
- 🖍️ Quickly bootstrap a new project
- 📏 Bundle analysis
- ⬇️ Download and bundle remote URL imports
-2
View File
@@ -1,2 +0,0 @@
#!/usr/bin/env node
import '../dist/cli.js';
-30
View File
@@ -1,30 +0,0 @@
{
"name": "demo",
"version": "1.0.0",
"description": "Demo extension for WXT",
"type": "module",
"scripts": {
"dev": "pnpm -w build && wxt",
"build": "pnpm -w build && wxt build",
"build:all": "pnpm -w build && run-s -s 'build:all:*'",
"build:all:chrome-mv3": "wxt build",
"build:all:chrome-mv2": "wxt build --mv2",
"build:all:firefox-mv3": "wxt build -b firefox --mv3",
"build:all:firefox-mv2": "wxt build -b firefox",
"test": "pnpm -w build && vitest",
"zip": "pnpm -w build && wxt zip",
"compile": "pnpm -w build && tsc --noEmit",
"postinstall": "pnpm -w build && wxt prepare"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"vitest": "^1.2.2"
},
"devDependencies": {
"@types/react": "^18.2.34",
"@types/react-dom": "^18.2.14",
"sass": "^1.69.5",
"wxt": "workspace:*"
}
}
-29
View File
@@ -1,29 +0,0 @@
{
"prompt_for_name": {
"message": "What's your name?",
"description": "Ask for the user's name"
},
"hello": {
"message": "Hello, $USER$",
"description": "Greet the user",
"placeholders": {
"user": {
"content": "$1",
"example": "Cira"
}
}
},
"bye": {
"message": "Goodbye, $USER$. Come back to $OUR_SITE$ soon!",
"description": "Say goodbye to the user",
"placeholders": {
"our_site": {
"content": "Example.com"
},
"user": {
"content": "$1",
"example": "Cira"
}
}
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 504 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 936 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

-7
View File
@@ -1,7 +0,0 @@
{
"extends": ["../tsconfig.base.json", "./.wxt/tsconfig.json"],
"compilerOptions": {
"allowImportingTsExtensions": true,
"jsx": "react-jsx"
}
}
@@ -33,7 +33,7 @@ For production builds, none of the above modifications will be applied, and you'
## Configure Browser Startup
WXT uses [`web-ext` by Mozilla](https://github.com/mozilla/web-ext) to automatically open a browser with the extension installed. You can configure the runner's behavior via the [`runner`](/api/wxt/interfaces/InlineConfig#runner) option, or in a separate gitignored file, `web-ext.config.ts`.
WXT uses [`web-ext` by Mozilla](https://github.com/mozilla/web-ext) to automatically open a browser with the extension installed. You can configure the runner's behavior via the [`runner`](/api/reference/wxt/interfaces/InlineConfig#runner) option, or in a separate gitignored file, `web-ext.config.ts`.
:::code-group
@@ -59,7 +59,7 @@ export default defineRunnerConfig({
### Browser Binaries
`web-ext`'s browser discovery is very limited. By default, it only guesses at where Chrome and Firefox are installed. If you've customized your install locations, you may need to tell `web-ext` where the binaries/executables are located using the [`binaries` option](/api/wxt/interfaces/ExtensionRunnerConfig#binaries). For other Chromium based browsers, like Edge or Opera, you'll need to explicitly list them in the `binaries` option as well, otherwise they will open in Chrome by default.
`web-ext`'s browser discovery is very limited. By default, it only guesses at where Chrome and Firefox are installed. If you've customized your install locations, you may need to tell `web-ext` where the binaries/executables are located using the [`binaries` option](/api/reference/wxt/interfaces/ExtensionRunnerConfig#binaries). For other Chromium based browsers, like Edge or Opera, you'll need to explicitly list them in the `binaries` option as well, otherwise they will open in Chrome by default.
```ts
// ~/web-ext.config.ts
@@ -89,11 +89,11 @@ import { defineRunnerConfig } from 'wxt';
export default defineRunnerConfig({
startUrls: ['https://google.com', 'https://duckduckgo.com'],
chromiumProfile: '/path/to/profile/to/use',
chromiumArgs: ['--window-size=400x300'],
chromiumArgs: ['--window-size=400,300'],
});
```
For a full list of options, see the [API Reference](/api/wxt/interfaces/ExtensionRunnerConfig).
For a full list of options, see the [API Reference](/api/reference/wxt/interfaces/ExtensionRunnerConfig).
## Reload the Extension
@@ -1,34 +0,0 @@
<script lang="ts" setup>
import { ref, onMounted, computed } from 'vue';
const props = defineProps<{
tag?: string;
}>();
const examples = ref();
onMounted(async () => {
const res = await fetch(
'https://raw.githubusercontent.com/wxt-dev/wxt-examples/main/examples.json',
);
examples.value = await res.json();
});
const filteredExamples = computed(() => {
if (props.tag == null) return examples.value;
return examples.value.filter((example) => {
return example.tags?.includes(props.tag);
});
});
</script>
<template>
<ul>
<li v-if="examples == null">Loading...</li>
<template v-else>
<li v-for="example of filteredExamples">
<a :href="example.url" target="_blank">{{ example.name }}</a>
</li>
</template>
</ul>
</template>
@@ -0,0 +1,226 @@
<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>
@@ -0,0 +1,100 @@
<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>
@@ -0,0 +1,72 @@
<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 &rarr;</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>
+60 -77
View File
@@ -21,6 +21,23 @@ const chromeExtensionIds = [
'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
];
const { data, err, isLoading } = useListExtensionDetails(chromeExtensionIds);
@@ -46,90 +63,56 @@ function getStoreUrl(extension: ChromeExtension) {
</script>
<template>
<section class="vp-doc">
<div class="container">
<h2 id="whos-using-wxt">Who's Using WXT?</h2>
<p>
Battle tested and ready for production. Explore chrome extensions made
with WXT.
</p>
<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">
<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="https://github.com/wxt-dev/wxt/edit/main/docs/.vitepress/components/UsingWxtSection.vue"
:href="getStoreUrl(extension)"
target="_blank"
>Open a PR</a
:title="extension.name"
class="extension-name"
>{{ extension.name }}</a
>
to add your extension to the list!
<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>
</div>
</section>
</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>
.vp-doc {
padding: 0 24px;
}
@media (min-width: 640px) {
.vp-doc {
padding: 0 48px;
}
}
@media (min-width: 960px) {
.vp-doc {
padding: 0 64px;
}
}
.container {
max-width: 1152px;
margin: 0 auto;
display: flex;
flex-direction: column;
}
li img {
width: 116px;
height: 116px;
+130 -106
View File
@@ -1,23 +1,16 @@
import { DefaultTheme, defineConfig } from 'vitepress';
import { generateCliDocs } from './plugins/generate-cli-docs';
import typedocSidebar from '../api/typedoc-sidebar.json';
const filteredTypedocSidebar = typedocSidebar.filter(
(item) => item.text !== 'API',
);
// Typedoc's markdown theme adds collapse: true to all our items, event ones without any children,
// so they need to be removed.
function removeCollapsedWithNoItems(items: DefaultTheme.SidebarItem[]) {
for (const item of items) {
if (item.items) removeCollapsedWithNoItems(item.items);
else delete item.collapsed;
}
}
removeCollapsedWithNoItems(filteredTypedocSidebar);
import { 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';
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 chrome extensions for all browsers. With built-in utilities for building, zipping, and publishing your extension, it's easy to get started.";
const ogTitle = `${title}${titleSuffix}`;
@@ -31,7 +24,6 @@ export default defineConfig({
description,
vite: {
clearScreen: false,
plugins: [generateCliDocs()],
},
lastUpdated: true,
sitemap: {
@@ -39,20 +31,16 @@ export default defineConfig({
},
head: [
['meta', { property: 'og:type', content: 'website' }],
['meta', { property: 'og:title', content: ogTitle }],
['meta', { property: 'og:image', content: ogImage }],
['meta', { property: 'og:url', content: ogUrl }],
['meta', { property: 'og:description', content: description }],
['meta', { name: 'twitter:card', content: 'summary_large_image' }],
[
'script',
{
async: '',
'data-website-id': 'c1840c18-a12c-4a45-a848-55ae85ef7915',
src: 'https://umami.aklinker1.io/script.js',
},
],
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: '',
}),
],
themeConfig: {
@@ -61,91 +49,127 @@ export default defineConfig({
src: '/logo.svg',
alt: 'WXT logo',
},
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: [
{ text: 'Guide', link: '/guide/installation.md' },
{ text: 'Entrypoints', link: '/entrypoints/background.md' },
{ text: 'Examples', link: '/examples.md' },
{ text: 'API', link: '/api/cli.md' },
navItem('Get Started', '/get-started/introduction'),
navItem('Guide', '/guide/key-concepts/manifest'),
navItem('API', '/api/reference/wxt'),
navItem('Examples', '/examples'),
],
sidebar: {
'/guide/': [
{
text: 'Guide',
items: [
{ text: 'Introduction', link: '/guide/introduction.md' },
{ text: 'Installation', link: '/guide/installation.md' },
{ text: 'Configuration', link: '/guide/configuration.md' },
{ text: 'Entrypoints', link: '/guide/entrypoints.md' },
{ text: 'Manifest.json', link: '/guide/manifest.md' },
{ text: 'Extension APIs', link: '/guide/extension-apis.md' },
{ text: 'Storage', link: '/guide/storage.md' },
{ text: 'Assets', link: '/guide/assets.md' },
{ text: 'Content Script UI', link: '/guide/content-script-ui.md' },
{ text: 'Multiple Browsers', link: '/guide/multiple-browsers.md' },
{ text: 'ES Modules', link: '/guide/esm.md' },
{ text: 'Auto-imports', link: '/guide/auto-imports.md' },
{ text: 'Vite', link: '/guide/vite.md' },
{ text: 'Remote Code', link: '/guide/remote-code.md' },
{ text: 'Publishing', link: '/guide/publishing.md' },
{ text: 'Development', link: '/guide/development.md' },
{ text: 'Testing', link: '/guide/testing.md' },
],
},
{
text: 'Other',
items: [
{ text: 'Migrate to WXT', link: '/guide/migrate-to-wxt.md' },
{ text: 'Compare', link: '/guide/compare.md' },
],
},
],
'/entrypoints/': [
{
text: 'Entrypoints',
items: [
{ text: 'Background', link: '/entrypoints/background.md' },
{ text: 'Bookmarks', link: '/entrypoints/bookmarks.md' },
{
text: 'Content Scripts',
link: '/entrypoints/content-scripts.md',
},
{ text: 'CSS', link: '/entrypoints/css.md' },
{ text: 'Devtools', link: '/entrypoints/devtools.md' },
{ text: 'History', link: '/entrypoints/history.md' },
{ text: 'Newtab', link: '/entrypoints/newtab.md' },
{ text: 'Options', link: '/entrypoints/options.md' },
{ text: 'Popup', link: '/entrypoints/popup.md' },
{ text: 'Sandbox', link: '/entrypoints/sandbox.md' },
{ text: 'Side Panel', link: '/entrypoints/sidepanel.md' },
{ text: 'Unlisted Pages', link: '/entrypoints/unlisted-pages.md' },
{
text: 'Unlisted Scripts',
link: '/entrypoints/unlisted-scripts.md',
},
].sort((l, r) => l.text.localeCompare(r.text)),
},
],
'/api/': [
{
items: [
{ text: 'CLI', link: '/api/cli.md' },
{
text: 'Modules',
items: filteredTypedocSidebar,
},
],
},
],
},
'/get-started/': menuRoot([
menuGroup('Get Started', '/get-started/', [
menuItem('Introduction', 'introduction'),
menuItem('Installation', 'installation'),
menuItem('Configuration', 'configuration'),
menuItem('Entrypoints', 'entrypoints'),
menuItem('Assets', 'assets'),
menuItem('Publishing', 'publishing'),
menuItem('Migrate to WXT', 'migrate-to-wxt'),
menuItem('Compare', 'compare'),
]),
]),
'/guide/': menuRoot([
menuGroup('Key Concepts', '/guide/key-concepts/', [
menuItem('Manifest', 'manifest'),
menuItem('Auto-imports', 'auto-imports'),
menuItem('Web Extension Polyfill', 'web-extension-polyfill'),
menuItem('Frontend Frameworks', 'frontend-frameworks'),
menuItem('Content Script UI', 'content-script-ui'),
]),
menuGroup('Directory Structure', '/guide/directory-structure/', [
// Folders
menuItem('.output/', 'output'),
menuItem('.wxt/', 'wxt'),
menuItem('assets/', 'assets'),
menuItem('components/', 'components'),
menuItem('composables/', 'composables'),
menuGroup('entrypoints/', '/guide/directory-structure/entrypoints/', [
menuItem('background', 'background.md'),
menuItem('bookmarks', 'bookmarks.md'),
menuItem('*.content.ts', 'content-scripts.md'),
menuItem('*.css', 'css.md'),
menuItem('devtools', 'devtools.md'),
menuItem('history', 'history.md'),
menuItem('newtab', 'newtab.md'),
menuItem('options', 'options.md'),
menuItem('popup', 'popup.md'),
menuItem('sandbox', 'sandbox.md'),
menuItem('sidepanel', 'sidepanel.md'),
menuItem('*.html', 'unlisted-pages.md'),
menuItem('*.ts', 'unlisted-scripts.md'),
]),
menuItem('hooks/', 'hooks'),
menuItem('public/', 'public/', [
menuItem('_locales/', 'public/locales'),
]),
menuItem('utils/', 'utils'),
socialLinks: [{ icon: 'github', link: 'https://github.com/wxt-dev/wxt' }],
// Files
menuItem('.env', 'env'),
menuItem('app.config.ts', 'app-config'),
menuItem('package.json', 'package'),
menuItem('tsconfig.json', 'tsconfig'),
menuItem('web-ext.config.ts', 'web-ext-config'),
menuItem('wxt.config.ts', 'wxt-config'),
]),
menuGroup('Extension APIs', '/guide/extension-apis/', [
menuItem('Storage', 'storage'),
menuItem('Messaging', 'messaging'),
menuItem('I18n', 'i18n'),
menuItem('Scripting', 'scripting'),
menuItem('Others', 'others'),
]),
menuGroup('Go Further', '/guide/go-further/', [
menuItem('Testing', 'testing'),
menuItem('ES Modules', 'es-modules'),
menuItem('Debugging', 'debugging'),
menuItem('Handling Updates', 'handling-updates'),
menuItem('Vite', 'vite'),
menuItem('Custom Events', 'custom-events'),
menuItem('Reusable Modules', 'reusable-modules'),
menuItem('Remote Code', 'remote-code'),
menuItem('Entrypoint Loaders', 'entrypoint-loaders'),
menuItem('How WXT Works', 'how-wxt-works'),
]),
menuGroup('Upgrade Guide', '/guide/upgrade-guide/', [
menuItem('wxt', 'wxt'),
]),
menuGroup('@wxt-dev/i18n', '/guide/i18n/', [
menuItem('Introduction', 'introduction.md'),
menuItem('Installation', 'installation.md'),
menuItem('Messages File Format', 'messages-file-format.md'),
menuItem('Build Integrations', 'build-integrations.md'),
menuItem('Editor Support', 'editor-support.md'),
]),
]),
'/api/': menuRoot([
menuGroup('CLI', '/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'),
]),
menuGroup('API Reference', prepareTypedocSidebar(typedocSidebar)),
]),
},
},
});
+60
View File
@@ -0,0 +1,60 @@
import { resolve, join } from 'node:path';
import consola from 'consola';
import { execaCommand } from 'execa';
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 res = await execaCommand(command + ' --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;
}
-5
View File
@@ -1,5 +0,0 @@
# CLI Reference
> Reference generated from `wxt <command> --help`
{{ DOCS }}
@@ -1,114 +0,0 @@
import { relative, resolve } from 'node:path';
import { readFileSync, writeFileSync } from 'node:fs';
import { format } from 'prettier';
import consola from 'consola';
import { execaCommand } from 'execa';
let hasGenerated = false;
const cliDir = resolve('src/cli/commands');
const cliDirGlob = resolve(cliDir, '**');
const cliTemplatePath = resolve('docs/.vitepress/plugins/cli.tpl.md');
const cliPath = resolve('docs/api/cli.md');
const PREFACE = `<!--
DO NOT EDIT
Generated by \`wxt/docs/.vitepress/plugins/generate-config-docs.ts\`
To make changes to the config reference, update the JSDoc in \`src/core/types/external.ts\`.
-->`;
export function generateCliDocs() {
writeFileSync(cliPath, '');
const generateDocs = async () => {
consola.info(`Generating ${relative(process.cwd(), cliPath)}`);
try {
const res = await execaCommand('pnpm -s wxt --help');
const dev = splitInfo(res.stdout);
const lines: Array<string | string[]> = [
`## \`wxt\``,
'```sh',
dev.rest,
'```',
];
const commands = await Promise.allSettled(
extractCommands(dev.info).map(async (command) => {
const res = await execaCommand(`pnpm -s wxt ${command} --help`);
const { rest: docs } = splitInfo(res.stdout);
return [`## \`wxt ${command}\``, '```sh', docs, '```'];
}),
);
lines.push(
...commands
.filter((res) => res.status === 'fulfilled')
.map(
(res) => (res as unknown as PromiseFulfilledResult<string>).value,
),
);
const text = await format(
PREFACE +
'\n\n' +
readFileSync(cliTemplatePath, 'utf-8').replace(
'{{ DOCS }}',
lines.flat().join('\n'),
),
{ parser: 'markdown' },
);
writeFileSync(cliPath, text);
consola.success(`Generated ${relative(process.cwd(), cliPath)}`);
} catch (err) {
consola.fail(`Failed to generate ${relative(process.cwd(), cliPath)}`);
consola.error(err.message);
}
};
return {
name: 'docs:generate-cli-docs',
async config() {
if (!hasGenerated) {
hasGenerated = true;
await generateDocs();
}
},
configureServer(server: any) {
server.watcher.add(cliDirGlob);
},
async handleHotUpdate(ctx: { file: string }) {
if (ctx.file === cliTemplatePath || ctx.file.includes(cliDir)) {
await generateDocs();
}
},
};
}
function splitInfo(text: string): { info: string; rest: string } {
const infoStart = text.indexOf('For more info,');
const infoEnd = text.indexOf('\n\nOptions:');
if (infoStart === -1 || infoEnd === -1) {
return { info: '', rest: text };
}
const info = text.substring(infoStart, infoEnd).trim();
const rest = text.replace(info, '').trim().replace('\n\n\n\n', '\n\n');
return { info, rest };
}
function extractCommands(info: string): string[] {
const commands: string[] = [];
// Split the info by line and iterate through each line
info.split('\n').forEach((line) => {
// Use regex to capture the command after "$ wxt " and before "--help"
const match = line.match(/\$ wxt (\w+) --help/);
if (match && match[1]) {
commands.push(match[1]);
}
});
return commands;
}
+39
View File
@@ -72,6 +72,45 @@
.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.level-0.collapsible {
padding-bottom: 0.5rem;
}
.VPSidebarItem.level-0.collapsible .items {
/*border-left: 1px solid var(--vp-c-divider);*/
}
.VPSidebarItem.level-1 {
padding-left: 0.75rem;
}
.VPSidebar .group + .group {
border-top: none;
padding-top: 0;
}
.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);
}
+2 -2
View File
@@ -2,7 +2,7 @@ import DefaultTheme from 'vitepress/theme';
import Icon from '../components/Icon.vue';
import EntrypointPatterns from '../components/EntrypointPatterns.vue';
import UsingWxtSection from '../components/UsingWxtSection.vue';
import ExampleList from '../components/ExampleList.vue';
import ExampleSearch from '../components/ExampleSearch.vue';
import './custom.css';
export default {
@@ -11,6 +11,6 @@ export default {
ctx.app.component('Icon', Icon);
ctx.app.component('EntrypointPatterns', EntrypointPatterns);
ctx.app.component('UsingWxtSection', UsingWxtSection);
ctx.app.component('ExampleList', ExampleList);
ctx.app.component('ExampleSearch', ExampleSearch);
},
};
+28
View File
@@ -0,0 +1,28 @@
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,
},
];
}
+88
View File
@@ -0,0 +1,88 @@
import { DefaultTheme } from 'vitepress';
type SidebarItem = DefaultTheme.SidebarItem;
type NavItem = DefaultTheme.NavItem;
export function navItem(text: string, link: string): NavItem {
return { text, link };
}
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[]): SidebarItem;
export function menuGroup(
text: string,
base: string,
items: SidebarItem[],
): SidebarItem;
export function menuGroup(
text: string,
a: string | SidebarItem[],
b?: SidebarItem[],
): SidebarItem {
const collapsed = true;
if (typeof a === 'string') {
return {
text,
base: a,
items: b,
collapsed,
};
}
return {
text,
items: a,
collapsed,
};
}
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;
}
+18
View File
@@ -0,0 +1,18 @@
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>;
+7
View File
@@ -0,0 +1,7 @@
# `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>
+7
View File
@@ -0,0 +1,7 @@
# `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>
+7
View File
@@ -0,0 +1,7 @@
# `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>
+7
View File
@@ -0,0 +1,7 @@
# `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>
+9
View File
@@ -0,0 +1,9 @@
# `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>
+9
View File
@@ -0,0 +1,9 @@
# `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>
+7
View File
@@ -0,0 +1,7 @@
# `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>
+7
View File
@@ -0,0 +1,7 @@
# `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>
+16 -4
View File
@@ -1,7 +1,19 @@
# Examples
---
layout: page
---
Simple walkthroughs to accomplish common tasks or patterns with WXT.
<style>
.examples-container {
padding: 32px;
}
</style>
<ExampleList />
<div class="examples-container">
<div class="vp-doc">
<h1>Examples</h1>
</div>
> Full code available at [`wxt-dev/wxt-examples`](https://github.com/wxt-dev/wxt-examples)
<br />
<ExampleSearch />
</div>
+33
View File
@@ -0,0 +1,33 @@
# Assets
WXT has two directories for storing assets like CSS, images, or fonts.
- [public directory](/guide/directory-structure/public/): Store files that will be copied into the output directory as-is
- [assets directory](/guide/directory-structure/assets): Store files that will be processed by Vite during the build process
To learn more about how to use assets at runtime from either of these directories, visit their guides linked above.
## Public Directory
Place static files like the extension icon or `_locales/` directory here. These files will be copied over to the output directory without being transformed by Vite.
```
<srcDir>
└─ public/
├─ icon-16.png
├─ icon-32.png
├─ icon-48.png
├─ icon-96.png
└─ icon-128.png
```
## Assets Directory
Files in the assets directory will be processed by Vite. They are imported in your source code, and will be transformed or renamed in the output directory.
```
<srcDir>
└─ assets/
├─ tailwind.css
└─ illustration.svg
```
+47
View File
@@ -0,0 +1,47 @@
# Compare
Lets compare the features of WXT vs [Plasmo](https://docs.plasmo.com/framework) (another framework) and [CRXJS](https://crxjs.dev/vite-plugin) (a bundler plugin).
## Overview
| Features | WXT | Plasmo | CRXJS |
| ---------------------------------------------------- | :--------------: | :-------------: | :--------------: |
| Supports all browsers | ✅ | ✅ | 🟡 <sup>10</sup> |
| MV2 Support | ✅ | ✅ | 🟡 <sup>1</sup> |
| MV3 Support | ✅ | ✅ | 🟡 <sup>1</sup> |
| Create Extension ZIPs | ✅ | ✅ | ❌ |
| Create Firefox Sources ZIP | ✅ | ❌ | ❌ |
| First-class TypeScript support | ✅ | ✅ | ✅ |
| Entrypoint discovery | ✅ <sup>2</sup> | ✅ <sup>2</sup> | ❌ |
| Inline entrypoint config | ✅ | ✅ | ❌ <sup>9</sup> |
| Auto-imports | ✅ | ❌ | ❌ |
| Supports all frontend frameworks | ✅ | 🟡 <sup>3</sup> | ✅ |
| Framework specific entrypoints (like `Popup.tsx`) | 🟡 <sup>4</sup> | ✅ <sup>5</sup> | ❌ |
| Automated publishing | ✅ | ✅ | ❌ |
| Remote Code Bundling (Google Analytics) | ✅ | ✅ | ❌ |
| <strong style="opacity: 50%">Dev Mode</strong> | | |
| `.env` Files | ✅ | ✅ | ✅ |
| Opens browser with extension installed | ✅ | ❌ | ❌ |
| HMR for UIs | ✅ | 🟡 <sup>6</sup> | ✅ |
| Reload HTML Files on Change | ✅ | 🟡 <sup>7</sup> | ✅ |
| Reload Content Scripts on Change | ✅ | 🟡 <sup>7</sup> | ✅ |
| Reload Background on Change | 🟡 <sup>7</sup> | 🟡 <sup>7</sup> | 🟡 <sup>7</sup> |
| Respects Content Script `run_at` | ✅ | ✅ | ❌ <sup>8</sup> |
| <strong style="opacity: 50%">Built-in Utils</strong> | | | |
| Storage | ✅ | ✅ | ❌ <sup>11</sup> |
| Messaging | ❌ <sup>11</sup> | ✅ | ❌ <sup>11</sup> |
| Content Script UI | ✅ | ✅ | ❌ <sup>11</sup> |
<small>
<sup>1</sup>: Either MV2 or MV3, not both.
<br/><sup>2</sup>: File based.
<br/><sup>3</sup>: Only React, Vue, and Svelte.
<br/><sup>4</sup>: <code>.html</code> <code>.ts</code> <code>.tsx</code>.
<br/><sup>5</sup>: <code>.html</code> <code>.ts</code> <code>.tsx</code>. <code>.vue</code> <code>.svelte</code>.
<br/><sup>6</sup>: React only.
<br/><sup>7</sup>: Reloads entire extension.
<br/><sup>8</sup>: ESM-style loaders run asynchronously.
<br/><sup>9</sup>: Entrypoint options all configured in `manifest.json`.
<br/><sup>10</sup>: As of <code>v2.0.0-beta.23</code>, but v2 stable hasn't been released yet.
<br/><sup>11</sup>: There is no built-in wrapper around this API. However, you can still access the standard APIs via <code>chrome</code>/<code>browser</code> globals or use any 3rd party NPM package.
</small>
+57
View File
@@ -0,0 +1,57 @@
# Configuration
By default, WXT provides sensible configuration for bundling web extensions with Vite.
## Config File
To configure WXT, create a `wxt.config.ts` file in your project root. It should have the following contents:
```ts
import { defineConfig } from 'wxt';
export default defineConfig({
// My WXT config
});
```
:::info
For more information on configuring WXT via the `wxt.config.ts` file, read the dedicated [`wxt.config.ts` guide](/guide/directory-structure/wxt-config).
:::
## Manifest.json
WXT generates your extension's `manifest.json` based on the project structure. To add additional properties, like permissions, use the [`manifest` property](/api/reference/wxt/interfaces/InlineConfig#manifest).
```ts
import { defineConfig } from 'wxt';
export default defineConfig({
manifest: {
permissions: ['storage'],
},
});
```
:::info
For more information on configuring the manifest, read the dedicated [Manifest guide](/guide/key-concepts/manifest).
:::
## Environment
WXT can read `.env` files, and variables are accessible via `import.meta.env.*`.
:::code-group
```sh [.env]
VITE_OAUTH_CLIENT_ID=abc123
```
```ts [JS]
import.meta.env.VITE_OAUTH_CLIENT_ID;
```
:::
:::info
For more information on using .env files, read the dedicated [`.env` guide](/guide/directory-structure/env).
:::
+60
View File
@@ -0,0 +1,60 @@
# Entrypoints
An "entrypoint" is any HTML, JS, or CSS file that needs to be bundled and included with your extension, which will be loaded and executed by the browser.
## Defining Entrypoints
In WXT, you create an entrypoint by adding a file to the `entrypoints/` directory.
```
<rootDir>
└─ entrypoints/
├─ background.ts
├─ content.ts
├─ injected.ts
└─ popup.html
```
Some entrypoint filesname patterns are reserved by WXT and effect how the manifest is generated.
- `popup` adds an `action` to the manifest
- `background` adds a background script/service worker
- `*.content.ts` adds a content script
- ...
> For a full list of recognized filenames, see the the [Entrypoints Directory guide](/guide/directory-structure/entrypoints/background).
Any other files, whether JS, CSS, or HTML, is considered "unlisted". Unlisted files, like `injected.ts` from above, are just bundled to the output directory and not added to the manifest. You can still access or load them at runtime.
## Entrypoint Options
Most entrypoints allow customizing their options in the file you define them in. This differs from regular web extension development, where all options are placed in the `manifest.json`.
WXT looks for custom options in the entrypoint, and adds them to the manifest when generated.
In HTML files, options are listed as `meta` tags:
```html
<html>
<head>
<!-- Defining the popup's "default_icon" field -->
<meta name="manifest.default_icon" content="{ '16': '/icon/16.png' }" />
</head>
</html>
```
In TS files, options are apart of the file's default export:
```ts
export default defineContentScript({
matches: ['*://*.google.com/*'],
runAt: 'document_start',
main() {
// ...
},
});
```
:::info
All options for each entrypoint type is listed in the [entrypoints directory docs](/guide/directory-structure/entrypoints/background).
:::
@@ -1,6 +1,6 @@
# Installation
Bootstrap a new project, start from scratch, or [migrate an existing project](/guide/migrate-to-wxt).
Bootstrap a new project, start from scratch, or [migrate an existing project](/get-started/migrate-to-wxt).
## Bootstrap Project
@@ -15,7 +15,14 @@ npx wxt@latest init <project-name>
```
```sh [bun]
bunx wxt@latest init <project-name>
# The "wxt init" command currently fails when ran with bunx.
# Use NPX as a workaround, and select "bun" as your package
# manager. To stay up to date with this issue, follow
# https://github.com/wxt-dev/wxt/issues/707
#
# bunx wxt@latest init <project-name>
npx wxt@latest init <project-name>
```
:::
@@ -36,54 +43,27 @@ All templates default to TypeScript. Rename the file extensions to `.js` to use
## From Scratch
Create a new NPM project:
Initialize a project and install `wxt`:
:::code-group
```sh [pnpm]
mkdir project-name
cd project-name
pnpm init
echo 'shamefully-hoist=true' >> .npmrc
```
```sh [npm]
mkdir project-name
cd project-name
npm init
```
```sh [yarn]
mkdir project-name
cd project-name
yarn init
```
```sh [bun]
mkdir project-name
cd project-name
bun init
```
:::
Then install `wxt`:
:::code-group
```sh [pnpm]
pnpm add -D wxt
```
```sh [npm]
npm init
npm i --save-dev wxt
```
```sh [yarn]
yarn init
yarn add --dev wxt
```
```sh [bun]
bun init
bun add --dev wxt
```
@@ -98,7 +78,7 @@ export default defineBackground(() => {
});
```
Finally, add scripts to your `package.json`:
And add scripts to your `package.json`:
```json
{
@@ -114,51 +94,23 @@ Finally, add scripts to your `package.json`:
}
```
## Migrate an Existing Project
Before starting the migration, it is recommended to run `pnpm dlx wxt@latest init` to see what a basic project looks like. Once you have an understanding of how WXT projects are structured, you're ready to convert the project, using the initialized project as a reference.
Migrating a project to WXT comes down to a few steps:
1. Install WXT and remove any old build tools: `pnpm i -D wxt`
1. Refactoring/move your entrypoints to the `entrypoints` directory
1. Moving public assets to the `public` directory
1. Update the dev and build scripts to use WXT
1. Ensure project is compatible with Vite, which is used under the hood to bundle your extension
:::info
Since projects vary greatly in setup, [start a discussion on GitHub](https://github.com/wxt-dev/wxt/discussions/new/choose) if you need help migrating your project to WXT.
:::
## Development
Once you've installed WXT, you can start the development server using the `dev` script.
Once the project is setup, you can start the development server using the `dev` script.
```sh
pnpm dev
```
:::tip 🎉&ensp;Well done!
The dev command will build the extension for development, open the browser, and reload the different parts of the extension when you save changes.
:::
:::details Development Manifest
When running the dev command, WXT will make several changes to your `manifest.json` to improve your development experience:
- If missing, add a background script/service worker to enable fast reloads
- Add several `permissions` and `host_permissions` to enable HMR and fast reloads
- Modify the CSP to allow connections with the dev server
- Remove `content_scripts` and register them at runtime so they can be easily reloaded when you save a file
If you're an experienced web extension developer and think the dev manifest looks wrong, this is why. Run a production build with `wxt build` to see the unmodified `manifest.json`.
:::
## Next Steps
You're ready to build your web extension!
- Learn how to [add entrypoints](./entrypoints) like the popup, options page, or content scripts
- Configure your entrypoints to [use ESM](./esm) at runtime
- Read the rest of the "Get Started" pages for a high-overview of what WXT can do
- Read the [Guide](/guide/key-concepts/manifest) to learn in-depth about each feature WXT supports
- [Configure WXT](./configuration) by creating a `wxt.config.ts` file
- Checkout [example projects](https://github.com/wxt-dev/wxt-examples) to see how to perform common tasks with WXT
- Checkout [example projects](https://github.com/wxt-dev/examples) to see how to perform common tasks with WXT
@@ -7,9 +7,11 @@ head:
# Introduction
## Overview
WXT is a free and open source framework for building web extensions in an conventional, intuitive, and safe way **_for all browsers_**.
WXT is based of [Nuxt](https://nuxt.com), and aims to provide the same great DX with TypeScript, auto-imports, and an opinionated project structure.
WXT is based on [Nuxt](https://nuxt.com), and aims to provide the same great DX with TypeScript, auto-imports, and an opinionated project structure.
![Example build output](../assets/cli-output.png)
@@ -37,3 +39,9 @@ In addition, WXT fully supports Firefox's source code requirements when using a
:::info
See [Publishing](./publishing) for more info around production builds.
:::
## New to Extension Development?
Most of these docs assume you have a basic understanding of how to write a chrome or web extension.
If you've never written a web extension before or need a refresher, follow Google's ["Hello, World!" tutorial](https://developer.chrome.com/docs/extensions/get-started/tutorial/hello-world) to understand the basics.
@@ -4,7 +4,7 @@ outline: deep
# Migrate to WXT
> If you have problems migrating to WXT, feel free to ask for help in GitHub by [starting a discussion](https://github.com/wxt-dev/wxt/discussions/new?category=q-a)!
> If you have problems migrating to WXT, feel free to ask for help in GitHub by [starting a discussion](https://github.com/wxt-dev/wxt/discussions/new?category=q-a) or in [Discord](https://discord.gg/ZFsZqGery9)!
## Overview
@@ -17,16 +17,16 @@ pnpm dlx wxt@latest init example-wxt --template vanilla
In general, you'll need to:
<input type="checkbox" /> Install `wxt`<br />
<input type="checkbox" /> Update/create `package.json` scripts to use `wxt` (don't forget about `postinstall`)<br />
<input type="checkbox" /> Move entrypoints into `entrypoints/` directory<br />
<input type="checkbox" /> Move assets into either the `assets/` or `public/` directories<br />
<input type="checkbox" /> Move manifest.json content into `wxt.config.ts`<br />
<input type="checkbox" /> Convert custom import syntax to be compatible with Vite<br />
<input type="checkbox" /> Add a default export to JS entrypoints<br />
<input type="checkbox" /> Use the `browser` global instead of `chrome`<br />
<input type="checkbox" /> Compare final `manifest.json` files, making sure permissions and host permissions are unchanged<br />
<input type="checkbox" /> Extension output by `wxt build` works the same way as before the migration<br />
&ensp;<input type="checkbox" /> Install `wxt`<br />
&ensp;<input type="checkbox" /> Update/create `package.json` scripts to use `wxt` (don't forget about `postinstall`)<br />
&ensp;<input type="checkbox" /> Move entrypoints into `entrypoints/` directory<br />
&ensp;<input type="checkbox" /> Move assets into either the `assets/` or `public/` directories<br />
&ensp;<input type="checkbox" /> Move manifest.json content into `wxt.config.ts`<br />
&ensp;<input type="checkbox" /> Convert custom import syntax to be compatible with Vite<br />
&ensp;<input type="checkbox" /> Add a default export to JS entrypoints<br />
&ensp;<input type="checkbox" /> Use the `browser` global instead of `chrome`<br />
&ensp;<input type="checkbox" /> Compare final `manifest.json` files, making sure permissions and host permissions are unchanged. Use [Google's update testing tool](https://github.com/GoogleChromeLabs/extension-update-testing-tool) if your extension is already live on the Chrome Web Store<br />
&ensp;<input type="checkbox" /> Extension output by `wxt build` works the same way as before the migration<br />
Every project is different, so there's no one-solution-fits-all to migrating your project. Just make sure `wxt dev` runs, `wxt build` results in a working extension, and the list of permissions in the `manifest.json` hasn't changed. If all that looks good, you've finished migrating your extension!
@@ -55,3 +55,11 @@ Since you're already using Vite, it's a simple refactor.
5. Convert Plasmo's custom import resolutions to Vite's
6. If importing remote code via a URL, add a `url:` prefix so it works with WXT
7. Compare your output `manifest.json` files from before the migration to after the migration. They should have the same content. If not, tweak your entrypoints and config to get as close as possible.
<!--
## Migrate an Existing Project
:::info
Since projects vary greatly in setup, [start a discussion on GitHub](https://github.com/wxt-dev/wxt/discussions/new/choose) if you need help migrating your project to WXT.
:::
-->
@@ -20,8 +20,8 @@ For specific details about each store, see the stores sections below.
WXT provides two commands to help automate the release process:
- `wxt submit init`: Setup all the required secrets and options for the `wxt submit` command
- `wxt submit`: Submit new versions of your extension for review (and publish them automatically once approved)
- `wxt submit init`: Help setup all the required secrets and options for the `wxt submit` command
To get started, run `wxt submit init` and follow the prompts. Once finished, you should have a `.env.submit` file! WXT will use this file to submit your updates.
@@ -78,9 +78,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v3
with:
version: 'latest'
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
@@ -178,16 +176,16 @@ bun zip:firefox
:::
Ensure that you have a `README.md` or `SOURCE_CODE_REVIEW.md` file with the above commands so that the Firefox team knows how to build your extension.
Make sure the build output is the exact same when running `wxt build -b firefox` in your main project and inside the zipped sources.
:::warning
If you use a `.env` files, they can effect the chunk hashes in the output directory. Either delete the .env file before running `wxt zip -b firefox`, or include it in your sources zip with the [`zip.includeSources`](/api/wxt/interfaces/InlineConfig#includesources) option. Be careful to not include any secrets in your `.env` files.
If you use a `.env` files, they can effect the chunk hashes in the output directory. Either delete the .env file before running `wxt zip -b firefox`, or include it in your sources zip with the [`zip.includeSources`](/api/reference/wxt/interfaces/InlineConfig#includesources) option. Be careful to not include any secrets in your `.env` files.
See Issue [#377](https://github.com/wxt-dev/wxt/issues/377) for more details.
:::
Ensure that you have a `README.md` or `SOURCE_CODE_REVIEW.md` file with the above commands so that the Firefox team knows how to build your extension.
#### Private Packages
If you use private packages and you don't want to provide your auth token to the Firefox team during the review process, you can use `zip.downloadPackages` to download any private packages and include them in the zip.
-85
View File
@@ -1,85 +0,0 @@
# Assets
WXT has two directories for storing assets like CSS, images, or fonts.
- `<srcDir>/public`: Store files that will be copied into the output directory as-is
- `<srcDir>/assets`: Store files that will be processed by Vite during the build process
## `/public` Directory
Place static files like the extension icon or `_locales/` directory here. These files will be copied over to the output directory without being transformed by Vite.
```
<srcDir>
└─ public/
├─ icon-16.png
├─ icon-32.png
├─ icon-48.png
├─ icon-96.png
└─ icon-128.png
```
### Example
You can reference these files by using absolute paths in HTML files or `browser.runtime.getURL` in content scripts.
:::code-group
```html [popup.html]
<img src="/icon-128.png" />
```
```ts [content.ts]
defineContentScript({
main() {
const image = document.createElement('img');
image.src = browser.runtime.getURL('/icon-128.png');
document.body.append(image);
},
});
```
:::
## `/assets` Directory
Files in the assets directory will be processed by Vite. They are imported in your source code, and will be transformed or renamed in the output directory.
```
<srcDir>
└─ assets/
├─ style.css
└─ illustration.svg
```
### Example
:::code-group
```html [popup.html]
<html>
<head>
<link rel="stylesheet" href="~/assets/style.css" />
<!-- ... -->
</head>
<body>
<img src="~/illustration.svg" />
<!-- ... -->
</body>
</html>
```
```ts [content.ts]
import '~/assets/style.css';
import illustration from '~/assets/style.svg';
defineContentScript({
main() {
const image = document.createElement('img');
image.src = illustration;
document.body.append(image);
},
});
```
:::
-80
View File
@@ -1,80 +0,0 @@
# Auto-imports
WXT uses the same tool as Nuxt for auto-imports, [`unimport`](https://github.com/unjs/unimport).
:::info Testing
To setup your test environment for auto-imports, see [Testing](/guide/testing).
:::
## WXT Auto-imports
Some WXT APIs can be used without importing them:
- [`browser`](/api/wxt/browser/variables/browser) from `wxt/browser`, a small wrapper around `webextension-polyfill`
- [`defineContentScript`](/api/wxt/sandbox/functions/defineContentScript) from `wxt/sandbox`
- [`defineBackground`](/api/wxt/sandbox/functions/defineBackground) from `wxt/sandbox`
- [`defineUnlistedScript`](/api/wxt/sandbox/functions/defineUnlistedScript) from `wxt/sandbox`
- [`createIntegratedUi`](/api/wxt/client/functions/createIntegratedUi) from `wxt/client`
- [`createShadowRootUi`](/api/wxt/client/functions/createShadowRootUi) from `wxt/client`
- [`createIframeUi`](/api/wxt/client/functions/createIframeUi) from `wxt/client`
- [`fakeBrowser`](/api/wxt/testing/variables/fakeBrowser) from `wxt/testing`
And more!
## Project Auto-imports
In addition WXT APIs, default and named exports from inside the following directories can be used without listing them in imports.
- `<srcDir>/components/*`
- `<srcDir>/composables/*`
- `<srcDir>/hooks/*`
- `<srcDir>/utils/*`
To add auto-imports from subdirectories, like `utils/api/some-file.ts`, re-export them from the base directory:
```ts
// utils/index.ts
export * from './api/some-file.ts';
```
Alternatively, you could add the directory to the list of auto-import directories in your config file.
## TypeScript
For TypeScript to work, you need to run the `wxt prepare` command. This will ensure types are generated for auto-imports.
This should be added to your `postinstall` script:
```json
// package.json
{
"scripts": {
"postinstall": "wxt prepare" // [!code ++]
}
}
```
## Customization
You can override the default auto-import behavior in your `wxt.config.ts` file.
See [`unimport`'s documentation](https://github.com/unjs/unimport#configurations) for a complete list of options.
```ts
import { defineConfig } from 'wxt';
export default defineConfig({
imports: {
// Add auto-imports for vue functions like createApp, ref, computed, watch, toRaw, etc...
presets: ['vue'],
},
});
```
To disable auto-imports, set `imports: false`
```ts
export default defineConfig({
imports: false,
});
```
-50
View File
@@ -1,50 +0,0 @@
# Compare
Lets compare the features of WXT vs [Plasmo](https://docs.plasmo.com/framework) (another web extension framework) and [CRXJS](https://crxjs.dev/vite-plugin) (the most popular bundler plugin).
## Overview
| Features | WXT | Plasmo | CRXJS |
| ---------------------------------------------------- | :-------------------------: | :--------------------------------------: | :---------------------------------------------------------------------: |
| Supports all browsers | ✅ | ✅ | ❌ See [#56](https://github.com/crxjs/chrome-extension-tools/issues/56) |
| MV2 Support | ✅ | ✅ | 🟡 Either MV2 or MV3 |
| MV3 Support | ✅ | ✅ | 🟡 Either MV2 or MV3 |
| Create Extension ZIPs | ✅ | ✅ | ❌ |
| Create Firefox Sources ZIP | ✅ | ❌ | ❌ |
| First-class TypeScript support | ✅ | ✅ | ✅ |
| Entrypoint discovery | File based | File based | ❌ |
| Inline entrypoint config | ✅ | ✅ | Manifest based |
| Auto-imports | ✅ | ❌ | ❌ |
| Supports all frontend frameworks | ✅ | 🟡 Only React, Vue, and Svelte | ✅ |
| Framework specific entrypoints (like `Popup.tsx`) | 🟡 `.html` `.ts` `.tsx` | ✅ `.html` `.ts` `.tsx` `.vue` `.svelte` | ❌ |
| Automated publishing | ✅ | ✅ | ❌ |
| Remote Code Bundling (Google Analytics) | ✅ | ✅ | ❌ |
| <strong style="opacity: 50%">Dev Mode</strong> | | |
| `.env` Files | ✅ | ✅ | ✅ |
| Opens browser and install extension | ✅ | ❌ | ❌ |
| HMR for UIs | ✅ | 🟡 React only | ✅ |
| Reload HTML Files on Change | ✅ | 🟡 Reloads entire extension | ✅ |
| Reload Content Scripts on Change | ✅ | 🟡 Reloads entire extension | ✅ |
| Reload Background on Change | 🟡 Reloads entire extension | 🟡 Reloads entire extension | 🟡 Reloads entire extension |
| Respects Content Script `run_at` | ✅ | ✅ | ❌ ESM-style loaders run asynchronously |
| <strong style="opacity: 50%">Built-in Utils</strong> | | | |
| Storage | ✅ | ✅ | ❌ |
| Messaging | ❌ | ✅ | ❌ |
| Content Script UI | ✅ | ✅ | ❌ |
## Why use WXT?
WXT's main goal is improving the development experience (DX) of creating web extensions, while not sacrificing support. There are two things WXT does differently:
1. Automatically opens a browser with the extension installed when starting development
2. Reload each part of the extension individually rather than reloading the entire extension
Opening a browser automatically makes it super easy to start and stop development without having to manually load the extension in your browser.
Reloading each part of the extension individually improves your iteration speed while developing UIs. This is because reloading the entire extension on every change will close the popup and any tabs open to an extension page, like options. If you save a file associated with a UI and a content script while working on the UI, it will randomly close because it needed to reload the extension when the content script changed. This interrupts your development flow and is really annoying.
WXT solves this problem by reloading HTML pages and content scripts individually (when possible) to keep your UIs open while you develop them. This is a MV3 feature, so if you're developing a MV2 extension, you'll get the same dev experience as Plasmo.
:::info
Unfortunately, there isn't an API for reloading the background page/service worker individually, so if you change a file used by the background, the entire extension will reload. See [Issue #53](https://github.com/wxt-dev/wxt/issues/53) for more details.
:::
-99
View File
@@ -1,99 +0,0 @@
# Configuration
WXT's behavior can be configured via the `wxt.config.ts` file. In this file, you can add Vite plugins, change the directory structure of your project, and set fields on your `manifest.json`.
## Config File
To configure WXT, create a `wxt.config.ts` file in your project root. It should have the following contents:
```ts
import { defineConfig } from 'wxt';
export default defineConfig({
// My WXT config
});
```
:::info
See the [Config reference](/api/wxt/interfaces/InlineConfig) for a full list of options.
:::
## Directory Config
WXT allows you to edit several directories to your liking:
- `root` (default: `process.cwd()`) - Root of the WXT project
- `srcDir` (default: `<rootDir>`) - Location of all your source code
- `entrypointsDir` (default: `<srcDir>/entrypoints`) - Folder containing all the entrypoints.
- `publicDir` (default: `<srcDir>/public`) - Folder containing [public assets](/guide/assets)
### Example
You want a `src/` directory to contain all your source code, and you want to rename `entrypoints/` &rarr; `entries/`:
```
<rootDir>
├─ src/
│ └─ entries/
│ ├─ background.ts
│ └─ ...
└─ wxt.config.ts
```
Your config would look like this:
```ts
import { defineConfig } from 'wxt';
export default defineConfig({
srcDir: 'src',
entrypointsDir: 'entries',
});
```
## Frontend Frameworks
Adding a framework like Vue, React, or Svelte is easy!
In the `wxt.config.ts` file, install and add the framework's Vite plugin to the config.
:::code-group
```ts [Vue]
import { defineConfig } from 'wxt';
import vue from '@vitejs/plugin-vue';
export default defineConfig({
vite: () => ({
plugins: [vue()],
}),
});
```
```ts [React]
import { defineConfig } from 'wxt';
import react from '@vitejs/plugin-react';
export default defineConfig({
vite: () => ({
plugins: [react()],
}),
});
```
```ts [Svelte]
import { defineConfig } from 'wxt';
import { svelte } from '@sveltejs/vite-plugin-svelte';
export default defineConfig({
vite: () => ({
plugins: [svelte()],
}),
});
```
:::
:::info
Internally, WXT runs `vite build` multiple times during a single build. It can't share the same instance of some plugins between each build, so a function is used to return completely new instances of each plugin for each build.
:::
@@ -0,0 +1,61 @@
# `<srcDir>/app.config.ts`
:::warning Nuxt Users
If you're familiar with Nuxt, this file is meant to be a direct equivalent to Nuxt's `app.config.ts` file.
However, some of Nuxt's features, like overriding the app config based on a `.env` file or automatically generating the config's types, are not implemented. They are planned, just not implemented yet. Feel free to open a PR!
:::
## Overview
Define runtime configuration in a single place.
```ts
// <srcDir>/app.config.ts
import { defineAppConfig } from 'wxt/sandbox';
// Define types for your config
declare module 'wxt/sandbox' {
export interface WxtAppConfig {
theme?: 'light' | 'dark';
}
}
export default defineAppConfig({
theme: 'dark',
});
```
Then access the config in your extension by calling `useAppConfig`:
```ts
console.log(useAppConfig()); // { theme: "dark" }
```
## Environment Variables
If you have a `.env` file, you can access any variables defined in it here. You can convert them to better types (like booleans), add types for them, or leave them as is.
```txt
# .env
VITE_BUG_REPORTING_DISABLED=true
VITE_API_KEY=...
```
```ts
// <srcDir>/app.config.ts
declare module 'wxt/sandbox' {
export interface WxtAppConfig {
bugReportingDisabled: boolean;
apiKey?: string;
}
}
export default defineAppConfig({
bugReportingDisabled: import.meta.env.VITE_BUG_REPORTING_DISABLED === 'true',
apiKey: import.meta.env.VITE_API_KEY,
});
```
> You don't have to do this, you can use `import.meta.env.VITE_*` anywhere in your runtime code, but putting them here consolidates them to one place and defines what variables are expected.
+42
View File
@@ -0,0 +1,42 @@
# `<srcDir>/assets`
Files in the assets directory will be processed by Vite. They are imported in your source code, and will be transformed or renamed in the output directory.
```
<srcDir>
└─ assets/
├─ style.css
└─ illustration.svg
```
### Example
:::code-group
```html [popup.html]
<html>
<head>
<link rel="stylesheet" href="~/assets/style.css" />
<!-- ... -->
</head>
<body>
<img src="~/assets/illustration.svg" />
<!-- ... -->
</body>
</html>
```
```ts [content.ts]
import '~/assets/style.css';
import illustration from '~/assets/style.svg';
defineContentScript({
main() {
const image = document.createElement('img');
image.src = illustration;
document.body.append(image);
},
});
```
:::
@@ -0,0 +1,5 @@
# `<srcDir>/components`
:::warning 🚧 Under construction
These docs will be coming soon!
:::
@@ -0,0 +1,5 @@
# `<srcDir>/composables`
:::warning 🚧 Under construction
These docs will be coming soon!
:::
@@ -40,7 +40,7 @@ export default defineContentScript({
// Configure how/when content script will be registered
registration: undefined | "manifest" | "runtime",
main(ctx) {
main(ctx: ContentScriptContext) {
// Executed when content script is loaded
},
});
@@ -50,52 +50,6 @@ export default defineContentScript({
When defining multiple content scripts, content script entrypoints that have the same set of options will be merged into a single `content_script` item in the manifest.
## Context
Old content scripts are not automatically stopped when an extension updates and reloads. Often, this leads to "Invalidated context" errors in production when a content script from an old version of your extension tries to use a web extension API (ie, the `browser` or `chrome` globals).
WXT provides a utility for handling this process: `ContentScriptContext`. An instance of this class is provided to you automatically inside the `main` function of your content script.
When your extension updates or is uninstalled, the context will become invalidated, and will trigger any `ctx.onInvalidated` listeners you add:
```ts
export default defineContentScript({
// ...
main(ctx: ContentScriptContext) {
// Add custom listeners for stopping work
ctx.onInvalidated(() => {
// ...
});
// Timeout utilities that are automatically cleared when invalidated
ctx.setTimeout(() => {
// ...
}, 5e3);
ctx.setInterval(() => {
// ...
}, 60e3);
// Or add event listeners that get removed when invalidated
ctx.addEventListener(document, 'visibilitychange', (event) => {
// ...
});
// You can also stop fetch requests
fetch('...url', { signal: ctx.signal });
},
});
```
The class extends [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) and provides other utilities for stopping a content script's logic once it becomes invalidated.
:::warning
When working with content scripts, **you should always use the `ctx` object to stop any async or future work.**
This prevents old content scripts from interfering with new content scripts, and prevents error messages from the console in production.
If you're using a framework like React, Vue, Svelte, etc., make sure you're unmounting your UI properly in the `onRemove` option of [`createShadowRootUi`](https://wxt.dev/guide/content-script-ui.html#shadow-root).
:::
## CSS
To include CSS with your content script, import the CSS file at the top of your entrypoint.
@@ -150,4 +104,4 @@ export default defineContentScript({
});
```
See [Content Script UI](/guide/content-script-ui) for more info on creating UIs and including CSS in content scripts.
See [Content Script UI](/guide/key-concepts/content-script-ui) for more info on creating UIs and including CSS in content scripts.
@@ -2,10 +2,10 @@
WXT can build CSS entrypoints individually. CSS entrypoints are always unlisted.
See [Content Script CSS](/entrypoints/content-scripts#css) documentation for the recommended approach to include CSS with a content script.
See [Content Script CSS](/guide/directory-structure/entrypoints/content-scripts#css) documentation for the recommended approach to include CSS with a content script.
:::info
If the recommended approach doesn't work for your use case, you can use any of the filename patterns below to build the styles separate from the JS and use the [`transformManifest` hook](/api/wxt/interfaces/InlineConfig#transformmanifest) to manually add your CSS file to the manifest.
If the recommended approach doesn't work for your use case, you can use any of the filename patterns below to build the styles separate from the JS and use the [`transformManifest` hook](/api/reference/wxt/interfaces/InlineConfig#transformmanifest) to manually add your CSS file to the manifest.
:::
## Filenames
@@ -37,4 +37,4 @@ Chrome extensions allow you to add panels and side panes to the devtools window.
See the WXT's examples for a full walkthrough of extending the devtools window:
<ExampleList tag="devtools" />
- [Devtools Setup](https://github.com/wxt-dev/wxt-examples/tree/main/examples/vanilla-devtools#readme)
@@ -12,8 +12,8 @@ Firefox does not support sandboxed pages.
:patterns="[
['sandbox.html', 'sandbox.html'],
['sandbox/index.html', 'sandbox.html'],
['<name>.sandbox.html', '<name>.html` '],
['<name>.sandbox/index.html', '<name>.html` '],
['<name>.sandbox.html', '<name>.html'],
['<name>.sandbox/index.html', '<name>.html'],
]"
/>
@@ -24,7 +24,7 @@ If you plan on using the page in an iframe, don't forget to add the page to [`we
Pages are accessible at `'/<name>.html'`:
```ts
const url = browser.runtime.getURL('/<name>.html');
const url = browser.runtime.getURL('/<name>.html', '<html></html>');
console.log(url); // "chrome-extension://<id>/<name>.html"
```
+5
View File
@@ -0,0 +1,5 @@
# `<root>/.env`
:::warning 🚧 Under construction
These docs will be coming soon!
:::
+5
View File
@@ -0,0 +1,5 @@
# `<srcDir>/hooks`
:::warning 🚧 Under construction
These docs will be coming soon!
:::
+5
View File
@@ -0,0 +1,5 @@
# `<root>/.output`
:::warning 🚧 Under construction
These docs will be coming soon!
:::
@@ -0,0 +1,5 @@
# `<root>/package.json`
:::warning 🚧 Under construction
These docs will be coming soon!
:::
@@ -0,0 +1,35 @@
# `public/`
Place static files like the extension icon or `_locales/` directory here. These files will be copied over to the output directory without being transformed by Vite.
```
<srcDir>
└─ public/
├─ icon-16.png
├─ icon-32.png
├─ icon-48.png
├─ icon-96.png
└─ icon-128.png
```
### Example
You can reference these files by using absolute paths in HTML files or `browser.runtime.getURL` in content scripts.
:::code-group
```html [popup.html]
<img src="/icon-128.png" />
```
```ts [content.ts]
defineContentScript({
main() {
const image = document.createElement('img');
image.src = browser.runtime.getURL('/icon-128.png');
document.body.append(image);
},
});
```
:::
@@ -0,0 +1,5 @@
# `public/_locales/`
:::warning 🚧 Under construction
These docs will be coming soon!
:::
@@ -0,0 +1,5 @@
# `<root>/tsconfig.json`
:::warning 🚧 Under construction
These docs will be coming soon!
:::
+5
View File
@@ -0,0 +1,5 @@
# `<srcDir>/utils`
:::warning 🚧 Under construction
These docs will be coming soon!
:::
@@ -0,0 +1,65 @@
# `web-ext.config.ts`
This file lets you configure the browser startup when running `wxt dev`.
```ts
import { defineRunnerConfig } from 'wxt';
export default defineRunnerConfig({
startUrls: ['https://google.com', 'https://youtube.com'],
});
```
There are three places you can customize the runner:
- `<root>/wxt.config.ts` - Use the `runner` option. Changes here will be committed and shared with everyone developing the project.
- `<root>/web-ext.config.ts` - A gitignored file for you to customize the startup behavior to your liking without effecting others
- `$HOME/web-ext.config.ts` - Stores system-wide config effecting all projects running on your machine.
See below examples on how to accomplish common configuration:
[[toc]]
## Configuring Binaries
`web-ext`'s browser discovery is very limited. By default, it only guesses at where Chrome and Firefox are installed. If you've customized your install locations, you may need to tell `web-ext` where the binaries/executables are located using the [`binaries` option](/api/reference/wxt/interfaces/ExtensionRunnerConfig#binaries). For other Chromium based browsers, like Edge or Opera, you'll need to explicitly list them in the `binaries` option as well, otherwise they will open in Chrome by default.
```ts
import { defineRunnerConfig } from 'wxt';
export default defineRunnerConfig({
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"
},
});
```
## Disable Opening Browser
Disabling the browser can be useful if it's difficult to develop your extension with fresh profiles. Maybe you need to sign into a website to see a content script run, and a fresh profile isn't helpful because it doesn't save your login info.
To disable opening the extension automatically in a new window, just disable the runner:
```ts
export default defineRunnerConfig({
disabled: true,
});
```
## Profile Customization
Another option, instead of disabling the runner, to stay logged into websites is to use a custom profile.
`web-ext` comes with some built-in ways of using an existing profile, but it's not really using the same profile. It copies the profile to a temp directory, and uses that.
Instead, I've found it's better to pass Chrome's `--user-data-dir` argument. This let's you use a fresh profile initially, and customize it to your liking. You can install devtool extensions, set custom flags, and log into websites. Next time you run the extension in dev mode, all that will be remembered!
```ts
export default defineRunnerConfig({
chromiumArgs: ['--user-data-dir=./chrome-data'],
});
```
> This only works for Chrome. You'll have to use `firefoxProfile` option instead, which has the same limitations mentioned above, where you won't be signed into websites automatically.
@@ -0,0 +1,5 @@
# `<root>/wxt.config.ts`
:::warning 🚧 Under construction
These docs will be coming soon!
:::
+5
View File
@@ -0,0 +1,5 @@
# `.wxt/`
:::warning 🚧 Under construction
These docs will be coming soon!
:::
-141
View File
@@ -1,141 +0,0 @@
# Defining Entrypoints
An "entrypoint" is any HTML, JS, or CSS file that needs to be bundled and included with the extension.
Entrypoints may or may not be listed in the extension's `manifest.json`.
## `/entrypoints` Directory
In WXT, entrypoints are defined by adding a file to the `entrypoints/` directory.
For example, a project that looks like this:
```
<rootDir>
└─ entrypoints/
├─ background.ts
├─ content.ts
├─ injected.ts
└─ popup.html
```
would result in the following `manifest.json`:
```json
{
// ...
"manifest_version": 3,
"action": {
// ...
"default_popup": "popup.html"
},
"background": {
// ...
"service_worker": "background.js"
},
"content_scripts": [
{
// ...
"js": ["content-scripts/content.js"]
}
]
}
```
If a file uses a special name recognized by WXT, it will be added to the manifest. In this case:
- `popup.html` &rarr; `action.default_popup`
- `content.ts` &rarr; `content_scripts.0.js.0`
- `background.ts` &rarr; `background.service_worker`
But not all entrypoints are added to the `manifest.json`. If the filename is not recognized by WXT, they are still built and included in the extension, but they are considered "unlisted" and are not apart of the manifest.
In this case, `injected.ts` gets output to `<outdir>/injected.js` and is accessible via `browser.runtime.getURL("/injected.js")`.
:::info
See [`/entrypoints` folder](/entrypoints/background) documentation for a full list of recognized entrypoint filenames.
:::
## Entrypoint Options
Some entrypoints, like content scripts, actions, or the background, can receive additional options.
In HTML files, options are listed as `meta` tags:
```html
<html>
<head>
<!-- Defining the popup's "default_icon" field -->
<meta name="manifest.default_icon" content="{ '16': '/icon/16.png' }" />
</head>
</html>
```
In TS files, options are apart of the file's default export:
```ts
export default defineContentScript({
matches: ['*://*.google.com/*'],
runAt: 'document_start',
main() {
// ...
},
});
```
:::info
For a full list of entrypoints and each of their options, see the [`/entrypoints` folder](/entrypoints/background) documentation.
:::
### Side Effects
You cannot use imported variables outside the `main` function is JS entrypoints. This includes options, as shown below:
```ts
// entrypoints/content.ts
import { GOOGLE_MATCHES } from '~/utils/match-patterns';
export default defineContentScript({
matches: GOOGLE_MATCHES,
main() {
// ...
},
});
```
```
$ wxt build
wxt build
WXT 0.14.1
Building chrome-mv3 for production with Vite 5.0.5
✖ Command failed after 360 ms
[8:55:54 AM] ERROR entrypoints/content.ts: Cannot use imported variable "GOOGLE_MATCHES" before main function. See https://wxt.dev/guide/entrypoints.html#side-effects
```
This throws an error because WXT needs to import each entrypoint during the build process to extract its definition (containing the `match`, `runAt`, `include`/`exclude`, etc.) to render the `manifest.json` correctly. Before loading an entrypoint, a transformation is applied to remove all imports. This prevents imported modules (local or NPM) with side-effects from running during the build process, potentially throwing an error.
:::details Why?
When importing your entrypoint to get its definition, the file is imported in a **_node environment_**, and doesn't have access to the `window`, `chrome`, or `browser` globals a web extension usually has access to. If WXT doesn't remove all the imports from the file, the imported modules could try and access one of these variables, throwing an error.
:::
:::warning
See [`wxt-dev/wxt#336`](https://github.com/wxt-dev/wxt/issues/336) to track the status of this bug.
:::
Usually, this error occurs when you try to extract options into a shared file or try to run code outside the `main` function. To fix the example from above, use literal values when defining an entrypoint instead of importing them:
```ts
import { GOOGLE_MATCHES } from '~/utils/match-patterns'; // [!code --]
export default defineContentScript({
matches: GOOGLE_MATCHES, // [!code --]
matches: ['*//*.google.com/*'], // [!code ++]
main() {
// ...
},
});
```
-94
View File
@@ -1,94 +0,0 @@
# Extension APIs
WXT is built on top of [`webextension-polyfill`](https://www.npmjs.com/package/webextension-polyfill), which uses the standard `browser` global.
If you're used to Chrome's `chrome` global, its a simple switch:
1. Replace `chrome` with `browser`
2. [Replace callbacks with async/await](https://developer.chrome.com/docs/extensions/mv3/promises/)
And that's it! Your extension now supports Chrome, Firefox, Safari, Edge, and other Chromium browsers.
## Basic Usage
The `browser` variable is available globally via [auto-imports](/guide/auto-imports), or it can be imported manually.
```ts
import { browser } from 'wxt/browser';
```
The `wxt/browser` module exports a customized version of `webextension-polyfill`'s browser with improved typing.
### Example
Let's save the date the extension was installed. Just like `chrome`, some APIs require the permission is added to your manifest before the API is defined. Here, we need to add the `storage` permission to your manifest.
```ts
// wxt.config.ts
import { defineConfig } from 'wxt';
export default defineConfig({
manifest: {
permissions: ['storage'],
},
});
```
Then we can use `browser.storage` to save the install date to local storage.
```ts
// background.ts
export default defineBackground(() => {
browser.runtime.onInstall.addEventListener(({ reason }) => {
if (reason === 'install') {
browser.storage.local.setItem({ installDate: Date.now() });
}
});
});
```
## Messaging
Follow [Chrome's message passing guide](https://developer.chrome.com/docs/extensions/mv3/messaging/) to understand how message passing works in web extensions. In Google's examples, just replace `chrome` with `browser`, and it will work in WXT.
Here's a basic request/response example:
```ts
// popup/main.ts
const res = await browser.runtime.sendMessage('ping');
console.log(res); // "pong"
```
```ts
// background.ts
export default defineBackground(() => {
browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
console.log(message); // "ping"
// Wait 1 second and respond with "pong"
setTimeout(() => sendResponse('pong'), 1000);
return true;
});
});
```
There are a number of message passing libraries you can use to improve the message passing experience.
Here are some that are compatible with WXT (because they are based off `webextension-polyfill` as well):
- [`@webext-core/messaging`](https://webext-core.aklinker1.io/guide/messaging/) - "A light-weight, type-safe wrapper around the `browser.runtime` messaging APIs"
- [`@webext-core/proxy-service`](https://webext-core.aklinker1.io/guide/proxy-service/) - "Create TRPC-like services that can be called from anywhere but run in the background"
- [`webext-bridge`](https://github.com/zikaari/webext-bridge) - "Messaging in Web Extensions made super easy. Out of the box."
## Browser Differences
Some APIs are only available on certain browsers or manifest versions. You will have to check if an API exists at runtime if it is not in the `browser` standard.
```ts
if ('session' in browser.storage) {
// Do something with the non-standard session storage API
}
```
> If you're using TypeScript, knowing what is non-standard is easy! APIs that are not typed are non-standard.
+56
View File
@@ -0,0 +1,56 @@
# Internationalization
This guide is for using the vanilla, `browser.i18n` APIs. There are two other alternatives:
1. [`@wxt-dev/i18n`](/guide/i18n/installation) - a wrapper around `browser.i18n` APIs with additional features, a simplified localization file format, and editor support
2. Third party packages - You can use any i18n package on NPM, most of which are more feature rich than `browser.i18n` and `@wxt-dev/i18n`
:::info
Currently, using the `browser.i18n` APIs are the recommended approach. WXT has some built-in support for them and they work well enough. `@wxt-dev/i18n` was recently released, and it will become the recommended approach after some of the bugs have been worked out. Head over to [it's docs](/guide/i18n/introduction.md) to learn more.
:::
## Setup
First familiarize yourself with [Chrome's docs](https://developer.chrome.com/docs/extensions/reference/api/i18n). The only difference when using these APIs with WXT is where you put the localization files - in the [`public` directory](/guide/directory-structure/public/).
```
<srcDir>/
└─ public/
└─ _locales/
├─ en/
│ └─ messages.json
├─ de/
│ └─ messages.json
└─ ko/
└─ messages.json
```
Next, to set a `default_locale` on your manifest, add it to your `wxt.config.ts` file:
```ts
// wxt.config.ts
export default defineConfig({
manifest: {
default_locale: 'en',
name: '__MSG_extName__',
description: '__MSG_extDescription__',
},
});
```
> You can localize the `name` and `description` of your extension from the `manifest` config as well.
Finally, to get a translation, call `browser.i18n.getMessage`:
```ts
browser.i18n.getMessage('extName');
browser.i18n.getMessage('extDescription');
browser.i18n.getMessage(/* etc */);
```
## Examples
See the official localization examples for more details:
- [I18n](https://github.com/wxt-dev/wxt-examples/tree/main/examples/vanilla-i18n#readme)
- [Vue I18n](https://github.com/wxt-dev/wxt-examples/tree/main/examples/vue-i18n#readme)
+36
View File
@@ -0,0 +1,36 @@
# Messaging
## Overview
Follow [Chrome's message passing guide](https://developer.chrome.com/docs/extensions/mv3/messaging/) to understand how message passing works in web extensions. In Google's examples, just replace `chrome` with `browser`, and it will work in WXT.
Here's a basic request/response example:
```ts
// popup/main.ts
const res = await browser.runtime.sendMessage('ping');
console.log(res); // "pong"
```
```ts
// background.ts
export default defineBackground(() => {
browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
console.log(message); // "ping"
// Wait 1 second and respond with "pong"
setTimeout(() => sendResponse('pong'), 1000);
return true;
});
});
```
## Third Party Libraries
There are a number of message passing libraries you can use to improve the message passing experience.
- [`@webext-core/messaging`](https://webext-core.aklinker1.io/guide/messaging/) - "A light-weight, type-safe wrapper around the `browser.runtime` messaging APIs"
- [`@webext-core/proxy-service`](https://webext-core.aklinker1.io/guide/proxy-service/) - "Create RPC-like services that can be called from anywhere but run in the background"
- [`webext-bridge`](https://github.com/zikaari/webext-bridge) - "Messaging in Web Extensions made super easy. Out of the box."
- [`trpc-chrome`](https://www.npmjs.com/package/trpc-chrome) - "tRPC adapter for Web Extensions 🧩"
+5
View File
@@ -0,0 +1,5 @@
# All Other APIs
:::warning 🚧 Under construction
These docs will be coming soon!
:::
+26
View File
@@ -0,0 +1,26 @@
# `browser.scripting`
[Chrome Docs](https://developer.chrome.com/docs/extensions/reference/api/scripting) &bull; [Firefox Docs](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/scripting)
Refer to the browser docs above for basics on how the API works.
## Execute Script Return Values
When using `browser.scripting.executeScript`, you can execute content scripts or unlisted scripts. To return a value, just return a value from the script's main function.
```ts
// entrypoints/background.ts
const res = await browser.scripting.executeScript({
target: { tabId },
files: ['injected.js'],
});
console.log(res); // "Hello John!"
```
```ts
// entrypoints/injected.js
export default defineContentScript(() => {
console.log('Script was injected!');
return 'Hello John!';
});
```
@@ -10,6 +10,21 @@ WXT provides a simplified API to replace the `browser.storage.*` APIs. Use the `
import { storage } from 'wxt/storage';
```
:::warning
To use the `wxt/storage` API, the `"storage"` permission must be added to the manifest:
```ts
// wxt.config.ts
export default defineConfig({
manifest: {
permissions: ['storage'],
},
});
```
More info on permissions [here](/guide/key-concepts/manifest#permissions).
:::
[[toc]]
## Basic Usage
@@ -39,7 +54,7 @@ await storage.watch<number>(
await storage.getMeta<{ v: number }>('local:installDate');
```
For a full list of methods available, see the [API reference](/api/wxt/storage/interfaces/WxtStorage).
For a full list of methods available, see the [API reference](/api/reference/wxt/storage/interfaces/WxtStorage).
## Watchers
@@ -106,7 +121,7 @@ Storage items contain the same APIs as the `storage` variable, but you can confi
const showChangelogOnUpdate = storage.defineItem<boolean>(
'local:showChangelogOnUpdate',
{
defaultValue: true,
fallback: true,
},
);
```
@@ -117,12 +132,12 @@ Now, instead of using the `storage` variable, you can use the helper functions o
await showChangelogOnUpdate.getValue();
await showChangelogOnUpdate.setValue(false);
await showChangelogOnUpdate.removeValue();
const unwatch = showChangelogOnUpdate.watch(() => {
const unwatch = showChangelogOnUpdate.watch((newValue) => {
// ...
});
```
For a full list of properties and methods available, see the [API reference](/api/wxt/storage/interfaces/WxtStorageItem).
For a full list of properties and methods available, see the [API reference](/api/reference/wxt/storage/interfaces/WxtStorageItem).
### Versioning
@@ -138,7 +153,7 @@ type IgnoredWebsiteV1 = string;
export const ignoredWebsites = storage.defineItem<IgnoredWebsiteV1[]>(
'local:ignoredWebsites',
{
defaultValue: [],
fallback: [],
version: 1,
},
);
@@ -158,7 +173,7 @@ export const ignoredWebsites = storage.defineItem<IgnoredWebsiteV1[]>( // [!code
export const ignoredWebsites = storage.defineItem<IgnoredWebsiteV2[]>( // [!code ++]
'local:ignoredWebsites',
{
defaultValue: [],
fallback: [],
version: 1, // [!code --]
version: 2, // [!code ++]
migrations: { // [!code ++]
@@ -190,7 +205,7 @@ export const ignoredWebsites = storage.defineItem<IgnoredWebsiteV2[]>( // [!code
export const ignoredWebsites = storage.defineItem<IgnoredWebsiteV3[]>( // [!code ++]
'local:ignoredWebsites',
{
defaultValue: [],
fallback: [],
version: 2, // [!code --]
version: 3, // [!code ++]
migrations: {
@@ -227,7 +242,7 @@ Lets look at the same ignored websites example from before, but start with an un
export const ignoredWebsites = storage.defineItem<string[]>(
'local:ignoredWebsites',
{
defaultValue: [],
fallback: [],
},
);
```
@@ -247,7 +262,7 @@ export const ignoredWebsites = storage.defineItem<string[]>( // [!code --]
export const ignoredWebsites = storage.defineItem<IgnoredWebsiteV2[]>( // [!code ++]
'local:ignoredWebsites',
{
defaultValue: [],
fallback: [],
version: 2, // [!code ++]
migrations: { // [!code ++]
// Ran when migrating from v1 to v2 // [!code ++]
@@ -264,3 +279,35 @@ export const ignoredWebsites = storage.defineItem<IgnoredWebsiteV2[]>( // [!code
### Running Migrations
As soon as `storage.defineItem` is called, WXT checks if migrations need to be ran, and if so, runs them. Calls to get or update the storage item's value or metadata (`getValue`, `setValue`, `removeValue`, `getMeta`, etc) will automatically wait for the migration process to finish before actually reading or writing values.
### Default Values
With `storage.defineItem`, there are multiple ways of defining default values:
1. `fallback` - Return this value from `getValue` instead of `null` if the value is missing.
This option is great for providing default values for settings:
```ts
const theme = storage.defineItem('local:theme', {
fallback: 'dark',
});
const allowEditing = storage.defineItem('local:allow-editing', {
fallback: true,
});
```
2. `init` - Initialize and save a value in storage if it is not already saved.
This is great for values that need to be initialized or set once:
```ts
const userId = storage.defineItem('local:user-id', {
init: () => globalThis.crypto.randomUUID(),
});
const installDate = storage.defineItem('local:install-date', {
init: () => new Date().getTime(),
});
```
The value is initialized in storage immediately.
+5
View File
@@ -0,0 +1,5 @@
# Custom Events
:::warning 🚧 Under construction
These docs will be coming soon!
:::
+5
View File
@@ -0,0 +1,5 @@
# Debugging
:::warning 🚧 Under construction
These docs will be coming soon!
:::
+120
View File
@@ -0,0 +1,120 @@
# Entrypoint Loaders
Because entrypoint options, like content script `matches`, are listed in the entrypoint's JS file, WXT has to import them during the build process to use those options when generating the manifest.
There are two options for loading your entrypoints:
1. `vite-node` - default as of `v0.19.0`
2. `jiti` (**DEPRECATED, will be removed in `v0.20.0`**) - Default before `v0.19.0`
## vite-node
Since 0.19.0, WXT uses `vite-node`, the same tool that powers Vitest and Nuxt, to import your entrypoint files.
If you use any runtime packages that depend on `webextension-polyfill`, you need to add them to [Vite's `ssr.noExternal` option](https://vitejs.dev/config/ssr-options#ssr-noexternal):
```ts
export default defineConfig({
vite: () => ({
ssr: {
noExternal: ['@webext-core/messaging', '@webext-core/proxy-service'],
},
}),
});
```
:::details Why?
This tells Vite it needs process these module's, letting WXT properly disable the polyfill in the NodeJS environment so it doesn't cause any build errors like this:
```
ERROR This script should only be loaded in a browser extension
```
:::
To get a list of installed packages that use on `webextension-polyfill`, run your package manager's `list` command. Here's an example with PNPM:
```sh
$ pnpm why webextension-polyfill
dependencies:
@webext-core/messaging 1.4.0
└── webextension-polyfill 0.10.0
@webext-core/proxy-service 1.2.0
├─┬ @webext-core/messaging 1.4.0 peer
│ └── webextension-polyfill 0.10.0
└── webextension-polyfill 0.12.0 peer
devDependencies:
@wxt-dev/module-vue 1.0.0
└─┬ wxt 0.19.0-alpha1 peer
└── webextension-polyfill 0.12.0
webextension-polyfill 0.12.0
wxt 0.19.0-alpha1
└── webextension-polyfill 0.12.0
```
Ignoring WXT itself (it's added automatically for you), there are three packages that depend on the polyfill: `@wxt-dev/module-vue`, `@webext-core/messaging`, and `@webext-core/proxy-service`. Since the vue module is a build dependency, with no runtime code, you don't have to add it. That means for this case, you need to add `@webext-core/messaging`, and `@webext-core/proxy-service`, as shown in the original code snippet.
## jiti
The original method WXT used to import TS files. However, because it doesn't support vite plugins like `vite-node`, there is one main caveot to it's usage: **_module side-effects_**.
To enable `jiti`:
```ts
export default defineConfig({
entrypointLoader: 'jiti',
});
```
You cannot use imported variables outside the `main` function in JS entrypoints. This includes options, as shown below:
```ts
// entrypoints/content.ts
import { GOOGLE_MATCHES } from '~/utils/match-patterns';
export default defineContentScript({
matches: GOOGLE_MATCHES,
main() {
// ...
},
});
```
```
$ wxt build
wxt build
WXT 0.14.1
Building chrome-mv3 for production with Vite 5.0.5
✖ Command failed after 360 ms
[8:55:54 AM] ERROR entrypoints/content.ts: Cannot use imported variable "GOOGLE_MATCHES" before main function. See https://wxt.dev/guide/entrypoints.html#side-effects
```
This throws an error because WXT needs to import each entrypoint during the build process to extract its definition (containing the `match`, `runAt`, `include`/`exclude`, etc.) to render the `manifest.json` correctly. Before loading an entrypoint, a transformation is applied to remove all imports. This prevents imported modules (local or NPM) with side-effects from running during the build process, potentially throwing an error.
:::details Why?
When importing your entrypoint to get its definition, the file is imported in a **_node environment_**, and doesn't have access to the `window`, `chrome`, or `browser` globals a web extension usually has access to. If WXT doesn't remove all the imports from the file, the imported modules could try and access one of these variables, throwing an error.
:::
:::warning
See [`wxt-dev/wxt#336`](https://github.com/wxt-dev/wxt/issues/336) to track the status of this bug.
:::
Usually, this error occurs when you try to extract options into a shared file or try to run code outside the `main` function. To fix the example from above, use literal values when defining an entrypoint instead of importing them:
```ts
import { GOOGLE_MATCHES } from '~/utils/match-patterns'; // [!code --]
export default defineContentScript({
matches: GOOGLE_MATCHES, // [!code --]
matches: ['*//*.google.com/*'], // [!code ++]
main() {
// ...
},
});
```
@@ -35,4 +35,6 @@ Only MV3 support ESM background scripts/service workers. When targeting MV2, the
## Content Scripts
Coming soon. Follow [Content Script ESM Support #357](https://github.com/wxt-dev/wxt/issues/357) for updates.
WXT does not include built-in support for ESM content scripts. There are several technical issues that make implementing a generic solution impossible. See [Content Script ESM Support #357](https://github.com/wxt-dev/wxt/issues/357) for details.
Instead, depending on your requirements, 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 get started.
+76
View File
@@ -0,0 +1,76 @@
# Handling Extension Updates
When releasing an update to your extension, there's a couple of things you need to keep in mind:
[[toc]]
## Content Script Cleanup
Old content scripts are not automatically stopped when an extension updates and reloads. Often, this leads to "Invalidated context" errors in production when a content script from an old version of your extension tries to use an extension API.
WXT provides a utility for handling this process: `ContentScriptContext`. An instance of this class is provided to you automatically inside the `main` function of each content script.
When your extension updates or reloads, the context will become invalidated, and will trigger any `ctx.onInvalidated` listeners you add:
```ts
export default defineContentScript({
main(ctx) {
ctx.onInvalidated(() => {
// Do something
});
},
)
```
The `ctx` also provides other convenient APIs for stopping your content script without manually calling `onInvalidated` to add a listener:
1. Setting timers:
```ts
ctx.setTimeout(() => { ... }, ...);
ctx.setInterval(() => { ... }, ...);
ctx.requestAnimationFrame(() => { ... });
```
1. Adding DOM events:
```ts
ctx.addEventListener(window, "mousemove", (event) => { ... });
```
1. Implements [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) for canceling standard APIs:
```ts
fetch('...', {
signal: ctx.signal,
});
```
Other WXT APIs require a `ctx` object so they can clean themselves up. For example, [`createIntegratedUi`](/guide/key-concepts/content-script-ui#integrated), [`createShadowRootUi`](/guide/key-concepts/content-script-ui#shadow-root), and [`createIframeUi`](/guide/key-concepts/content-script-ui#iframe) automatically unmount and stop a UI when the script is invalidated.
:::warning
When working with content scripts, **you should always use the `ctx` object to stop any async or future work.**
This prevents old content scripts from interfering with new content scripts, and prevents error messages from being logged to the console in production.
:::
## Testing Permission Changes
When `permissions`/`host_permissions` change during an update, depending on what exactly changed, the browser will disable your extension until the user accepts the new permissions.
You can test if your permission changes will result in a disabled extension:
- Chromium: Use [Google's Extension Update Testing tool](https://github.com/GoogleChromeLabs/extension-update-testing-tool)
- Firefox/Safari: Everyone breaks something in production eventually... 🫡 Good luck soldier
## Update Event
You can setup a callback that runs after your extension updates like so:
```ts
browser.runtime.onInstalled.addListener(({ reason }) => {
if (reason === 'update') {
// Do something
}
});
```
If the logic is simple, write a unit test to cover this logic. If you feel the need to manually test this callback, you can either:
1. In dev mode, remove the `if` statement and reload the extension from `chrome://extensions`
2. Use [Google's Extension Update Testing tool](https://github.com/GoogleChromeLabs/extension-update-testing-tool)
+5
View File
@@ -0,0 +1,5 @@
# How WXT Works
:::warning 🚧 Under construction
These docs will be coming soon!
:::
@@ -1,10 +1,10 @@
# Remote Code
WXT will automatically download and bundle imports with the `url:` prefix so the extension does not depend of remote code, [a requirement from Google for MV3](https://developer.chrome.com/docs/extensions/migrating/improve-security/#remove-remote-code).
WXT will automatically download and bundle imports with the `url:` prefix so the extension does not depend on remote code, [a requirement from Google for MV3](https://developer.chrome.com/docs/extensions/migrating/improve-security/#remove-remote-code).
## Google Analytics
For example, you can import google analytics:
For example, you can import Google Analytics:
```ts
// utils/google-analytics.ts
+186
View File
@@ -0,0 +1,186 @@
---
outline: deep
---
# Reusable Modules
## Overview
WXT provides a "module" API that lets you modify the build process. This API lets you add entrypoints, inject runtime code, add vite plugins, and more!
What's more, these modules can be shared on NPM and re-used between projects!
## Adding a Module
There are two ways to add a module to your project:
1. **Local file**: Any file present in the `modules/` directory will be treated as a module and loaded at build-time by WXT. You can use `modules/*.ts` or `modules/*/index.ts`, similar to entrypoints.
```ts
// modules/example.ts
import { defineWxtModule } from 'wxt/modules';
export default defineWxtModule((wxt) => {
// ...
});
```
2. **NPM package**: Find WXT modules on NPM and include them in your project:
```ts
// wxt.config.ts
export default defineConfig({
// Add the module to your project
modules: ['@wxt-dev/auto-icons'],
});
```
## Writing Modules
Modules contain a setup function that is executed at the beginning of the build process.
:::code-group
```ts [Function Definition]
import { defineWxtModule } from 'wxt/modules';
export default defineWxtModule((wxt) => {
// ...
});
```
```ts [Object Definition]
import { defineWxtModule } from 'wxt/modules';
export default defineWxtModule({
// Add metadata...
setup(wxt) {
// ...
},
});
```
:::
### Module Options
You can define custom options for your module by setting the `configKey`:
```ts
// modules/analytics.ts
import { defineWxtModule } from 'wxt/modules';
export default defineWxtModule<AnalyticsModuleOptions>({
configKey: 'analytics',
setup(wxt, options) {
console.log(options); // { clientId: "..." }
},
});
// Define the option types
export interface AnalyticsModuleOptions {
clientId: string;
}
// Use "module augmentation" to add types for the new key
declare module 'wxt' {
export interface InlineConfig {
analytics: AnalyticsModuleOptions;
}
}
```
Now, when the user provides options to the `analytics` key in their `wxt.config.ts`, those options are passed into the setup function as the second argument.
```ts
export default defineConfig({
analytics: { clientId: '...' },
});
```
### Actually Doing Something
The first argument of the setup function, `wxt`, provides full access to the current build's context. You can access the resolved configuration via `wxt.config`, or setup hooks to manipulate the build at different steps of the build process with `wxt.hooks`.
Here's an example that updates the `outDir` based on the build mode. It's a very simple example of how to access config and setup a hook.
```ts
export default defineWxtModule((wxt) => {
if (wxt.config.mode === 'development') {
// Use the "ready" hook to update wxt.config
wxt.hooks.hook('ready', (wxt) => {
wxt.config.outDir = wxt.config.outDir.replace('.output', '.output/dev');
});
}
});
```
:::info Async Modules
Both the `setup` function and hook callbacks can be async. Don't forget to add `await`!
:::
It's important to understand the basics of how hooks work. Make sure to read the [API reference](/api/reference/wxt/interfaces/WxtHooks.html) for the full list of hooks and what they should be used for. They are the key to modifying your extension.
### Module Utils
Additionally, WXT provides several helper functions that setup hooks behind the scenes to streamline common operations.
For example, if you want to include an entrypoint from inside a module, you can use the `addEntrypoint` util:
```ts
// modules/changelog.ts
import { defineWxtModule, addEntrypoint } from 'wxt/modules';
import { resolve } from 'node:path';
export default defineWxtModule({
name: 'changelog',
setup(wxt) {
addEntrypoint(wxt, {
type: 'unlisted-page',
name: 'changelog',
// Point to the "modules/changelog.html" file
inputPath: resolve(__dirname, 'changelog.html'),
outputDir: wxt.config.outputDir,
options: {},
});
},
});
```
Refer to the [API reference](/api/reference/wxt/modules/#functions) for the full list of the utilities.
## Plugins
Whereas modules are executed at build-time, plugins are executed at runtime. As of now, the only way to add a plugin is with the `addWxtPlugin` helper inside a module.
Here's a minimal example to execute something at runtime.
:::code-group
```ts [modules/example/index.ts]
import { defineWxtModule, addWxtPlugin } from 'wxt/modules';
import { resolve } from 'node:path';
export default defineWxtModule((wxt) => {
addWxtPlugin(wxt, resolve(__dirname, 'plugin.ts'));
});
```
```ts [modules/example/plugin.ts]
import { defineWxtPlugin } from 'wxt/sandbox';
export default defineWxtPlugin(() => {
console.log('Executing plugin!');
});
```
:::
:::warning Async Plugins
Unlike modules, **_plugins cannot be async_**!! If you need to do some async work and expose that result to the rest of the extension, store the result's promise synchronously and await it later on.
:::
## Publishing to NPM
:::warning 🚧 Under construction
These docs will be coming soon!
:::
@@ -6,7 +6,9 @@ WXT officially supports [Vitest](https://vitest.dev/) for unit tests and either
For details setting up each testing framework, see the official examples:
<ExampleList tag="testing" />
- [Vitest](https://github.com/wxt-dev/wxt-examples/tree/main/examples/vanilla-vitest#readme)
- [Playwright](https://github.com/wxt-dev/wxt-examples/tree/main/examples/vanilla-playwright#readme)
- [Puppeteer](https://github.com/wxt-dev/wxt-examples/tree/main/examples/vanilla-puppeteer#readme)
### Unofficial Frameworks
@@ -17,9 +19,9 @@ There are other options for unit tests however, like [Jest](https://jestjs.io/),
If you want to try to use a different framework for unit tests, you will need to configure the environment manually:
- **Auto-imports**: Add `unimport` to your test environment or disable them by setting `imports: false` in your `wxt.config.ts` file
- **`browser` mock**: Mock the `webextension-polyfill` module globally with `wxt/dist/virtual/mock-browser.js`
- **[Remote Code Bundling](/guide/remote-code)**: If you use it, configure your environment to handle the `url:` module prefix
- **`browser` mock**: Mock the `webextension-polyfill` module globally with `wxt/dist/virtual/mock-browser.mjs`
- **[Remote Code Bundling](/guide/go-further/remote-code)**: If you use it, configure your environment to handle the `url:` module prefix
- **Global Variables**: If you consume them, manually define globals provided by WXT (like `import.meta.env.BROWSER`) by adding them to the global scope before accessing them (`import.meta.env.BROWSER = "chrome"`)
- **Import paths**: If you use the `@/` or `~/` path aliases, add them to your test environment
[Here's how Vitest is configured](https://github.com/wxt-dev/wxt/blob/main/src/testing/wxt-vitest-plugin.ts) for reference.
[Here's how Vitest is configured](https://github.com/wxt-dev/wxt/blob/main/packages/wxt/src/testing/wxt-vitest-plugin.ts) for reference.
@@ -18,9 +18,7 @@ export default defineConfig({
## Using Plugins
Plugins can be passed into the `vite` configuration in you `wxt.config.ts` file, just like any other option.
All plugins should work in WXT, but it is worth pointing out that since WXT orchestrates multiple vite builds to bundle an extension, plugins will be executed multiple times if necessary.
Plugins can be passed into the `vite` configuration in your `wxt.config.ts` file, just like any other option.
```ts
import { defineConfig } from 'wxt';
@@ -33,3 +31,9 @@ export default defineConfig({
}),
});
```
:::warning UNEXPECTED BEHAVIOR
Due to the way WXT orchestrates Vite builds, some plugins may not work as expected. 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 one doesn't exist, please open a [new issue](https://github.com/wxt-dev/wxt/issues/new/choose)!
:::

Some files were not shown because too many files have changed in this diff Show More