Compare commits

..

12 Commits

Author SHA1 Message Date
GitHub Actions 145038c6a2 chore(release): v0.1.2 2023-07-11 14:45:39 +00:00
Aaron Klinker 6e7184d98d fix: Generate valid type for EntrypointPath when there are no entrypoints 2023-07-11 09:42:08 -05:00
Aaron Klinker ee49837804 feat: Accept a function for config.manifest 2023-07-11 09:41:43 -05:00
Aaron Klinker 67f972eab8 Remove milestone warning from README 2023-07-10 23:19:27 -05:00
Aaron Klinker b29c3c6fdd fix: Only add imports to JS files 2023-07-10 23:19:13 -05:00
Aaron Klinker ef6001e0c0 types: Change config.vite to UserConfig 2023-07-10 23:00:30 -05:00
Aaron Klinker 636aa48e95 fix: Add missing types for webextension-polyfill and the manifest option 2023-07-10 22:55:40 -05:00
Aaron Klinker ec66b6172c Update changelog after release 2023-07-10 22:22:31 -05:00
GitHub Actions 1edd94e8f4 chore(release): v0.1.1 2023-07-11 03:21:27 +00:00
Aaron 2efc193b45 fix: Unable to read entrypoint options (#28) 2023-07-10 22:18:20 -05:00
Aaron Klinker 2e51e7349d fix: Allow dashes in entrypoint names 2023-07-10 22:16:08 -05:00
Aaron Klinker 28733df5f9 chore: Update changelog after release 2023-07-10 18:34:55 -05:00
18 changed files with 368 additions and 172 deletions
+1
View File
@@ -1,3 +1,4 @@
.output
coverage
dist
e2e/project
+42 -8
View File
@@ -1,13 +1,54 @@
# Changelog
## v0.1.2
[compare changes](https://github.com/aklinker1/wxt/compare/v0.1.1...v0.1.2)
### 🚀 Enhancements
- Accept a function for `config.manifest` ([ee49837](https://github.com/aklinker1/wxt/commit/ee49837))
### 🩹 Fixes
- Add missing types for `webextension-polyfill` and the `manifest` option ([636aa48](https://github.com/aklinker1/wxt/commit/636aa48))
- Only add imports to JS files ([b29c3c6](https://github.com/aklinker1/wxt/commit/b29c3c6))
- Generate valid type for `EntrypointPath` when there are no entrypoints ([6e7184d](https://github.com/aklinker1/wxt/commit/6e7184d))
### 🌊 Types
- Change `config.vite` to `UserConfig` ([ef6001e](https://github.com/aklinker1/wxt/commit/ef6001e))
### ❤️ Contributors
- Aaron Klinker
## v0.1.1
[compare changes](https://github.com/aklinker1/wxt/compare/v0.1.0...v0.1.1)
### 🩹 Fixes
- Allow dashes in entrypoint names ([2e51e73](https://github.com/aklinker1/wxt/commit/2e51e73))
- Unable to read entrypoint options ([#28](https://github.com/aklinker1/wxt/pull/28))
### ❤️ Contributors
- Aaron Klinker
## v0.1.0
Initial release of WXT. Full support for production builds and initial toolkit for development:
- HMR support when HTML page dependencies change
- Reload extension when background changes
- Reload HTML pages when saving them directly
- Re-register and reload tabs when content scripts change
[compare changes](https://github.com/aklinker1/wxt/compare/v0.0.2...v0.1.0)
### 🚀 Enhancements
- Content scripts reloading ([#25](https://github.com/aklinker1/wxt/pull/25))
- ⚠️ Initial release ([afe838a](https://github.com/aklinker1/wxt/commit/afe838a))
### 📖 Documentation
@@ -17,14 +58,9 @@
- Create github release ([b7c078f](https://github.com/aklinker1/wxt/commit/b7c078f))
#### ⚠️ Breaking Changes
- ⚠️ Initial release ([afe838a](https://github.com/aklinker1/wxt/commit/afe838a))
### ❤️ Contributors
- Aaron Klinker
- Aaron
## v0.0.2
@@ -51,7 +87,6 @@
### 🏡 Chore
- Update changelog ([a9af4d3](https://github.com/aklinker1/wxt/commit/a9af4d3))
- Refactor build output type ([#19](https://github.com/aklinker1/wxt/pull/19))
- Refactor build outputs to support transpiled templates ([a78aada](https://github.com/aklinker1/wxt/commit/a78aada))
- Rename `templates` to `virtual-modules` ([#24](https://github.com/aklinker1/wxt/pull/24))
@@ -60,7 +95,6 @@
### ❤️ Contributors
- Aaron Klinker
- Aaron
## v0.0.1
-8
View File
@@ -4,14 +4,6 @@
![Example CLI Output](./.github/assets/cli-output.png)
> **Warning**
>
> [![GitHub milestone](https://img.shields.io/github/milestones/progress-percent/aklinker1/wxt/1)](https://github.com/aklinker1/wxt/milestone/1)
>
> WXT is not ready for use yet. Production builds work, but dev mode is incomplete.
>
> See the [Initial Release Candidate](https://github.com/aklinker1/wxt/milestone/1) milestone for more details.
## Features
- 🌐 Supports all browsers
+24
View File
@@ -69,4 +69,28 @@ describe('Output Directory Structure', () => {
{\\"manifest_version\\":3,\\"name\\":\\"E2E Extension\\",\\"version\\":\\"0.0.0\\",\\"version_name\\":\\"0.0.0-test\\",\\"content_scripts\\":[{\\"matches\\":[\\"*://*/*\\"],\\"css\\":[\\"assets/one.css\\",\\"assets/two.css\\"],\\"js\\":[\\"content-scripts/one.js\\",\\"content-scripts/two.js\\"]}]}"
`);
});
it('should allow inputs with invalid JS variable names, like dashes', async () => {
const project = new TestProject();
project.addFile(
'entrypoints/overlay-one.content.ts',
`export default defineContentScript({
matches: ["*://*/*"],
main: () => {},
})`,
);
await project.build();
expect(await project.serializeOutput()).toMatchInlineSnapshot(`
".output/chrome-mv3/content-scripts/overlay-one.js
----------------------------------------
(function(){\\"use strict\\";function i(n){return n}const o={matches:[\\"*://*/*\\"],main:()=>{}};function t(n,...e){if(typeof e[0]==\\"string\\"){const c=e.shift();n(\`[wxt] \${c}\`,...e)}else n(\\"[wxt]\\",...e)}var r={debug:(...n)=>t(console.debug,...n),log:(...n)=>t(console.log,...n),warn:(...n)=>t(console.warn,...n),error:(...n)=>t(console.error,...n)};(async()=>{try{await o.main()}catch(n){r.error(\\"The content script crashed on startup!\\",n)}})()})();
================================================================================
.output/chrome-mv3/manifest.json
----------------------------------------
{\\"manifest_version\\":3,\\"name\\":\\"E2E Extension\\",\\"version\\":\\"0.0.0\\",\\"version_name\\":\\"0.0.0-test\\",\\"content_scripts\\":[{\\"matches\\":[\\"*://*/*\\"],\\"js\\":[\\"content-scripts/overlay-one.js\\"]}]}"
`);
});
});
+23
View File
@@ -55,4 +55,27 @@ describe('User Config', () => {
{\\"manifest_version\\":3,\\"name\\":\\"E2E Extension\\",\\"version\\":\\"0.0.0\\",\\"version_name\\":\\"0.0.0-test\\",\\"background\\":{\\"service_worker\\":\\"background.js\\"}}"
`);
});
it('should accept a function for a manifest', async () => {
const project = new TestProject();
await project.build({
// @ts-expect-error: Specifically setting an invalid field for the test - it should show up in the snapshot
manifest: ({ mode, browser, manifestVersion, command }) => ({
example_customization: [
mode,
browser,
String(manifestVersion),
command,
],
}),
});
const output = await project.serializeOutput();
expect(output).toMatchInlineSnapshot(`
".output/chrome-mv3/manifest.json
----------------------------------------
{\\"manifest_version\\":3,\\"name\\":\\"E2E Extension\\",\\"version\\":\\"0.0.0\\",\\"version_name\\":\\"0.0.0-test\\",\\"example_customization\\":[\\"production\\",\\"chrome\\",\\"3\\",\\"build\\"]}"
`);
});
});
+4 -2
View File
@@ -1,7 +1,7 @@
{
"name": "wxt",
"type": "module",
"version": "0.1.0",
"version": "0.1.2",
"description": "Next gen framework for developing web extensions",
"repository": {
"type": "git",
@@ -52,6 +52,8 @@
"prepublish": "pnpm -s build"
},
"dependencies": {
"@types/webextension-polyfill": "^0.10.0",
"@webext-core/fake-browser": "^1.2.2",
"@webext-core/match-patterns": "^1.0.1",
"async-mutex": "^0.4.0",
"c12": "^1.4.2",
@@ -76,7 +78,6 @@
"@types/lodash.merge": "^4.6.7",
"@types/node": "^20.3.1",
"@types/picomatch": "^2.3.0",
"@types/webextension-polyfill": "^0.10.0",
"@vitest/coverage-v8": "^0.32.2",
"lodash.merge": "^4.6.2",
"npm-run-all": "^4.1.5",
@@ -88,6 +89,7 @@
"tsx": "^3.12.7",
"typescript": "^5.1.3",
"vitest": "^0.32.4",
"vitest-mock-extended": "^1.1.4",
"webextension-polyfill": "^0.10.0"
},
"peerDependencies": {
+111 -74
View File
@@ -10,6 +10,7 @@ importers:
'@types/picomatch': ^2.3.0
'@types/webextension-polyfill': ^0.10.0
'@vitest/coverage-v8': ^0.32.2
'@webext-core/fake-browser': ^1.2.2
'@webext-core/match-patterns': ^1.0.1
async-mutex: ^0.4.0
c12: ^1.4.2
@@ -35,9 +36,12 @@ importers:
unimport: ^3.0.8
vite: ^4.3.9
vitest: ^0.32.4
vitest-mock-extended: ^1.1.4
web-ext: ^7.6.2
webextension-polyfill: ^0.10.0
dependencies:
'@types/webextension-polyfill': 0.10.0
'@webext-core/fake-browser': 1.2.2
'@webext-core/match-patterns': 1.0.1
async-mutex: 0.4.0
c12: 1.4.2
@@ -61,7 +65,6 @@ importers:
'@types/lodash.merge': 4.6.7
'@types/node': 20.3.1
'@types/picomatch': 2.3.0
'@types/webextension-polyfill': 0.10.0
'@vitest/coverage-v8': 0.32.2_vitest@0.32.4
lodash.merge: 4.6.2
npm-run-all: 4.1.5
@@ -73,6 +76,7 @@ importers:
tsx: 3.12.7
typescript: 5.1.3
vitest: 0.32.4
vitest-mock-extended: 1.1.4_ekuvgbe6yxmpeqet3xraeb3oaa
demo:
specifiers:
@@ -220,10 +224,10 @@ packages:
requiresBuild: true
optional: true
/@esbuild/android-arm/0.18.5:
/@esbuild/android-arm/0.18.11:
resolution:
{
integrity: sha512-+8GXQzuASxGg/rb47Z5zJe3vjOfL7RRce/DILuk6kbB/8HO0p3CPo72CbR349P2K8YP1h5NvNqU+2GDRbNJylw==,
integrity: sha512-q4qlUf5ucwbUJZXF5tEQ8LF7y0Nk4P58hOsGk3ucY0oCwgQqAnqXVbUuahCddVHfrxmpyewRpiTHwVHIETYu7Q==,
}
engines: { node: '>=12' }
cpu: [arm]
@@ -243,10 +247,10 @@ packages:
requiresBuild: true
optional: true
/@esbuild/android-arm64/0.18.5:
/@esbuild/android-arm64/0.18.11:
resolution:
{
integrity: sha512-410IPUj7ZOxZ2dwK0B7o7Nibu7YEyaLBvYOfYBpuA1TpY0fOkDM5r4bwn+hT8Uma06DBI4RnYNN09fn55PYInQ==,
integrity: sha512-snieiq75Z1z5LJX9cduSAjUr7vEI1OdlzFPMw0HH5YI7qQHDd3qs+WZoMrWYDsfRJSq36lIA6mfZBkvL46KoIw==,
}
engines: { node: '>=12' }
cpu: [arm64]
@@ -266,10 +270,10 @@ packages:
requiresBuild: true
optional: true
/@esbuild/android-x64/0.18.5:
/@esbuild/android-x64/0.18.11:
resolution:
{
integrity: sha512-+fdfceCYwcz9OReheSWYOGaAAt03n0BnG5/UW9tyGyo15PjSOF14ylxfjvz+0atDx0S/RxyezMsH/mbnWhnC8w==,
integrity: sha512-iPuoxQEV34+hTF6FT7om+Qwziv1U519lEOvekXO9zaMMlT9+XneAhKL32DW3H7okrCOBQ44BMihE8dclbZtTuw==,
}
engines: { node: '>=12' }
cpu: [x64]
@@ -289,10 +293,10 @@ packages:
requiresBuild: true
optional: true
/@esbuild/darwin-arm64/0.18.5:
/@esbuild/darwin-arm64/0.18.11:
resolution:
{
integrity: sha512-L7noeTaus5xEtgd5J7u/lGrZfSiYkvZb0gOD7rvKTuuWbdGM4bunz5DUFsWBbEIlloslpOO5PDy4Hnd6mZT20A==,
integrity: sha512-Gm0QkI3k402OpfMKyQEEMG0RuW2LQsSmI6OeO4El2ojJMoF5NLYb3qMIjvbG/lbMeLOGiW6ooU8xqc+S0fgz2w==,
}
engines: { node: '>=12' }
cpu: [arm64]
@@ -312,10 +316,10 @@ packages:
requiresBuild: true
optional: true
/@esbuild/darwin-x64/0.18.5:
/@esbuild/darwin-x64/0.18.11:
resolution:
{
integrity: sha512-eA39B8SxbxRdSSILD4AsePzvJiVao6ZaYrcTOJqg89jnnMEGR/EAh+ehV7E4GOx4WXQoWeJRP1P9JQSzIrROeg==,
integrity: sha512-N15Vzy0YNHu6cfyDOjiyfJlRJCB/ngKOAvoBf1qybG3eOq0SL2Lutzz9N7DYUbb7Q23XtHPn6lMDF6uWbGv9Fw==,
}
engines: { node: '>=12' }
cpu: [x64]
@@ -335,10 +339,10 @@ packages:
requiresBuild: true
optional: true
/@esbuild/freebsd-arm64/0.18.5:
/@esbuild/freebsd-arm64/0.18.11:
resolution:
{
integrity: sha512-Eg1UnkTZHfsphgcy1Wj/McNModSO/F+kqtWqvtvEZc9BAgvdwxAt11BESgBczU+Gti0G2dLvHs0Sfb3gavwhGg==,
integrity: sha512-atEyuq6a3omEY5qAh5jIORWk8MzFnCpSTUruBgeyN9jZq1K/QI9uke0ATi3MHu4L8c59CnIi4+1jDKMuqmR71A==,
}
engines: { node: '>=12' }
cpu: [arm64]
@@ -358,10 +362,10 @@ packages:
requiresBuild: true
optional: true
/@esbuild/freebsd-x64/0.18.5:
/@esbuild/freebsd-x64/0.18.11:
resolution:
{
integrity: sha512-GNTMSJ55gl7Tf5VUqVRkMJhRGzH6vI9vFBfZCj4Zjm7RgfXCWxLnTyjMgZZKT8pOzW40KD2KlrGbqwnnJWyGWw==,
integrity: sha512-XtuPrEfBj/YYYnAAB7KcorzzpGTvOr/dTtXPGesRfmflqhA4LMF0Gh/n5+a9JBzPuJ+CGk17CA++Hmr1F/gI0Q==,
}
engines: { node: '>=12' }
cpu: [x64]
@@ -381,10 +385,10 @@ packages:
requiresBuild: true
optional: true
/@esbuild/linux-arm/0.18.5:
/@esbuild/linux-arm/0.18.11:
resolution:
{
integrity: sha512-6R+vEIyfEvp+gOWKSc+m6hdnhWKQYzicqONQYiDGT6qepc6OGsLEZcyFwoz6BvFx5j233CBWMcJ69eXFrwXw9A==,
integrity: sha512-Idipz+Taso/toi2ETugShXjQ3S59b6m62KmLHkJlSq/cBejixmIydqrtM2XTvNCywFl3VC7SreSf6NV0i6sRyg==,
}
engines: { node: '>=12' }
cpu: [arm]
@@ -404,10 +408,10 @@ packages:
requiresBuild: true
optional: true
/@esbuild/linux-arm64/0.18.5:
/@esbuild/linux-arm64/0.18.11:
resolution:
{
integrity: sha512-r08LmhqyPRj6FtuNPBTu8BliKh6h+oNEhMkWmmR/aWs4DWjDOivyDfLGznPdgtSThL23fk1QgSBUEbuCIzjA2A==,
integrity: sha512-c6Vh2WS9VFKxKZ2TvJdA7gdy0n6eSy+yunBvv4aqNCEhSWVor1TU43wNRp2YLO9Vng2G+W94aRz+ILDSwAiYog==,
}
engines: { node: '>=12' }
cpu: [arm64]
@@ -427,10 +431,10 @@ packages:
requiresBuild: true
optional: true
/@esbuild/linux-ia32/0.18.5:
/@esbuild/linux-ia32/0.18.11:
resolution:
{
integrity: sha512-ph6M9iEMc6BHgv2XuIE8qeQrQCH+2l116c8L9ysmmXYwpNXa3E7JNIu/O7hI0I9qDvh1P19AGbIh+/y0GAZijA==,
integrity: sha512-S3hkIF6KUqRh9n1Q0dSyYcWmcVa9Cg+mSoZEfFuzoYXXsk6196qndrM+ZiHNwpZKi3XOXpShZZ+9dfN5ykqjjw==,
}
engines: { node: '>=12' }
cpu: [ia32]
@@ -450,10 +454,10 @@ packages:
requiresBuild: true
optional: true
/@esbuild/linux-loong64/0.18.5:
/@esbuild/linux-loong64/0.18.11:
resolution:
{
integrity: sha512-s6Nup5FMQ8R8OKJG2rSxtV40s8LRdfC73XGHGaFlGiC+2SeCyq4dl3MMfLdzLowYzyDjfc4GRrXWUNMX3kNxYA==,
integrity: sha512-MRESANOoObQINBA+RMZW+Z0TJWpibtE7cPFnahzyQHDCA9X9LOmGh68MVimZlM9J8n5Ia8lU773te6O3ILW8kw==,
}
engines: { node: '>=12' }
cpu: [loong64]
@@ -473,10 +477,10 @@ packages:
requiresBuild: true
optional: true
/@esbuild/linux-mips64el/0.18.5:
/@esbuild/linux-mips64el/0.18.11:
resolution:
{
integrity: sha512-DxW4nNDIGbivZxnJD01C5PlwKPpin8YgSwWtToCy4w4lNigT7Iaf5A+wcPT2laibdgbcgPKpPOXUg6RFGTt8xA==,
integrity: sha512-qVyPIZrXNMOLYegtD1u8EBccCrBVshxMrn5MkuFc3mEVsw7CCQHaqZ4jm9hbn4gWY95XFnb7i4SsT3eflxZsUg==,
}
engines: { node: '>=12' }
cpu: [mips64el]
@@ -496,10 +500,10 @@ packages:
requiresBuild: true
optional: true
/@esbuild/linux-ppc64/0.18.5:
/@esbuild/linux-ppc64/0.18.11:
resolution:
{
integrity: sha512-BksOs2uYTafS+u75QiN4RoLbEMNjE192adJCBalncI3E2PWyR2i1kEs9rEghHK7pw0SD0uWgV9otRmV7G5b2lQ==,
integrity: sha512-T3yd8vJXfPirZaUOoA9D2ZjxZX4Gr3QuC3GztBJA6PklLotc/7sXTOuuRkhE9W/5JvJP/K9b99ayPNAD+R+4qQ==,
}
engines: { node: '>=12' }
cpu: [ppc64]
@@ -519,10 +523,10 @@ packages:
requiresBuild: true
optional: true
/@esbuild/linux-riscv64/0.18.5:
/@esbuild/linux-riscv64/0.18.11:
resolution:
{
integrity: sha512-mGv8BOJXsV7bZyjyMdeDs55CDXZ5vrY3oKa58DNRz2vPn54dREyj4BhhyWuqSuzSURJhFg7pM/1fI2vnAHGkHw==,
integrity: sha512-evUoRPWiwuFk++snjH9e2cAjF5VVSTj+Dnf+rkO/Q20tRqv+644279TZlPK8nUGunjPAtQRCj1jQkDAvL6rm2w==,
}
engines: { node: '>=12' }
cpu: [riscv64]
@@ -542,10 +546,10 @@ packages:
requiresBuild: true
optional: true
/@esbuild/linux-s390x/0.18.5:
/@esbuild/linux-s390x/0.18.11:
resolution:
{
integrity: sha512-m4uIYyrl5znGnNHgiM/Zsw6I9Se513NqdTxeUxZ66/VDWbuUp8ACe1KOSpwF4NNxfYy6Q3W8beZsIdF4F85q8Q==,
integrity: sha512-/SlRJ15XR6i93gRWquRxYCfhTeC5PdqEapKoLbX63PLCmAkXZHY2uQm2l9bN0oPHBsOw2IswRZctMYS0MijFcg==,
}
engines: { node: '>=12' }
cpu: [s390x]
@@ -565,10 +569,10 @@ packages:
requiresBuild: true
optional: true
/@esbuild/linux-x64/0.18.5:
/@esbuild/linux-x64/0.18.11:
resolution:
{
integrity: sha512-R1C7X30YjXmOZYOzx4dJ/QvRNfrkK/sDCFfcGNhlHFX6B/iodJdk81h7EhnKVUQy+3BaARxF7udd91iSSzMlbQ==,
integrity: sha512-xcncej+wF16WEmIwPtCHi0qmx1FweBqgsRtEL1mSHLFR6/mb3GEZfLQnx+pUDfRDEM4DQF8dpXIW7eDOZl1IbA==,
}
engines: { node: '>=12' }
cpu: [x64]
@@ -588,10 +592,10 @@ packages:
requiresBuild: true
optional: true
/@esbuild/netbsd-x64/0.18.5:
/@esbuild/netbsd-x64/0.18.11:
resolution:
{
integrity: sha512-MABnKzjMcXjO0NEYyexOhqjcrgM6dE8BXnm+lctm2x2aPpYg5iL0Ew3aABSTZyp9dS3Z4VzFu5PPoOYEw8akTQ==,
integrity: sha512-aSjMHj/F7BuS1CptSXNg6S3M4F3bLp5wfFPIJM+Km2NfIVfFKhdmfHF9frhiCLIGVzDziggqWll0B+9AUbud/Q==,
}
engines: { node: '>=12' }
cpu: [x64]
@@ -611,10 +615,10 @@ packages:
requiresBuild: true
optional: true
/@esbuild/openbsd-x64/0.18.5:
/@esbuild/openbsd-x64/0.18.11:
resolution:
{
integrity: sha512-aU7R0tLIUMaQuAgBjKrq02Z98rcY9Pxk76hynSqcGeld2C/ro1uBbS2i9rh7vdwBAY0rG08Og4wnDnlx5rU+fQ==,
integrity: sha512-tNBq+6XIBZtht0xJGv7IBB5XaSyvYPCm1PxJ33zLQONdZoLVM0bgGqUrXnJyiEguD9LU4AHiu+GCXy/Hm9LsdQ==,
}
engines: { node: '>=12' }
cpu: [x64]
@@ -634,10 +638,10 @@ packages:
requiresBuild: true
optional: true
/@esbuild/sunos-x64/0.18.5:
/@esbuild/sunos-x64/0.18.11:
resolution:
{
integrity: sha512-ngm3fVv2VxufI8zH/Phk0mYkgvFjFGnS+l7uxxd20mmeLTNI/8OXDJpNqTUbvzJh3tqhI/Gof0N2+5xJbqEaxA==,
integrity: sha512-kxfbDOrH4dHuAAOhr7D7EqaYf+W45LsAOOhAet99EyuxxQmjbk8M9N4ezHcEiCYPaiW8Dj3K26Z2V17Gt6p3ng==,
}
engines: { node: '>=12' }
cpu: [x64]
@@ -657,10 +661,10 @@ packages:
requiresBuild: true
optional: true
/@esbuild/win32-arm64/0.18.5:
/@esbuild/win32-arm64/0.18.11:
resolution:
{
integrity: sha512-XqpS89+MGLzR8YtQQkBYsLCfAv1ySflMb+FEH99rOp6kOPv/ORO+ujEB5ICDBZZbvYqB75uFrNELo1BVEQbS3g==,
integrity: sha512-Sh0dDRyk1Xi348idbal7lZyfSkjhJsdFeuC13zqdipsvMetlGiFQNdO+Yfp6f6B4FbyQm7qsk16yaZk25LChzg==,
}
engines: { node: '>=12' }
cpu: [arm64]
@@ -680,10 +684,10 @@ packages:
requiresBuild: true
optional: true
/@esbuild/win32-ia32/0.18.5:
/@esbuild/win32-ia32/0.18.11:
resolution:
{
integrity: sha512-V3xj/nb9uie0I4mn1f8nPZSgHldtNJrqTKYjTyMPMBnHbMYF5Loz8ZHsp7+La8kI6NxIF1ClQ9XBV+G3RtSkww==,
integrity: sha512-o9JUIKF1j0rqJTFbIoF4bXj6rvrTZYOrfRcGyL0Vm5uJ/j5CkBD/51tpdxe9lXEDouhRgdr/BYzUrDOvrWwJpg==,
}
engines: { node: '>=12' }
cpu: [ia32]
@@ -703,10 +707,10 @@ packages:
requiresBuild: true
optional: true
/@esbuild/win32-x64/0.18.5:
/@esbuild/win32-x64/0.18.11:
resolution:
{
integrity: sha512-gMxWvQeTQWDpa8ExPP41al+Ho7HyK24h7y41JdGKqE24KzXXQPxESUtrCoIES+HwF+OGq2smtibU9UvZ8WH3JQ==,
integrity: sha512-rQI4cjLHd2hGsM1LqgDI7oOCYbQ6IBOVsX9ejuRMSze0GqXUG2ekwiKkiBU1pRGSeCqFFHxTrcEydB2Hyoz9CA==,
}
engines: { node: '>=12' }
cpu: [x64]
@@ -1080,7 +1084,6 @@ packages:
{
integrity: sha512-If4EcaHzYTqcbNMp/FdReVdRmLL/Te42ivnJII551bYjhX19bWem5m14FERCqdJA732OloGuxCRvLBvcMGsn4A==,
}
dev: true
/@types/yauzl/2.10.0:
resolution:
@@ -1175,6 +1178,15 @@ packages:
}
dev: false
/@webext-core/fake-browser/1.2.2:
resolution:
{
integrity: sha512-3w0lU0gAYODoMklGQfBuGwIxR+lakYK8FONRFUg8aEdpHUMMzbf5jPwRaTrnsgqupE0JAoBwk8vF6san/BtDeQ==,
}
dependencies:
lodash.merge: 4.6.2
dev: false
/@webext-core/match-patterns/1.0.1:
resolution:
{
@@ -1691,7 +1703,7 @@ packages:
base64-js: 1.5.1
ieee754: 1.2.1
/bundle-require/4.0.1_esbuild@0.18.5:
/bundle-require/4.0.1_esbuild@0.18.11:
resolution:
{
integrity: sha512-9NQkRHlNdNpDBGmLpngF3EFDcwodhMUuLz9PaWYciVcQF9SE4LFjM2DB/xV1Li5JiuDMv7ZUWuC3rGbqR0MAXQ==,
@@ -1700,7 +1712,7 @@ packages:
peerDependencies:
esbuild: '>=0.17'
dependencies:
esbuild: 0.18.5
esbuild: 0.18.11
load-tsconfig: 0.2.5
dev: true
@@ -2668,37 +2680,37 @@ packages:
'@esbuild/win32-ia32': 0.17.19
'@esbuild/win32-x64': 0.17.19
/esbuild/0.18.5:
/esbuild/0.18.11:
resolution:
{
integrity: sha512-ztF1Z53Mc8ijEo1ZWFduHZXIqRWufo76JHm1ikvhGjIzO1mj84LdKXSGmRzahfgvWSwky48MkT+o5yUIkQtDPA==,
integrity: sha512-i8u6mQF0JKJUlGR3OdFLKldJQMMs8OqM9Cc3UCi9XXziJ9WERM5bfkHaEAy0YAvPRMgqSW55W7xYn84XtEFTtA==,
}
engines: { node: '>=12' }
hasBin: true
requiresBuild: true
optionalDependencies:
'@esbuild/android-arm': 0.18.5
'@esbuild/android-arm64': 0.18.5
'@esbuild/android-x64': 0.18.5
'@esbuild/darwin-arm64': 0.18.5
'@esbuild/darwin-x64': 0.18.5
'@esbuild/freebsd-arm64': 0.18.5
'@esbuild/freebsd-x64': 0.18.5
'@esbuild/linux-arm': 0.18.5
'@esbuild/linux-arm64': 0.18.5
'@esbuild/linux-ia32': 0.18.5
'@esbuild/linux-loong64': 0.18.5
'@esbuild/linux-mips64el': 0.18.5
'@esbuild/linux-ppc64': 0.18.5
'@esbuild/linux-riscv64': 0.18.5
'@esbuild/linux-s390x': 0.18.5
'@esbuild/linux-x64': 0.18.5
'@esbuild/netbsd-x64': 0.18.5
'@esbuild/openbsd-x64': 0.18.5
'@esbuild/sunos-x64': 0.18.5
'@esbuild/win32-arm64': 0.18.5
'@esbuild/win32-ia32': 0.18.5
'@esbuild/win32-x64': 0.18.5
'@esbuild/android-arm': 0.18.11
'@esbuild/android-arm64': 0.18.11
'@esbuild/android-x64': 0.18.11
'@esbuild/darwin-arm64': 0.18.11
'@esbuild/darwin-x64': 0.18.11
'@esbuild/freebsd-arm64': 0.18.11
'@esbuild/freebsd-x64': 0.18.11
'@esbuild/linux-arm': 0.18.11
'@esbuild/linux-arm64': 0.18.11
'@esbuild/linux-ia32': 0.18.11
'@esbuild/linux-loong64': 0.18.11
'@esbuild/linux-mips64el': 0.18.11
'@esbuild/linux-ppc64': 0.18.11
'@esbuild/linux-riscv64': 0.18.11
'@esbuild/linux-s390x': 0.18.11
'@esbuild/linux-x64': 0.18.11
'@esbuild/netbsd-x64': 0.18.11
'@esbuild/openbsd-x64': 0.18.11
'@esbuild/sunos-x64': 0.18.11
'@esbuild/win32-arm64': 0.18.11
'@esbuild/win32-ia32': 0.18.11
'@esbuild/win32-x64': 0.18.11
dev: true
/escalade/3.1.1:
@@ -6881,6 +6893,17 @@ packages:
hasBin: true
dev: true
/ts-essentials/9.3.2_typescript@5.1.3:
resolution:
{
integrity: sha512-JxKJzuWqH1MmH4ZFHtJzGEhkfN3QvVR3C3w+4BIoWeoY68UVVoA2Np/Bca9z0IPSErVCWhv439aT0We4Dks8kQ==,
}
peerDependencies:
typescript: '>=4.1.0'
dependencies:
typescript: 5.1.3
dev: true
/ts-interface-checker/0.1.13:
resolution:
{
@@ -6914,11 +6937,11 @@ packages:
typescript:
optional: true
dependencies:
bundle-require: 4.0.1_esbuild@0.18.5
bundle-require: 4.0.1_esbuild@0.18.11
cac: 6.7.14
chokidar: 3.5.3
debug: 4.3.4
esbuild: 0.18.5
esbuild: 0.18.11
execa: 5.1.1
globby: 11.1.0
joycon: 3.1.1
@@ -7281,6 +7304,20 @@ packages:
optionalDependencies:
fsevents: 2.3.2
/vitest-mock-extended/1.1.4_ekuvgbe6yxmpeqet3xraeb3oaa:
resolution:
{
integrity: sha512-MKPdepFjk0CE7Ocb5txntHK/sloHO9s0Kk9dr630uL03shRSHMkZtSs5CBPsbJ8K/CvYLv0GHUmMt2zWks2eXg==,
}
peerDependencies:
typescript: 3.x || 4.x || 5.x
vitest: '>=0.31.1'
dependencies:
ts-essentials: 9.3.2_typescript@5.1.3
typescript: 5.1.3
vitest: 0.32.4
dev: true
/vitest/0.32.4:
resolution:
{
+7
View File
@@ -57,6 +57,13 @@ await Promise.all([
sourcemap: true,
silent: true,
}),
tsup.build({
entry: {
'virtual-modules/fake-browser': `src/client/virtual-modules/fake-browser.ts`,
},
format: ['esm', 'cjs'],
silent: true,
}),
]).catch((err) => {
spinner.fail();
console.error(err);
@@ -0,0 +1,3 @@
import { fakeBrowser as browser } from '@webext-core/fake-browser';
export default browser;
@@ -7,10 +7,11 @@ import {
PopupEntrypoint,
} from '../../types';
import { resolve } from 'path';
import { FindEntrypointsConfig, findEntrypoints } from '../findEntrypoints';
import { findEntrypoints } from '../findEntrypoints';
import fs from 'fs-extra';
import { importTsFile } from '../../utils/importTsFile';
import glob from 'fast-glob';
import { fakeInternalConfig } from '../../../testing/fake-objects';
vi.mock('../../utils/importTsFile');
const importTsFileMock = vi.mocked(importTsFile);
@@ -24,24 +25,11 @@ const readFileMock = vi.mocked(
);
describe('findEntrypoints', () => {
const config: FindEntrypointsConfig = {
const config = fakeInternalConfig({
root: '/',
entrypointsDir: resolve('/src/entrypoints'),
outDir: resolve('.output'),
logger: {
debug: vi.fn(),
error: vi.fn(),
fatal: (...args) => {
throw Error('logger.fatal called with: ' + JSON.stringify(args));
},
info: vi.fn(),
log: vi.fn(),
warn: vi.fn(),
success: vi.fn(),
},
command: 'build',
mode: 'production',
};
});
it.each<[string, string, PopupEntrypoint]>([
[
@@ -189,7 +177,7 @@ describe('findEntrypoints', () => {
expect(entrypoints).toHaveLength(1);
expect(entrypoints[0]).toEqual({ ...expected, options });
expect(importTsFileMock).toBeCalledWith(config.root, expected.inputPath);
expect(importTsFileMock).toBeCalledWith(expected.inputPath, config);
},
);
@@ -216,7 +204,7 @@ describe('findEntrypoints', () => {
expect(entrypoints).toHaveLength(1);
expect(entrypoints[0]).toEqual({ ...expected, options });
expect(importTsFileMock).toBeCalledWith(config.root, expected.inputPath);
expect(importTsFileMock).toBeCalledWith(expected.inputPath, config);
},
);
+4 -4
View File
@@ -45,12 +45,12 @@ async function buildSingleEntrypoint(
? `virtual:wxt-${entrypoint.type}?${entrypoint.inputPath}`
: entrypoint.inputPath;
const libMode: vite.InlineConfig = {
const libMode: vite.UserConfig = {
build: {
lib: {
entry,
formats: ['iife'],
name: entrypoint.name,
name: '_',
fileName: entrypoint.name,
},
rollupOptions: {
@@ -89,7 +89,7 @@ async function buildMultipleEntrypoints(
entrypoints: Entrypoint[],
config: InternalConfig,
): Promise<BuildStepOutput> {
const multiPage: vite.InlineConfig = {
const multiPage: vite.UserConfig = {
plugins: [plugins.multipageMove(entrypoints, config)],
build: {
rollupOptions: {
@@ -112,7 +112,7 @@ async function buildMultipleEntrypoints(
const entryConfig = vite.mergeConfig(
multiPage,
config.vite,
) as vite.InlineConfig;
) as vite.UserConfig;
const result = await vite.build(entryConfig);
return {
+7 -12
View File
@@ -21,7 +21,7 @@ import { getEntrypointName } from '../utils/entrypoints';
* Return entrypoints and their configuration by looking through the
*/
export async function findEntrypoints(
config: FindEntrypointsConfig,
config: InternalConfig,
): Promise<Entrypoint[]> {
const relativePaths = await glob('**/*', {
cwd: config.entrypointsDir,
@@ -103,7 +103,7 @@ export async function findEntrypoints(
* @param content String contents of the file at the path.
*/
async function getPopupEntrypoint(
config: FindEntrypointsConfig,
config: InternalConfig,
path: string,
): Promise<PopupEntrypoint> {
const options: PopupEntrypoint['options'] = {};
@@ -150,7 +150,7 @@ async function getPopupEntrypoint(
* @param content String contents of the file at the path.
*/
async function getOptionsEntrypoint(
config: FindEntrypointsConfig,
config: InternalConfig,
path: string,
): Promise<OptionsEntrypoint> {
const options: OptionsEntrypoint['options'] = {};
@@ -192,11 +192,11 @@ async function getOptionsEntrypoint(
* @param path Absolute path to the background's TS file.
*/
async function getBackgroundEntrypoint(
config: FindEntrypointsConfig,
config: InternalConfig,
path: string,
): Promise<BackgroundEntrypoint> {
const { main: _, ...options } =
await importTsFile<BackgroundScriptDefintition>(config.root, path);
await importTsFile<BackgroundScriptDefintition>(path, config);
if (options == null) {
throw Error('Background script does not have a default export');
}
@@ -213,13 +213,13 @@ async function getBackgroundEntrypoint(
* @param path Absolute path to the content script's TS file.
*/
async function getContentScriptEntrypoint(
config: FindEntrypointsConfig,
config: InternalConfig,
name: string,
path: string,
): Promise<ContentScriptEntrypoint> {
const { main: _, ...options } = await importTsFile<ContentScriptDefinition>(
config.root,
path,
config,
);
if (options == null) {
throw Error(`Content script ${name} does not have a default export`);
@@ -274,8 +274,3 @@ const PATH_GLOB_TO_TYPE_MAP: Record<string, Entrypoint['type'] | 'ignored'> = {
// Don't warn about any files in subdirectories, like CSS or JS entrypoints for HTML files
'*/*': 'ignored',
};
export type FindEntrypointsConfig = Pick<
InternalConfig,
'root' | 'entrypointsDir' | 'outDir' | 'logger' | 'mode' | 'command'
>;
+11 -10
View File
@@ -48,22 +48,23 @@ async function writePathsDeclarationFile(
config: InternalConfig,
): Promise<string> {
const filePath = resolve(config.typesDir, 'paths.d.ts');
const unions = entrypoints
.map((entry) => {
const path = getEntrypointBundlePath(
entry,
config.outDir,
entry.inputPath.endsWith('.html') ? '.html' : '.js',
);
return ` | "/${path}"`;
})
.sort();
await fs.writeFile(
filePath,
[
'// Generated by wxt',
'type EntrypointPath =',
...entrypoints
.map((entry) => {
const path = getEntrypointBundlePath(
entry,
config.outDir,
entry.inputPath.endsWith('.html') ? '.html' : '.js',
);
return ` | "/${path}"`;
})
.sort(),
...(unions.length === 0 ? [' never'] : unions),
].join('\n') + '\n',
);
+19 -2
View File
@@ -19,8 +19,8 @@ export interface InlineConfig {
browser?: TargetBrowser;
manifestVersion?: TargetManifestVersion;
logger?: Logger;
vite?: Omit<vite.InlineConfig, 'root' | 'configFile' | 'mode'>;
manifest?: UserManifest;
vite?: Omit<vite.UserConfig, 'root' | 'configFile' | 'mode'>;
manifest?: UserManifest | Promise<UserManifest> | UserManifestFn;
server?: WxtDevServer;
runner?: ExtensionRunnerConfig;
}
@@ -226,6 +226,23 @@ export type UserManifest = Omit<
| 'version_name'
>;
export type UserManifestFn = (
env: ConfigEnv,
) => UserManifest | Promise<UserManifest>;
export interface ConfigEnv {
mode: string;
command: 'build' | 'serve';
/**
* Browser passed in from the CLI
*/
browser: TargetBrowser;
/**
* Manifest version passed in from the CLI
*/
manifestVersion: 2 | 3;
}
/**
* Configure how the browser starts up.
*/
+17 -6
View File
@@ -3,11 +3,11 @@ import {
InlineConfig,
InternalConfig,
UserConfig,
UserManifest,
} from '../types';
import path, { resolve } from 'node:path';
import * as vite from 'vite';
import { consola } from 'consola';
import { importTsFile } from './importTsFile';
import * as plugins from '../vite-plugins';
import { createFsCache } from './createFsCache';
import { getGlobals } from './globals';
@@ -32,6 +32,15 @@ export async function getInternalConfig(
const outDir = path.resolve(outBaseDir, `${browser}-mv${manifestVersion}`);
const logger = config.logger ?? consola;
const manifest: UserManifest = await (typeof config.manifest === 'function'
? config.manifest({
browser,
command,
manifestVersion,
mode,
})
: config.manifest ?? {});
const baseConfig: InternalConfigNoUserDirs = {
root,
outDir,
@@ -43,7 +52,7 @@ export async function getInternalConfig(
command,
logger,
vite: config.vite ?? {},
manifest: config.manifest ?? {},
manifest,
imports: config.imports ?? {},
runnerConfig: await loadConfig<ExtensionRunnerConfig>({
name: 'web-ext',
@@ -59,10 +68,12 @@ export async function getInternalConfig(
mode,
};
if (config.configFile !== false) {
userConfig = await importTsFile<UserConfig>(
root,
path.resolve(root, config.configFile ?? 'wxt.config.ts'),
);
const loaded = await loadConfig<UserConfig>({
name: 'wxt',
cwd: root,
rcFile: false,
});
userConfig = loaded.config ?? {};
}
// Merge inline and user configs
+50 -27
View File
@@ -1,44 +1,67 @@
import { consola } from 'consola';
import createJITI from 'jiti';
import transform from 'jiti/dist/babel';
import { InternalConfig } from '../types';
import { createUnimport } from 'unimport';
import fs from 'fs-extra';
import { resolve } from 'path';
import { scanExports } from 'unimport';
import transform from 'jiti/dist/babel';
import { getUnimportOptions } from './auto-imports';
export async function importTsFile<T>(root: string, path: string): Promise<T> {
const clientImports = await scanExports(
resolve(root, 'node_modules/wxt/dist/client.js'),
/**
* Get the value from the default export of a `path`.
*
* It works by:
*
* 1. Reading the file text
* 2. Stripping all imports from it via regex
* 3. Auto-import only the client helper functions
*
* This prevents resolving imports of imports, speeding things up and preventing "xxx is not
* defined" errors.
*
* Downside is that code cannot be executed outside of the main fucntion for the entrypoint,
* otherwise you will see "xxx is not defined" errors for any imports used outside of main function.
*/
export async function importTsFile<T>(
path: string,
config: InternalConfig,
): Promise<T> {
config.logger.debug('Loading file metadata:', path);
const unimport = createUnimport({
...getUnimportOptions(config),
// Only allow specific imports, not all from the project
imports: [{ name: '*', as: 'browser', from: 'webextension-polyfill' }],
dirs: [],
});
await unimport.init();
const text = await fs.readFile(path, 'utf-8');
const textNoImports = text.replace(/import.*[\n;]/gm, '');
const { code } = await unimport.injectImports(textNoImports);
config.logger.debug(
['Text:', text, 'No imports:', textNoImports, 'Code:', code].join('\n'),
);
const jiti = createJITI(__filename, {
cache: false,
esmResolve: true,
interopDefault: true,
alias: {
'webextension-polyfill': resolve(
config.root,
'node_modules/wxt/dist/virtual-modules/fake-browser.js',
),
},
transform(opts) {
// Remove CSS imports from the source code - Jiti can't handle them.
opts.source = opts.source.replace(/^import ['"].*\.css['"];?$/gm, '');
opts.source = opts.source.replace(
/^import\s+.*\s+from ['"]webextension-polyfill['"];?$/gm,
'',
);
// Append any wxt/client functions so babel doesn't complain about undefined variables
if (opts.filename === path) {
// TODO: Only append import if it isn't already imported
const imports =
clientImports
.map((i) => `import { ${i.name} } from "${i.from}";`)
.join('\n') + '\n';
opts.source = imports + opts.source;
}
// Call the default babel transformer with our modified source code
return transform(opts);
if (opts.filename === path) return transform({ ...opts, source: code });
else return transform(opts);
},
});
try {
return await jiti(path);
} catch (err) {
consola.error(`Failed to import file: ${path}`);
config.logger.error(err);
throw err;
}
}
+12 -1
View File
@@ -2,6 +2,16 @@ import { createUnimport } from 'unimport';
import { InternalConfig } from '../types';
import { getUnimportOptions } from '../utils/auto-imports';
import { Plugin } from 'vite';
import { extname } from 'path';
const ENABLED_EXTENSIONS: Record<string, boolean | undefined> = {
'.js': true,
'.jsx': true,
'.ts': true,
'.tsx': true,
'.vue': true,
'.svelte': true,
};
/**
* Inject any global imports defined by unimport
@@ -16,7 +26,8 @@ export function unimport(config: InternalConfig): Plugin {
await unimport.scanImportsFromDir(undefined, { cwd: config.srcDir });
},
async transform(code, id) {
return unimport.injectImports(code, id);
const ext = extname(id);
if (ENABLED_EXTENSIONS[ext]) return unimport.injectImports(code, id);
},
};
}
+27
View File
@@ -13,6 +13,8 @@ import { faker } from '@faker-js/faker';
import merge from 'lodash.merge';
import { Rollup } from 'vite';
import { Manifest } from 'webextension-polyfill';
import { FsCache, InternalConfig, WxtDevServer } from '../core/types';
import { mock } from 'vitest-mock-extended';
faker.seed(__TEST_SEED__);
@@ -192,3 +194,28 @@ 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: {},
},
srcDir: fakeDir(),
storeIds: {},
typesDir: fakeDir(),
vite: {},
wxtDir: fakeDir(),
server: mock<WxtDevServer>(),
}));