Compare commits

...

48 Commits

Author SHA1 Message Date
Aaron 229dfc822d 0.19.0-alpha1 2024-07-24 15:47:44 -05:00
Aaron 7177405c11 Fix dead links 2024-07-24 15:36:40 -05:00
Aaron 24e4abc087 Fix docs 2024-07-24 15:27:04 -05:00
Aaron ac9a4380b1 cleanup 2024-07-24 15:14:25 -05:00
Aaron 71620a02ab Fix tests 2024-07-24 15:13:38 -05:00
Aaron 0aca961629 Fix browser types 2024-07-24 14:59:36 -05:00
Aaron d64af5d4f0 Move option out of experimental 2024-07-24 13:39:30 -05:00
Aaron 7eb0a36245 WIP 2024-07-24 13:31:09 -05:00
Aaron 14bae66bba Update testing setup 2024-07-24 12:10:59 -05:00
Aaron e4ec4a28f9 Exclude dev-only declaration files from build 2024-07-24 11:30:44 -05:00
Aaron 7b32dd7062 Restructure types 2024-07-24 11:28:35 -05:00
Aaron b1ef71a77b Cleanup 2024-07-24 11:23:44 -05:00
Aaron 2f7fb30467 Fix everything 2024-07-24 11:06:43 -05:00
Aaron 4c684e7966 WIP 2024-07-24 08:54:16 -05:00
Aaron 8d5fbb2a32 feat(experimental): Replace disableWebextensionPolyfill with extensionApi 2024-07-24 08:51:34 -05:00
Aaron 5eb5be7123 perf(size)!: Switch from tsup to unbuild for building WXT (#848) 2024-07-24 08:48:48 -05:00
Florian Metz 886b2081c2 fix: wrong module hook type (#849) 2024-07-23 20:02:26 -05:00
Radek Grebski c69e51ce50 docs: Added "RespondEasy" to homepage (#844)
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2024-07-23 09:14:59 -05:00
Hagatopaxi 861efa3415 docs: fix typo (#845) 2024-07-22 23:53:00 -05:00
Aaron 792b57542d updtae lockfile 2024-07-21 11:53:34 -05:00
Aaron 97e6678e5b Upgrade vitest's listed version 2024-07-21 11:46:23 -05:00
Aaron 66c4ec3f99 chore(dev-deps): Upgrade happy-dom from 13 to 14 (#843) 2024-07-21 11:44:52 -05:00
Aaron 8988d6a241 chore(deps): Upgrade minimatch from 9 to 10 (#840) 2024-07-21 11:42:33 -05:00
Aaron b52856bea4 chore(deps): Upgrade webextension-polyfill from 0.10 to 0.12 (#842) 2024-07-21 11:39:40 -05:00
Aaron 16fee19b85 chore(deps): Upgrade ora from 7 to 8 (#841) 2024-07-21 11:39:03 -05:00
Aaron 14011c19cb chore(deps): Upgrade vite-node from 1.6 to 2.0 (#839) 2024-07-21 11:36:02 -05:00
Aaron 005a9dff16 chore(deps): Upgrade esbuild from 0.19.12 to 0.23.0 (#838) 2024-07-21 11:33:39 -05:00
Aaron 3109bbadbe chore(deps): Upgrade async-mutex from 0.4.1 to 0.5.0 (#837) 2024-07-21 11:31:35 -05:00
Aaron 34ae689569 chore(dev-deps): Upgrade vitest from 1.6 to 2.0 (#836) 2024-07-21 11:24:23 -05:00
Aaron 1f216dd57b chore(deps): Bump all non-major dependencies (#834) 2024-07-21 10:01:51 -05:00
GitHub Actions a7963e23db chore(release): wxt v0.18.15 2024-07-21 13:43:02 +00:00
Aaron 069bd6c435 fix: Externalize app config during dependency optimization (#833) 2024-07-21 08:37:09 -05:00
Aaron 88a1244ca9 fix: Build latest version of package before packing 2024-07-21 08:36:45 -05:00
Aaron 7ee391f688 fix: Don't throw error if localization file is missing (#832) 2024-07-21 07:53:38 -05:00
Aaron 2b3eab9c2a docs: Add link to google's update testing tool in migration guide and improve host permission docs 2024-07-20 11:33:17 -05:00
eetann a3fc9e1e18 docs: fix link to unimport (#826) 2024-07-17 07:40:34 -05:00
Aaron 559d32e6eb Update README.md 2024-07-12 08:19:59 -05:00
Aaron f904b79367 Update README.md 2024-07-12 08:19:33 -05:00
eetann 9cd7cca81c docs: fix links to Guide pages (#821) 2024-07-12 07:25:11 -05:00
GitHub Actions 3366c1e35f chore(release): wxt v0.18.14 2024-07-09 16:03:18 +00:00
Aaron 82be31a408 fix(modules): Add types from all wxt node_modules, not just ones with config (#817) 2024-07-09 10:58:41 -05:00
GitHub Actions d767f3f598 chore(release): wxt v0.18.13 2024-07-09 15:07:38 +00:00
Ayub Kokabi 48967c7c5f feat: add XPath support to getAnchor() (#813)
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2024-07-09 10:02:00 -05:00
Aaron 6c4da7225d fix: Add debug logs for vite builder (#816) 2024-07-09 09:58:59 -05:00
多吃点 e9025fb13e docs: Update manifest.md (#815) 2024-07-09 08:12:38 -05:00
jy00566722 8db6b3187b docs: Add "Exchange Rate Converter" extensions to homepage (#808) 2024-07-07 14:41:48 -05:00
Aaron a19f9e12c4 feat(config): dev.server.hostname (#807) 2024-07-07 09:31:38 -05:00
Farzad Soltani a82eb46511 docs: fix grammar (#806) 2024-07-07 09:16:03 -05:00
155 changed files with 1961 additions and 1725 deletions
+2 -2
View File
@@ -35,7 +35,7 @@ jobs:
- uses: ./.github/actions/setup
- uses: oven-sh/setup-bun@v2
- name: pnpm test:coverage
run: pnpm test:coverage --reporter=default --reporter=hanging-process
run: pnpm test:coverage -- --reporter=default --reporter=hanging-process
- uses: codecov/codecov-action@v4
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
@@ -44,7 +44,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup
- run: pnpm test run
- run: pnpm test
template:
runs-on: ubuntu-22.04
strategy:
+1 -1
View File
@@ -37,7 +37,7 @@
## Demo
<video src="https://github.com/wxt-dev/wxt/assets/10101283/4d678939-1bdb-495c-9c36-3aa281d84c94"></video>
https://github.com/wxt-dev/wxt/assets/10101283/4d678939-1bdb-495c-9c36-3aa281d84c94
## Quick Start
@@ -32,6 +32,9 @@ const chromeExtensionIds = [
'khjdmjcmpolknpccmaaipmidphjokhdf', // WorkFlowy MultiFlow
'fencadnndhdeggodopebjgdfdlhcimfk', // 香草布丁🌿🍮- https://github.com/Xdy1579883916/vanilla-pudding
'bnacincmbaknlbegecpioobkfgejlojp', // MaxFocus: Link Preview
'bcpgdpedphodjcjlminjbdeejccjbimp', // 汇率转换-中文版本
'loeilaonggnalkaiiaepbegccilkmjjp', // Currency Converter Plus
'npcnninnjghigjfiecefheeibomjpkak', // Respond Easy
];
const { data, err, isLoading } = useListExtensionDetails(chromeExtensionIds);
+1 -1
View File
@@ -17,7 +17,7 @@ In WXT, you create an entrypoint by adding a file to the `entrypoints/` director
Some entrypoint filesname patterns are reserved by WXT and effect how the manifest is generated.
- `popup` adds a `action` to the manifest
- `popup` adds an `action` to the manifest
- `background` adds a background script/service worker
- `*.content.ts` adds a content script
- ...
+1 -1
View File
@@ -25,7 +25,7 @@ In general, you'll need to:
&ensp;<input type="checkbox" /> Convert custom import syntax to be compatible with Vite<br />
&ensp;<input type="checkbox" /> Add a default export to JS entrypoints<br />
&ensp;<input type="checkbox" /> Use the `browser` global instead of `chrome`<br />
&ensp;<input type="checkbox" /> Compare final `manifest.json` files, making sure permissions and host permissions are unchanged<br />
&ensp;<input type="checkbox" /> Compare final `manifest.json` files, making sure permissions and host permissions are unchanged. Use [Google's update testing tool](https://github.com/GoogleChromeLabs/extension-update-testing-tool) if your extension is already live on the Chrome Web Store<br />
&ensp;<input type="checkbox" /> Extension output by `wxt build` works the same way as before the migration<br />
Every project is different, so there's no one-solution-fits-all to migrating your project. Just make sure `wxt dev` runs, `wxt build` results in a working extension, and the list of permissions in the `manifest.json` hasn't changed. If all that looks good, you've finished migrating your extension!
+1 -1
View File
@@ -19,7 +19,7 @@ There are other options for unit tests however, like [Jest](https://jestjs.io/),
If you want to try to use a different framework for unit tests, you will need to configure the environment manually:
- **Auto-imports**: Add `unimport` to your test environment or disable them by setting `imports: false` in your `wxt.config.ts` file
- **`browser` mock**: Mock the `webextension-polyfill` module globally with `wxt/dist/virtual/mock-browser.js`
- **`browser` mock**: Mock the `webextension-polyfill` module globally with `wxt/dist/virtual/mock-browser.mjs`
- **[Remote Code Bundling](/guide/go-further/remote-code)**: If you use it, configure your environment to handle the `url:` module prefix
- **Global Variables**: If you consume them, manually define globals provided by WXT (like `import.meta.env.BROWSER`) by adding them to the global scope before accessing them (`import.meta.env.BROWSER = "chrome"`)
- **Import paths**: If you use the `@/` or `~/` path aliases, add them to your test environment
+1 -1
View File
@@ -6,7 +6,7 @@ WXT uses the same tool as Nuxt for auto-imports, [`unimport`](https://github.com
Some WXT APIs can be used without importing them:
- [`browser`](/api/reference/wxt/browser/variables/browser) from `wxt/browser`, a small wrapper around `webextension-polyfill`
- [`browser`](/api/reference/wxt/browser/#browser) from `wxt/browser`, a small wrapper around `webextension-polyfill`
- [`defineContentScript`](/api/reference/wxt/sandbox/functions/defineContentScript) from `wxt/sandbox`
- [`defineBackground`](/api/reference/wxt/sandbox/functions/defineBackground) from `wxt/sandbox`
- [`defineUnlistedScript`](/api/reference/wxt/sandbox/functions/defineUnlistedScript) from `wxt/sandbox`
@@ -95,7 +95,7 @@ Usually, this means each entrypoint should be a directory with it's own files in
├ App.vue
├ main.ts
├ style.css
└ rotuer.ts
└ router.ts
```
## Configuring Routers
+26 -1
View File
@@ -147,6 +147,31 @@ export default defineConfig({
});
```
### Host Permissions
[Host Permissions](https://developer.chrome.com/docs/extensions/develop/concepts/declare-permissions#host-permissions) must be listed in the manifest config.
```ts
export default defineConfig({
manifest: {
host_permissions: ['*://*.google.com/*'],
},
});
```
:::warning
If you use host permissions and target both MV2 and MV3, make sure to only include the required host permissions for each version:
```ts
export default defineConfig({
manifest: ({ manifestVersion }) => ({
host_permissions: manifestVersion === 2 ? [...] : [...],
}),
});
```
:::
## Localization
Similar to the icon, the [`_locales` directory](https://developer.chrome.com/docs/extensions/reference/i18n/) should be placed inside the the WXT's [`public` directory](/guide/directory-structure/public/).
@@ -229,7 +254,7 @@ The `manifest` option can also be set equal to a function, letting you use logic
```ts
// wxt.config.ts
export default defineConfig({
manifest: ({ manifestVersion, browser, mode, comamnd }) => {
manifest: ({ manifestVersion, browser, mode, command }) => {
return { ... }
}
})
+10 -12
View File
@@ -5,11 +5,11 @@
"node": ">=18.20.3",
"pnpm": "^8.6.3"
},
"packageManager": "pnpm@8.15.8",
"packageManager": "pnpm@8.15.9",
"scripts": {
"check": "check && pnpm -r --sequential run check",
"test": "vitest",
"test:coverage": "vitest run --coverage.enabled \"--coverage.include=packages/wxt/src/**\" \"--coverage.exclude=packages/wxt/src/core/utils/testing/**\" \"--coverage.exclude=**/*.d.ts\" \"--coverage.exclude=**/fixtures/**\"",
"test": "pnpm -r --sequential run test run",
"test:coverage": "pnpm -r --sequential run test:coverage",
"prepare": "simple-git-hooks",
"prepublish": "pnpm -s build",
"docs:gen": "typedoc --options docs/typedoc.json",
@@ -18,10 +18,10 @@
"docs:preview": "pnpm -s docs:gen && vitepress preview docs"
},
"devDependencies": {
"@aklinker1/buildc": "^1.0.10",
"@aklinker1/buildc": "^1.0.11",
"@aklinker1/check": "^1.3.1",
"@types/fs-extra": "^11.0.4",
"@vitest/coverage-v8": "^1.6.0",
"@vitest/coverage-v8": "^2.0.0",
"changelogen": "^0.5.5",
"consola": "^3.2.3",
"dependency-graph": "^1.0.0",
@@ -31,18 +31,16 @@
"hasha": "^6.0.0",
"lint-staged": "^15.2.7",
"npm-run-all": "^4.1.5",
"prettier": "^3.3.2",
"prettier": "^3.3.3",
"simple-git-hooks": "^2.11.1",
"tsx": "4.15.7",
"typedoc": "^0.25.4",
"typedoc-plugin-markdown": "4.0.0-next.23",
"typedoc-vitepress-theme": "1.0.0-next.3",
"typescript": "^5.5.2",
"vitepress": "^1.2.3",
"vitest": "^1.6.0",
"vitest-mock-extended": "^1.3.1",
"vitest-plugin-random-seed": "^1.1.0",
"vue": "^3.4.31",
"typescript": "^5.5.3",
"vitepress": "^1.3.1",
"vitest-mock-extended": "^1.3.2",
"vue": "^3.4.33",
"wxt": "workspace:*",
"yaml": "^2.4.5"
},
+1
View File
@@ -9,6 +9,7 @@ export default defineWxtModule<ReactModuleOptions>({
const { vite } = options ?? {};
addViteConfig(wxt, () => ({
// @ts-expect-error: Vite version conflicts
plugins: [react(vite)],
}));
+2 -2
View File
@@ -36,10 +36,10 @@
"@aklinker1/check": "^1.3.1",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"publint": "^0.2.8",
"publint": "^0.2.9",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"typescript": "^5.5.2",
"typescript": "^5.5.3",
"unbuild": "^2.0.0",
"wxt": "workspace:*"
}
+1
View File
@@ -9,6 +9,7 @@ export default defineWxtModule<SolidModuleOptions>({
const { vite } = options ?? {};
addViteConfig(wxt, () => ({
// @ts-expect-error: Vite version mismatch
plugins: [solid(vite)],
build: {
target: 'esnext',
+3 -3
View File
@@ -34,9 +34,9 @@
},
"devDependencies": {
"@aklinker1/check": "^1.3.1",
"publint": "^0.2.8",
"solid-js": "^1.8.17",
"typescript": "^5.5.2",
"publint": "^0.2.9",
"solid-js": "^1.8.18",
"typescript": "^5.5.3",
"unbuild": "^2.0.0",
"wxt": "workspace:*"
}
+1 -1
View File
@@ -5,7 +5,7 @@ Enables the use of [Svelte](https://svelte.dev/) in your web extension, in HTML
This plugin makes a few changes:
1. Adds `@sveltejs/vite-plugin-svelte` to vite
2. Adds the [`svelte` preset](https://github.com/unjs/unimport/blob/main/src/presets/vue.ts) to auto-imports
2. Adds the [`svelte` preset](https://github.com/unjs/unimport/blob/main/src/presets/svelte.ts) to auto-imports
## Usage
+2 -2
View File
@@ -32,8 +32,8 @@
},
"devDependencies": {
"@aklinker1/check": "^1.3.1",
"publint": "^0.2.8",
"typescript": "^5.5.2",
"publint": "^0.2.9",
"typescript": "^5.5.3",
"unbuild": "^2.0.0",
"wxt": "workspace:*"
}
+1
View File
@@ -14,6 +14,7 @@ export default defineWxtModule<SvelteModuleOptions>({
addViteConfig(wxt, () => ({
plugins: [
// @ts-expect-error: Vite version mismatch
svelte({
// Using a svelte.config.js file causes a segmentation fault when importing the file
configFile: false,
+2 -2
View File
@@ -32,8 +32,8 @@
},
"devDependencies": {
"@aklinker1/check": "^1.3.1",
"publint": "^0.2.8",
"typescript": "^5.5.2",
"publint": "^0.2.9",
"typescript": "^5.5.3",
"unbuild": "^2.0.0",
"wxt": "workspace:*"
}
+6 -3
View File
@@ -5,7 +5,7 @@
"type": "module",
"scripts": {
"dev": "buildc --deps-only -- wxt",
"build": "buildc -- wxt build",
"build": "buildc --deps-only -- wxt build",
"build:all": "buildc --deps-only -- run-s -s 'build:all:*'",
"build:all:chrome-mv3": "wxt build",
"build:all:chrome-mv2": "wxt build --mv2",
@@ -21,10 +21,13 @@
"react-dom": "^18.3.1"
},
"devDependencies": {
"@types/chrome": "^0.0.268",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"sass": "^1.77.6",
"typescript": "^5.5.2",
"sass": "^1.77.8",
"typescript": "^5.5.3",
"vitest": "^2.0.3",
"vitest-plugin-random-seed": "^1.1.0",
"wxt": "workspace:*"
},
"buildc": {
+2 -1
View File
@@ -2,6 +2,7 @@
"extends": ["../../tsconfig.base.json", "./.wxt/tsconfig.json"],
"compilerOptions": {
"allowImportingTsExtensions": true,
"jsx": "react-jsx"
"jsx": "react-jsx",
"types": ["vitest-plugin-random-seed/types"]
}
}
+4 -1
View File
@@ -6,5 +6,8 @@ export default defineProject({
mockReset: true,
restoreMocks: true,
},
plugins: [WxtVitest()],
plugins: [
// @ts-expect-error: Vite version mismatch
WxtVitest(),
],
});
+1
View File
@@ -2,6 +2,7 @@ import { defineConfig } from 'wxt';
export default defineConfig({
srcDir: 'src',
extensionApi: 'chrome',
manifest: {
permissions: ['storage'],
default_locale: 'en',
+43
View File
@@ -1,5 +1,48 @@
# Changelog
## v0.18.15
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.18.14...wxt-v0.18.15)
### 🩹 Fixes
- Don't throw error if localization file is missing ([#832](https://github.com/wxt-dev/wxt/pull/832))
- Build latest version of package before packing ([88a1244](https://github.com/wxt-dev/wxt/commit/88a1244))
- Externalize app config during dependency optimization ([#833](https://github.com/wxt-dev/wxt/pull/833))
### 📖 Documentation
- Fix links to Guide pages ([#821](https://github.com/wxt-dev/wxt/pull/821))
### ❤️ Contributors
- Eetann ([@eetann](http://github.com/eetann))
## v0.18.14
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.18.13...wxt-v0.18.14)
### 🩹 Fixes
- **modules:** Add types from all wxt node_modules, not just ones with config ([#817](https://github.com/wxt-dev/wxt/pull/817))
## v0.18.13
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.18.12...wxt-v0.18.13)
### 🚀 Enhancements
- **config:** `dev.server.hostname` ([#807](https://github.com/wxt-dev/wxt/pull/807))
- Add XPath support to getAnchor() ([#813](https://github.com/wxt-dev/wxt/pull/813))
### 🩹 Fixes
- Add debug logs for vite builder ([#816](https://github.com/wxt-dev/wxt/pull/816))
### ❤️ Contributors
- Ayub Kokabi ([@sir-kokabi](http://github.com/sir-kokabi))
## v0.18.12
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.18.11...wxt-v0.18.12)
+1 -1
View File
@@ -37,7 +37,7 @@
## Demo
<video src="https://github.com/wxt-dev/wxt/assets/10101283/4d678939-1bdb-495c-9c36-3aa281d84c94"></video>
https://github.com/wxt-dev/wxt/assets/10101283/4d678939-1bdb-495c-9c36-3aa281d84c94
## Quick Start
+1 -1
View File
@@ -1,2 +1,2 @@
#!/usr/bin/env node
import '../dist/cli.js';
import '../dist/cli/index.mjs';
+49
View File
@@ -0,0 +1,49 @@
import { defineBuildConfig } from 'unbuild';
import { version } from './package.json';
import { readFile, writeFile } from 'fs/promises';
import {
virtualEntrypointModuleNames,
virtualModuleNames,
} from './src/core/utils/virtual-modules';
export default defineBuildConfig([
// Non-virtual modules can be transpiled with mkdist
{
entries: [
{
builder: 'mkdist',
input: 'src',
pattern: ['**/*', '!**/__tests__', '!**/*.md', '!virtual', '!@types'],
declaration: true,
},
],
hooks: {
async 'build:done'() {
// Replace any template variables in output files
await replaceVars('dist/version.mjs', { version });
},
},
},
// Virtual modules must be bundled individually
...virtualModuleNames.map((moduleName) => ({
entries: [`src/virtual/${moduleName}.ts`],
externals: [
...virtualEntrypointModuleNames.map((name) => `virtual:user-${name}`),
'virtual:wxt-plugins',
'virtual:app-config',
'wxt/browser',
'wxt/sandbox',
'wxt/client',
'wxt/testing',
],
})),
]);
async function replaceVars(file: string, vars: Record<string, string>) {
let text = await readFile(file, 'utf8');
Object.entries(vars).forEach(([name, value]) => {
text = text.replaceAll(`{{${name}}}`, value);
});
await writeFile(file, text, 'utf8');
}
+1 -1
View File
@@ -1,6 +1,6 @@
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { TestProject } from '../utils';
import { resetBundleIncrement } from '~/core/builders/vite/plugins';
import { resetBundleIncrement } from '../../src/core/builders/vite/plugins';
import open from 'open';
vi.mock('open');
+1 -1
View File
@@ -1,6 +1,6 @@
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { TestProject } from '../utils';
import { WxtHooks } from '~/types';
import { WxtHooks } from '../../src/types';
const hooks: WxtHooks = {
ready: vi.fn(),
+1 -2
View File
@@ -1,9 +1,8 @@
import { describe, it, expect } from 'vitest';
import { TestProject } from '../utils';
import { TestProject, WXT_PACKAGE_DIR } from '../utils';
import { execaCommand } from 'execa';
import glob from 'fast-glob';
import { mkdir, writeJson } from 'fs-extra';
import { WXT_PACKAGE_DIR } from '../utils';
describe('Init command', () => {
it('should download and create a template', async () => {
+9 -17
View File
@@ -2,7 +2,7 @@ import { describe, it, expect, vi } from 'vitest';
import { TestProject } from '../utils';
import type { GenericEntrypoint, InlineConfig } from '../../src/types';
import { readFile } from 'fs-extra';
import { normalizePath } from '~/core/utils/paths';
import { normalizePath } from '../../src/core/utils/paths';
describe('Module Helpers', () => {
describe('options', () => {
@@ -192,10 +192,8 @@ describe('Module Helpers', () => {
const expectedText = addPluginModule(project);
await project.build({
experimental: {
// reduce build output when comparing test failures
includeBrowserPolyfill: false,
},
// reduce build output when comparing test failures
extensionApi: 'chrome',
});
await expect(project.serializeOutput()).resolves.toContain(expectedText);
@@ -214,10 +212,8 @@ describe('Module Helpers', () => {
const expectedText = addPluginModule(project);
await project.build({
experimental: {
// reduce build output when comparing test failures
includeBrowserPolyfill: false,
},
// reduce build output when comparing test failures
extensionApi: 'chrome',
});
await expect(project.serializeOutput()).resolves.toContain(expectedText);
@@ -237,10 +233,8 @@ describe('Module Helpers', () => {
const expectedText = addPluginModule(project);
await project.build({
experimental: {
// reduce build output when comparing test failures
includeBrowserPolyfill: false,
},
// reduce build output when comparing test failures
extensionApi: 'chrome',
});
await expect(project.serializeOutput()).resolves.toContain(expectedText);
@@ -255,10 +249,8 @@ describe('Module Helpers', () => {
const expectedText = addPluginModule(project);
await project.build({
experimental: {
// reduce build output when comparing test failures
includeBrowserPolyfill: false,
},
// reduce build output when comparing test failures
extensionApi: 'chrome',
});
await expect(project.serializeOutput()).resolves.toContain(expectedText);
+24 -16
View File
@@ -262,10 +262,9 @@ describe('Output Directory Structure', () => {
project.addFile('entrypoints/popup/main.ts', `logHello('popup')`);
await project.build({
experimental: {
// Simplify the build output for comparison
includeBrowserPolyfill: false,
},
// Simplify the build output for comparison
extensionApi: 'chrome',
vite: () => ({
build: {
// Make output for snapshot readible
@@ -278,6 +277,7 @@ describe('Output Directory Structure', () => {
.toMatchInlineSnapshot(`
".output/chrome-mv3/background.js
----------------------------------------
var _a, _b;
import { l as logHello, i as initPlugins } from "./chunks/_virtual_wxt-plugins-OjKtWpmY.js";
function defineBackground(arg) {
if (typeof arg === "function") return { main: arg };
@@ -289,17 +289,21 @@ describe('Output Directory Structure', () => {
logHello("background");
}
});
chrome;
// @ts-expect-error
((_b = (_a = globalThis.browser) == null ? void 0 : _a.runtime) == null ? void 0 : _b.id) == null ? globalThis.chrome : (
// @ts-expect-error
globalThis.browser
);
function print(method, ...args) {
return;
}
var logger = {
const logger = {
debug: (...args) => print(console.debug, ...args),
log: (...args) => print(console.log, ...args),
warn: (...args) => print(console.warn, ...args),
error: (...args) => print(console.error, ...args)
};
var result;
let result;
try {
initPlugins();
result = definition.main();
@@ -343,10 +347,9 @@ describe('Output Directory Structure', () => {
project.addFile('entrypoints/popup/main.ts', `logHello('popup')`);
await project.build({
experimental: {
// Simplify the build output for comparison
includeBrowserPolyfill: false,
},
// Simplify the build output for comparison
extensionApi: 'chrome',
vite: () => ({
build: {
// Make output for snapshot readible
@@ -361,6 +364,7 @@ describe('Output Directory Structure', () => {
----------------------------------------
var _background = function() {
"use strict";
var _a, _b;
function defineBackground(arg) {
if (typeof arg === "function") return { main: arg };
return arg;
@@ -377,17 +381,21 @@ describe('Output Directory Structure', () => {
_background;
function initPlugins() {
}
chrome;
// @ts-expect-error
((_b = (_a = globalThis.browser) == null ? void 0 : _a.runtime) == null ? void 0 : _b.id) == null ? globalThis.chrome : (
// @ts-expect-error
globalThis.browser
);
function print(method, ...args) {
return;
}
var logger = {
const logger = {
debug: (...args) => print(console.debug, ...args),
log: (...args) => print(console.log, ...args),
warn: (...args) => print(console.warn, ...args),
error: (...args) => print(console.error, ...args)
};
var result;
let result;
try {
initPlugins();
result = definition.main();
@@ -400,8 +408,8 @@ describe('Output Directory Structure', () => {
logger.error("The background crashed on startup!");
throw err;
}
var background_entrypoint_default = result;
return background_entrypoint_default;
const result$1 = result;
return result$1;
}();
_background;
"
@@ -53,7 +53,7 @@ describe('TypeScript Project', () => {
| "/popup.html"
| "/sandbox.html"
type HtmlPublicPath = Extract<PublicPath, \`\${string}.html\`>
export interface WxtRuntime extends Runtime.Static {
export interface WxtRuntime {
getURL(path: PublicPath): string;
getURL(path: \`\${HtmlPublicPath}\${string}\`): string;
}
+3 -5
View File
@@ -1,6 +1,6 @@
import { describe, it, expect } from 'vitest';
import { TestProject } from '../utils';
import { InlineConfig } from '~/types';
import { InlineConfig } from '../../src/types';
describe('User Config', () => {
// Root directory is tested with all tests.
@@ -88,7 +88,7 @@ describe('User Config', () => {
`);
});
it('should exclude the polyfill when the experimental setting is set to false', async () => {
it('should exclude the polyfill when extensionApi="chrome"', async () => {
const buildBackground = async (config?: InlineConfig) => {
const background = `export default defineBackground(() => console.log(browser.runtime.id));`;
const projectWithPolyfill = new TestProject();
@@ -101,9 +101,7 @@ describe('User Config', () => {
const withPolyfill = await buildBackground();
const withoutPolyfill = await buildBackground({
experimental: {
includeBrowserPolyfill: false,
},
extensionApi: 'chrome',
});
expect(withoutPolyfill).not.toBe(withPolyfill);
});
+53 -58
View File
@@ -1,7 +1,7 @@
{
"name": "wxt",
"type": "module",
"version": "0.18.12",
"version": "0.19.0-alpha1",
"description": "Next gen framework for developing web extensions",
"repository": {
"type": "git",
@@ -30,75 +30,59 @@
"wxt": "./bin/wxt.mjs",
"wxt-publish-extension": "./bin/wxt-publish-extension.cjs"
},
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"exports": {
".": {
"import": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"require": {
"types": "./dist/index.d.cts",
"default": "./dist/index.cjs"
}
"types": "./dist/index.d.ts",
"default": "./dist/index.mjs"
},
"./client": {
"types": "./dist/client.d.ts",
"import": "./dist/client.js"
"types": "./dist/client/index.d.ts",
"default": "./dist/client/index.mjs"
},
"./sandbox": {
"types": "./dist/sandbox.d.ts",
"import": "./dist/sandbox.js"
"types": "./dist/sandbox/index.d.ts",
"default": "./dist/sandbox/index.mjs"
},
"./browser": {
"types": "./dist/browser.d.ts",
"import": "./dist/browser.js"
"types": "./dist/browser/index.d.ts",
"default": "./dist/browser/index.mjs"
},
"./browser/chrome": {
"types": "./dist/browser/chrome.d.ts",
"import": "./dist/browser/chrome.mjs"
},
"./browser/webextension-polyfill": {
"types": "./dist/browser/webextension-polyfill.d.ts",
"import": "./dist/browser/webextension-polyfill.mjs"
},
"./testing": {
"import": {
"types": "./dist/testing.d.ts",
"default": "./dist/testing.js"
},
"require": {
"types": "./dist/testing.d.cts",
"default": "./dist/testing.cjs"
}
"types": "./dist/testing/index.d.ts",
"default": "./dist/testing/index.mjs"
},
"./storage": {
"import": {
"types": "./dist/storage.d.ts",
"default": "./dist/storage.js"
},
"require": {
"types": "./dist/storage.d.cts",
"default": "./dist/storage.cjs"
}
"types": "./dist/storage.d.ts",
"default": "./dist/storage.mjs"
},
"./vite-builder-env": {
"types": "./dist/vite-builder-env.d.ts"
},
"./modules": {
"import": {
"types": "./dist/modules.d.ts",
"default": "./dist/modules.js"
},
"require": {
"types": "./dist/modules.d.cts",
"default": "./dist/modules.cjs"
}
"types": "./dist/modules.d.ts",
"default": "./dist/modules.mjs"
}
},
"scripts": {
"wxt": "tsx src/cli/index.ts",
"build": "buildc -- tsx scripts/build.ts",
"build": "buildc -- unbuild",
"check": "buildc --deps-only -- run-s -c check:*",
"check:default": "check",
"check:tsc-virtual": "tsc --noEmit -p src/virtual",
"test": "buildc --deps-only -- vitest",
"test:e2e": "buildc --deps-only -- vitest -r e2e",
"sync-releases": "pnpx changelogen@latest gh release"
"test:coverage": "pnpm test -- run --coverage",
"sync-releases": "pnpx changelogen@latest gh release",
"prepack": "pnpm build"
},
"dependencies": {
"@aklinker1/rollup-plugin-visualizer": "5.12.0",
@@ -106,16 +90,16 @@
"@webext-core/fake-browser": "^1.3.1",
"@webext-core/isolated-element": "^1.1.2",
"@webext-core/match-patterns": "^1.0.3",
"async-mutex": "^0.4.1",
"async-mutex": "^0.5.0",
"c12": "^1.11.1",
"cac": "^6.7.14",
"chokidar": "^3.6.0",
"ci-info": "^4.0.0",
"defu": "^6.1.4",
"dequal": "^2.0.3",
"esbuild": "^0.19.12",
"esbuild": "^0.23.0",
"fast-glob": "^3.3.2",
"filesize": "^10.1.2",
"filesize": "^10.1.4",
"fs-extra": "^11.2.0",
"get-port": "^7.1.0",
"giget": "^1.2.3",
@@ -126,39 +110,50 @@
"jszip": "^3.10.1",
"linkedom": "^0.18.4",
"magicast": "^0.3.4",
"minimatch": "^9.0.5",
"minimatch": "^10.0.1",
"natural-compare": "^1.4.0",
"normalize-path": "^3.0.0",
"nypm": "^0.3.9",
"ohash": "^1.1.3",
"open": "^10.1.0",
"ora": "^7.0.1",
"ora": "^8.0.1",
"picocolors": "^1.0.1",
"prompts": "^2.4.2",
"publish-browser-extension": "^2.1.3",
"unimport": "^3.7.2",
"vite": "^5.3.2",
"vite-node": "^1.6.0",
"unimport": "^3.9.0",
"vite": "^5.3.4",
"vite-node": "^2.0.0",
"web-ext-run": "^0.2.1",
"webextension-polyfill": "^0.10.0"
"webextension-polyfill": "^0.12.0"
},
"devDependencies": {
"@aklinker1/check": "^1.3.1",
"@faker-js/faker": "^8.4.1",
"@types/chrome": "^0.0.268",
"@types/fs-extra": "^11.0.4",
"@types/lodash.merge": "^4.6.9",
"@types/natural-compare": "^1.4.3",
"@types/node": "^20.14.9",
"@types/node": "^20.14.11",
"@types/normalize-path": "^3.0.2",
"@types/prompts": "^2.4.9",
"execa": "^9.3.0",
"extract-zip": "^2.0.1",
"happy-dom": "^13.10.1",
"happy-dom": "^14.12.3",
"lodash.merge": "^4.6.2",
"p-map": "^7.0.2",
"publint": "^0.2.8",
"tsup": "^8.1.0",
"publint": "^0.2.9",
"tsx": "4.15.7",
"typescript": "^5.5.2"
"typescript": "^5.5.3",
"unbuild": "^2.0.0",
"vitest": "^2.0.3",
"vitest-plugin-random-seed": "^1.1.0"
},
"peerDependencies": {
"@types/chrome": "*"
},
"peerDependenciesMeta": {
"@types/chrome": {
"optional": true
}
}
}
-126
View File
@@ -1,126 +0,0 @@
import tsup from 'tsup';
import glob from 'fast-glob';
import { printFileList } from '~/core/utils/log';
import { formatDuration } from '~/core/utils/time';
import ora from 'ora';
import fs from 'fs-extra';
import { consola } from 'consola';
import pMap from 'p-map';
import os from 'node:os';
import path from 'node:path';
import {
virtualModuleNames,
virtualEntrypointModuleNames,
} from '~/core/utils/virtual-modules';
const spinnerText = 'Building WXT';
const spinner = ora(spinnerText).start();
const startTime = Date.now();
const outDir = 'dist';
await fs.rm(path.join(outDir, '*'), { recursive: true, force: true });
const preset = {
dts: true,
silent: true,
sourcemap: false,
external: [
...virtualEntrypointModuleNames.map((name) => `virtual:user-${name}`),
'virtual:wxt-plugins',
'virtual:app-config',
],
} satisfies tsup.Options;
function spinnerPMap(configs: tsup.Options[]) {
let progress = 1;
const updateSpinner = () => {
spinner.text = `${spinnerText} [${progress}/${configs.length}]`;
};
updateSpinner();
return pMap(
config,
async (config) => {
const res = await tsup.build(config);
progress++;
updateSpinner();
return res;
},
{
stopOnError: true,
concurrency: process.env.CI === 'true' ? os.cpus().length : Infinity,
},
);
}
const config: tsup.Options[] = [
// CJS/ESM
{
...preset,
entry: {
index: 'src/index.ts',
testing: 'src/testing/index.ts',
storage: 'src/storage.ts',
modules: 'src/modules.ts',
},
format: ['cjs', 'esm'],
clean: true,
},
// ESM-only
{
...preset,
entry: {
browser: 'src/browser.ts',
sandbox: 'src/sandbox/index.ts',
client: 'src/client/index.ts',
},
format: ['esm'],
},
{
...preset,
entry: virtualModuleNames.reduce<Record<string, string>>(
(acc, moduleName) => {
acc[`virtual/${moduleName}`] = `src/virtual/${moduleName}.ts`;
return acc;
},
{},
),
format: ['esm'],
splitting: false,
dts: false,
external: [...preset.external, 'wxt'],
},
// CJS-only
{
...preset,
entry: {
cli: 'src/cli/index.ts',
},
format: ['esm'],
banner: {
// Fixes dynamic require of nodejs modules. See https://github.com/wxt-dev/wxt/issues/355
// https://github.com/evanw/esbuild/issues/1921#issuecomment-1152991694
js: "import { createRequire } from 'module';const require = createRequire(import.meta.url);",
},
},
];
await spinnerPMap(config).catch((err) => {
spinner.fail();
console.error(err);
process.exit(1);
});
// Copy "public" files that need shipped inside WXT
await fs.copyFile('src/vite-builder-env.d.ts', 'dist/vite-builder-env.d.ts');
spinner.clear().stop();
const duration = Date.now() - startTime;
const outFiles = await glob(`${outDir}/**`, { absolute: true });
await printFileList(
consola.success,
`Built WXT in ${formatDuration(duration)}`,
outDir,
outFiles,
);
@@ -49,8 +49,3 @@ declare module 'web-ext-run/util/logger' {
}
export const consoleStream: IConsoleStream;
}
declare module 'wxt/browser' {
// Overridden when types are generated per project
export type PublicPath = string;
}
+1 -1
View File
@@ -1,4 +1,4 @@
import { fakeWxt } from '~/core/utils/testing/fake-objects';
import { fakeWxt } from '../core/utils/testing/fake-objects';
import { addImportPreset, addViteConfig } from '../modules';
import { describe, it, expect } from 'vitest';
import { createHooks } from 'hookable';
+2 -2
View File
@@ -1,7 +1,7 @@
import { fakeBrowser } from '@webext-core/fake-browser';
import { describe, it, expect, beforeEach, vi, expectTypeOf } from 'vitest';
import { browser } from '~/browser';
import { WxtStorageItem, storage } from '~/storage';
import { browser } from 'wxt/browser';
import { WxtStorageItem, storage } from '../storage';
/**
* This works because fakeBrowser is synchronous, and is will finish any number of chained
+28
View File
@@ -0,0 +1,28 @@
/// <reference types="chrome" />
/**
* EXPERIMENTAL
*
* Includes the `chrome` API and types when using `extensionApi: 'chrome'`.
*
* @module wxt/browser/chrome
*/
export interface WxtRuntime {
// Overriden per-project
}
export interface WxtI18n {
// Overriden per-project
}
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 const browser: WxtBrowser =
// @ts-expect-error
globalThis.browser?.runtime?.id == null
? globalThis.chrome
: // @ts-expect-error
globalThis.browser;
+4
View File
@@ -0,0 +1,4 @@
/**
* @module wxt/browser
*/
export * from './webextension-polyfill';
@@ -1,6 +1,9 @@
/**
* @module wxt/browser
* Includes the `browser` API and types when using `extensionApi: 'webextension-polyfill'` (the default).
*
* @module wxt/browser/webextension-polyfill
*/
import originalBrowser, { Browser, Runtime, I18n } from 'webextension-polyfill';
export interface AugmentedBrowser extends Browser {
+1 -1
View File
@@ -1,4 +1,4 @@
import { WxtModule } from '~/types';
import { WxtModule } from '../types';
import unimport from './unimport';
export const builtinModules: WxtModule<any>[] = [unimport];
+2 -2
View File
@@ -1,10 +1,10 @@
import { addViteConfig, defineWxtModule } from '~/modules';
import { addViteConfig, defineWxtModule } from '../modules';
import type {
EslintGlobalsPropValue,
WxtDirFileEntry,
WxtModule,
WxtResolvedUnimportOptions,
} from '~/types';
} from '../types';
import { type Unimport, createUnimport } from 'unimport';
import { Plugin } from 'vite';
import { extname } from 'node:path';
+13 -13
View File
@@ -1,29 +1,29 @@
import { describe, it, vi, beforeEach, expect } from 'vitest';
import { build } from '~/core/build';
import { createServer } from '~/core/create-server';
import { zip } from '~/core/zip';
import { prepare } from '~/core/prepare';
import { clean } from '~/core/clean';
import { initialize } from '~/core/initialize';
import { build } from '../../core/build';
import { createServer } from '../../core/create-server';
import { zip } from '../../core/zip';
import { prepare } from '../../core/prepare';
import { clean } from '../../core/clean';
import { initialize } from '../../core/initialize';
import { mock } from 'vitest-mock-extended';
import consola from 'consola';
vi.mock('~/core/build');
vi.mock('../../core/build');
const buildMock = vi.mocked(build);
vi.mock('~/core/create-server');
vi.mock('../../core/create-server');
const createServerMock = vi.mocked(createServer);
vi.mock('~/core/zip');
vi.mock('../../core/zip');
const zipMock = vi.mocked(zip);
vi.mock('~/core/prepare');
vi.mock('../../core/prepare');
const prepareMock = vi.mocked(prepare);
vi.mock('~/core/clean');
vi.mock('../../core/clean');
const cleanMock = vi.mocked(clean);
vi.mock('~/core/initialize');
vi.mock('../../core/initialize');
const initializeMock = vi.mocked(initialize);
consola.wrapConsole();
@@ -35,7 +35,7 @@ function mockArgv(...args: string[]) {
}
async function importCli() {
await import('~/cli');
await import('../../cli');
}
describe('CLI', () => {
+5 -5
View File
@@ -1,10 +1,10 @@
import { CAC, Command } from 'cac';
import consola, { LogLevels } from 'consola';
import { filterTruthy, toArray } from '~/core/utils/arrays';
import { printHeader } from '~/core/utils/log';
import { formatDuration } from '~/core/utils/time';
import { ValidationError } from '~/core/utils/validation';
import { registerWxt } from '~/core/wxt';
import { filterTruthy, toArray } from '../core/utils/arrays';
import { printHeader } from '../core/utils/log';
import { formatDuration } from '../core/utils/time';
import { ValidationError } from '../core/utils/validation';
import { registerWxt } from '../core/wxt';
/**
* Wrap an action handler to add a timer, error handling, and maybe enable debug mode.
+1 -1
View File
@@ -1,5 +1,5 @@
import cac from 'cac';
import { build, clean, createServer, initialize, prepare, zip } from '~/core';
import { build, clean, createServer, initialize, prepare, zip } from '../core';
import {
createAliasedCommand,
getArrayFromFlags,
+1 -1
View File
@@ -1,5 +1,5 @@
import cli from './commands';
import { version } from '~/version';
import { version } from '../version';
import { isAliasedCommand } from './cli-utils';
// TODO: Remove. See https://github.com/wxt-dev/wxt/issues/277
+1 -1
View File
@@ -1,6 +1,6 @@
// @ts-expect-error: Untyped virtual module
import appConfig from 'virtual:app-config';
import type { WxtAppConfig } from '~/sandbox/define-app-config';
import type { WxtAppConfig } from '../sandbox/define-app-config';
export function useAppConfig(): WxtAppConfig {
return appConfig;
@@ -1,6 +1,6 @@
import { ContentScriptDefinition } from '~/types';
import { browser } from '~/browser';
import { logger } from '~/sandbox/utils/logger';
import { ContentScriptDefinition } from '../../types';
import { browser } from 'wxt/browser';
import { logger } from '../../sandbox/utils/logger';
import { WxtLocationChangeEvent, getUniqueEventName } from './custom-events';
import { createLocationWatcher } from './location-watcher';
@@ -1,4 +1,4 @@
import { browser } from '~/browser';
import { browser } from 'wxt/browser';
export class WxtLocationChangeEvent extends Event {
static EVENT_NAME = getUniqueEventName('wxt:locationchange');
@@ -22,5 +22,5 @@ export function getUniqueEventName(eventName: string): string {
? 'build'
: import.meta.env.ENTRYPOINT;
return `${browser.runtime.id}:${entrypointName}:${eventName}`;
return `${browser?.runtime?.id}:${entrypointName}:${eventName}`;
}
@@ -252,6 +252,24 @@ describe('Content Script UIs', () => {
document.querySelector('#parent > div[data-wxt-integrated]'),
).not.toBeNull();
});
it('should append the element using an XPath string', () => {
vi.stubGlobal('XPathResult', { FIRST_ORDERED_NODE_TYPE: 9 });
document.evaluate = vi.fn().mockReturnValue({
singleNodeValue: document.querySelector('#three'),
});
const ui = createIntegratedUi(ctx, {
position: 'inline',
onMount: appendTestApp,
anchor: '//p[@id="three"]',
});
ui.mount();
expect(
document.querySelector('#three > div[data-wxt-integrated]'),
).not.toBeNull();
});
});
describe('Element', () => {
@@ -1,4 +1,4 @@
import { browser } from '~/browser';
import { browser } from 'wxt/browser';
import { ContentScriptContext } from '..';
import {
ContentScriptAnchoredOptions,
@@ -10,7 +10,7 @@ import {
ShadowRootContentScriptUi,
ShadowRootContentScriptUiOptions,
} from './types';
import { logger } from '~/sandbox/utils/logger';
import { logger } from '../../../sandbox/utils/logger';
import { createIsolatedElement } from '@webext-core/isolated-element';
export * from './types';
@@ -199,8 +199,25 @@ function getAnchor(options: ContentScriptAnchoredOptions): Element | undefined {
let resolved =
typeof options.anchor === 'function' ? options.anchor() : options.anchor;
if (typeof resolved === 'string')
return document.querySelector<Element>(resolved) ?? undefined;
if (typeof resolved === 'string') {
// If the string is an XPath expression (starts with '//' or '/')
if (resolved.startsWith('/')) {
// Evaluate the XPath and return the first ordered node
const result = document.evaluate(
resolved,
document,
null,
XPathResult.FIRST_ORDERED_NODE_TYPE,
null,
);
return (result.singleNodeValue as Element) ?? undefined;
} else {
// If the string is a CSS selector, query the document and return the element
return document.querySelector<Element>(resolved) ?? undefined;
}
}
return resolved ?? undefined;
}
@@ -194,7 +194,7 @@ export type ContentScriptPositioningOptions =
export interface ContentScriptAnchoredOptions {
/**
* A CSS selector, element, or function that returns one of the two. Along with `append`, the
* A CSS selector, XPath expression, element, or function that returns one of the three. Along with `append`, the
* `anchor` dictates where in the page the UI will be added.
*/
anchor?:
+1 -1
View File
@@ -1,4 +1,4 @@
import { BuildOutput, InlineConfig } from '~/types';
import { BuildOutput, InlineConfig } from '../types';
import { internalBuild } from './utils/building';
import { registerWxt } from './wxt';
+9 -9
View File
@@ -7,20 +7,20 @@ import {
WxtBuilderServer,
WxtDevServer,
WxtHooks,
} from '~/types';
} from '../../../types';
import * as wxtPlugins from './plugins';
import {
getEntrypointBundlePath,
isHtmlEntrypoint,
} from '~/core/utils/entrypoints';
} from '../../utils/entrypoints';
import {
VirtualEntrypointType,
VirtualModuleId,
} from '~/core/utils/virtual-modules';
} from '../../utils/virtual-modules';
import { Hookable } from 'hookable';
import { toArray } from '~/core/utils/arrays';
import { safeVarName } from '~/core/utils/strings';
import { importEntrypointFile } from '~/core/utils/building';
import { toArray } from '../../utils/arrays';
import { safeVarName } from '../../utils/strings';
import { importEntrypointFile } from '../../utils/building';
import { ViteNodeServer } from 'vite-node/server';
import { ViteNodeRunner } from 'vite-node/client';
import { installSourcemapsSupport } from 'vite-node/source-map';
@@ -66,7 +66,7 @@ export async function createViteBuilder(
wxtPlugins.tsconfigPaths(wxtConfig),
wxtPlugins.noopBackground(),
wxtPlugins.globals(wxtConfig),
wxtPlugins.excludeBrowserPolyfill(wxtConfig),
wxtPlugins.resolveExtensionApi(wxtConfig),
wxtPlugins.defineImportMeta(),
wxtPlugins.wxtPluginLoader(wxtConfig),
wxtPlugins.resolveAppConfig(wxtConfig),
@@ -218,7 +218,7 @@ export async function createViteBuilder(
const baseConfig = await getBaseConfig();
const envConfig: vite.InlineConfig = {
plugins: [
wxtPlugins.webextensionPolyfillMock(wxtConfig),
wxtPlugins.extensionApiMock(wxtConfig),
wxtPlugins.removeEntrypointMainFunction(wxtConfig, path),
],
};
@@ -238,7 +238,7 @@ export async function createViteBuilder(
baseConfig.optimizeDeps.include = [];
const envConfig: vite.InlineConfig = {
plugins: [
wxtPlugins.webextensionPolyfillMock(wxtConfig),
wxtPlugins.extensionApiMock(wxtConfig),
wxtPlugins.removeEntrypointMainFunction(wxtConfig, path),
],
};
@@ -4,8 +4,8 @@ import { pointToDevServer } from '../devHtmlPrerender';
import {
fakeDevServer,
fakeResolvedConfig,
} from '~/core/utils/testing/fake-objects';
import { normalizePath } from '~/core/utils/paths';
} from '../../../../utils/testing/fake-objects';
import { normalizePath } from '../../../../utils/paths';
import { resolve } from 'node:path';
describe('Dev HTML Prerender Plugin', () => {
@@ -1,11 +1,12 @@
import type * as vite from 'vite';
import { visualizer } from '@aklinker1/rollup-plugin-visualizer';
import { ResolvedConfig } from '~/types';
import { ResolvedConfig } from '../../../../types';
import path from 'node:path';
let increment = 0;
export function bundleAnalysis(config: ResolvedConfig): vite.Plugin {
// @ts-expect-error: Vite version mismatch
return visualizer({
template: 'raw-data',
filename: path.resolve(
@@ -1,6 +1,6 @@
import type * as vite from 'vite';
import { Entrypoint, ResolvedConfig } from '~/types';
import { getEntrypointBundlePath } from '~/core/utils/entrypoints';
import { Entrypoint, ResolvedConfig } from '../../../../types';
import { getEntrypointBundlePath } from '../../../utils/entrypoints';
/**
* Rename CSS entrypoint outputs to ensure a JS file is not generated, and that the CSS file is
@@ -1,9 +1,9 @@
import type * as vite from 'vite';
import { ResolvedConfig, WxtDevServer } from '~/types';
import { getEntrypointName } from '~/core/utils/entrypoints';
import { ResolvedConfig, WxtDevServer } from '../../../../types';
import { getEntrypointName } from '../../../utils/entrypoints';
import { parseHTML } from 'linkedom';
import { dirname, relative, resolve } from 'node:path';
import { normalizePath } from '~/core/utils/paths';
import { normalizePath } from '../../../utils/paths';
import { murmurHash } from 'ohash';
// Stored outside the plugin to effect all instances of the devHtmlPrerender plugin.
@@ -19,7 +19,7 @@ export function devHtmlPrerender(
const htmlReloadId = '@wxt/reload-html';
const resolvedHtmlReloadId = resolve(
config.wxtModuleDir,
'dist/virtual/reload-html.js',
'dist/virtual/reload-html.mjs',
);
const virtualInlineScript = 'virtual:wxt-inline-script';
@@ -1,5 +1,5 @@
import { Plugin } from 'vite';
import { ResolvedConfig, WxtDevServer } from '~/types';
import { ResolvedConfig, WxtDevServer } from '../../../../types';
/**
* Defines global constants about the dev server. Helps scripts connect to the server's web socket.
@@ -1,6 +1,6 @@
import { Plugin } from 'vite';
import { ResolvedConfig } from '~/types';
import { fetchCached } from '~/core/utils/network';
import { ResolvedConfig } from '../../../../types';
import { fetchCached } from '../../../utils/network';
/**
* Downloads any URL imports, like Google Analytics, into virtual modules so they are bundled with
@@ -1,6 +1,6 @@
import type * as vite from 'vite';
import { EntrypointGroup } from '~/types';
import { getEntrypointGlobals } from '~/core/utils/globals';
import { EntrypointGroup } from '../../../../types';
import { getEntrypointGlobals } from '../../../utils/globals';
/**
* Define a set of global variables specific to an entrypoint.
@@ -1,33 +0,0 @@
import { ResolvedConfig } from '~/types';
import type * as vite from 'vite';
/**
* Apply the experimental config for disabling the polyfill. It works by aliasing the
* `webextension-polyfill` module to a virtual module and exporting the `chrome` global from the
* virtual module.
*/
export function excludeBrowserPolyfill(config: ResolvedConfig): vite.Plugin {
const virtualId = 'virtual:wxt-webextension-polyfill-disabled';
return {
name: 'wxt:exclude-browser-polyfill',
config() {
// Only apply the config if we're disabling the polyfill
if (config.experimental.includeBrowserPolyfill) return;
return {
resolve: {
alias: {
'webextension-polyfill': virtualId,
},
},
};
},
load(id) {
if (id === virtualId) {
// Use chrome instead of the polyfill when disabled.
return 'export default chrome';
}
},
};
}
@@ -0,0 +1,37 @@
import path from 'node:path';
import type * as vite from 'vite';
import { ResolvedConfig } from '../../../../types';
/**
* Mock `webextension-polyfill`, `wxt/browser`, and `wxt/browser/*` by inlining
* all dependencies that import them and adding a custom alias so that Vite
* resolves to a mocked version of the module.
*
* TODO: Detect non-wxt dependencies (like `@webext-core/*`) that import `webextension-polyfill` via
* `npm list` and inline them automatically.
*/
export function extensionApiMock(config: ResolvedConfig): vite.PluginOption {
return {
name: 'wxt:extension-api-mock',
config() {
const replacement = path.resolve(
config.wxtModuleDir,
'dist/virtual/mock-browser',
);
return {
resolve: {
alias: [
{ find: 'webextension-polyfill', replacement },
// wxt/browser, wxt/browser/...
{ find: /^wxt\/browser.*/, replacement },
],
},
ssr: {
// Inline all WXT modules so vite processes them so the aliases can
// be resolved
noExternal: ['wxt'],
},
};
},
};
}
@@ -1,6 +1,6 @@
import type * as vite from 'vite';
import { ResolvedConfig } from '~/types';
import { getGlobals } from '~/core/utils/globals';
import { ResolvedConfig } from '../../../../types';
import { getGlobals } from '../../../utils/globals';
export function globals(config: ResolvedConfig): vite.PluginOption {
return {
@@ -8,8 +8,8 @@ export * from './noopBackground';
export * from './cssEntrypoints';
export * from './bundleAnalysis';
export * from './globals';
export * from './webextensionPolyfillMock';
export * from './excludeBrowserPolyfill';
export * from './extensionApiMock';
export * from './resolveExtensionApi';
export * from './entrypointGroupGlobals';
export * from './defineImportMeta';
export * from './removeEntrypointMainFunction';
@@ -1,9 +1,9 @@
import type * as vite from 'vite';
import { Entrypoint, ResolvedConfig } from '~/types';
import { Entrypoint, ResolvedConfig } from '../../../../types';
import { dirname, extname, resolve, join } from 'node:path';
import { getEntrypointBundlePath } from '~/core/utils/entrypoints';
import { getEntrypointBundlePath } from '../../../utils/entrypoints';
import fs, { ensureDir } from 'fs-extra';
import { normalizePath } from '~/core/utils/paths';
import { normalizePath } from '../../../utils/paths';
/**
* Ensures the HTML files output by a multipage build are in the correct location. This does two
@@ -1,5 +1,5 @@
import { Plugin } from 'vite';
import { VIRTUAL_NOOP_BACKGROUND_MODULE_ID } from '~/core/utils/constants';
import { VIRTUAL_NOOP_BACKGROUND_MODULE_ID } from '../../../utils/constants';
/**
* In dev mode, if there's not a background script listed, we need to add one so that the web socket
@@ -1,7 +1,7 @@
import { ResolvedConfig } from '~/types';
import { ResolvedConfig } from '../../../../types';
import * as vite from 'vite';
import { normalizePath } from '~/core/utils/paths';
import { removeMainFunctionCode } from '~/core/utils/transform';
import { normalizePath } from '../../../utils/paths';
import { removeMainFunctionCode } from '../../../utils/transform';
import { resolve } from 'node:path';
/**
@@ -1,7 +1,7 @@
import { exists } from 'fs-extra';
import { resolve } from 'node:path';
import type * as vite from 'vite';
import { ResolvedConfig } from '~/types';
import { ResolvedConfig } from '../../../../types';
/**
* When importing `virtual:app-config`, resolve it to the `app.config.ts` file in the project.
@@ -13,6 +13,15 @@ export function resolveAppConfig(config: ResolvedConfig): vite.Plugin {
return {
name: 'wxt:resolve-app-config',
config() {
return {
optimizeDeps: {
// Prevent ESBuild from attempting to resolve the virtual module
// while optimizing WXT.
exclude: [virtualModuleId],
},
};
},
async resolveId(id) {
if (id !== virtualModuleId) return;
@@ -0,0 +1,27 @@
import { ResolvedConfig } from '../../../../types';
import type * as vite from 'vite';
/**
* Apply the experimental config for which extension API is used. This only
* effects the extension API included at RUNTIME - during development, types
* depend on the import.
*
* NOTE: this only works if we import `wxt/browser` instead of using the relative path.
*/
export function resolveExtensionApi(config: ResolvedConfig): vite.Plugin {
return {
name: 'wxt:resolve-extension-api',
config() {
// Only apply the config if we're disabling the polyfill
if (config.extensionApi === 'webextension-polyfill') return;
return {
resolve: {
alias: [
{ find: /^wxt\/browser$/, replacement: 'wxt/browser/chrome' },
],
},
};
},
};
}
@@ -1,10 +1,10 @@
import { Plugin } from 'vite';
import { ResolvedConfig } from '~/types';
import { normalizePath } from '~/core/utils/paths';
import { ResolvedConfig } from '../../../../types';
import { normalizePath } from '../../../utils/paths';
import {
VirtualModuleId,
virtualModuleNames,
} from '~/core/utils/virtual-modules';
} from '../../../utils/virtual-modules';
import fs from 'fs-extra';
import { resolve } from 'path';
@@ -31,7 +31,7 @@ export function resolveVirtualModules(config: ResolvedConfig): Plugin[] {
const inputPath = id.replace(resolvedVirtualId, '');
const template = await fs.readFile(
resolve(config.wxtModuleDir, `dist/virtual/${name}.js`),
resolve(config.wxtModuleDir, `dist/virtual/${name}.mjs`),
'utf-8',
);
return template.replace(`virtual:user-${name}`, inputPath);
@@ -1,4 +1,4 @@
import { ResolvedConfig } from '~/types';
import { ResolvedConfig } from '../../../../types';
import type * as vite from 'vite';
export function tsconfigPaths(config: ResolvedConfig): vite.Plugin {
@@ -1,41 +0,0 @@
import path from 'node:path';
import type * as vite from 'vite';
import { ResolvedConfig } from '~/types';
/**
* Mock `webextension-polyfill` by inlining all dependencies that import it and adding a custom
* alias so that Vite resolves to a mocked version of the module.
*
* There are two ways to mark a module as inline:
* 1. Use partial file paths ("wxt/dist/browser.js") in the `test.server.deps.inline` option.
* 2. Use module names ("wxt" or "@webext-core/messaging") in the `ssr.noExternalize` option.
*
* This plugin uses the second approach since it's a little more intuative to understand.
*
* TODO: Detect non-wxt dependencies (like `@webext-core/*`) that import `webextension-polyfill` via
* `npm list` and inline them automatically.
*/
export function webextensionPolyfillMock(
config: ResolvedConfig,
): vite.PluginOption {
return {
name: 'wxt:testing-inline-deps',
config() {
return {
resolve: {
alias: {
// Alias to use a mocked version of the polyfill
'webextension-polyfill': path.resolve(
config.wxtModuleDir,
'dist/virtual/mock-browser',
),
},
},
ssr: {
// Inline all WXT modules
noExternal: ['wxt'],
},
};
},
};
}
@@ -1,7 +1,7 @@
import { parseHTML } from 'linkedom';
import type * as vite from 'vite';
import { normalizePath } from '~/core/utils/paths';
import { ResolvedConfig } from '~/types';
import { normalizePath } from '../../../utils/paths';
import { ResolvedConfig } from '../../../../types';
/**
* Resolve and load plugins for each entrypoint. This handles both JS entrypoints via the `virtual:wxt-plugins` import, and HTML files by adding `virtual:wxt-html-plugins` to the document's `<head>`
+1 -1
View File
@@ -2,7 +2,7 @@ import path from 'node:path';
import glob from 'fast-glob';
import fs from 'fs-extra';
import pc from 'picocolors';
import { InlineConfig } from '~/types';
import { InlineConfig } from '../types';
import { registerWxt, wxt } from './wxt';
/**
+5 -8
View File
@@ -4,22 +4,19 @@ import {
InlineConfig,
ServerInfo,
WxtDevServer,
} from '~/types';
import {
getEntrypointBundlePath,
isHtmlEntrypoint,
} from '~/core/utils/entrypoints';
} from '../types';
import { getEntrypointBundlePath, isHtmlEntrypoint } from './utils/entrypoints';
import {
getContentScriptCssFiles,
getContentScriptsCssMap,
} from '~/core/utils/manifest';
} from './utils/manifest';
import {
internalBuild,
detectDevChanges,
rebuild,
findEntrypoints,
} from '~/core/utils/building';
import { createExtensionRunner } from '~/core/runners';
} from './utils/building';
import { createExtensionRunner } from './runners';
import { Mutex } from 'async-mutex';
import pc from 'picocolors';
import { relative } from 'node:path';
+1 -1
View File
@@ -1,4 +1,4 @@
import { UserConfig } from '~/types';
import { UserConfig } from '../types';
export function defineConfig(config: UserConfig): UserConfig {
return config;
@@ -1,4 +1,4 @@
import { ExtensionRunnerConfig } from '~/types';
import { ExtensionRunnerConfig } from '../types';
export function defineRunnerConfig(
config: ExtensionRunnerConfig,
@@ -8,7 +8,7 @@ import {
PackageManager,
PackageManagerName,
} from 'nypm';
import { WxtPackageManager } from '~/types';
import { WxtPackageManager } from '../../types';
import { bun } from './bun';
import { WxtPackageManagerImpl } from './types';
import { yarn } from './yarn';
@@ -1,4 +1,4 @@
import { Dependency } from '~/types';
import { Dependency } from '../../types';
import { WxtPackageManagerImpl } from './types';
import path from 'node:path';
import { ensureDir } from 'fs-extra';
@@ -1,4 +1,4 @@
import { WxtPackageManager } from '~/types';
import { WxtPackageManager } from '../../types';
export type WxtPackageManagerImpl = Pick<
WxtPackageManager,
@@ -1,4 +1,4 @@
import { Dependency } from '~/types';
import { Dependency } from '../../types';
import { WxtPackageManagerImpl } from './types';
import { dedupeDependencies, npm } from './npm';
+2 -2
View File
@@ -1,5 +1,5 @@
import { InlineConfig } from '~/types';
import { findEntrypoints, generateTypesDir } from '~/core/utils/building';
import { InlineConfig } from '../types';
import { findEntrypoints, generateTypesDir } from './utils/building';
import { registerWxt, wxt } from './wxt';
export async function prepare(config: InlineConfig) {
@@ -1,13 +1,13 @@
import { describe, expect, it, vi } from 'vitest';
import { createExtensionRunner } from '..';
import { setFakeWxt } from '~/core/utils/testing/fake-objects';
import { setFakeWxt } from '../../utils/testing/fake-objects';
import { mock } from 'vitest-mock-extended';
import { createSafariRunner } from '../safari';
import { createWslRunner } from '../wsl';
import { createManualRunner } from '../manual';
import { isWsl } from '../../utils/wsl';
import { createWebExtRunner } from '../web-ext';
import { ExtensionRunner } from '~/types';
import { ExtensionRunner } from '../../../types';
vi.mock('../../utils/wsl');
const isWslMock = vi.mocked(isWsl);
+2 -2
View File
@@ -1,9 +1,9 @@
import { ExtensionRunner } from '~/types';
import { ExtensionRunner } from '../../types';
import { createWslRunner } from './wsl';
import { createWebExtRunner } from './web-ext';
import { createSafariRunner } from './safari';
import { createManualRunner } from './manual';
import { isWsl } from '~/core/utils/wsl';
import { isWsl } from '../utils/wsl';
import { wxt } from '../wxt';
export async function createExtensionRunner(): Promise<ExtensionRunner> {
+1 -1
View File
@@ -1,4 +1,4 @@
import { ExtensionRunner } from '~/types';
import { ExtensionRunner } from '../../types';
import { relative } from 'node:path';
import { wxt } from '../wxt';
+1 -1
View File
@@ -1,4 +1,4 @@
import { ExtensionRunner } from '~/types';
import { ExtensionRunner } from '../../types';
import { relative } from 'node:path';
import { wxt } from '../wxt';
+1 -1
View File
@@ -1,5 +1,5 @@
import type { WebExtRunInstance } from 'web-ext-run';
import { ExtensionRunner } from '~/types';
import { ExtensionRunner } from '../../types';
import { formatDuration } from '../utils/time';
import defu from 'defu';
import { wxt } from '../wxt';
+1 -1
View File
@@ -1,4 +1,4 @@
import { ExtensionRunner } from '~/types';
import { ExtensionRunner } from '../../types';
import { relative } from 'node:path';
import { wxt } from '../wxt';
@@ -1,5 +1,5 @@
import { describe, it, expect } from 'vitest';
import { every, some } from '~/core/utils/arrays';
import { every, some } from '../arrays';
describe('Array Utils', () => {
describe('every', () => {
@@ -1,6 +1,6 @@
import { describe, expect, it, beforeEach } from 'vitest';
import { hashContentScriptOptions } from '~/core/utils/content-scripts';
import { setFakeWxt } from '~/core/utils/testing/fake-objects';
import { hashContentScriptOptions } from '../content-scripts';
import { setFakeWxt } from '../testing/fake-objects';
describe('Content Script Utils', () => {
beforeEach(() => {
@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vitest';
import { ContentSecurityPolicy } from '~/core/utils/content-security-policy';
import { ContentSecurityPolicy } from '../content-security-policy';
describe('Content Security Policy Builder', () => {
it('should add values to new directives correctly', () => {
@@ -3,8 +3,8 @@ import {
getEntrypointName,
getEntrypointOutputFile,
resolvePerBrowserOption,
} from '~/core/utils/entrypoints';
import { Entrypoint } from '~/types';
} from '../entrypoints';
import { Entrypoint } from '../../../types';
import { resolve } from 'path';
describe('Entrypoint Utils', () => {
@@ -19,7 +19,7 @@ import {
ContentScriptEntrypoint,
Entrypoint,
OutputAsset,
} from '~/types';
} from '../../../types';
import { wxt } from '../../wxt';
const outDir = '/output';
@@ -2,7 +2,7 @@ import { describe, it, expect } from 'vitest';
import { getPackageJson } from '../package';
import { setFakeWxt } from '../testing/fake-objects';
import { mock } from 'vitest-mock-extended';
import { Logger } from '~/types';
import { Logger } from '../../../types';
import { WXT_PACKAGE_DIR } from '../../../../e2e/utils';
describe('Package JSON Utils', () => {
@@ -1,5 +1,5 @@
import { beforeEach, describe, expect, it } from 'vitest';
import { DevModeChange, detectDevChanges } from '~/core/utils/building';
import { DevModeChange, detectDevChanges } from '../../../utils/building';
import {
fakeBackgroundEntrypoint,
fakeContentScriptEntrypoint,
@@ -12,8 +12,8 @@ import {
fakeOutputChunk,
fakeWxt,
setFakeWxt,
} from '~/core/utils/testing/fake-objects';
import { BuildOutput, BuildStepOutput } from '~/types';
} from '../../../utils/testing/fake-objects';
import { BuildOutput, BuildStepOutput } from '../../../../types';
import { setWxtForTesting } from '../../../wxt';
describe('Detect Dev Changes', () => {
@@ -8,7 +8,7 @@ import {
OptionsEntrypoint,
PopupEntrypoint,
SidepanelEntrypoint,
} from '~/types';
} from '../../../../types';
import { resolve } from 'path';
import { findEntrypoints } from '../find-entrypoints';
import fs from 'fs-extra';
@@ -16,9 +16,9 @@ import glob from 'fast-glob';
import {
fakeResolvedConfig,
setFakeWxt,
} from '~/core/utils/testing/fake-objects';
import { unnormalizePath } from '~/core/utils/paths';
import { wxt } from '~/core/wxt';
} from '../../../utils/testing/fake-objects';
import { unnormalizePath } from '../../../utils/paths';
import { wxt } from '../../../wxt';
vi.mock('fast-glob');
const globMock = vi.mocked(glob);

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