Compare commits

...

40 Commits

Author SHA1 Message Date
GitHub Actions b15dc7fc11 chore(release): v0.6.6 2023-09-30 15:05:16 +00:00
Aaron 89d15babc2 feat: Disable opening browser automatically during dev mode (#136) 2023-09-30 08:45:24 -05:00
GitHub Actions c616125689 chore(release): v0.6.5 2023-09-30 03:15:10 +00:00
Aaron e97071b7d7 fix: Support loading tsx entrypoints (#134) 2023-09-29 22:08:20 -05:00
Aaron 1fa049c5a7 Update badge colors 2023-09-29 12:43:28 -05:00
Aaron Klinker b48cee9715 fix: Don't crash when <all_urls> matches is used in dev mode 2023-09-29 08:18:56 -05:00
Aaron Klinker 24e69fe1bf docs: Add link to update extensions using WXT 2023-09-28 12:26:29 -05:00
Aaron Klinker 41e154992a docs: Fix DX section sizing 2023-09-28 12:22:56 -05:00
Aaron Klinker 55707932a9 docs: Add more content to the homepage 2023-09-28 12:08:21 -05:00
Aaron Klinker 08115a40ae Add explicit title to homepage 2023-09-28 10:22:20 -05:00
Aaron Klinker 96be879918 docs: Add tags for SEO and socials 2023-09-28 10:13:18 -05:00
Aaron 1fc4ada66d Add badges to README 2023-09-27 12:41:37 -05:00
Aaron Klinker d27f299641 Remove files from coverage 2023-09-27 12:27:58 -05:00
Aaron 7183114370 chore: Code coverage improvements (#131) 2023-09-27 12:21:50 -05:00
GitHub Actions 7bd940450f chore(release): v0.6.4 2023-09-27 17:12:03 +00:00
Aaron cf5a7d1411 fix: Use execaCommand instead of node:child_process (#130) 2023-09-27 12:06:44 -05:00
Aaron Klinker 5482b2f934 chore: Increase E2E test timeout
GitHub actions windows fails every once in a while due to a timeout, this should reduce those errors
2023-09-27 11:36:37 -05:00
Aaron Klinker c4a6ff928d Remove Aaron from release contributors 2023-09-27 11:34:18 -05:00
Aaron Klinker 455e7f3765 fix(content-scripts): Don't throw an error when including include or exclude options on a content script 2023-09-27 11:29:50 -05:00
Aaron 25b6ab92f5 chore(templates): Add .wxt directory to gitignore (#129) 2023-09-27 11:24:04 -05:00
GitHub Actions 50f6289ac5 chore(release): v0.6.3 2023-09-26 22:28:00 +00:00
Aaron a0e1b4741e feat(client): Add block and addEventListener utils to ContentScriptContext (#128) 2023-09-26 17:19:56 -05:00
GitHub Actions ab672e9dbd chore(release): v0.6.2 2023-09-25 19:31:40 +00:00
Aaron 7b3ea52e02 feat: Show spinner when building entrypoints (#126) 2023-09-25 14:23:19 -05:00
Aaron e0929a68ba docs: Update vite docs to use function 2023-09-25 00:14:38 -05:00
Aaron 4c430725a5 docs: Fix import typo 2023-09-25 00:10:35 -05:00
Aaron 7d745f6ec7 Remove vercel config
Using netlify
2023-09-23 16:17:10 -05:00
Aaron Klinker 10091d7769 Update feature list 2023-09-23 16:05:43 -05:00
Aaron 2e142b3038 feat: --analyze build flag (#125) 2023-09-23 16:00:35 -05:00
GitHub Actions 361bb2dcc8 chore(release): v0.6.1 2023-09-23 02:13:38 +00:00
Aaron 26fca5c0a2 feat: Add transformManifest option (#124) 2023-09-22 21:08:03 -05:00
Aaron 30a61f4384 fix: Don't open browser during development when using WSL (#123) 2023-09-22 20:32:31 -05:00
Aaron Klinker 8e0a189d77 docs: Load extension details from CWS 2023-09-22 14:37:20 -05:00
Aaron Klinker cae44c9732 Update changelog 2023-09-22 12:47:34 -05:00
GitHub Actions fba8f0d017 chore(release): v0.6.0 2023-09-22 17:45:55 +00:00
Aaron Klinker 3f260ee777 fix: Disable dev logs in production
This closes #119
2023-09-22 12:05:05 -05:00
Aaron Klinker 1f6a931b02 fix: Use the same mode for each build step 2023-09-22 11:57:36 -05:00
Aaron 07891d028b feat!: Require a function for vite configuration (#121)
BREAKING CHANGE: The `vite` config option must now be a function. If you were using an object before, change it from `vite: { ... }` to `vite: () => ({ ... })`.
2023-09-22 11:51:55 -05:00
Aaron Klinker 1f448d1bf0 feat: Export ContentScriptContext from wxt/client 2023-09-22 11:00:28 -05:00
Aaron Klinker 7722986537 Update changelog authors 2023-09-22 10:56:22 -05:00
66 changed files with 1375 additions and 469 deletions
+5
View File
@@ -51,6 +51,11 @@ jobs:
- name: Tests
run: pnpm test:coverage --reporter=default --reporter=hanging-process
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v3
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
project-templates:
name: Project Templates
runs-on: ubuntu-22.04
+1
View File
@@ -18,3 +18,4 @@ templates/*/pnpm-lock.yaml
templates/*/yarn.lock
templates/*/package-lock.json
docs/config.md
stats.html
+2
View File
@@ -10,3 +10,5 @@ CHANGELOG.md
.prettierignore
*.png
*.svg
*.txt
_gitignore
+99 -108
View File
@@ -1,5 +1,103 @@
# Changelog
## v0.6.6
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.6.5...v0.6.6)
### 🚀 Enhancements
- Disable opening browser automatically during dev mode ([#136](https://github.com/wxt-dev/wxt/pull/136))
## v0.6.5
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.6.4...v0.6.5)
### 🩹 Fixes
- Don't crash when `<all_urls>` matches is used in dev mode ([b48cee9](https://github.com/wxt-dev/wxt/commit/b48cee9))
- Support loading `tsx` entrypoints ([#134](https://github.com/wxt-dev/wxt/pull/134))
### 📖 Documentation
- Add tags for SEO and socials ([96be879](https://github.com/wxt-dev/wxt/commit/96be879))
- Add more content to the homepage ([5570793](https://github.com/wxt-dev/wxt/commit/5570793))
- Fix DX section sizing ([41e1549](https://github.com/wxt-dev/wxt/commit/41e1549))
- Add link to update extensions using WXT ([24e69fe](https://github.com/wxt-dev/wxt/commit/24e69fe))
### 🏡 Chore
- Code coverage improvements ([#131](https://github.com/wxt-dev/wxt/pull/131))
## v0.6.4
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.6.3...v0.6.4)
### 🩹 Fixes
- **content-scripts:** Don't throw an error when including `include` or `exclude` options on a content script ([455e7f3](https://github.com/wxt-dev/wxt/commit/455e7f3))
- Use `execaCommand` instead of `node:child_process` ([#130](https://github.com/wxt-dev/wxt/pull/130))
### 🏡 Chore
- **templates:** Add `.wxt` directory to gitignore ([#129](https://github.com/wxt-dev/wxt/pull/129))
- Increase E2E test timeout ([5482b2f](https://github.com/wxt-dev/wxt/commit/5482b2f))
## v0.6.3
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.6.2...v0.6.3)
### 🚀 Enhancements
- **client:** Add `block` and `addEventListener` utils to `ContentScriptContext` ([#128](https://github.com/wxt-dev/wxt/pull/128))
## v0.6.2
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.6.1...v0.6.2)
### 🚀 Enhancements
- `--analyze` build flag ([#125](https://github.com/wxt-dev/wxt/pull/125))
- Show spinner when building entrypoints ([#126](https://github.com/wxt-dev/wxt/pull/126))
### 📖 Documentation
- Fix import typo ([4c43072](https://github.com/wxt-dev/wxt/commit/4c43072))
- Update vite docs to use function ([e0929a6](https://github.com/wxt-dev/wxt/commit/e0929a6))
## v0.6.1
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.6.0...v0.6.1)
### 🚀 Enhancements
- Add `transformManifest` option ([#124](https://github.com/wxt-dev/wxt/pull/124))
### 🩹 Fixes
- Don't open browser during development when using WSL ([#123](https://github.com/wxt-dev/wxt/pull/123))
### 📖 Documentation
- Load extension details from CWS ([8e0a189](https://github.com/wxt-dev/wxt/commit/8e0a189))
## v0.6.0
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.5.6...v0.6.0)
### 🚀 Enhancements
- Export `ContentScriptContext` from `wxt/client` ([1f448d1](https://github.com/wxt-dev/wxt/commit/1f448d1))
- ⚠️ Require a function for `vite` configuration ([#121](https://github.com/wxt-dev/wxt/pull/121))
### 🩹 Fixes
- Use the same mode for each build step ([1f6a931](https://github.com/wxt-dev/wxt/commit/1f6a931))
- Disable dev logs in production ([3f260ee](https://github.com/wxt-dev/wxt/commit/3f260ee))
#### ⚠️ Breaking Changes
- ⚠️ The `vite` config option must now be a function. If you were using an object before, change it from `vite: { ... }` to `vite: () => ({ ... })`. ([#121](https://github.com/wxt-dev/wxt/pull/121))
## v0.5.6
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.5.5...v0.5.6)
@@ -8,10 +106,6 @@
- Add `ContentScriptContext` util for stopping invalidated content scripts ([#120](https://github.com/wxt-dev/wxt/pull/120))
### ❤️ Contributors
- Aaron <aaronklinker1@gmail.com>
## v0.5.5
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.5.4...v0.5.5)
@@ -20,10 +114,6 @@
- Automatically replace vite's `process.env.NODE_ENV` output in lib mode with the mode ([92039b8](https://github.com/wxt-dev/wxt/commit/92039b8))
### ❤️ Contributors
- Aaron Klinker <aaronklinker1@gmail.com>
## v0.5.4
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.5.3...v0.5.4)
@@ -33,10 +123,6 @@
- Recognize `background/index.ts` as an entrypoint ([419fab8](https://github.com/wxt-dev/wxt/commit/419fab8))
- Don't warn about deep entrypoint subdirectories not being recognized ([87e8df9](https://github.com/wxt-dev/wxt/commit/87e8df9))
### ❤️ Contributors
- Aaron Klinker <aaronklinker1@gmail.com>
## v0.5.3
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.5.2...v0.5.3)
@@ -49,11 +135,6 @@
- Refactor how config is resolved ([#118](https://github.com/wxt-dev/wxt/pull/118))
### ❤️ Contributors
- Aaron <aaronklinker1@gmail.com>
- Aaron Klinker <aaronklinker1@gmail.com>
## v0.5.2
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.5.1...v0.5.2)
@@ -62,10 +143,6 @@
- Import client utils when getting entrypoint config ([#117](https://github.com/wxt-dev/wxt/pull/117))
### ❤️ Contributors
- Aaron <aaronklinker1@gmail.com>
## v0.5.1
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.5.0...v0.5.1)
@@ -79,11 +156,6 @@
- Allow any string for target browser ([b4de93d](https://github.com/wxt-dev/wxt/commit/b4de93d))
### ❤️ Contributors
- Aaron <aaronklinker1@gmail.com>
- Aaron Klinker <aaronklinker1@gmail.com>
## v0.5.0
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.4.1...v0.5.0)
@@ -113,10 +185,6 @@
- ⚠️ Change default `publicDir` to `<srcDir>/public` ([5f15f9c](https://github.com/wxt-dev/wxt/commit/5f15f9c))
### ❤️ Contributors
- Aaron Klinker ([@aklinker1](https://github.com/aklinker1))
## v0.4.1
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.4.0...v0.4.1)
@@ -129,10 +197,6 @@
- **init:** Don't show `cd .` when initializing the current directory ([e086374](https://github.com/wxt-dev/wxt/commit/e086374))
### ❤️ Contributors
- Aaron Klinker ([@aklinker1](https://github.com/aklinker1))
## v0.4.0
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.3.2...v0.4.0)
@@ -182,10 +246,6 @@
- ⚠️ Use relative path aliases inside `.wxt/tsconfig.json` ([#102](https://github.com/wxt-dev/wxt/pull/102))
### ❤️ Contributors
- Aaron Klinker ([@aklinker1](https://github.com/aklinker1))
## v0.3.2
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.3.1...v0.3.2)
@@ -215,10 +275,6 @@
- List vite version when validating project templates ([ef140dc](https://github.com/wxt-dev/wxt/commit/ef140dc))
- Validate templates using tarball to avoid version conflicts within the `wxt/node_modules` directory ([edfa075](https://github.com/wxt-dev/wxt/commit/edfa075))
### ❤️ Contributors
- Aaron Klinker ([@aklinker1](https://github.com/aklinker1))
## v0.3.1
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.3.0...v0.3.1)
@@ -250,9 +306,8 @@
- Speed up demo validation ([3a9fd39](https://github.com/wxt-dev/wxt/commit/3a9fd39))
- Fix flakey failure when validating templates ([25677ba](https://github.com/wxt-dev/wxt/commit/25677ba))
### ❤️ Contributors
### ❤️ Contributors
- Aaron Klinker ([@aklinker1](https://github.com/aklinker1))
- BeanWei ([@BeanWei](https://github.com/BeanWei))
## v0.3.0
@@ -286,10 +341,6 @@
- ⚠️ Add type safety to `browser.runtime.getURL` ([58a84ec](https://github.com/wxt-dev/wxt/commit/58a84ec))
- ⚠️ Change default `publicDir` to `<rootDir>/public` ([19c0948](https://github.com/wxt-dev/wxt/commit/19c0948))
### ❤️ Contributors
- Aaron Klinker ([@aklinker1](https://github.com/aklinker1))
## v0.2.5
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.2.4...v0.2.5)
@@ -312,10 +363,6 @@
- Validate project templates ([9ac756f](https://github.com/wxt-dev/wxt/commit/9ac756f))
### ❤️ Contributors
- Aaron Klinker ([@aklinker1](https://github.com/aklinker1))
## v0.2.4
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.2.3...v0.2.4)
@@ -324,10 +371,6 @@
- Add `wxt zip` command ([#47](https://github.com/wxt-dev/wxt/pull/47))
### ❤️ Contributors
- Aaron Klinker ([@aklinker1](https://github.com/aklinker1))
## v0.2.3
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.2.2...v0.2.3)
@@ -338,10 +381,6 @@
- Read boolean maniest options from meta tags correctly ([495c5c8](https://github.com/wxt-dev/wxt/commit/495c5c8))
- Some fields cannot be overridden from `config.manifest` ([#46](https://github.com/wxt-dev/wxt/pull/46))
### ❤️ Contributors
- Aaron Klinker ([@aklinker1](https://github.com/aklinker1))
## v0.2.2
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.2.1...v0.2.2)
@@ -350,10 +389,6 @@
- Register content scripts correctly in dev mode ([2fb5a54](https://github.com/wxt-dev/wxt/commit/2fb5a54))
### ❤️ Contributors
- Aaron Klinker ([@aklinker1](https://github.com/aklinker1))
## v0.2.1
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.2.0...v0.2.1)
@@ -366,10 +401,6 @@
- Remove HMR log ([90fa6bf](https://github.com/wxt-dev/wxt/commit/90fa6bf))
### ❤️ Contributors
- Aaron Klinker ([@aklinker1](https://github.com/aklinker1))
## v0.2.0
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.1.6...v0.2.0)
@@ -394,10 +425,6 @@
- ⚠️ Rename `defineBackgroundScript` to `defineBackground` ([5b48ae9](https://github.com/wxt-dev/wxt/commit/5b48ae9))
### ❤️ Contributors
- Aaron Klinker ([@aklinker1](https://github.com/aklinker1))
## v0.1.6
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.1.5...v0.1.6)
@@ -412,10 +439,6 @@
- React and Vue starter templates ([#33](https://github.com/wxt-dev/wxt/pull/33))
- Svelte template ([#34](https://github.com/wxt-dev/wxt/pull/34))
### ❤️ Contributors
- Aaron Klinker ([@aklinker1](https://github.com/aklinker1))
## v0.1.5
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.1.4...v0.1.5)
@@ -424,10 +447,6 @@
- Include `vite/client` types ([371be99](https://github.com/wxt-dev/wxt/commit/371be99))
### ❤️ Contributors
- Aaron Klinker ([@aklinker1](https://github.com/aklinker1))
## v0.1.4
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.1.3...v0.1.4)
@@ -445,10 +464,6 @@
- Update prettier ignore ([68611ae](https://github.com/wxt-dev/wxt/commit/68611ae))
### ❤️ Contributors
- Aaron Klinker ([@aklinker1](https://github.com/aklinker1))
## v0.1.3
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.1.2...v0.1.3)
@@ -470,10 +485,6 @@
- Upgrade to pnpm 8 ([0ce7c9d](https://github.com/wxt-dev/wxt/commit/0ce7c9d))
### ❤️ Contributors
- Aaron Klinker ([@aklinker1](https://github.com/aklinker1))
## v0.1.2
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.1.1...v0.1.2)
@@ -492,10 +503,6 @@
- Change `config.vite` to `UserConfig` ([ef6001e](https://github.com/wxt-dev/wxt/commit/ef6001e))
### ❤️ Contributors
- Aaron Klinker ([@aklinker1](https://github.com/aklinker1))
## v0.1.1
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.1.0...v0.1.1)
@@ -505,10 +512,6 @@
- Allow dashes in entrypoint names ([2e51e73](https://github.com/wxt-dev/wxt/commit/2e51e73))
- Unable to read entrypoint options ([#28](https://github.com/wxt-dev/wxt/pull/28))
### ❤️ Contributors
- Aaron Klinker ([@aklinker1](https://github.com/aklinker1))
## v0.1.0
Initial release of WXT. Full support for production builds and initial toolkit for development:
@@ -532,10 +535,6 @@ Initial release of WXT. Full support for production builds and initial toolkit f
- Create github release ([b7c078f](https://github.com/wxt-dev/wxt/commit/b7c078f))
### ❤️ Contributors
- Aaron Klinker ([@aklinker1](https://github.com/aklinker1))
## v0.0.2
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.0.1...v0.0.2)
@@ -566,10 +565,6 @@ Initial release of WXT. Full support for production builds and initial toolkit f
- Rename `templates` to `virtual-modules` ([#24](https://github.com/wxt-dev/wxt/pull/24))
- Update cli screenshot ([54eb118](https://github.com/wxt-dev/wxt/commit/54eb118))
### ❤️ Contributors
- Aaron Klinker ([@aklinker1](https://github.com/aklinker1))
## v0.0.1
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.0.0...v0.0.1)
@@ -639,7 +634,3 @@ Initial release of WXT. Full support for production builds and initial toolkit f
- Create validation workflow ([#12](https://github.com/wxt-dev/wxt/pull/12))
- Create release workflow ([#13](https://github.com/wxt-dev/wxt/pull/13))
### ❤️ Contributors
- Aaron Klinker ([@aklinker1](https://github.com/aklinker1))
+15 -1
View File
@@ -3,6 +3,20 @@
<span>WXT</span>
</h1>
<p align="center">
<a href="https://www.npmjs.com/package/wxt" target="_blank">
<img alt="npm" src="https://img.shields.io/npm/v/wxt?labelColor=black&color=%2353bc4a">
</a>
<span> </span>
<img alt="npm" src="https://img.shields.io/npm/dm/wxt?labelColor=black&color=%2353bc4a">
<span> </span>
<img alt="NPM" src="https://img.shields.io/npm/l/wxt?labelColor=black&color=%2353bc4a">
<span> </span>
<a href="https://codecov.io/github/wxt-dev/wxt" target="_blank">
<img alt="Codecov" src="https://img.shields.io/codecov/c/github/wxt-dev/wxt?labelColor=black&color=%2353bc4a">
</a>
</p>
<p align="center">
<span>Next-gen framework for developing web extensions.</span>
<br/>
@@ -44,10 +58,10 @@ Or see the [installation guide](https://wxt.dev/get-started/installation.html) t
- ⬇️ Download and bundle remote URL imports
- 🎨 Frontend framework agnostic: works with Vue, React, Svelte, etc
- 🖍️ Quickly bootstrap a new project
- 📏 Bundle analysis
### Coming Soon
- 📏 Bundle analysis
- 🤖 Automated publishing
## Contributors
+5 -1
View File
@@ -16,9 +16,13 @@
"postinstall": "pnpm -w build && wxt prepare"
},
"dependencies": {
"webextension-polyfill": "^0.10.0"
"webextension-polyfill": "^0.10.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/react": "^18.2.14",
"@types/react-dom": "^18.2.6",
"@types/webextension-polyfill": "^0.10.0",
"sass": "^1.64.0",
"wxt": "workspace:*"
+2
View File
@@ -19,4 +19,6 @@ export default defineBackground(() => {
browser.i18n.getMessage('hello', 'Aaron');
browser.i18n.getMessage('bye', ['Aaron']);
browser.i18n.getMessage('@@extension_id');
console.log('WXT MODE:', import.meta.env.MODE);
});
@@ -0,0 +1,15 @@
import ReactDOM from 'react-dom/client';
export default defineContentScript({
matches: ['<all_urls>'],
async main() {
const container = document.createElement('div');
document.body.append(container);
ReactDOM.createRoot(container).render(<SomeComponent />);
},
});
function SomeComponent() {
return <div>Some component</div>;
}
+2
View File
@@ -3,3 +3,5 @@ import 'url:https://code.jquery.com/jquery-3.7.1.slim.min.js';
console.log(browser.runtime.id);
logId();
console.log(2);
console.log('WXT MODE:', import.meta.env.MODE);
@@ -1,14 +1,18 @@
import '../../common/style.css';
export default defineContentScript({
matches: ['*://*/*'],
matches: ['<all_urls>'],
async main(ctx) {
console.log(browser.runtime.id);
logId();
console.log('WXT MODE:', import.meta.env.MODE);
const n = (Math.random() * 100).toFixed(1);
ctx.setInterval(() => {
console.log(n, browser.runtime.id);
}, 1e3);
mountContentScriptUi();
},
});
+5 -1
View File
@@ -1,3 +1,7 @@
{
"extends": ["../tsconfig.base.json", "./.wxt/tsconfig.json"]
"extends": ["../tsconfig.base.json", "./.wxt/tsconfig.json"],
"compilerOptions": {
"allowImportingTsExtensions": true,
"jsx": "react-jsx"
}
}
+110 -43
View File
@@ -1,26 +1,68 @@
<script lang="ts" setup>
const extensions = [
{
name: 'GitHub: Better Line Counts',
description: 'Remove generated files from GitHub line counts.',
icon: 'https://lh3.googleusercontent.com/GcffNyCJaxT2G9dsQCJHhUEMlu_E0vEzph5cLPrQj7UHKat7QyCzGu69Dmp_DDUL8rY-bPMFJceQarS1wcqdwTalTg=s256',
link: 'https://chrome.google.com/webstore/detail/github-better-line-counts/ocfdgncpifmegplaglcnglhioflaimkd',
},
import { computed } from 'vue';
import useListExtensionDetails, {
ChromeExtension,
} from '../composables/useListExtensionDetails';
// Add extension IDs here. Order doesn't matter, will be sorted by weekly active users
const chromeExtensionIds = [
'ocfdgncpifmegplaglcnglhioflaimkd', // GitHub: Better Line Counts
'mgmdkjcljneegjfajchedjpdhbadklcf', // Anime Skip Player
];
const { data } = useListExtensionDetails(chromeExtensionIds);
const sortedExtensions = computed(() =>
!data.value
? undefined
: [...data.value].sort((l, r) => r.weeklyActiveUsers - l.weeklyActiveUsers),
);
function getStoreUrl(extension: ChromeExtension) {
const url = new URL(extension.storeUrl);
url.searchParams.set('utm_source', 'wxt.dev');
return url.href;
}
</script>
<template>
<section class="vp-doc">
<div class="container">
<h2>Who's Using WXT?</h2>
<p>
Battle tested and ready for production. Explore chrome extensions made
with WXT.
</p>
<ul>
<li v-for="extension of extensions">
<img :src="extension.icon" :alt="`${extension.name} icon`" />
<a :href="extension.link" target="_blank">{{ extension.name }}</a>
<small>{{ extension.description }}</small>
<li v-for="extension of sortedExtensions">
<img
:src="extension.iconUrl"
:alt="`${extension.name} icon`"
referrerpolicy="no-referrer"
/>
<div>
<a
:href="getStoreUrl(extension)"
target="_blank"
:title="extension.name"
>{{ extension.name }}</a
>
<p class="description" :title="extension.shortDescription">
{{ extension.shortDescription }}
</p>
<p class="user-count">
{{ extension.weeklyActiveUsers.toLocaleString() }} users
</p>
</div>
</li>
</ul>
<p>Open a PR to add your extension to the list!</p>
<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>
</div>
</section>
</template>
@@ -30,10 +72,6 @@ const extensions = [
padding: 0 24px;
}
h2 {
margin-bottom: 32px;
}
@media (min-width: 640px) {
.vp-doc {
padding: 0 48px;
@@ -53,57 +91,86 @@ h2 {
flex-direction: column;
}
img {
width: 96px;
height: 96px;
margin-bottom: 16px;
li img {
width: 116px;
height: 116px;
padding: 16px;
border-radius: 8px;
background-color: var(--vp-c-default-soft);
}
ul {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-template-columns: repeat(1, 1fr);
align-items: stretch;
gap: 16px;
list-style: none;
margin: 0;
margin: 16px 0;
padding: 0;
}
@media (min-width: 640px) {
ul {
grid-template-columns: repeat(3, 1fr);
}
}
@media (min-width: 960px) {
ul {
grid-template-columns: repeat(4, 1fr);
grid-template-columns: repeat(2, 1fr);
}
}
li {
margin: 0 !important;
padding: 12px;
padding: 16px;
display: flex;
flex-direction: column;
align-items: center;
background-color: var(--vp-c-bg-soft);
border-radius: 12px;
flex: 1;
}
a,
small {
text-align: center;
}
small {
opacity: 50%;
gap: 16px;
}
p {
.centered {
text-align: center;
opacity: 50%;
}
a {
color: var(--vp-c-text-1);
li a,
li .user-count,
li .description {
padding: 0;
margin: 0;
}
li .user-count {
opacity: 70%;
text-align: right;
width: 100%;
font-size: small;
}
li a {
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
overflow: hidden;
cursor: pointer;
padding: 0;
margin: 0;
text-decoration: none;
}
li a:hover {
text-decoration: underline;
}
li div {
flex: 1;
display: flex;
flex-direction: column;
}
li .description {
opacity: 90%;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
flex-grow: 1;
}
.pr {
opacity: 70%;
}
</style>
@@ -0,0 +1,53 @@
import { ref } from 'vue';
export interface ChromeExtension {
id: string;
name: string;
iconUrl: string;
weeklyActiveUsers: number;
shortDescription: string;
storeUrl: string;
}
const operationName = 'WxtDocsUsedBy';
const query = `query ${operationName}($ids:[String!]!) {
chromeExtensions(ids: $ids) {
id
name
iconUrl
weeklyActiveUsers
shortDescription
storeUrl
}
}`;
export default function (ids: string[]) {
const data = ref<ChromeExtension[]>();
const err = ref<unknown>();
fetch('https://queue.wxt.dev/api', {
method: 'POST',
body: JSON.stringify({
operationName,
query,
variables: { ids },
}),
})
.then(async (res) => {
const {
data: { chromeExtensions },
} = await res.json();
data.value = chromeExtensions;
err.value = undefined;
})
.catch((error) => {
console.error(error);
data.value = undefined;
err.value = error;
});
return {
data,
err,
};
}
+28 -6
View File
@@ -1,30 +1,52 @@
import { defineConfig } from 'vitepress';
import { generateConfigDocs } from './plugins/generate-config-docs';
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 utilties for building, zipping, and publishing your extension, it's easy to get started.";
const ogTitle = `${title}${titleSuffix}`;
const ogUrl = 'https://wxt.dev';
const ogImage = 'https://wxt.dev/social-preview.png';
// https://vitepress.dev/reference/site-config
export default defineConfig({
titleTemplate: `:title${titleSuffix}`,
title: 'WXT',
description,
vite: {
clearScreen: false,
plugins: [generateConfigDocs()],
},
description: 'Next gen framework for developing web extensions',
lastUpdated: true,
sitemap: {
hostname: 'https://wxt.dev',
},
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",
'script',
{
async: "",
"data-website-id": "c1840c18-a12c-4a45-a848-55ae85ef7915",
src: "https://umami.aklinker1.io/script.js",
async: '',
'data-website-id': 'c1840c18-a12c-4a45-a848-55ae85ef7915',
src: 'https://umami.aklinker1.io/script.js',
},
],
],
themeConfig: {
// https://vitepress.dev/reference/default-theme-config
logo: '/logo.svg',
logo: {
src: '/logo.svg',
alt: 'WXT logo',
},
editLink: {
pattern: 'https://github.com/wxt-dev/wxt/edit/main/docs/:path',
},
-6
View File
@@ -2,12 +2,6 @@
Bootstrap a new project, start from scratch, or migrate an existing project.
:::warning 🚧&ensp;WSL Support
**_WXT does not support [Windows Subsystem for Linux](https://learn.microsoft.com/en-us/windows/wsl/) yet_**. See [Issue #55](https://github.com/wxt-dev/wxt/issues/55) to track progress.
In the meantime, you can use `cmd` instead.
:::
## Bootstrap Project
:::code-group
+7
View File
@@ -1,3 +1,10 @@
---
head:
- - link
- rel: canonical
href: https://wxt.dev
---
# Introduction
WXT is a free and open source framework for building web extensions in an conventional, intuative, and safe way **_for all browsers_**.
+1 -1
View File
@@ -14,7 +14,7 @@ And that's it! Your extension now supports Chrome, Firefox, Safari, Edge, and ot
The `browser` variable is available globally via [auto-imports](/guide/auto-imports.md), or it can be imported manually.
```ts
import browser from 'wxt/browser';
import { browser } from 'wxt/browser';
```
The `wxt/browser` module exports a customized version of `webextension-polyfill`'s browser with improved typing.
+4 -4
View File
@@ -10,9 +10,9 @@ All of Vite's config can be customized by setting the `vite` configuration in yo
import { defineConfig } from 'wxt';
export default defineConfig({
vite: {
vite: () => ({
// Same as `defineConfig({ ... })` inside vite.config.ts
},
}),
});
```
@@ -26,10 +26,10 @@ All plugins should work in WXT, but it is worth pointing out that since WXT orch
import { defineConfig } from 'wxt';
export default defineConfig({
vite: {
vite: () => ({
plugins: [
// ...
],
},
}),
});
```
+53 -13
View File
@@ -1,12 +1,12 @@
---
# https://vitepress.dev/reference/default-theme-home-page
layout: home
titleTemplate: 'Next Generation Web Extension Framework'
title: Next-gen Web Extension Framework
hero:
name: WXT
text: Next-gen Web Extension Framework
tagline: Powered by Vite, inspired by Nuxt.
tagline: An open source tool that makes Chrome Extension devlopment faster than ever before.
image:
src: /hero-logo.svg
alt: WXT
@@ -21,37 +21,77 @@ hero:
features:
- icon: 🌐
title: Supported Browsers
details: Chrome, Firefox, Edge, Safari, and any Chromium based browser.
details: WXT will build extensions for Chrome, Firefox, Edge, Safari, and any Chromium based browser.
link: /get-started/build-targets
linkText: Read docs
- icon: ✅
title: MV2 and MV3
details: Supports both manifest versions for each browser.
details: Build Manifest V2 or V3 extensions for any browser using the same codebase.
link: /get-started/build-targets#target-manifest-version
linkText: Read docs
- icon: ⚡
title: Fast Dev Mode
details: HMR for UIs and fast reload for background and content scripts.
details: Lighting fast HMR for UI development and fast reloads for content/background scripts enables faster iterations.
link: /get-started/introduction.html#development
linkText: Learn more
- icon: 📂
title: File Based Entrypoints
details: Manifest is generated based on files inside the project.
details: Manifest is generated based on files in the project with inline configuration.
link: /get-started/entrypoints
linkText: See project structure
- icon: 🚔
title: TypeScript
details: Scale projects with full TS support.
details: Create large projects with confidence using TS by default.
- icon: 🦾
title: Auto-imports
details: Nuxt-like auto-imports to speed up development.
link: /guide/auto-imports
linkText: Read docs
- icon: ⬇️
title: Bundle Remote Code
details: Downloads and bundles remote code imported from URLs.
link: guide/remote-code
linkText: Read docs
- icon: 🎨
title: Frontend Framework Agnostic
details: Works with any front-end framework with a Vite plugin.
link: /get-started/configuration#frontend-frameworks
linkText: Add a framework
- icon: 🖍️
title: Bootstrap a New Project
details: Comes with starter templates for all major frontend frameworks.
- icon: 🤖
title: Automated Publishing
details: 'TODO: Automatically zip, upload, and release extensions.'
details: Get started quickly with several awesome project templates.
link: /get-started/installation#bootstrap-project
linkText: See templates
- icon: 📏
title: Bundle Analysis
details: 'TODO: Tools for analyizing the final extension bundle.'
details: Tools for analyizing the final extension bundle and minimizing your extension's size.
- icon: 🤖
title: Automated Publishing
details: 'Coming soon. Automatically zip, upload, and release extensions.'
---
<UsingWxtSection />
<section class="vp-doc">
<div class="container">
<h2>Put <span style="color: var(--vp-c-brand-1)">Developer Experience</span> First</h2>
<p>
WXT's simplifies the chrome extension development process by providing tools for zipping and publishing, the best-in-class dev mode, an opinionated project structure, and more. Iterate faster, develop features not build scripts, and use everything the JS ecosystem has to offer.
</p>
<div style="margin: auto; width: 100%; max-width: 700px; text-align: center">
<img src="./assets/cli-output.png" alt="Screenshot of WXT's build output" />
<small>
And who doesn't appreciate a beautiful CLI?
</small>
</div>
</div>
</section>
<ClientOnly>
<UsingWxtSection />
</ClientOnly>
<style scoped>
.container {
margin: 0 auto;
max-width: 1152px;
}
</style>
+5
View File
@@ -0,0 +1,5 @@
User-agent: *
Disallow: /api.html
Disallow: /config.html
Sitemap: https://wxt.dev/sitemap.xml
+1
View File
@@ -16,6 +16,7 @@ describe('Auto Imports', () => {
// Generated by wxt
export {}
declare global {
const ContentScriptContext: typeof import('wxt/client')['ContentScriptContext']
const browser: typeof import('wxt/browser')['browser']
const defineBackground: typeof import('wxt/client')['defineBackground']
const defineConfig: typeof import('wxt')['defineConfig']
+1 -1
View File
@@ -40,5 +40,5 @@ describe('Init command', () => {
"wxt.config.ts",
]
`);
}, 30e3);
});
});
+25
View File
@@ -306,4 +306,29 @@ describe('Manifest Content', () => {
js: ['content-scripts/one.js'],
});
});
it('should respect the transformManifest option', async () => {
const project = new TestProject();
project.addFile(
'wxt.config.ts',
`import { defineConfig } from 'wxt';
export default defineConfig({
transformManifest(manifest) {
manifest.author = "Custom Author"
}
})`,
);
await project.build();
const output = await project.serializeFile(
'.output/chrome-mv3/manifest.json',
);
expect(output).toMatchInlineSnapshot(`
".output/chrome-mv3/manifest.json
----------------------------------------
{\\"manifest_version\\":3,\\"name\\":\\"E2E Extension\\",\\"description\\":\\"Example description\\",\\"version\\":\\"0.0.0\\",\\"version_name\\":\\"0.0.0-test\\",\\"author\\":\\"Custom Author\\"}"
`);
});
});
+26
View File
@@ -139,4 +139,30 @@ describe('Output Directory Structure', () => {
false,
);
});
it('should generate a stats file when analyzing the bundle', async () => {
const project = new TestProject();
project.setConfigFileConfig({
analysis: {
enabled: true,
template: 'sunburst',
},
});
project.addFile(
'entrypoints/background.ts',
`export default defineBackground(() => {});`,
);
project.addFile('entrypoints/popup.html', '<html></html>');
project.addFile(
'entrypoints/overlay.content.html',
`export default defineContentScript({
matches: [],
main() {},
});`,
);
await project.build();
expect(await project.fileExists('stats.html')).toBe(true);
});
});
+43
View File
@@ -0,0 +1,43 @@
import { describe, expect, it } from 'vitest';
import { TestProject } from '../utils';
describe('React', () => {
it('should prepare and build an project with a tsx entrypoint', async () => {
const project = new TestProject({
dependencies: {
react: '^18.2.0',
'react-dom': '^18.2.0',
},
devDependencies: {
'@types/react': '^18.2.14',
'@types/react-dom': '^18.2.6',
},
});
project.addFile(
'entrypoints/demo.content.tsx',
`import ReactDOM from 'react-dom/client';
export default defineContentScript({
matches: "<all_urls>",
main() {
const container = document.createElement("div");
document.body.append(container)
const root = ReactDOM.createRoot(container);
root.render(<h1>Hello, world!</h1>);
}
})`,
);
await project.build();
expect(
await project.fileExists('.output/chrome-mv3/content-scripts/demo.js'),
).toBe(true);
expect(await project.serializeFile('.output/chrome-mv3/manifest.json'))
.toMatchInlineSnapshot(`
".output/chrome-mv3/manifest.json
----------------------------------------
{\\"manifest_version\\":3,\\"name\\":\\"E2E Extension\\",\\"description\\":\\"Example description\\",\\"version\\":\\"0.0.0\\",\\"version_name\\":\\"0.0.0-test\\",\\"content_scripts\\":[{\\"matches\\":\\"<all_urls>\\",\\"js\\":[\\"content-scripts/demo.js\\"]}]}"
`);
});
});
File diff suppressed because one or more lines are too long
+15 -11
View File
@@ -1,32 +1,36 @@
import { dirname, join, relative, resolve } from 'path';
import fs from 'fs-extra';
import glob from 'fast-glob';
import { execSync } from 'child_process';
import { execaCommand } from 'execa';
import { InlineConfig, UserConfig, build } from '../src';
import { normalizePath } from '../src/core/utils/paths';
import merge from 'lodash.merge';
export class TestProject {
files: Array<[string, string]> = [];
config: UserConfig | undefined;
readonly root: string;
constructor(root = 'e2e/dist') {
constructor(packageJson: any = {}) {
// We can't put each test's project inside e2e/dist directly, otherwise the wxt.config.ts
// file is cached and cannot be different between each test. Instead, we add a random ID to the
// end to make each test's path unique.
const id = Math.random().toString(32).substring(3);
this.root = join(root, id);
this.root = join('e2e/dist', id);
this.files.push([
'package.json',
JSON.stringify(
{
name: 'E2E Extension',
description: 'Example description',
version: '0.0.0-test',
dependencies: {
wxt: '../../..',
merge(
{
name: 'E2E Extension',
description: 'Example description',
version: '0.0.0-test',
dependencies: {
wxt: '../../..',
},
},
},
packageJson,
),
null,
2,
),
@@ -72,8 +76,8 @@ export class TestProject {
await fs.ensureDir(fileDir);
await fs.writeFile(filePath, content ?? '', 'utf-8');
}
execSync('npm i --ignore-scripts', { cwd: this.root });
await execaCommand('npm i --ignore-scripts', { cwd: this.root });
await build({ ...config, root: this.root });
}
+14 -5
View File
@@ -1,7 +1,7 @@
{
"name": "wxt",
"type": "module",
"version": "0.5.6",
"version": "0.6.6",
"description": "Next gen framework for developing web extensions",
"engines": {
"node": ">=18.16.0",
@@ -56,7 +56,7 @@
"format:check": "prettier --write .",
"compile": "tsc --noEmit",
"test": "vitest",
"test:coverage": "vitest run --coverage",
"test:coverage": "vitest run --coverage.enabled --coverage.exclude=e2e --coverage.exclude=src/testing",
"prepare": "simple-git-hooks",
"prepublish": "pnpm -s build",
"docs:dev": "vitepress dev docs",
@@ -67,22 +67,27 @@
"dependencies": {
"@types/webextension-polyfill": "^0.10.1",
"@webext-core/fake-browser": "^1.2.2",
"@webext-core/match-patterns": "^1.0.1",
"@webext-core/match-patterns": "^1.0.2",
"async-mutex": "^0.4.0",
"c12": "^1.4.2",
"cac": "^6.7.14",
"consola": "^3.2.3",
"esbuild": "^0.19.4",
"fast-glob": "^3.3.1",
"filesize": "^10.0.8",
"fs-extra": "^11.1.1",
"get-port": "^7.0.0",
"giget": "^1.1.2",
"immer": "^10.0.2",
"is-wsl": "^3.0.0",
"jiti": "^1.19.1",
"json5": "^2.2.3",
"linkedom": "^0.15.1",
"minimatch": "^9.0.3",
"ora": "^7.0.1",
"picocolors": "^1.0.0",
"prompts": "^2.4.2",
"rollup-plugin-visualizer": "^5.9.2",
"unimport": "^3.1.0",
"vite": "^4.4.7",
"web-ext-run": "^0.1.0",
@@ -94,14 +99,12 @@
"@types/fs-extra": "^11.0.1",
"@types/lodash.merge": "^4.6.7",
"@types/node": "^20.4.5",
"@types/prettier": "^3.0.0",
"@types/prompts": "^2.4.4",
"@vitest/coverage-v8": "^0.34.1",
"execa": "^7.2.0",
"lint-staged": "^14.0.0",
"lodash.merge": "^4.6.2",
"npm-run-all": "^4.1.5",
"ora": "^7.0.1",
"prettier": "^3.0.1",
"simple-git-hooks": "^2.9.0",
"ts-morph": "^19.0.0",
@@ -111,6 +114,7 @@
"vitepress": "1.0.0-rc.10",
"vitest": "^0.34.1",
"vitest-mock-extended": "^1.1.4",
"vue": "^3.3.4",
"webextension-polyfill": "^0.10.0"
},
"peerDependencies": {
@@ -123,6 +127,11 @@
"lint-staged": {
"*": "prettier --write"
},
"changelog": {
"excludeAuthors": [
"aaronklinker1@gmail.com"
]
},
"pnpm": {
"peerDependencyRules": {
"ignoreMissing": [
+360 -166
View File
File diff suppressed because it is too large Load Diff
+4
View File
@@ -11,6 +11,7 @@ export const build = defineCommand<
mv3?: boolean;
mv2?: boolean;
debug?: boolean;
analyze?: boolean;
},
]
>(async (root, flags) => {
@@ -21,6 +22,9 @@ export const build = defineCommand<
manifestVersion: flags.mv3 ? 3 : flags.mv2 ? 2 : undefined,
configFile: flags.config,
debug: flags.debug,
analysis: {
enabled: flags.analyze,
},
};
await wxt.build(cliConfig);
+1 -1
View File
@@ -1,6 +1,5 @@
import { defineCommand } from '../utils/defineCommand';
import prompts from 'prompts';
import ora from 'ora';
import { consola } from 'consola';
import { downloadTemplate } from 'giget';
import fs from 'fs-extra';
@@ -133,6 +132,7 @@ async function cloneProject({
template: Template;
packageManager: string;
}) {
const { default: ora } = await import('ora');
const spinner = ora('Downloading template').start();
try {
// 1. Clone repo
+1
View File
@@ -26,6 +26,7 @@ cli
.option('-b, --browser <browser>', 'specify a browser')
.option('--mv3', 'target manifest v3')
.option('--mv2', 'target manifest v2')
.option('--analyze', 'visualize extension bundle')
.action(commands.build);
// ZIP
+1
View File
@@ -1,3 +1,4 @@
export * from './defineContentScript';
export * from './defineBackground';
export * from './mountContentScriptUi';
export * from './utils/ContentScriptContext';
+40
View File
@@ -54,6 +54,23 @@ export class ContentScriptContext extends AbortController {
return () => this.signal.removeEventListener('abort', cb);
}
/**
* Return a promise that never resolves. Useful if you have an async function that shouldn't run
* after the context is expired.
*
* @example
* const getValueFromStorage = async () => {
* if (ctx.isInvalid) return ctx.block();
*
* // ...
* }
*/
block<T>(): Promise<T> {
return new Promise(() => {
// noop
});
}
/**
* Wrapper around `window.setInterval` that automatically clears the interval when invalidated.
*/
@@ -105,6 +122,29 @@ export class ContentScriptContext extends AbortController {
return id;
}
/**
* Call `target.addEventListener` and remove the event listener when the context is invalidated.
*
* @example
* ctx.addEventListener(window, "mousemove", () => {
* // ...
* });
* ctx.addEventListener(document, "visibilitychange", () => {
* // ...
* });
*/
addEventListener(
target: any,
type: string,
handler: (event: Event) => void,
options?: AddEventListenerOptions,
) {
target.addEventListener?.(type, handler, options);
this.onInvalidated(
() => target.removeEventListener?.(type, handler, options),
);
}
/**
* Abort the abort controller and execute all `onInvalidated` listeners.
*/
+2
View File
@@ -1,4 +1,6 @@
function print(method: (...args: any[]) => void, ...args: any[]) {
if (import.meta.env.MODE === 'production') return;
if (typeof args[0] === 'string') {
const message = args.shift();
method(`[wxt] ${message}`, ...args);
+32 -1
View File
@@ -11,6 +11,9 @@ import fs from 'fs-extra';
import { groupEntrypoints } from './utils/groupEntrypoints';
import { formatDuration } from './utils/formatDuration';
import { printBuildSummary } from './log/printBuildSummary';
import { execaCommand } from 'execa';
import glob from 'fast-glob';
import { unnormalizePath } from './utils/paths';
/**
* Builds the extension based on an internal config.
@@ -50,6 +53,13 @@ export async function buildInternal(
config,
);
if (config.analysis.enabled) {
await combineAnalysisStats(config);
config.logger.info(
`Analysis complete:\n ${pc.gray('└─')} ${pc.yellow('stats.html')}`,
);
}
return output;
}
@@ -71,6 +81,9 @@ export async function rebuild(
publicAssets: [],
},
): Promise<{ output: BuildOutput; manifest: Manifest.WebExtensionManifest }> {
const { default: ora } = await import('ora');
const spinner = ora(`Preparing...`).start();
// Update types directory with new files and types
const allEntrypoints = await findEntrypoints(config);
await generateTypesDir(allEntrypoints, config).catch((err) => {
@@ -80,7 +93,7 @@ export async function rebuild(
});
// Build and merge the outputs
const newOutput = await buildEntrypoints(entrypointGroups, config);
const newOutput = await buildEntrypoints(entrypointGroups, config, spinner);
const mergedOutput: Omit<BuildOutput, 'manifest'> = {
steps: [...existingOutput.steps, ...newOutput.steps],
publicAssets: [...existingOutput.publicAssets, ...newOutput.publicAssets],
@@ -99,6 +112,9 @@ export async function rebuild(
// Write manifest
await writeManifest(newManifest, finalOutput, config);
// Stop the spinner and remove it from the CLI output
spinner.clear().stop();
return {
output: {
manifest: newManifest,
@@ -111,3 +127,18 @@ export async function rebuild(
manifest: newManifest,
};
}
async function combineAnalysisStats(config: InternalConfig): Promise<void> {
const unixFiles = await glob(`stats-*.json`, {
cwd: config.outDir,
absolute: true,
});
const absolutePaths = unixFiles.map(unnormalizePath);
await execaCommand(
`rollup-plugin-visualizer ${absolutePaths.join(' ')} --template ${
config.analysis.template
}`,
{ cwd: config.root, stdio: 'inherit' },
);
}
+15 -3
View File
@@ -13,13 +13,25 @@ import fs from 'fs-extra';
import { dirname, resolve } from 'path';
import { getPublicFiles } from '../utils/public';
import { getEntrypointGlobals } from '../utils/globals';
import type { Ora } from 'ora';
import pc from 'picocolors';
export async function buildEntrypoints(
groups: EntrypointGroup[],
config: InternalConfig,
spinner: Ora,
): Promise<Omit<BuildOutput, 'manifest'>> {
const steps: BuildStepOutput[] = [];
for (const group of groups) {
for (let i = 0; i < groups.length; i++) {
const group = groups[i];
spinner.text =
pc.dim(`[${i + 1}/${groups.length}]`) +
` ${[group]
.flat()
.map((e) => e.name)
.join(pc.dim(', '))}`;
const step = Array.isArray(group)
? await buildMultipleEntrypoints(group, config)
: await buildSingleEntrypoint(group, config);
@@ -89,7 +101,7 @@ async function buildSingleEntrypoint(
}
const entryConfig = vite.mergeConfig(
libMode,
config.vite,
await config.vite(config.env),
) as vite.InlineConfig;
const result = await vite.build(entryConfig);
@@ -132,7 +144,7 @@ async function buildMultipleEntrypoints(
const entryConfig = vite.mergeConfig(
multiPage,
config.vite,
await config.vite(config.env),
) as vite.UserConfig;
const result = await vite.build(entryConfig);
+79
View File
@@ -0,0 +1,79 @@
import { describe, expect, it, vi } from 'vitest';
import { createExtensionRunner } from '..';
import { fakeInternalConfig } from '../../../testing/fake-objects';
import { mock } from 'vitest-mock-extended';
import { createSafariRunner } from '../safari';
import { ExtensionRunner } from '../extension-runner';
import { createWslRunner } from '../wsl';
import { createManualRunner } from '../manual';
import { isWsl } from '../../utils/wsl';
import { createWebExtRunner } from '../web-ext';
vi.mock('../../utils/wsl');
const isWslMock = vi.mocked(isWsl);
vi.mock('../safari');
const createSafariRunnerMock = vi.mocked(createSafariRunner);
vi.mock('../wsl');
const createWslRunnerMock = vi.mocked(createWslRunner);
vi.mock('../manual');
const createManualRunnerMock = vi.mocked(createManualRunner);
vi.mock('../web-ext');
const createWebExtRunnerMock = vi.mocked(createWebExtRunner);
describe('createExtensionRunner', () => {
it('should return a Safari runner when browser is "safari"', async () => {
const config = fakeInternalConfig({
browser: 'safari',
});
const safariRunner = mock<ExtensionRunner>();
createSafariRunnerMock.mockReturnValue(safariRunner);
await expect(createExtensionRunner(config)).resolves.toBe(safariRunner);
});
it('should return a WSL runner when `is-wsl` is true', async () => {
isWslMock.mockResolvedValueOnce(true);
const config = fakeInternalConfig({
browser: 'chrome',
});
const wslRunner = mock<ExtensionRunner>();
createWslRunnerMock.mockReturnValue(wslRunner);
await expect(createExtensionRunner(config)).resolves.toBe(wslRunner);
});
it('should return a manual runner when `runner.disabled` is true', async () => {
isWslMock.mockResolvedValueOnce(false);
const config = fakeInternalConfig({
browser: 'chrome',
runnerConfig: {
config: {
disabled: true,
},
},
});
const manualRunner = mock<ExtensionRunner>();
createManualRunnerMock.mockReturnValue(manualRunner);
await expect(createExtensionRunner(config)).resolves.toBe(manualRunner);
});
it('should return a web-ext runner otherwise', async () => {
const config = fakeInternalConfig({
browser: 'chrome',
runnerConfig: {
config: {
disabled: undefined,
},
},
});
const manualRunner = mock<ExtensionRunner>();
createWebExtRunnerMock.mockReturnValue(manualRunner);
await expect(createExtensionRunner(config)).resolves.toBe(manualRunner);
});
});
+18
View File
@@ -0,0 +1,18 @@
import { InternalConfig } from '../types';
import { ExtensionRunner } from './extension-runner';
import { createWslRunner } from './wsl';
import { createWebExtRunner } from './web-ext';
import { createSafariRunner } from './safari';
import { createManualRunner } from './manual';
import { isWsl } from '../utils/wsl';
export async function createExtensionRunner(
config: InternalConfig,
): Promise<ExtensionRunner> {
if (config.browser === 'safari') return createSafariRunner();
if (await isWsl()) return createWslRunner();
if (config.runnerConfig.config?.disabled) return createManualRunner();
return createWebExtRunner();
}
+21
View File
@@ -0,0 +1,21 @@
import { ExtensionRunner } from './extension-runner';
import { relative } from 'node:path';
/**
* The manual runner tells the user to load the unpacked extension manually.
*/
export function createManualRunner(): ExtensionRunner {
return {
async openBrowser(config) {
config.logger.info(
`Load "${relative(
process.cwd(),
config.outDir,
)}" as an unpacked extension manually`,
);
},
async closeBrowser() {
// noop
},
};
}
+21
View File
@@ -0,0 +1,21 @@
import { ExtensionRunner } from './extension-runner';
import { relative } from 'node:path';
/**
* The Safari runner just logs a warning message because `web-ext` doesn't work with Safari.
*/
export function createSafariRunner(): ExtensionRunner {
return {
async openBrowser(config) {
config.logger.warn(
`Cannot Safari using web-ext. Load "${relative(
process.cwd(),
config.outDir,
)}" as an unpacked extension manually`,
);
},
async closeBrowser() {
// noop
},
};
}
@@ -1,5 +1,5 @@
import type { WebExtRunInstance } from 'web-ext-run';
import { ExtensionRunner } from './ExtensionRunner';
import { ExtensionRunner } from './extension-runner';
/**
* Create an `ExtensionRunner` backed by `web-ext`.
@@ -9,10 +9,7 @@ export function createWebExtRunner(): ExtensionRunner {
return {
async openBrowser(config) {
if (config.browser === 'safari') {
config.logger.warn('Cannot open safari automatically.');
return;
}
config.logger.info('Opening browser...');
// Use the plugin's logger instead of web-ext's built-in one.
const webExtLogger = await import('web-ext-run/util/logger');
@@ -57,6 +54,8 @@ export function createWebExtRunner(): ExtensionRunner {
const webExt = await import('web-ext-run');
runner = await webExt.default.cmd.run(finalConfig, options);
config.logger.success('Opened!');
},
async closeBrowser() {
+21
View File
@@ -0,0 +1,21 @@
import { ExtensionRunner } from './extension-runner';
import { relative } from 'node:path';
/**
* The WSL runner just logs a warning message because `web-ext` doesn't work in WSL.
*/
export function createWslRunner(): ExtensionRunner {
return {
async openBrowser(config) {
config.logger.warn(
`Cannot open browser when using WSL. Load "${relative(
process.cwd(),
config.outDir,
)}" as an unpacked extension manually`,
);
},
async closeBrowser() {
// noop
},
};
}
+6 -6
View File
@@ -8,8 +8,8 @@ import * as vite from 'vite';
import { Scripting } from 'webextension-polyfill';
import { getEntrypointBundlePath } from './utils/entrypoints';
import { getContentScriptCssFiles } from './utils/manifest';
import { createWebExtRunner } from './runners/createWebExtRunner';
import { buildInternal } from './build';
import { createExtensionRunner } from './runners';
export async function getServerInfo(): Promise<ServerInfo> {
const { default: getPort, portNumbers } = await import('get-port');
@@ -34,10 +34,10 @@ export async function setupServer(
serverInfo: ServerInfo,
config: InternalConfig,
): Promise<WxtDevServer> {
const runner = createWebExtRunner();
const runner = await createExtensionRunner(config);
const viteServer = await vite.createServer(
vite.mergeConfig(serverInfo, config.vite),
vite.mergeConfig(serverInfo, await config.vite(config.env)),
);
const start = async () => {
@@ -45,9 +45,7 @@ export async function setupServer(
config.logger.success(`Started dev server @ ${serverInfo.origin}`);
server.currentOutput = await buildInternal(config);
config.logger.info('Opening browser...');
await runner.openBrowser(config);
config.logger.success('Opened!');
};
const reloadExtension = () => {
@@ -103,8 +101,10 @@ export function reloadContentScripts(
const js = [getEntrypointBundlePath(entry, config.outDir, '.js')];
const css = getContentScriptCssFiles([entry], server.currentOutput);
const { include: _1, exclude: _2, ...options } = entry.options;
server.reloadContentScript({
...entry.options,
...options,
js,
css,
});
+50 -5
View File
@@ -4,6 +4,7 @@ import { UnimportOptions } from 'unimport';
import { EntrypointGroup } from '.';
import { LogLevel } from 'consola';
import { ContentScriptContext } from '../../client/utils/ContentScriptContext';
import type { PluginVisualizerOptions } from 'rollup-plugin-visualizer';
export interface InlineConfig {
/**
@@ -84,13 +85,16 @@ export interface InlineConfig {
*/
logger?: Logger;
/**
* Custom Vite options, see <https://vitejs.dev/config/shared-options.html>.
* Return custom Vite options from a function. See
* <https://vitejs.dev/config/shared-options.html>.
*
* [`root`](#root), [`configFile`](#configfile), and [`mode`](#mode) should be set in WXT's config.
* [`root`](#root), [`configFile`](#configfile), and [`mode`](#mode) should be set in WXT's config
* instead of Vite's.
*
* This is a function because any vite plugins added need to be recreated for each individual
* build step, incase they have internal state causing them to fail when reused.
*/
vite?:
| WxtViteConfig
| ((env: ConfigEnv) => WxtViteConfig | Promise<WxtViteConfig>);
vite?: (env: ConfigEnv) => WxtViteConfig | Promise<WxtViteConfig>;
/**
* Customize the `manifest.json` output. Can be an object, promise, or function that returns an
* object or promise.
@@ -152,6 +156,41 @@ export interface InlineConfig {
*/
ignoredSources?: string[];
};
/**
* Transform the final manifest before it's written to the file system. Edit the `manifest`
* parameter directly, do not return a new object. Return values are ignored.
*
* @example
* defineConfig({
* // Add a CSS-only content script.
* transformManifest(manifest) {
* manifest.content_scripts.push({
* matches: ["*://google.com/*"],
* css: ["content-scripts/some-example.css"],
* });
* }
* })
*/
transformManifest?: (manifest: Manifest.WebExtensionManifest) => void;
analysis?: {
/**
* Explicitly include bundle analysis when running `wxt build`. This can be overridden by the
* command line `--analysis` option.
*
* @default false
*/
enabled?: boolean;
/**
* When running `wxt build --analyze` or setting `analysis.enabled` to true, customize how the
* bundle will be visualized. See
* [`rollup-plugin-visualizer`](https://github.com/btd/rollup-plugin-visualizer#how-to-use-generated-files)
* for more details.
*
* @default "treemap"
*/
template?: PluginVisualizerOptions['template'];
};
}
export interface WxtInlineViteConfig
@@ -439,6 +478,12 @@ export interface ConfigEnv {
* Configure how the browser starts up.
*/
export interface ExtensionRunnerConfig {
/**
* Whether or not to open the browser with the extension installed in dev mode.
*
* @default false
*/
disabled?: boolean;
/**
* @see https://extensionworkshop.com/documentation/develop/web-ext-command-reference/#browser-console
*/
+10 -1
View File
@@ -7,9 +7,12 @@ import {
TargetManifestVersion,
UserManifest,
ExtensionRunnerConfig,
ConfigEnv,
} from './external';
import { UnimportOptions } from 'unimport';
import { ResolvedConfig } from 'c12';
import { Manifest } from 'webextension-polyfill';
import type { PluginVisualizerOptions } from 'rollup-plugin-visualizer';
export interface InternalConfig {
root: string;
@@ -25,9 +28,10 @@ export interface InternalConfig {
command: 'build' | 'serve';
browser: TargetBrowser;
manifestVersion: TargetManifestVersion;
env: ConfigEnv;
logger: Logger;
imports: false | Partial<UnimportOptions>;
vite: vite.InlineConfig;
vite: (env: ConfigEnv) => Promise<vite.InlineConfig> | vite.InlineConfig;
manifest: UserManifest;
fsCache: FsCache;
server?: WxtDevServer;
@@ -39,6 +43,11 @@ export interface InternalConfig {
ignoredSources: string[];
sourcesRoot: string;
};
transformManifest: (manifest: Manifest.WebExtensionManifest) => void;
analysis: {
enabled: boolean;
template: NonNullable<PluginVisualizerOptions['template']>;
};
}
export type EntrypointGroup = Entrypoint | Entrypoint[];
+29 -21
View File
@@ -75,7 +75,8 @@ export async function getInternalConfig(
cwd: root,
globalRc: true,
rcFile: '.webextrc',
overrides: mergedConfig.runner,
overrides: inlineConfig.runner,
defaults: userConfig.runner,
});
const finalConfig: InternalConfig = {
@@ -83,6 +84,7 @@ export async function getInternalConfig(
command,
debug,
entrypointsDir,
env,
fsCache: createFsCache(wxtDir),
imports: mergedConfig.imports ?? {},
logger,
@@ -96,16 +98,21 @@ export async function getInternalConfig(
runnerConfig,
srcDir,
typesDir,
vite: {}, // Real value added after this object is initialized.
vite: () => ({}), // Real value added after this object is initialized.
wxtDir,
zip: resolveInternalZipConfig(root, mergedConfig),
transformManifest(manifest) {
userConfig.transformManifest?.(manifest);
inlineConfig.transformManifest?.(manifest);
},
analysis: {
enabled: mergedConfig.analysis?.enabled ?? false,
template: mergedConfig.analysis?.template ?? 'treemap',
},
};
finalConfig.vite = await resolveInternalViteConfig(
env,
mergedConfig,
finalConfig,
);
finalConfig.vite = (env) =>
resolveInternalViteConfig(env, mergedConfig, finalConfig);
return finalConfig;
}
@@ -143,9 +150,9 @@ function mergeInlineConfig(
return vite.mergeConfig(user, inline);
};
const viteConfig = async (env: ConfigEnv): Promise<WxtViteConfig> => {
const user = await resolveViteConfig(env, userConfig.vite);
const inline = await resolveViteConfig(env, inlineConfig.vite);
return vite.mergeConfig(user, inline);
const user = await userConfig.vite?.(env);
const inline = await inlineConfig.vite?.(env);
return vite.mergeConfig(user ?? {}, inline ?? {});
};
const runner: InlineConfig['runner'] = vite.mergeConfig(
userConfig.runner ?? {},
@@ -172,16 +179,14 @@ function mergeInlineConfig(
srcDir: inlineConfig.srcDir ?? userConfig.srcDir,
vite: viteConfig,
zip,
analysis: {
enabled: inlineConfig.analysis?.enabled ?? userConfig.analysis?.enabled,
template:
inlineConfig.analysis?.template ?? userConfig.analysis?.template,
},
};
}
async function resolveViteConfig(
env: ConfigEnv,
vite: InlineConfig['vite'],
): Promise<WxtViteConfig> {
return await (typeof vite === 'function' ? vite(env) : vite ?? {});
}
function resolveInternalZipConfig(
root: string,
mergedConfig: InlineConfig,
@@ -211,13 +216,13 @@ async function resolveInternalViteConfig(
mergedConfig: InlineConfig,
finalConfig: InternalConfig,
) {
const internalVite: vite.InlineConfig = await resolveViteConfig(
env,
mergedConfig.vite,
);
const internalVite: vite.InlineConfig =
(await mergedConfig.vite?.(env)) ?? {};
internalVite.root = finalConfig.root;
internalVite.configFile = false;
internalVite.logLevel = 'warn';
internalVite.mode = env.mode;
internalVite.build ??= {};
internalVite.build.outDir = finalConfig.outDir;
@@ -236,6 +241,9 @@ async function resolveInternalViteConfig(
internalVite.plugins.push(plugins.devServerGlobals(finalConfig));
internalVite.plugins.push(plugins.tsconfigPaths(finalConfig));
internalVite.plugins.push(plugins.noopBackground());
if (finalConfig.analysis.enabled) {
internalVite.plugins.push(plugins.bundleAnalysis());
}
internalVite.define ??= {};
for (const global of getGlobals(finalConfig)) {
+19 -5
View File
@@ -1,12 +1,12 @@
import createJITI from 'jiti';
import createJITI, { TransformOptions as JitiTransformOptions } from 'jiti';
import { InternalConfig } from '../types';
import { createUnimport } from 'unimport';
import fs from 'fs-extra';
import { resolve } from 'path';
import transform from 'jiti/dist/babel';
import { getUnimportOptions } from './auto-imports';
import { removeProjectImportStatements } from './strings';
import { normalizePath } from './paths';
import { TransformOptions, transformSync } from 'esbuild';
/**
* Get the value from the default export of a `path`.
@@ -47,6 +47,7 @@ export async function importEntrypointFile<T>(
const jiti = createJITI(__filename, {
cache: false,
debug: config.debug,
esmResolve: true,
interopDefault: true,
alias: {
@@ -55,10 +56,14 @@ export async function importEntrypointFile<T>(
'node_modules/wxt/dist/virtual-modules/fake-browser.js',
),
},
extensions: ['.ts', '.tsx', '.cjs', '.js', '.mjs'],
transform(opts) {
if (opts.filename === normalPath)
return transform({ ...opts, source: code });
else return transform(opts);
const isEntrypoint = opts.filename === normalPath;
return transformSync(
// Use modified source code for entrypoints
isEntrypoint ? code : opts.source,
getEsbuildOptions(opts),
);
},
});
@@ -69,3 +74,12 @@ export async function importEntrypointFile<T>(
throw err;
}
}
function getEsbuildOptions(opts: JitiTransformOptions): TransformOptions {
const isJsx = opts.filename?.endsWith('x');
return {
format: 'cjs',
loader: isJsx ? 'tsx' : 'ts',
jsx: isJsx ? 'automatic' : undefined,
};
}
+2 -1
View File
@@ -19,6 +19,7 @@ import {
import { getPackageJson } from './package';
import { normalizePath } from './paths';
import { writeFileIfDifferent } from './fs';
import { produce } from 'immer';
/**
* Writes the manifest to the output directory and the build output.
@@ -89,7 +90,7 @@ export async function generateMainfest(
);
}
return manifest;
return produce(manifest, config.transformManifest);
}
/**
+7
View File
@@ -0,0 +1,7 @@
/**
* Returns true when running on WSL or WSL2.
*/
export async function isWsl(): Promise<boolean> {
const { default: isWsl } = await import('is-wsl'); // ESM only, requires dynamic import
return isWsl;
}
+12
View File
@@ -0,0 +1,12 @@
import * as vite from 'vite';
import { visualizer } from 'rollup-plugin-visualizer';
let increment = 0;
export function bundleAnalysis(): vite.Plugin {
return visualizer({
emitFile: true,
template: 'raw-data',
filename: `stats-${increment++}.json`,
}) as vite.Plugin;
}
+1
View File
@@ -7,3 +7,4 @@ export * from './virtualEntrypoint';
export * from './tsconfigPaths';
export * from './noopBackground';
export * from './cssEntrypoints';
export * from './bundleAnalysis';
+1 -1
View File
@@ -41,7 +41,7 @@ export async function createServer(
return getInternalConfig(
{
...config,
vite: serverInfo.viteServerConfig,
vite: () => serverInfo.viteServerConfig,
},
'serve',
);
+44 -31
View File
@@ -198,34 +198,47 @@ export function fakeArray<T>(createItem: () => T, count = 3): T[] {
return array;
}
export const fakeInternalConfig = fakeObjectCreator<InternalConfig>(() => ({
browser: faker.helpers.arrayElement(['chrome', 'firefox']),
command: faker.helpers.arrayElement(['build', 'serve']),
entrypointsDir: fakeDir(),
fsCache: mock<FsCache>(),
imports: {},
logger: mock(),
manifest: fakeManifest(),
manifestVersion: faker.helpers.arrayElement([2, 3]),
mode: faker.helpers.arrayElement(['development', 'production']),
outBaseDir: fakeDir(),
outDir: fakeDir(),
publicDir: fakeDir(),
root: fakeDir(),
runnerConfig: {
config: {},
},
debug: faker.datatype.boolean(),
srcDir: fakeDir(),
typesDir: fakeDir(),
vite: {},
wxtDir: fakeDir(),
server: mock<WxtDevServer>(),
zip: {
artifactTemplate: '{{name}}-{{version}}.zip',
ignoredSources: [],
sourcesRoot: fakeDir(),
sourcesTemplate: '{{name}}-sources.zip',
name: faker.person.firstName().toLowerCase(),
},
}));
export const fakeInternalConfig = fakeObjectCreator<InternalConfig>(() => {
const browser = faker.helpers.arrayElement(['chrome', 'firefox']);
const command = faker.helpers.arrayElement(['build', 'serve'] as const);
const manifestVersion = faker.helpers.arrayElement([2, 3] as const);
const mode = faker.helpers.arrayElement(['development', 'production']);
return {
browser,
command,
entrypointsDir: fakeDir(),
env: { browser, command, manifestVersion, mode },
fsCache: mock<FsCache>(),
imports: {},
logger: mock(),
manifest: fakeManifest(),
manifestVersion,
mode,
outBaseDir: fakeDir(),
outDir: fakeDir(),
publicDir: fakeDir(),
root: fakeDir(),
runnerConfig: {
config: {},
},
debug: faker.datatype.boolean(),
srcDir: fakeDir(),
typesDir: fakeDir(),
vite: () => ({}),
wxtDir: fakeDir(),
server: mock<WxtDevServer>(),
analysis: {
enabled: false,
template: 'treemap',
},
zip: {
artifactTemplate: '{{name}}-{{version}}.zip',
ignoredSources: [],
sourcesRoot: fakeDir(),
sourcesTemplate: '{{name}}-sources.zip',
name: faker.person.firstName().toLowerCase(),
},
transformManifest: () => {},
};
});
+3
View File
@@ -9,6 +9,9 @@ lerna-debug.log*
node_modules
.output
stats.html
.wxt
web-ext.config.ts
# Editor directories and files
.vscode/*
+2 -2
View File
@@ -3,7 +3,7 @@ import react from '@vitejs/plugin-react';
// See https://wxt.dev/config.html
export default defineConfig({
vite: {
vite: () => ({
plugins: [react()],
},
}),
});
+3
View File
@@ -9,6 +9,9 @@ lerna-debug.log*
node_modules
.output
stats.html
.wxt
web-ext.config.ts
# Editor directories and files
.vscode/*
+2 -2
View File
@@ -3,10 +3,10 @@ import Solid from 'vite-plugin-solid';
// See https://wxt.dev/config.html
export default defineConfig({
vite: {
vite: () => ({
build: {
target: 'esnext',
},
plugins: [Solid()],
},
}),
});
+3
View File
@@ -9,6 +9,9 @@ lerna-debug.log*
node_modules
.output
stats.html
.wxt
web-ext.config.ts
# Editor directories and files
.vscode/*
+2 -2
View File
@@ -4,7 +4,7 @@ import { svelte, vitePreprocess } from '@sveltejs/vite-plugin-svelte';
// See https://wxt.dev/config.html
export default defineConfig({
srcDir: 'src',
vite: {
vite: () => ({
plugins: [
svelte({
// Using a svelte.config.js file causes a segmentation fault when importing the file
@@ -12,5 +12,5 @@ export default defineConfig({
preprocess: [vitePreprocess()],
}),
],
},
}),
});
+3
View File
@@ -9,6 +9,9 @@ lerna-debug.log*
node_modules
.output
stats.html
.wxt
web-ext.config.ts
# Editor directories and files
.vscode/*
+3
View File
@@ -9,6 +9,9 @@ lerna-debug.log*
node_modules
.output
stats.html
.wxt
web-ext.config.ts
# Editor directories and files
.vscode/*
+2 -2
View File
@@ -3,7 +3,7 @@ import vue from '@vitejs/plugin-vue';
// See https://wxt.dev/config.html
export default defineConfig({
vite: {
vite: () => ({
plugins: [vue()],
},
}),
});
-5
View File
@@ -1,5 +0,0 @@
{
"github": {
"silent": true
}
}
+1 -1
View File
@@ -33,7 +33,7 @@ export default defineWorkspace([
name: 'e2e',
dir: 'e2e',
singleThread: true,
testTimeout: 60e3,
testTimeout: 120e3,
},
plugins: [testSeed()],
},