Compare commits

...

29 Commits

Author SHA1 Message Date
GitHub Actions 3eb505dbde chore(release): wxt v0.19.9 2024-09-04 21:39:24 +00:00
1natsu fbe502fddf chore: Cleanup leftover E2E test artifacts (#968) 2024-09-04 16:35:18 -05:00
1natsu c143a9978d fix: Properly overload import.meta.env with WXT's own environment globals (#966) 2024-09-03 14:35:10 -05:00
Aaron Klinker e3555b663d Update description after 447d011 2024-09-03 14:34:32 -05:00
Aaron Klinker df934d252c Correct version number after 447d011 2024-09-03 14:31:27 -05:00
Aaron Klinker 447d011b8f docs: Retroactively mention breaking change in v0.18.5
See https://github.com/wxt-dev/wxt/discussions/950#discussioncomment-10512337
2024-09-03 14:30:10 -05:00
Aaron abe1263d27 feat: Use @types/chrome for config manifest type (#969) 2024-09-03 14:11:24 -05:00
Aaron Klinker 143b5ac81f docs: Add docs around importEntrypoint to relevant functions 2024-09-03 13:40:59 -05:00
dependabot[bot] 87fbb1f4c3 chore(deps): bump execa from 9.3.0 to 9.3.1 (#957)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-03 12:12:22 -05:00
dependabot[bot] 62f11bf605 chore(deps): bump sharp from 0.33.4 to 0.33.5 (#959)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-03 12:10:02 -05:00
dependabot[bot] 3ead54b58e chore(deps): bump unimport from 3.9.1 to 3.11.1 (#960)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-03 12:08:44 -05:00
dependabot[bot] 580f4f3cfe chore(deps): bump ora from 8.0.1 to 8.1.0 (#961)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-03 12:08:04 -05:00
1natsu da0accebe8 fix: duplicate BuildOutput.publicAssets (#951)
Co-authored-by: Aaron Klinker <aaronklinker1@gmail.com>
2024-09-03 12:06:21 -05:00
Aaron eb65d0b42a docs: Add link to testing permission changes in Firefox 2024-09-03 07:34:43 -05:00
Alex Nguyen c2784135b0 docs: Fix typo in frontend-frameworks.md (#952) 2024-09-01 19:43:11 -05:00
Aaron 61d54bd1f9 fix: Allow adding multiple hyphens in an entrypoint name (#949) 2024-08-30 04:56:23 -05:00
Aaron 0bd94fce3b chore: Add oxlint for linting (#947) 2024-08-30 04:14:20 -05:00
Amal Chandran 2a97c06443 docs: Add "Draftly" to homepage (#941)
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2024-08-30 02:51:32 -05:00
Aaron 8213aa776a chore: Fix type error (#946) 2024-08-30 02:45:36 -05:00
Aaron 026f78254d chore: Upgrade unbuild from 1.1.0 to 1.1.1 2024-08-29 08:19:56 -05:00
Aaron 0ebb013ba6 types(modules): Use NestedHooks instead of Partial for hooks object 2024-08-29 07:12:58 -05:00
Aaron c5f78d0c8d feat(modules): Add wxt.hook alias for wxt.hooks.hook 2024-08-29 07:12:13 -05:00
GitHub Actions 8771676e69 chore(release): wxt v0.19.8 2024-08-29 11:53:13 +00:00
1natsu aebbbb0685 fix: Fallback to GitHub API for listing templates when ungh is down (#944)
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2024-08-29 06:48:38 -05:00
Aaron 68183b648e chore(types): Cleanup types in wxt/browser/chrome (#932) 2024-08-23 08:49:39 -05:00
Aaron Klinker 45809c0198 chore: Update lockfile 2024-08-19 23:08:40 -05:00
Aaron Klinker 13163c9ba1 chore(dev-deps): Upgrade @aklinker1/buildc from v1.0.11 to v1.1.0 2024-08-19 21:49:01 -05:00
1natsu aedbba3f3d perf: Ignore output directories for all vite.watcher (#924) 2024-08-19 21:44:27 -05:00
GitHub Actions 763dbd5ee8 chore(release): wxt v0.19.7 2024-08-19 15:40:58 +00:00
42 changed files with 629 additions and 326 deletions
@@ -38,6 +38,7 @@ const chromeExtensionIds = [
'cfkdcideecefncbglkhneoflfnmhoicc', // mindful - stay focused on your goals
'lnhejcpclabmbgpiiomjbhalblnnbffg', // 1Proompt
'fonflmjnjbkigocpoommgmhljdpljain', // NiceTab - https://github.com/web-dahuyou/NiceTab
'fcffekbnfcfdemeekijbbmgmkognnmkd', // Draftly for LinkedIn
];
const { data, err, isLoading } = useListExtensionDetails(chromeExtensionIds);
+2 -1
View File
@@ -56,7 +56,8 @@ When `permissions`/`host_permissions` change during an update, depending on what
You can test if your permission changes will result in a disabled extension:
- Chromium: Use [Google's Extension Update Testing tool](https://github.com/GoogleChromeLabs/extension-update-testing-tool)
- Firefox/Safari: Everyone breaks something in production eventually... 🫡 Good luck soldier
- Firefox: See their [Test Permission Requests](https://extensionworkshop.com/documentation/develop/test-permission-requests/) page
- Safari: Everyone breaks something in production eventually... 🫡 Good luck soldier
## Update Event
@@ -100,7 +100,7 @@ Usually, this means each entrypoint should be a directory with it's own files in
## Configuring Routers
Lots of frameworks come with routers for building a multi-page app using the URL's path. Chrome extensions don't don't work like this. Since HTML files are static, `chrome-extension://{id}/popup.html`, there's no way to change the entire path for routing.
Lots of frameworks come with routers for building a multi-page app using the URL's path. Chrome extensions don't work like this. Since HTML files are static, `chrome-extension://{id}/popup.html`, there's no way to change the entire path for routing.
Instead, you need to configure the router to run in "hash" mode, where the routing information is apart of the URL's hash, not the path (ie: `popup.html#/` and `popup.html#/account/settings`).
+22 -1
View File
@@ -10,7 +10,7 @@ pnpm i wxt@latest
If there was a major version change, follow the steps below to fix breaking changes.
## v0.18.0 &rarr; v0.19.0
## v0.18.5 &rarr; v0.19.0
### `vite-node` Entrypoint Loader
@@ -86,6 +86,27 @@ WXT no longer ships with Common JS support. If you're using CJS, here's your mig
Vite also provides steps for migrating to ESM. Check them out for more details: https://vitejs.dev/guide/migration#deprecate-cjs-node-api
## v0.18.0 &rarr; v0.18.5
> When this version was released, it was not considered a breaking change... but it should have been.
### New `modules/` Directory
WXT now recognizes the `modules/` directory as a folder containing [WXT modules](/guide/go-further/reusable-modules).
If you already have `<srcDir>/modules` or `<srcDir>/Modules` directory, `wxt prepare` and other commands will fail.
You have two options:
1. [Recommended] Keep your files where they are and tell WXT to look in a different folder:
```ts
// wxt.config.ts
export default defineConfig({
modulesDir: 'wxt-modules', // defaults to "modules"
});
```
2. Rename your `modules` directory to something else.
## v0.17.0 &rarr; v0.18.0
### Automatic MV3 `host_permissions` to MV2 `permissions`
+3 -3
View File
@@ -17,14 +17,14 @@
"docs:preview": "pnpm -s docs:gen && vitepress preview docs"
},
"devDependencies": {
"@aklinker1/buildc": "^1.0.11",
"@aklinker1/check": "^1.3.1",
"@aklinker1/buildc": "^1.1.1",
"@aklinker1/check": "^1.4.5",
"@types/fs-extra": "^11.0.4",
"@vitest/coverage-v8": "^2.0.4",
"changelogen": "^0.5.5",
"consola": "^3.2.3",
"dependency-graph": "^1.0.0",
"execa": "^9.3.0",
"execa": "^9.3.1",
"fast-glob": "^3.3.2",
"fs-extra": "^11.2.0",
"hasha": "^6.0.0",
+3 -2
View File
@@ -45,7 +45,8 @@
"wxt": ">=0.19.0"
},
"devDependencies": {
"@aklinker1/check": "^1.3.1",
"@aklinker1/check": "^1.4.5",
"oxlint": "^0.9.1",
"publint": "^0.2.9",
"typescript": "^5.5.4",
"unbuild": "^2.0.0",
@@ -54,6 +55,6 @@
"dependencies": {
"defu": "^6.1.4",
"fs-extra": "^11.2.0",
"sharp": "^0.33.4"
"sharp": "^0.33.5"
}
}
+2 -1
View File
@@ -38,9 +38,10 @@
}
},
"devDependencies": {
"@aklinker1/check": "^1.3.1",
"@aklinker1/check": "^1.4.5",
"@types/chrome": "^0.0.268",
"@types/node": "^20.14.2",
"oxlint": "^0.9.1",
"publint": "^0.2.8",
"typescript": "^5.4.5",
"unbuild": "^2.0.0",
+1 -1
View File
@@ -14,7 +14,7 @@ export function applyChromeMessagePlaceholders(message: ChromeMessage): string {
export function getSubstitionCount(message: string): number {
return (
1 +
new Array(MAX_SUBSTITUTIONS).findLastIndex((_, i) =>
Array.from({ length: MAX_SUBSTITUTIONS }).findLastIndex((_, i) =>
message.match(new RegExp(`(?<!\\$)\\$${i + 1}`)),
)
);
+1 -1
View File
@@ -50,7 +50,7 @@
"@vitejs/plugin-react": "^4.3.1"
},
"devDependencies": {
"@aklinker1/check": "^1.3.1",
"@aklinker1/check": "^1.4.5",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"publint": "^0.2.9",
+1 -1
View File
@@ -50,7 +50,7 @@
"vite-plugin-solid": "^2.10.2"
},
"devDependencies": {
"@aklinker1/check": "^1.3.1",
"@aklinker1/check": "^1.4.5",
"publint": "^0.2.9",
"solid-js": "^1.8.19",
"typescript": "^5.5.4",
+1 -1
View File
@@ -48,7 +48,7 @@
"@sveltejs/vite-plugin-svelte": "^3.1.1"
},
"devDependencies": {
"@aklinker1/check": "^1.3.1",
"@aklinker1/check": "^1.4.5",
"publint": "^0.2.9",
"typescript": "^5.5.4",
"unbuild": "^2.0.0",
+1 -1
View File
@@ -48,7 +48,7 @@
"@vitejs/plugin-vue": "^5.1.1"
},
"devDependencies": {
"@aklinker1/check": "^1.3.1",
"@aklinker1/check": "^1.4.5",
"publint": "^0.2.9",
"typescript": "^5.5.4",
"unbuild": "^2.0.0",
+1
View File
@@ -0,0 +1 @@
src/core/utils/building/__tests__/test-entrypoints
+79 -1
View File
@@ -1,5 +1,83 @@
# Changelog
## v0.19.9
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.19.8...wxt-v0.19.9)
### 🚀 Enhancements
- **modules:** Add `wxt.hook` alias for `wxt.hooks.hook` ([c5f78d0](https://github.com/wxt-dev/wxt/commit/c5f78d0))
- Use `@types/chrome` for config manifest type ([#969](https://github.com/wxt-dev/wxt/pull/969))
### 🩹 Fixes
- Allow adding multiple hyphens in an entrypoint name ([#949](https://github.com/wxt-dev/wxt/pull/949))
- Duplicate `BuildOutput.publicAssets` ([#951](https://github.com/wxt-dev/wxt/pull/951))
- Properly overload `import.meta.env` with WXT's own environment globals ([#966](https://github.com/wxt-dev/wxt/pull/966))
### 📖 Documentation
- Add docs around `importEntrypoint` to relevant functions ([143b5ac](https://github.com/wxt-dev/wxt/commit/143b5ac))
### 🌊 Types
- **modules:** Use `NestedHooks` instead of `Partial` for hooks object ([0ebb013](https://github.com/wxt-dev/wxt/commit/0ebb013))
### 🏡 Chore
- Fix type error ([#946](https://github.com/wxt-dev/wxt/pull/946))
- Add `oxlint` for linting ([#947](https://github.com/wxt-dev/wxt/pull/947))
- **deps:** Bump ora from 8.0.1 to 8.1.0 ([#961](https://github.com/wxt-dev/wxt/pull/961))
- **deps:** Bump unimport from 3.9.1 to 3.11.1 ([#960](https://github.com/wxt-dev/wxt/pull/960))
- **deps:** Bump execa from 9.3.0 to 9.3.1 ([#957](https://github.com/wxt-dev/wxt/pull/957))
- Cleanup leftover E2E test artifacts ([#968](https://github.com/wxt-dev/wxt/pull/968))
### ❤️ Contributors
- 1natsu ([@1natsu172](http://github.com/1natsu172))
## v0.19.8
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.19.7...wxt-v0.19.8)
### 🔥 Performance
- Ignore output directories for all `vite.watcher` ([#924](https://github.com/wxt-dev/wxt/pull/924))
### 🩹 Fixes
- Fallback to GitHub API for listing templates when ungh is down ([#944](https://github.com/wxt-dev/wxt/pull/944))
### 🏡 Chore
- **types:** Cleanup types in wxt/browser/chrome ([#932](https://github.com/wxt-dev/wxt/pull/932))
### ❤️ Contributors
- 1natsu
## v0.19.7
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.19.6...wxt-v0.19.7)
### 🚀 Enhancements
- **testing:** Run WXT modules when setting up test environment ([#926](https://github.com/wxt-dev/wxt/pull/926))
- **modules:** Add `addAlias` helper ([#928](https://github.com/wxt-dev/wxt/pull/928))
### 🩹 Fixes
- **testing:** Stub `chrome` and `browser` globals with `fakeBrowser` automatically ([#925](https://github.com/wxt-dev/wxt/pull/925))
- Ensure TSConfig paths start with `../` or `./` so they are valid ([#927](https://github.com/wxt-dev/wxt/pull/927))
### 📖 Documentation
- Fix module name for `wxt/browser/chrome` ([751706d](https://github.com/wxt-dev/wxt/commit/751706d))
### 🏡 Chore
- Remove warning log for missing public directory ([5f2e1c3](https://github.com/wxt-dev/wxt/commit/5f2e1c3))
## v0.19.6
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.19.5...wxt-v0.19.6)
@@ -2390,4 +2468,4 @@ Initial release of WXT. Full support for production builds and initial toolkit f
### 🤖 CI
- Create validation workflow ([#12](https://github.com/wxt-dev/wxt/pull/12))
- Create release workflow ([#13](https://github.com/wxt-dev/wxt/pull/13))
- Create release workflow ([#13](https://github.com/wxt-dev/wxt/pull/13))
@@ -362,7 +362,7 @@ describe('Output Directory Structure', () => {
.toMatchInlineSnapshot(`
".output/chrome-mv3/background.js
----------------------------------------
var _background = function() {
var background = function() {
"use strict";
var _a, _b;
function defineBackground(arg) {
@@ -372,13 +372,13 @@ describe('Output Directory Structure', () => {
function logHello(name) {
console.log(\`Hello \${name}!\`);
}
_background;
background;
const definition = defineBackground({
main() {
logHello("background");
}
});
_background;
background;
function initPlugins() {
}
// @ts-expect-error
@@ -411,7 +411,7 @@ describe('Output Directory Structure', () => {
const result$1 = result;
return result$1;
}();
_background;
background;
"
`);
});
@@ -13,7 +13,6 @@ describe('TypeScript Project', () => {
".wxt/types/globals.d.ts
----------------------------------------
// Generated by wxt
export {}
interface ImportMetaEnv {
readonly MANIFEST_VERSION: 2 | 3;
readonly BROWSER: string;
+1 -1
View File
@@ -74,7 +74,7 @@ describe('User Config', () => {
);
await project.build({
// @ts-expect-error: Specifically setting an invalid field for the test - it should show up in the snapshot
// Specifically setting an invalid field for the test - it should show up in the snapshot
manifest: ({ manifestVersion, command }) => ({
example_customization: [String(manifestVersion), command],
}),
+8 -9
View File
@@ -1,7 +1,7 @@
{
"name": "wxt",
"type": "module",
"version": "0.19.6",
"version": "0.19.9",
"description": "Next gen framework for developing web extensions",
"repository": {
"type": "git",
@@ -81,6 +81,7 @@
"prepack": "pnpm build"
},
"dependencies": {
"@types/chrome": "^0.0.269",
"@aklinker1/rollup-plugin-visualizer": "5.12.0",
"@types/webextension-polyfill": "^0.10.7",
"@webext-core/fake-browser": "^1.3.1",
@@ -95,7 +96,7 @@
"defu": "^6.1.4",
"dequal": "^2.0.3",
"esbuild": "^0.23.0",
"execa": "^9.3.0",
"execa": "^9.3.1",
"fast-glob": "^3.3.2",
"filesize": "^10.1.4",
"fs-extra": "^11.2.0",
@@ -114,20 +115,20 @@
"nypm": "^0.3.9",
"ohash": "^1.1.3",
"open": "^10.1.0",
"ora": "^8.0.1",
"ora": "^8.1.0",
"picocolors": "^1.0.1",
"prompts": "^2.4.2",
"publish-browser-extension": "^2.1.3",
"unimport": "^3.9.1",
"scule": "^1.3.0",
"unimport": "^3.11.1",
"vite": "^5.3.5",
"vite-node": "^2.0.4",
"web-ext-run": "^0.2.1",
"webextension-polyfill": "^0.12.0"
},
"devDependencies": {
"@aklinker1/check": "^1.3.1",
"@aklinker1/check": "^1.4.5",
"@faker-js/faker": "^8.4.1",
"@types/chrome": "^0.0.269",
"@types/fs-extra": "^11.0.4",
"@types/lodash.merge": "^4.6.9",
"@types/natural-compare": "^1.4.3",
@@ -137,6 +138,7 @@
"extract-zip": "^2.0.1",
"happy-dom": "^14.12.3",
"lodash.merge": "^4.6.2",
"oxlint": "^0.9.1",
"p-map": "^7.0.2",
"publint": "^0.2.9",
"tsx": "4.15.7",
@@ -145,9 +147,6 @@
"vitest": "^2.0.4",
"vitest-plugin-random-seed": "^1.1.0"
},
"peerDependencies": {
"@types/chrome": "*"
},
"peerDependenciesMeta": {
"@types/chrome": {
"optional": true
+4 -9
View File
@@ -1,9 +1,4 @@
/// <reference types="chrome" />
/**
* @module wxt/browser/chrome
*/
import type { WxtRuntime, WxtI18n } from './index';
/**
* EXPERIMENTAL
*
@@ -11,11 +6,11 @@ import type { WxtRuntime, WxtI18n } from './index';
*
* @module wxt/browser/chrome
*/
import type { WxtRuntime, WxtI18n } from './index';
export type Chrome = typeof chrome;
export type WxtBrowser = Omit<Chrome, 'runtime' | 'i18n'> & {
runtime: WxtRuntime & Omit<Chrome['runtime'], 'getURL'>;
i18n: WxtI18n & Omit<Chrome['i18n'], 'getMessage'>;
export type WxtBrowser = Omit<typeof chrome, 'runtime' | 'i18n'> & {
runtime: WxtRuntime & Omit<(typeof chrome)['runtime'], 'getURL'>;
i18n: WxtI18n & Omit<(typeof chrome)['i18n'], 'getMessage'>;
};
export const browser: WxtBrowser =
+5 -3
View File
@@ -59,6 +59,11 @@ export async function createViteBuilder(
config.build.sourcemap = 'inline';
}
config.server ??= {};
config.server.watch = {
ignored: [`${wxtConfig.outBaseDir}/**`, `${wxtConfig.wxtDir}/**`],
};
config.plugins ??= [];
config.plugins.push(
wxtPlugins.download(wxtConfig),
@@ -287,9 +292,6 @@ export async function createViteBuilder(
strictPort: true,
host: info.hostname,
origin: info.origin,
watch: {
ignored: [`${wxtConfig.outBaseDir}/**`, `${wxtConfig.wxtDir}/**`],
},
},
};
const baseConfig = await getBaseConfig();
+1 -1
View File
@@ -211,7 +211,7 @@ function createFileReloader(server: WxtDevServer) {
wxt.logger.success(`Reloaded: ${getFilenameList(rebuiltNames)}`);
break;
}
} catch (err) {
} catch {
// Catch build errors instead of crashing. Don't log error either, builder should have already logged it
}
});
+55 -32
View File
@@ -99,53 +99,74 @@ interface Template {
}
async function listTemplates(): Promise<Template[]> {
try {
const res = await fetch('https://ungh.cc/repos/wxt-dev/wxt/files/main');
if (res.status >= 300)
throw Error(`Request failed with status ${res.status} ${res.statusText}`);
const templates = await listTemplatesUngh().catch((err) => {
consola.debug('Failed to load templates via ungh:', err);
return listTemplatesGithub();
});
return templates.sort((l, r) => {
const lWeight = TEMPLATE_SORT_WEIGHT[l.name] ?? Number.MAX_SAFE_INTEGER;
const rWeight = TEMPLATE_SORT_WEIGHT[r.name] ?? Number.MAX_SAFE_INTEGER;
const diff = lWeight - rWeight;
if (diff !== 0) return diff;
return l.name.localeCompare(r.name);
});
}
const data = (await res.json()) as {
meta: {
sha: string;
};
files: Array<{
path: string;
mode: string;
sha: string;
size: number;
}>;
async function listTemplatesUngh(): Promise<Template[]> {
const res = await fetch('https://ungh.cc/repos/wxt-dev/wxt/files/main');
if (res.status !== 200)
throw Error(
`Request failed with status ${res.status} ${res.statusText}: ${await res.text()}`,
);
const data = (await res.json()) as {
meta: {
sha: string;
};
return data.files
.map((item) => item.path.match(/templates\/(.+)\/package\.json/)?.[1])
.filter((name) => name != null)
.map((name) => ({ name: name!, path: `templates/${name}` }))
.sort((l, r) => {
const lWeight = TEMPLATE_SORT_WEIGHT[l.name] ?? Number.MAX_SAFE_INTEGER;
const rWeight = TEMPLATE_SORT_WEIGHT[r.name] ?? Number.MAX_SAFE_INTEGER;
const diff = lWeight - rWeight;
if (diff !== 0) return diff;
return l.name.localeCompare(r.name);
});
} catch (err) {
consola.error(err);
throw Error(`Failed to load templates`);
}
files: Array<{
path: string;
mode: string;
sha: string;
size: number;
}>;
};
return data.files
.map((item) => item.path.match(/templates\/(.+)\/package\.json/)?.[1])
.filter((name) => name != null)
.map((name) => ({ name: name!, path: `templates/${name}` }));
}
async function listTemplatesGithub(): Promise<Template[]> {
const res = await fetch(
`https://api.github.com/repos/${REPO}/contents/templates`,
{ headers: { Accept: 'application/vnd.github+json' } },
);
if (res.status !== 200)
throw Error(
`Request failed with status ${res.status} ${res.statusText}: ${await res.text()}`,
);
// Schema is Example4 of https://docs.github.com/en/rest/repos/contents?apiVersion=2022-11-28#get-repository-content
return (await res.json()) as Array<{
name: string;
path: string;
sha: string;
size: number;
}>;
}
async function cloneProject({
directory,
template,
packageManager,
}: {
directory: string;
template: Template;
packageManager: string;
}) {
const { default: ora } = await import('ora');
const spinner = ora('Downloading template').start();
try {
// 1. Clone repo
await downloadTemplate(`gh:wxt-dev/wxt/${template.path}`, {
await downloadTemplate(`gh:${REPO}/${template.path}`, {
dir: directory,
force: true,
});
@@ -180,3 +201,5 @@ const TEMPLATE_SORT_WEIGHT: Record<string, number> = {
vue: 1,
react: 2,
};
const REPO = 'wxt-dev/wxt';
@@ -21,9 +21,10 @@ describe('String utils', () => {
describe('safeVarName', () => {
it.each([
['Hello world!', '_hello_world'],
['Hello world!', 'helloWorld'],
['123', '_123'],
['abc-123', '_abc_123'],
['abc-123', 'abc123'],
['abc-123-xyz', 'abc123Xyz'],
['', '_'],
[' ', '_'],
['_', '_'],
@@ -201,7 +201,6 @@ async function getGlobalsDeclarationEntry(): Promise<WxtDirFileEntry> {
path: 'types/globals.d.ts',
text: [
'// Generated by wxt',
'export {}',
'interface ImportMetaEnv {',
...globals.map((global) => ` readonly ${global.name}: ${global.type};`),
'}',
@@ -47,14 +47,16 @@ export async function rebuild(
const newOutput = await buildEntrypoints(entrypointGroups, spinner);
const mergedOutput: Omit<BuildOutput, 'manifest'> = {
steps: [...existingOutput.steps, ...newOutput.steps],
publicAssets: [...existingOutput.publicAssets, ...newOutput.publicAssets],
// Do not merge existing because all publicAssets copied everytime
publicAssets: newOutput.publicAssets,
};
const { manifest: newManifest, warnings: manifestWarnings } =
await generateManifest(allEntrypoints, mergedOutput);
const finalOutput: BuildOutput = {
manifest: newManifest,
...newOutput,
...mergedOutput,
};
// Write manifest
@@ -64,14 +66,7 @@ export async function rebuild(
spinner.clear().stop();
return {
output: {
manifest: newManifest,
steps: [...existingOutput.steps, ...finalOutput.steps],
publicAssets: [
...existingOutput.publicAssets,
...finalOutput.publicAssets,
],
},
output: finalOutput,
manifest: newManifest,
warnings: manifestWarnings,
};
@@ -86,7 +86,7 @@ export async function resolveConfig(
if (await isDirMissing(entrypointsDir)) {
logMissingDir(logger, 'Entrypoints', entrypointsDir);
}
const filterEntrypoints = !!mergedConfig.filterEntrypoints?.length
const filterEntrypoints = mergedConfig.filterEntrypoints?.length
? new Set(mergedConfig.filterEntrypoints)
: undefined;
const publicDir = path.resolve(srcDir, mergedConfig.publicDir ?? 'public');
+1 -1
View File
@@ -14,7 +14,7 @@ export function getEntrypointName(
): string {
const relativePath = path.relative(entrypointsDir, inputPath);
// Grab the string up to the first . or / or \\
const name = relativePath.split(/[\.\/\\]/, 2)[0];
const name = relativePath.split(/[./\\]/, 2)[0];
return name;
}
@@ -42,7 +42,7 @@ export function applyGlobals(globals: EnvGlobals): void {
try {
// @ts-expect-error: Untyped key on globalThis
globalThis[key] = envValue;
} catch (err) {
} catch {
// ignore any globals that can't be set
}
});
+2 -1
View File
@@ -5,7 +5,8 @@ export async function getEslintVersion(): Promise<string[]> {
);
const { ESLint } = require('eslint');
return ESLint.version?.split('.') ?? [];
} catch (error) {
} catch {
// Return an empty version when there's an error importing ESLint
return [];
}
}
+4 -4
View File
@@ -272,14 +272,14 @@ function addEntrypoints(
options.browser_style = popup.options.browserStyle;
if (manifest.manifest_version === 3) {
manifest.action = {
...(manifest.action ?? {}),
...manifest.action,
...options,
default_popup,
};
} else {
const key = popup.options.mv2Key ?? 'browser_action';
manifest[key] = {
...(manifest[key] ?? {}),
...manifest[key],
...options,
default_popup,
};
@@ -434,8 +434,8 @@ function discoverIcons(
/^icon@([0-9]+)w\.png$/, // icon@16w.png
/^icon@([0-9]+)h\.png$/, // icon@16h.png
/^icon@([0-9]+)\.png$/, // icon@16.png
/^icons?[\/\\]([0-9]+)\.png$/, // icon/16.png | icons/16.png
/^icons?[\/\\]([0-9]+)x[0-9]+\.png$/, // icon/16x16.png | icons/16x16.png
/^icons?[/\\]([0-9]+)\.png$/, // icon/16.png | icons/16.png
/^icons?[/\\]([0-9]+)x[0-9]+\.png$/, // icon/16x16.png | icons/16x16.png
];
// #endregion snippet
+1
View File
@@ -16,6 +16,7 @@ export async function getPackageJson(): Promise<
} catch (err) {
wxt.logger.debug(
`Failed to read package.json at: ${file}. Returning undefined.`,
err,
);
return {};
}
+13 -2
View File
@@ -1,3 +1,5 @@
import { camelCase } from 'scule';
export function kebabCaseAlphanumeric(str: string): string {
return str
.toLowerCase()
@@ -9,8 +11,17 @@ export function kebabCaseAlphanumeric(str: string): string {
* Return a safe variable name for a given string.
*/
export function safeVarName(str: string): string {
// _ prefix to ensure it doesn't start with a number
return '_' + kebabCaseAlphanumeric(str.trim()).replace('-', '_');
const name = camelCase(kebabCaseAlphanumeric(str));
if (name.match(/^[a-z]/)) return name;
// _ prefix to ensure it doesn't start with a number or other invalid symbol
return '_' + name;
}
/**
* Converts a string to a valid filename (NOT path), stripping out invalid characters.
*/
export function safeFilename(str: string): string {
return kebabCaseAlphanumeric(str);
}
/**
@@ -311,6 +311,7 @@ export const fakeResolvedConfig = fakeObjectCreator<ResolvedConfig>(() => {
export const fakeWxt = fakeObjectCreator<Wxt>(() => ({
config: fakeResolvedConfig(),
hook: vi.fn(),
hooks: mock(),
logger: mock(),
reloadConfig: vi.fn(),
+1 -3
View File
@@ -162,9 +162,7 @@ function getSimpleAstJson(ast: any): any {
} else if (typeof ast === 'object') {
return Object.fromEntries(
Object.entries(ast)
.filter(
([key, value]) => key !== 'loc' && key !== 'start' && key !== 'end',
)
.filter(([key]) => key !== 'loc' && key !== 'start' && key !== 'end')
.map(([key, value]) => [key, getSimpleAstJson(value)]),
);
} else {
+1
View File
@@ -40,6 +40,7 @@ export async function registerWxt(
wxt = {
config,
hooks,
hook: hooks.hook.bind(hooks),
get logger() {
return config.logger;
},
+2 -4
View File
@@ -1,7 +1,7 @@
import { InlineConfig } from '../types';
import path from 'node:path';
import fs from 'fs-extra';
import { kebabCaseAlphanumeric } from './utils/strings';
import { safeFilename } from './utils/strings';
import { getPackageJson } from './utils/package';
import { minimatch } from 'minimatch';
import { formatDuration } from './utils/time';
@@ -27,9 +27,7 @@ export async function zip(config?: InlineConfig): Promise<string[]> {
const projectName =
wxt.config.zip.name ??
kebabCaseAlphanumeric(
(await getPackageJson())?.name || path.dirname(process.cwd()),
);
safeFilename((await getPackageJson())?.name || path.dirname(process.cwd()));
const applyTemplate = (template: string): string =>
template
.replaceAll('{{name}}', projectName)
+9 -5
View File
@@ -34,17 +34,21 @@ export function defineWxtModule<TOptions extends WxtModuleOptions>(
* the output directory. This will speed up project builds since it just has to
* copy some files instead of bundling them.
*
* To extract entrypoint options from a JS/TS file, use
* `wxt.builder.importEntrypoint` (see example).
*
* @param wxt The wxt instance provided by the module's setup function.
* @param entrypoint The entrypoint to be bundled along with the extension.
*
* @example
* export default defineWxtModule((wxt, options) => {
* export default defineWxtModule(async (wxt, options) => {
* const entrypointPath = "/path/to/my-entrypoint.ts";
* addEntrypoint(wxt, {
* type: "unlisted-page",
* name: "changelog",
* inputPath: "wxt-module-changelog/index.html"
* type: "content-script",
* name: "some-name",
* inputPath: entrypointPath,
* outputDir: wxt.config.outputDir,
* options: {},
* options: await wxt.builder.importEntrypoint(entrypointPath),
* });
* });
*/
+38 -3
View File
@@ -832,7 +832,8 @@ export type ResolvedPerBrowserOptions<T, TOmitted extends keyof T = never> = {
*/
export type UserManifest = Partial<
Omit<
Manifest.WebExtensionManifest,
chrome.runtime.ManifestV3,
| 'action'
| 'background'
| 'chrome_url_overrides'
| 'devtools_page'
@@ -841,7 +842,34 @@ export type UserManifest = Partial<
| 'options_ui'
| 'sandbox'
>
>;
> & {
// Add any Browser-specific or MV2 properties that WXT supports here
action?: chrome.runtime.ManifestV3['action'] & {
browser_style?: boolean;
};
browser_action?: chrome.runtime.ManifestV2['browser_action'] & {
browser_style?: boolean;
};
page_action?: chrome.runtime.ManifestV2['page_action'] & {
browser_style?: boolean;
};
browser_specific_settings?: {
gecko?: {
id?: string;
strict_min_version?: string;
strict_max_version?: string;
update_url?: string;
};
gecko_android?: {
strict_min_version?: string;
strict_max_version?: string;
};
safari?: {
strict_min_version?: string;
strict_max_version?: string;
};
};
};
export type UserManifestFn = (
env: ConfigEnv,
@@ -1107,6 +1135,9 @@ export interface WxtHooks {
) => HookResult;
/**
* Called once all entrypoints have been loaded from the `entrypointsDir`.
* Use `wxt.builder.importEntrypoint` to load entrypoint options from the
* file, or manually define them.
*
* @param wxt The configured WXT object
* @param entrypoints The list of entrypoints to be built
*/
@@ -1129,6 +1160,10 @@ export interface WxtHooks {
export interface Wxt {
config: ResolvedConfig;
hooks: Hookable<WxtHooks>;
/**
* Alias for `wxt.hooks.hook(...)`.
*/
hook: Hookable<WxtHooks>['hook'];
/**
* Alias for config.logger
*/
@@ -1375,7 +1410,7 @@ export interface WxtModule<TOptions extends WxtModuleOptions> {
* Alternative to adding hooks in setup function with `wxt.hooks`. Hooks are
* added before the `setup` function is called.
*/
hooks?: Partial<WxtHooks>;
hooks?: NestedHooks<WxtHooks>;
/**
* A custom function that can be used to setup hooks and call module-specific
* APIs.
+1 -1
View File
@@ -6,12 +6,12 @@ export default defineConfig({
test: {
mockReset: true,
restoreMocks: true,
setupFiles: ['vitest.setup.ts'],
testTimeout: 120e3,
coverage: {
include: ['src/**'],
exclude: ['**/dist', '**/__tests__', 'src/utils/testing'],
},
globalSetup: ['./vitest.globalSetup.ts'],
},
server: {
watch: {
+19
View File
@@ -0,0 +1,19 @@
import { exists, rm } from 'fs-extra';
let setupHappened = false;
export async function setup() {
if (setupHappened) {
throw new Error('setup called twice');
}
setupHappened = true;
// @ts-expect-error
globalThis.__ENTRYPOINT__ = 'test';
const e2eDistPath = './e2e/dist/';
if (await exists(e2eDistPath)) {
await rm(e2eDistPath, { recursive: true, force: true });
}
}
-2
View File
@@ -1,2 +0,0 @@
// @ts-expect-error
globalThis.__ENTRYPOINT__ = 'test';
+329 -210
View File
File diff suppressed because it is too large Load Diff