Compare commits

...

53 Commits

Author SHA1 Message Date
GitHub Actions 203a9cc234 chore(release): v0.18.2 2024-05-08 15:50:03 +00:00
Aaron 5fcaf7c68b fix: Automatically detect and add "sidePanel" permission 2024-05-08 10:42:07 -05:00
Aaron c74e530d4a docs: Fix iframe typos 2024-05-08 10:34:34 -05:00
Edoan 3f78be0c95 feat(runner): Add keepProfileChanges option (#655) 2024-05-07 22:20:51 -05:00
Linus Norton 2a3d52045d docs: Correct event handler name in handling-updates.md (#653) 2024-05-07 04:31:28 -05:00
Jeffrey Zang ea5b81d25e docs: Fix spelling mistake in remote-code.md (#652) 2024-05-06 21:58:36 -05:00
Emmanuel Ferdman cec9d7103a docs: Fix wxt-vitest-plugin reference (#650)
Signed-off-by: Emmanuel Ferdman <emmanuelferdman@gmail.com>
2024-05-05 08:30:40 -05:00
GitHub Actions 34dd2c1487 chore(release): v0.18.1 2024-05-04 16:42:09 +00:00
Aaron a5667f85d0 fix: _background is not defined (#649) 2024-05-04 11:39:29 -05:00
Aaron ec3dd52f83 chore: Add root README back 2024-05-04 11:03:55 -05:00
Aaron 87ebde3abb Fix sync releases workflow 2024-05-04 11:01:08 -05:00
Aaron dc5b55bffb ci: Fix sync releases workflow 2024-05-04 10:59:40 -05:00
Aaron df20993917 Fix changelog generation 2024-05-04 10:57:23 -05:00
Aaron caa0fb31e6 Add breaking change message to changelog 2024-05-04 10:53:35 -05:00
GitHub Actions 95da4fb054 chore(release): v0.18.0 2024-05-04 15:51:44 +00:00
Aaron a917f32a0e feat(experimental): Load entrypoint options with Vite Runtime API (#648) 2024-05-04 10:46:31 -05:00
Aaron 6ca376749c chore: Fix formatting after monorepo refactor 2024-05-04 09:44:07 -05:00
Aaron 792e3032b9 feat: Support returning values from scripts executed with the scripting API (#624) 2024-05-03 17:32:42 -05:00
alegal200 38a5a2c440 docs: Document required permission for storage API (#632)
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2024-05-03 17:28:52 -05:00
yacine-bens 21106ce188 docs: Add MS Edge TTS to homepage (#647) 2024-05-03 17:26:34 -05:00
Aaron ec7263e7de chore: Refactor repo to a standard monorepo (#646) 2024-05-03 17:16:33 -05:00
dependabot[bot] e7c3fc2a5e chore(deps-dev): bump simple-git-hooks from 2.9.0 to 2.11.1 (#640)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-02 08:14:03 -05:00
dependabot[bot] f808cb7526 chore(deps-dev): bump publint from 0.2.6 to 0.2.7 (#639)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-02 08:13:15 -05:00
dependabot[bot] c4795e7479 chore(deps): bump react and @types/react (#638)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-02 08:13:02 -05:00
dependabot[bot] b44a96ab81 chore(deps-dev): bump lint-staged from 15.2.1 to 15.2.2 (#637)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-02 08:12:45 -05:00
evsamson 3bfdc5c755 FIX: Chromium window-size example format (#630)
Co-authored-by: smsnbv <active.sock7816@fastmail.com>
2024-04-22 07:12:30 -05:00
Aaron acb75543ff docs: Add docs about handling updates
Related to #620
2024-04-20 00:04:05 -05:00
Aaron 25b45b9c09 fix(dep): Upgrade @webext-core/isolated-element to v1.1.2 (#625) 2024-04-19 22:09:16 -05:00
Aaron efd5c40043 fix!: Automatically move host_permissions to permissions for MV2 (#626)
BREAKING CHANGE: Out of an abundance of caution, I've marked this as a breaking change because permission generation has changed. ***If you list `host_permissions` in your `wxt.config.ts`'s manifest and have released your extension***, double check that your `permissions` and `host_permissions` have not changed for all browsers you target. Permission changes can cause the extension to be disabled on update, and can cause a drop in users, so be sure to double check for differences compared to the previous manifest version.
2024-04-19 22:08:52 -05:00
Aaron e47519fb76 docs: Update content script registration JSDoc
See https://github.com/wxt-dev/wxt/discussions/623
2024-04-19 15:59:14 -05:00
Ayden 171e32c272 docs: Add ElemSnap to homepage (#621) 2024-04-19 08:00:41 -05:00
wuzequanyouzi 54e5ed0bb4 chore: Update vue template config (#607)
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2024-04-15 12:43:43 -05:00
Aaron a94d673f31 docs: Fix typo in assets page 2024-04-15 12:17:02 -05:00
yacine-bens b7f7222c26 docs: Add Facebook Video Controls to homepage (#615) 2024-04-15 12:13:06 -05:00
Can Rau aa5a9d4fa9 docs: Tix typo in entrypoints.md (#614) 2024-04-14 17:21:12 -05:00
日高 凌 77da2d6ade docs: Fix typo on example for wxt.config.ts. (#609) 2024-04-12 09:00:15 -05:00
Bas van Zanten 3119c04e10 feat: Add zip compression settings (#605) 2024-04-12 08:59:54 -05:00
couriourc c09994263e doc: Fix bad extension API examples (#608) 2024-04-12 01:01:07 -05:00
ThinkStu 2a4fa9ae5c docs: Add Fluent Read to homepage (#600)
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2024-04-07 09:01:02 -05:00
Aaron c833d3b15b Update test snapshot after vite upgrade 2024-04-07 08:53:15 -05:00
Aaron d6e095bfce Fix type error 2024-04-07 08:47:52 -05:00
Aaron 825160a3cc chore(deps): Upgrade vite 2024-04-03 14:16:51 -05:00
Aaron e29ca33f82 Add missing cleanup from PR 2024-04-03 14:15:55 -05:00
GitHub Actions ca5a52c6f1 chore(release): v0.17.12 2024-04-03 19:04:03 +00:00
Aaron 982c69f8ae feat: Add hooks for extending vite config (#599) 2024-04-03 14:00:48 -05:00
Aaron 6fc7d9254a fix(content-script-ui): Properly assign and unassign mounted value (#598) 2024-04-03 12:38:46 -05:00
dependabot[bot] 2e0e104d48 chore(deps): bump c12 from 1.5.1 to 1.10.0 (#592)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-01 23:23:11 -05:00
dependabot[bot] 02430fd7b8 chore(deps-dev): bump sass from 1.69.5 to 1.72.0 (#591)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-01 23:23:01 -05:00
dependabot[bot] 2e6d35d193 chore(deps-dev): bump vue from 3.3.10 to 3.4.21 (#589)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-01 23:08:37 -05:00
dependabot[bot] 7cf412ac1f chore(deps): bump vitest from 1.2.2 to 1.4.0 (#590)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-01 22:15:44 -05:00
Aaron 9398cbb596 docs: Add discord server link (#593) 2024-04-01 19:13:12 -05:00
dependabot[bot] ca9b96142e chore(deps-dev): bump @aklinker1/check from 1.1.1 to 1.2.0 (#588)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-01 18:10:28 -05:00
Aaron db57c8e079 chore: Remove unnecssary 'Omit' types 2024-03-31 08:40:21 -05:00
247 changed files with 1977 additions and 930 deletions
+3
View File
@@ -25,11 +25,14 @@ jobs:
pnpx changelogen@latest --release
git push
git push --tags
working-directory: packages/wxt
- name: NPM
run: |
echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_AUTH_TOKEN }}" > ~/.npmrc
pnpm publish
working-directory: packages/wxt
- name: GitHub Release
run: pnpx changelogen@latest gh release --token ${{ secrets.GITHUB_TOKEN }}
working-directory: packages/wxt
+1
View File
@@ -20,3 +20,4 @@ jobs:
node-version: 18
cache: pnpm
- run: pnpm sync-releases all --token ${{ secrets.GITHUB_TOKEN }}
working-directory: packages/wxt
+5 -8
View File
@@ -13,19 +13,15 @@ jobs:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup
- run: pnpm check
validate-demo:
build-demo:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup
- run: pnpm tsc --noEmit
working-directory: demo
- run: pnpm build:all
working-directory: demo
working-directory: packages/wxt-demo
- run: pnpm wxt zip
working-directory: demo
- run: pnpm vitest run
working-directory: demo
working-directory: packages/wxt-demo
tests:
runs-on: ubuntu-22.04
steps:
@@ -57,9 +53,10 @@ jobs:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup
- run: pnpm pack
working-directory: packages/wxt
- run: npm i
working-directory: templates/${{ matrix.template }}
- run: npm i -D ../../wxt-*.tgz
- run: npm i -D ../../packages/wxt/wxt-*.tgz
working-directory: templates/${{ matrix.template }}
- run: pnpm compile
if: matrix.template != 'svelte'
-1
View File
@@ -1 +0,0 @@
ignore-workspace-root-check=true
+2
View File
@@ -29,6 +29,8 @@
<a href="https://wxt.dev/api/config.html" target="_blank">Configuration</a>
&bull;
<a href="https://wxt.dev/examples.html" target="_blank">Examples</a>
&bull;
<a href="https://discord.gg/ZFsZqGery9" target="_blank">Discord</a>
</p>
![Example CLI Output](./docs/assets/cli-output.png)
-30
View File
@@ -1,30 +0,0 @@
{
"name": "demo",
"version": "1.0.0",
"description": "Demo extension for WXT",
"type": "module",
"scripts": {
"dev": "pnpm -w build && wxt",
"build": "pnpm -w build && wxt build",
"build:all": "pnpm -w build && run-s -s 'build:all:*'",
"build:all:chrome-mv3": "wxt build",
"build:all:chrome-mv2": "wxt build --mv2",
"build:all:firefox-mv3": "wxt build -b firefox --mv3",
"build:all:firefox-mv2": "wxt build -b firefox",
"test": "pnpm -w build && vitest",
"zip": "pnpm -w build && wxt zip",
"compile": "pnpm -w build && tsc --noEmit",
"postinstall": "pnpm -w build && wxt prepare"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"vitest": "^1.2.2"
},
"devDependencies": {
"@types/react": "^18.2.34",
"@types/react-dom": "^18.2.14",
"sass": "^1.69.5",
"wxt": "workspace:*"
}
}
@@ -22,6 +22,10 @@ const chromeExtensionIds = [
'nomnkbngkijpffepcgbbofhcnafpkiep', // DocVersionRedirector
'ceicccfeikoipigeghddpocceifjelph', // Plex Skipper
'aelkipgppclpfimeamgmlonimflbhlgf', // GitHub Custom Notifier
'djnlaiohfaaifbibleebjggkghlmcpcj', // Fluent Read
'nhclljcpfmmaiojbhhnkpjcfmacfcian', // Facebook Video Controls
'mblkhbaakhbhiimkbcnmeciblfhmafna', // ElemSnap - Quick capture of webpage elements and conversion to images,
'oajalfneblkfiejoadecnmodfpnaeblh', // MS Edge TTS (Text to Speech)
];
const { data, err, isLoading } = useListExtensionDetails(chromeExtensionIds);
+5 -1
View File
@@ -95,6 +95,7 @@ export default defineConfig({
{ text: 'Vite', link: '/guide/vite.md' },
{ text: 'Remote Code', link: '/guide/remote-code.md' },
{ text: 'Publishing', link: '/guide/publishing.md' },
{ text: 'Handling Updates', link: '/guide/handling-updates.md' },
{ text: 'Development', link: '/guide/development.md' },
{ text: 'Testing', link: '/guide/testing.md' },
],
@@ -146,6 +147,9 @@ export default defineConfig({
],
},
socialLinks: [{ icon: 'github', link: 'https://github.com/wxt-dev/wxt' }],
socialLinks: [
{ icon: 'discord', link: 'https://discord.gg/ZFsZqGery9' },
{ icon: 'github', link: 'https://github.com/wxt-dev/wxt' },
],
},
});
+7 -3
View File
@@ -6,7 +6,7 @@ import { execaCommand } from 'execa';
let hasGenerated = false;
const cliDir = resolve('src/cli/commands');
const cliDir = resolve('packages/wxt/src/cli/commands');
const cliDirGlob = resolve(cliDir, '**');
const cliTemplatePath = resolve('docs/.vitepress/plugins/cli.tpl.md');
const cliPath = resolve('docs/api/cli.md');
@@ -23,7 +23,9 @@ export function generateCliDocs() {
const generateDocs = async () => {
consola.info(`Generating ${relative(process.cwd(), cliPath)}`);
try {
const res = await execaCommand('pnpm -s wxt --help');
const res = await execaCommand('pnpm -s wxt --help', {
cwd: 'packages/wxt',
});
const dev = splitInfo(res.stdout);
const lines: Array<string | string[]> = [
`## \`wxt\``,
@@ -34,7 +36,9 @@ export function generateCliDocs() {
const commands = await Promise.allSettled(
extractCommands(dev.info).map(async (command) => {
const res = await execaCommand(`pnpm -s wxt ${command} --help`);
const res = await execaCommand(`pnpm -s wxt ${command} --help`, {
cwd: 'packages/wxt',
});
const { rest: docs } = splitInfo(res.stdout);
return [`## \`wxt ${command}\``, '```sh', docs, '```'];
}),
+1 -47
View File
@@ -40,7 +40,7 @@ export default defineContentScript({
// Configure how/when content script will be registered
registration: undefined | "manifest" | "runtime",
main(ctx) {
main(ctx: ContentScriptContext) {
// Executed when content script is loaded
},
});
@@ -50,52 +50,6 @@ export default defineContentScript({
When defining multiple content scripts, content script entrypoints that have the same set of options will be merged into a single `content_script` item in the manifest.
## Context
Old content scripts are not automatically stopped when an extension updates and reloads. Often, this leads to "Invalidated context" errors in production when a content script from an old version of your extension tries to use a web extension API (ie, the `browser` or `chrome` globals).
WXT provides a utility for handling this process: `ContentScriptContext`. An instance of this class is provided to you automatically inside the `main` function of your content script.
When your extension updates or is uninstalled, the context will become invalidated, and will trigger any `ctx.onInvalidated` listeners you add:
```ts
export default defineContentScript({
// ...
main(ctx: ContentScriptContext) {
// Add custom listeners for stopping work
ctx.onInvalidated(() => {
// ...
});
// Timeout utilities that are automatically cleared when invalidated
ctx.setTimeout(() => {
// ...
}, 5e3);
ctx.setInterval(() => {
// ...
}, 60e3);
// Or add event listeners that get removed when invalidated
ctx.addEventListener(document, 'visibilitychange', (event) => {
// ...
});
// You can also stop fetch requests
fetch('...url', { signal: ctx.signal });
},
});
```
The class extends [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) and provides other utilities for stopping a content script's logic once it becomes invalidated.
:::warning
When working with content scripts, **you should always use the `ctx` object to stop any async or future work.**
This prevents old content scripts from interfering with new content scripts, and prevents error messages from the console in production.
If you're using a framework like React, Vue, Svelte, etc., make sure you're unmounting your UI properly in the `onRemove` option of [`createShadowRootUi`](https://wxt.dev/guide/content-script-ui.html#shadow-root).
:::
## CSS
To include CSS with your content script, import the CSS file at the top of your entrypoint.
+1 -1
View File
@@ -63,7 +63,7 @@ Files in the assets directory will be processed by Vite. They are imported in yo
<!-- ... -->
</head>
<body>
<img src="~/illustration.svg" />
<img src="~/assets/illustration.svg" />
<!-- ... -->
</body>
</html>
+3 -3
View File
@@ -388,14 +388,14 @@ WXT provides a helper function, [`createIframeUi`](/api/wxt/client/functions/cre
export default defineContentScript({
matches: ['<all_urls>'],
async main(ctx) {
main(ctx) {
// Define the UI
const ui = await createIframeUi(ctx, {
const ui = createIframeUi(ctx, {
page: '/example-iframe.html',
position: 'inline',
onMount: (wrapper, iframe) => {
// Add styles to the iframe like width
iframe.width = 123;
iframe.width = '123';
},
});
+1 -1
View File
@@ -89,7 +89,7 @@ import { defineRunnerConfig } from 'wxt';
export default defineRunnerConfig({
startUrls: ['https://google.com', 'https://duckduckgo.com'],
chromiumProfile: '/path/to/profile/to/use',
chromiumArgs: ['--window-size=400x300'],
chromiumArgs: ['--window-size=400,300'],
});
```
+1 -1
View File
@@ -89,7 +89,7 @@ For a full list of entrypoints and each of their options, see the [`/entrypoints
### Side Effects
You cannot use imported variables outside the `main` function is JS entrypoints. This includes options, as shown below:
You cannot use imported variables outside the `main` function in JS entrypoints. This includes options, as shown below:
```ts
// entrypoints/content.ts
+2 -2
View File
@@ -39,9 +39,9 @@ Then we can use `browser.storage` to save the install date to local storage.
```ts
// background.ts
export default defineBackground(() => {
browser.runtime.onInstall.addEventListener(({ reason }) => {
browser.runtime.onInstalled.addListener(({ reason }) => {
if (reason === 'install') {
browser.storage.local.setItem({ installDate: Date.now() });
browser.storage.local.set({ installDate: Date.now() });
}
});
});
+116
View File
@@ -0,0 +1,116 @@
# Handling Extension Updates
When releasing an update to your extension, there's a couple of things you need to keep in mind:
[[toc]]
## Content Script Cleanup
Old content scripts are not automatically stopped when an extension updates and reloads. Often, this leads to "Invalidated context" errors in production when a content script from an old version of your extension tries to use a web extension API (ie, the `browser` or `chrome` globals).
WXT provides a utility for handling this process: `ContentScriptContext`. An instance of this class is provided to you automatically inside the `main` function of each content script.
When your extension updates or reloads, the context will become invalidated, and will trigger any `ctx.onInvalidated` listeners you add:
```ts
export default defineContentScript({
main(ctx) {
ctx.onInvalidated(() => {
// Do something
});
},
)
```
The `ctx` also provides other convenient APIs for stopping your content script without manually calling `onInvalidated` to add a listener:
1. Setting timers:
```ts
ctx.setTimeout(() => { ... }, ...);
ctx.setInterval(() => { ... }, ...);
ctx.requestAnimationFrame(() => { ... });
```
1. Adding DOM events:
```ts
ctx.addEventListener(window, "mousemove", (event) => { ... });
```
1. Implements [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) for canceling standard APIs:
```ts
fetch('...', {
signal: ctx.signal,
});
```
Other WXT APIs require a `ctx` object so they can clean themselves up. For example, [`createIntegratedUi`](/guide/content-script-ui#integrated), [`createShadowRootUi`](/guide/content-script-ui#shadow-root), and [`createIframeUi`](/guide/content-script-ui#iframe) automatically unmount and stop a UI when the script is invalidated.
:::warning
When working with content scripts, **you should always use the `ctx` object to stop any async or future work.**
This prevents old content scripts from interfering with new content scripts, and prevents error messages from being logged to the console in production.
:::
## Testing Permission Changes
When `permissions`/`host_permissions` change during an update, depending on what exactly changed, Chrome will disable your extension until the user accepts the new permissions.
It is possible to test this before you release an update, but it's not a simple process:
1. Get 2 ZIPs of your extension, both generated by `wxt zip`. The first contains a previous version of your extension, the second contains the latest version. Make sure the second ZIP's version is higher than the first's.
2. Unzip the two ZIP files somewhere next to each other that's easy to locate.
3. In Chrome, open `chrome://extensions` and make sure developer mode is enabled
4. Pack the first extension into a CRX, generating a new private key:
1. Click "Pack Extension" in the top left
2. For "Extension root directory", enter the path to the first extracted zip directory. The directory should contain a `manifest.json` file
3. Leave "Private key file" blank
4. Click "Pack Extension". This will generate a `.crx` and `.pem` file
5. Pack the second extension into a CRX, reusing the private key generated by the previous step
1. Click "Pack Extension" in the top left
2. For "Extension root directory", enter the path to the second extracted zip directory.
3. For "Private key file", enter the path to the generated `.pem` private key file
4. Click "Pack Extension". This will generate a second `.crx` file.
6. Install the first CRX file by dragging and dropping it onto the `chrome://extensions` page
7. Install the second CRX file by dragging and dropping it onthe the `chrome://extensions` page
If a new permission must be accepted, you'll be prompted to accept it after dropping the second CRX file onto the page.
:::Info Note
Note: Chrome no longer allows self-signed CRX extensions to run, but that's OK for this test case. We're still prompted to accept new permissions, even if we can't interact with the installed extension.
To validate this, you can create a third ZIP file with a rare permission like `geolocation` in the manifest, that's guarenteed to reprompt permissions when added.
:::
## Update Event
You can setup a callback that runs after your extension updates like so:
```ts
browser.runtime.onInstalled.addListener(({ reason }) => {
if (reason === 'update') {
// Do something
}
});
```
If the logic is simple, write a unit test to cover this logic. If you feel the need to manually test this callback, you can either:
1. In dev mode, remove the `if` statement and reload the extension from `chrome://extensions`
2. Build two ZIPs with the same runtime ID and actually update the extension
The first approach is very straightforward. The second is more complicated...
Here are the steps:
So the steps:
1. Checkout an old commit.
2. [Add a `key`](https://developer.chrome.com/docs/extensions/reference/manifest/key#keep-consistent-id) to the `manifest` in your `wxt.config.ts`.
3. Run `wxt zip` to create the first ZIP.
4. Stash or reset changes and checkout your latest code.
5. Add back the same `key` to your manifest.
6. Make sure the extension's version is higher than the first zip. It can be any version that's higher, since you won't be releasing this version.
7. Run `wxt zip` to create the second ZIP.
8. In a fresh chrome profile, go to `chrome://extensions`, enable dev mode, and drag and drop the first zip onto the page to install it.
9. In the extension, play around and setup your test case.
10. Back on `chrome://extensions`, drag and drop your second zip onto the page.
If you setup the `key` correctly, it will cause the extension to act like it was updated instead of installing a second version of your extension.
+2 -2
View File
@@ -11,7 +11,7 @@ The manifest.json is generated at build-time based on files in the `entrypoints/
While entrypoints are generated and added to the manifest at build-time, you can customize or add to your `manifest.json` in the config file.
```ts
// wxt.config.tsentrypoint of your extension
// wxt.config.ts entrypoint of your extension
import { defineConfig } from 'wxt';
export default defineConfig({
@@ -69,7 +69,7 @@ public/
Icon files need to match the following regex to be automatically included in the manifest. Most design software can output icons in one of these formats
<<< @/../src/core/utils/manifest.ts#snippet
<<< @/../packages/wxt/src/core/utils/manifest.ts#snippet
If you prefer to use filenames in a different format, you can add the icons manually in your `wxt.config.ts` file:
+2 -2
View File
@@ -1,10 +1,10 @@
# Remote Code
WXT will automatically download and bundle imports with the `url:` prefix so the extension does not depend of remote code, [a requirement from Google for MV3](https://developer.chrome.com/docs/extensions/migrating/improve-security/#remove-remote-code).
WXT will automatically download and bundle imports with the `url:` prefix so the extension does not depend on remote code, [a requirement from Google for MV3](https://developer.chrome.com/docs/extensions/migrating/improve-security/#remove-remote-code).
## Google Analytics
For example, you can import google analytics:
For example, you can import Google Analytics:
```ts
// utils/google-analytics.ts
+16 -1
View File
@@ -10,6 +10,21 @@ WXT provides a simplified API to replace the `browser.storage.*` APIs. Use the `
import { storage } from 'wxt/storage';
```
:::warning
To use the `wxt/storage` API, the `"storage"` permission must be added to the manifest:
```ts
// wxt.config.ts
export default defineConfig({
manifest: {
permissions: ['storage'],
},
});
```
More info on permissions [here](/guide/manifest#permissions).
:::
[[toc]]
## Basic Usage
@@ -117,7 +132,7 @@ Now, instead of using the `storage` variable, you can use the helper functions o
await showChangelogOnUpdate.getValue();
await showChangelogOnUpdate.setValue(false);
await showChangelogOnUpdate.removeValue();
const unwatch = showChangelogOnUpdate.watch(() => {
const unwatch = showChangelogOnUpdate.watch((newValue) => {
// ...
});
```
+1 -1
View File
@@ -22,4 +22,4 @@ If you want to try to use a different framework for unit tests, you will need to
- **Global Variables**: If you consume them, manually define globals provided by WXT (like `import.meta.env.BROWSER`) by adding them to the global scope before accessing them (`import.meta.env.BROWSER = "chrome"`)
- **Import paths**: If you use the `@/` or `~/` path aliases, add them to your test environment
[Here's how Vitest is configured](https://github.com/wxt-dev/wxt/blob/main/src/testing/wxt-vitest-plugin.ts) for reference.
[Here's how Vitest is configured](https://github.com/wxt-dev/wxt/blob/main/packages/wxt/src/testing/wxt-vitest-plugin.ts) for reference.
+3 -8
View File
@@ -1,12 +1,7 @@
{
"entryPoints": [
"../src",
"../src/client",
"../src/browser.ts",
"../src/sandbox",
"../src/storage.ts",
"../src/testing"
],
"$schema": "https://typedoc.org/schema.json",
"entryPointStrategy": "packages",
"entryPoints": ["../packages/wxt"],
"plugin": ["typedoc-plugin-markdown", "typedoc-vitepress-theme"],
"out": "./api",
"githubPages": false,
-33
View File
@@ -1,33 +0,0 @@
import { describe, it, expect } from 'vitest';
import { TestProject } from '../utils';
describe('Manifest Content', () => {
it.each([
{ browser: undefined, outDir: 'chrome-mv3', expected: undefined },
{ browser: 'chrome', outDir: 'chrome-mv3', expected: undefined },
{ browser: 'firefox', outDir: 'firefox-mv2', expected: true },
{ browser: 'safari', outDir: 'safari-mv2', expected: false },
])(
'should respect the per-browser entrypoint option with %j',
async ({ browser, expected, outDir }) => {
const project = new TestProject();
project.addFile(
'entrypoints/background.ts',
`export default defineBackground({
persistent: {
firefox: true,
safari: false,
},
main: () => {},
})`,
);
await project.build({ browser });
const safariManifest = await project.getOutputManifest(
`.output/${outDir}/manifest.json`,
);
expect(safariManifest.background.persistent).toBe(expected);
},
);
});
+9 -150
View File
@@ -1,189 +1,48 @@
{
"name": "wxt",
"private": true,
"type": "module",
"version": "0.17.11",
"description": "Next gen framework for developing web extensions",
"engines": {
"node": ">=18",
"pnpm": ">=8"
},
"repository": {
"type": "git",
"url": "https://github.com/wxt-dev/wxt"
},
"homepage": "https://wxt.dev",
"keywords": [
"vite",
"chrome",
"web",
"extension",
"browser",
"bundler",
"framework"
],
"author": {
"name": "Aaron Klinker",
"email": "aaronklinker1+wxt@gmail.com"
},
"license": "MIT",
"files": [
"bin",
"dist"
],
"bin": {
"wxt": "./bin/wxt.mjs",
"wxt-publish-extension": "./bin/wxt-publish-extension.cjs"
},
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"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"
}
},
"./client": {
"types": "./dist/client.d.ts",
"import": "./dist/client.js"
},
"./sandbox": {
"types": "./dist/sandbox.d.ts",
"import": "./dist/sandbox.js"
},
"./browser": {
"types": "./dist/browser.d.ts",
"import": "./dist/browser.js"
},
"./testing": {
"import": {
"types": "./dist/testing.d.ts",
"default": "./dist/testing.js"
},
"require": {
"types": "./dist/testing.d.cts",
"default": "./dist/testing.cjs"
}
},
"./storage": {
"import": {
"types": "./dist/storage.d.ts",
"default": "./dist/storage.js"
},
"require": {
"types": "./dist/storage.d.cts",
"default": "./dist/storage.cjs"
}
},
"./vite-builder-env": {
"types": "./dist/vite-builder-env.d.ts"
}
},
"packageManager": "pnpm@8.6.3",
"scripts": {
"wxt": "tsx src/cli/index.ts",
"build": "tsx scripts/build.ts",
"check": "run-s -c check:*",
"check:default": "check",
"check:tsc-virtual": "tsc --noEmit -p src/virtual",
"check": "check && pnpm -r run check",
"test": "vitest",
"test:coverage": "vitest run --coverage.enabled \"--coverage.include=src/**\" \"--coverage.exclude=src/core/utils/testing/**\" \"--coverage.exclude=**/*.d.ts\"",
"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/**\"",
"prepare": "simple-git-hooks",
"prepublish": "pnpm -s build",
"docs:gen": "typedoc --options docs/typedoc.json",
"docs:dev": "pnpm -s docs:gen && vitepress dev docs",
"docs:build": "pnpm -s docs:gen && vitepress build docs",
"docs:preview": "pnpm -s docs:gen && vitepress preview docs",
"sync-releases": "pnpx changelogen@latest gh release"
},
"dependencies": {
"@aklinker1/rollup-plugin-visualizer": "5.12.0",
"@types/webextension-polyfill": "^0.10.5",
"@webext-core/fake-browser": "^1.3.1",
"@webext-core/isolated-element": "^1.1.1",
"@webext-core/match-patterns": "^1.0.3",
"async-mutex": "^0.4.0",
"c12": "^1.5.1",
"cac": "^6.7.14",
"chokidar": "^3.5.3",
"ci-info": "^4.0.0",
"consola": "^3.2.3",
"defu": "^6.1.3",
"dequal": "^2.0.3",
"esbuild": "^0.19.5",
"fast-glob": "^3.3.1",
"filesize": "^10.0.8",
"fs-extra": "^11.1.1",
"get-port": "^7.0.0",
"giget": "^1.1.3",
"hookable": "^5.5.3",
"is-wsl": "^3.0.0",
"jiti": "^1.21.0",
"json5": "^2.2.3",
"jszip": "^3.10.1",
"linkedom": "^0.16.1",
"minimatch": "^9.0.3",
"natural-compare": "^1.4.0",
"normalize-path": "^3.0.0",
"nypm": "^0.3.6",
"open": "^10.1.0",
"ora": "^7.0.1",
"picocolors": "^1.0.0",
"prompts": "^2.4.2",
"publish-browser-extension": "^2.1.3",
"unimport": "^3.4.0",
"vite": "^5.1.3",
"web-ext-run": "^0.2.0",
"webextension-polyfill": "^0.10.0"
"docs:preview": "pnpm -s docs:gen && vitepress preview docs"
},
"devDependencies": {
"@aklinker1/check": "^1.1.1",
"@faker-js/faker": "^8.3.1",
"@types/fs-extra": "^11.0.4",
"@types/lodash.merge": "^4.6.9",
"@types/natural-compare": "^1.4.3",
"@types/node": "^20.10.3",
"@types/normalize-path": "^3.0.2",
"@types/prompts": "^2.4.9",
"@vitest/coverage-v8": "^1.0.1",
"consola": "^3.2.3",
"execa": "^8.0.1",
"extract-zip": "^2.0.1",
"happy-dom": "^13.3.8",
"lint-staged": "^15.2.0",
"lodash.merge": "^4.6.2",
"npm-run-all": "^4.1.5",
"p-map": "^7.0.0",
"prettier": "^3.1.0",
"publint": "^0.2.6",
"simple-git-hooks": "^2.9.0",
"tsup": "^8.0.1",
"tsx": "^4.6.2",
"typedoc": "^0.25.4",
"typedoc-plugin-markdown": "4.0.0-next.23",
"typedoc-vitepress-theme": "1.0.0-next.3",
"typescript": "^5.3.2",
"vitepress": "1.0.0-rc.34",
"vitest": "^1.2.2",
"vitest": "^1.5.3",
"vitest-mock-extended": "^1.3.1",
"vitest-plugin-random-seed": "^1.0.2",
"vue": "^3.3.10"
"vue": "^3.3.10",
"wxt": "workspace:*"
},
"packageManager": "pnpm@8.6.3",
"simple-git-hooks": {
"pre-commit": "pnpm lint-staged"
},
"lint-staged": {
"*": "prettier --ignore-unknown --write"
},
"changelog": {
"excludeAuthors": [
"aaronklinker1@gmail.com"
]
},
"pnpm": {
"peerDependencyRules": {
"ignoreMissing": [
+31
View File
@@ -0,0 +1,31 @@
{
"name": "wxt-demo",
"version": "1.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "pnpm build:deps && wxt",
"build:deps": "pnpm --filter wxt build",
"build": "pnpm build:deps && wxt build",
"build:all": "pnpm build:deps && run-s -s 'build:all:*'",
"build:all:chrome-mv3": "wxt build",
"build:all:chrome-mv2": "wxt build --mv2",
"build:all:firefox-mv3": "wxt build -b firefox --mv3",
"build:all:firefox-mv2": "wxt build -b firefox",
"test": "pnpm build:deps && vitest",
"zip": "pnpm build:deps && wxt zip",
"check": "pnpm build:deps && check",
"postinstall": "pnpm build:deps && wxt prepare"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/react": "^18.2.34",
"@types/react-dom": "^18.2.14",
"sass": "^1.69.5",
"typescript": "^5.3.2",
"wxt": "workspace:*"
}
}

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Before

Width:  |  Height:  |  Size: 504 B

After

Width:  |  Height:  |  Size: 504 B

Before

Width:  |  Height:  |  Size: 936 B

After

Width:  |  Height:  |  Size: 936 B

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

@@ -1,5 +1,5 @@
{
"extends": ["../tsconfig.base.json", "./.wxt/tsconfig.json"],
"extends": ["../../tsconfig.base.json", "./.wxt/tsconfig.json"],
"compilerOptions": {
"allowImportingTsExtensions": true,
"jsx": "react-jsx"
@@ -1,7 +1,7 @@
import { defineConfig } from 'vitest/config';
import { defineProject } from 'vitest/config';
import { WxtVitest } from 'wxt/testing';
export default defineConfig({
export default defineProject({
test: {
mockReset: true,
restoreMocks: true,
@@ -18,4 +18,7 @@ export default defineConfig({
analysis: {
open: true,
},
experimental: {
viteRuntime: true,
},
});
+181 -61
View File
@@ -1,5 +1,124 @@
# Changelog
## v0.18.2
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.18.1...v0.18.2)
### 🚀 Enhancements
- **runner:** Add `keepProfileChanges` option ([#655](https://github.com/wxt-dev/wxt/pull/655))
### 🩹 Fixes
- Automatically detect and add "sidePanel" permission ([5fcaf7c](https://github.com/wxt-dev/wxt/commit/5fcaf7c))
### 📖 Documentation
- Fix `wxt-vitest-plugin` reference ([#650](https://github.com/wxt-dev/wxt/pull/650))
- Fix spelling mistake in remote-code.md ([#652](https://github.com/wxt-dev/wxt/pull/652))
- Correct event handler name in handling-updates.md ([#653](https://github.com/wxt-dev/wxt/pull/653))
- Fix iframe typos ([c74e530](https://github.com/wxt-dev/wxt/commit/c74e530))
### ❤️ Contributors
- Edoan ([@EdoanR](http://github.com/EdoanR))
- Linus Norton ([@linusnorton](http://github.com/linusnorton))
- Jeffrey Zang ([@jeffrey-zang](http://github.com/jeffrey-zang))
- Emmanuel Ferdman <emmanuelferdman@gmail.com>
## v0.18.1
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.18.0...v0.18.1)
### 🩹 Fixes
- `_background` is not defined ([#649](https://github.com/wxt-dev/wxt/pull/649))
### 🏡 Chore
- Add root README back ([ec3dd52](https://github.com/wxt-dev/wxt/commit/ec3dd52))
### 🤖 CI
- Fix sync releases workflow ([dc5b55b](https://github.com/wxt-dev/wxt/commit/dc5b55b))
## v0.18.0
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.17.12...v0.18.0)
### 🚀 Enhancements
- Add zip compression settings ([#605](https://github.com/wxt-dev/wxt/pull/605))
- Support returning values from scripts executed with the scripting API ([#624](https://github.com/wxt-dev/wxt/pull/624))
- **experimental:** Load entrypoint options with Vite Runtime API ([#648](https://github.com/wxt-dev/wxt/pull/648))
### 🩹 Fixes
- ⚠️ Automatically move `host_permissions` to `permissions` for MV2 ([#626](https://github.com/wxt-dev/wxt/pull/626))
- **dep:** Upgrade `@webext-core/isolated-element` to v1.1.2 ([#625](https://github.com/wxt-dev/wxt/pull/625))
### 📖 Documentation
- Add Fluent Read to homepage ([#600](https://github.com/wxt-dev/wxt/pull/600))
- Fix typo on example for wxt.config.ts. ([#609](https://github.com/wxt-dev/wxt/pull/609))
- Tix typo in `entrypoints.md` ([#614](https://github.com/wxt-dev/wxt/pull/614))
- Add Facebook Video Controls to homepage ([#615](https://github.com/wxt-dev/wxt/pull/615))
- Fix typo in assets page ([a94d673](https://github.com/wxt-dev/wxt/commit/a94d673))
- Add ElemSnap to homepage ([#621](https://github.com/wxt-dev/wxt/pull/621))
- Update content script registration JSDoc ([e47519f](https://github.com/wxt-dev/wxt/commit/e47519f))
- Add docs about handling updates ([acb7554](https://github.com/wxt-dev/wxt/commit/acb7554))
- Add MS Edge TTS to homepage ([#647](https://github.com/wxt-dev/wxt/pull/647))
- Document required permission for storage API ([#632](https://github.com/wxt-dev/wxt/pull/632))
### 🏡 Chore
- Update vue template config ([#607](https://github.com/wxt-dev/wxt/pull/607))
- **deps-dev:** Bump lint-staged from 15.2.1 to 15.2.2 ([#637](https://github.com/wxt-dev/wxt/pull/637))
- **deps-dev:** Bump publint from 0.2.6 to 0.2.7 ([#639](https://github.com/wxt-dev/wxt/pull/639))
- **deps-dev:** Bump simple-git-hooks from 2.9.0 to 2.11.1 ([#640](https://github.com/wxt-dev/wxt/pull/640))
- Refactor repo to a standard monorepo ([#646](https://github.com/wxt-dev/wxt/pull/646))
- Fix formatting after monorepo refactor ([6ca3767](https://github.com/wxt-dev/wxt/commit/6ca3767))
#### ⚠️ Breaking Changes
- ⚠️ Automatically move `host_permissions` to `permissions` for MV2 ([#626](https://github.com/wxt-dev/wxt/pull/626))
Out of an abundance of caution, I've marked this as a breaking change because permission generation has changed. **_If you list `host_permissions` in your `wxt.config.ts`'s manifest and have released your extension_**, double check that your `permissions` and `host_permissions` have not changed for all browsers you target in your `.output/*/manifest.json` files. Permission changes can cause the extension to be disabled on update, and can cause a drop in users, so be sure to double check for differences compared to the previous manifest version.
### ❤️ Contributors
- Alegal200 ([@alegal200](https://github.com/alegal200))
- Yacine-bens ([@yacine-bens](http://github.com/yacine-bens))
- Ayden ([@AydenGen](https://github.com/AydenGen))
- Wuzequanyouzi ([@wuzequanyouzi](http://github.com/wuzequanyouzi))
- Can Rau ([@CanRau](http://github.com/CanRau))
- 日高 凌 ([@ryohidaka](http://github.com/ryohidaka))
- Bas Van Zanten ([@Bas950](http://github.com/Bas950))
- ThinkStu ([@Bistutu](http://github.com/Bistutu))
## v0.17.12
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.17.11...v0.17.12)
### 🚀 Enhancements
- Add hooks for extending vite config ([#599](https://github.com/wxt-dev/wxt/pull/599))
### 🩹 Fixes
- **content-script-ui:** Properly assign and unassign mounted value ([#598](https://github.com/wxt-dev/wxt/pull/598))
### 📖 Documentation
- Add discord server link ([#593](https://github.com/wxt-dev/wxt/pull/593))
### 🏡 Chore
- Remove unnecssary 'Omit' types ([db57c8e](https://github.com/wxt-dev/wxt/commit/db57c8e))
- **deps-dev:** Bump @aklinker1/check from 1.1.1 to 1.2.0 ([#588](https://github.com/wxt-dev/wxt/pull/588))
- **deps-dev:** Bump vue from 3.3.10 to 3.4.21 ([#589](https://github.com/wxt-dev/wxt/pull/589))
- **deps-dev:** Bump sass from 1.69.5 to 1.72.0 ([#591](https://github.com/wxt-dev/wxt/pull/591))
## v0.17.11
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.17.10...v0.17.11)
@@ -236,11 +355,11 @@
### 🚀 Enhancements
- **storage:** ⚠️ Improved support for default values on storage items ([#477](https://github.com/wxt-dev/wxt/pull/477))
- **storage:** ⚠️ Improved support for default values on storage items ([#477](https://github.com/wxt-dev/wxt/pull/477))
### 🩹 Fixes
- **storage:** ⚠️ Only run migrations when the extension is updated ([#478](https://github.com/wxt-dev/wxt/pull/478))
- **storage:** ⚠️ Only run migrations when the extension is updated ([#478](https://github.com/wxt-dev/wxt/pull/478))
- Improve dev mode for content scripts registered at runtime ([#474](https://github.com/wxt-dev/wxt/pull/474))
### 📖 Documentation
@@ -268,12 +387,13 @@ const item = storage.defineItem<number | null>("local:count", {
})
```
The `defaultValue` property is now required if passing in the second options argument.
The `defaultValue` property is now required if passing in the second options argument.
If you exclude the second options argument, it will default to being nullable, as before.
```ts
const item: WxtStorageItem<number | null> = storage.defineItem<number>("local:count");
const item: WxtStorageItem<number | null> =
storage.defineItem<number>('local:count');
const value: number | null = await item.getValue();
```
@@ -283,13 +403,13 @@ For storage items that are not nullable, the `watch` callback types has improved
```ts
// >=0.17
const item = storage.defineItem<number>("local:count", { defaultValue: 0 });
const item = storage.defineItem<number>('local:count', { defaultValue: 0 });
item.watch((newValue: number | null, oldValue: number | null) => {
// ...
});
// >=0.17
const item = storage.defineItem<number>("local:count", { defaultValue: 0 });
const item = storage.defineItem<number>('local:count', { defaultValue: 0 });
item.watch((newValue: number, oldValue: number) => {
// ...
});
@@ -519,7 +639,7 @@ item.migrate();
### 🚀 Enhancements
- ⚠️ ESM background support ([#398](https://github.com/wxt-dev/wxt/pull/398))
- ⚠️ ESM background support ([#398](https://github.com/wxt-dev/wxt/pull/398))
### 📖 Documentation
@@ -536,23 +656,23 @@ item.migrate();
In [#398](https://github.com/wxt-dev/wxt/pull/398), HTML pages' JS entrypoints in the output directory have been moved. Unless you're doing some kind of post-build work referencing files, you don't have to make any changes.
- Before:
```
.output/
<target>/
chunks/
some-shared-chunk-<hash>.js
popup-<hash>.js
popup.html
```
```
.output/
<target>/
chunks/
some-shared-chunk-<hash>.js
popup-<hash>.js
popup.html
```
- After:
```
.output/
<target>/
chunks/
some-shared-chunk-<hash>.js
popup.html
popup.js
```
```
.output/
<target>/
chunks/
some-shared-chunk-<hash>.js
popup.html
popup.js
```
This effects all HTML files, not just the Popup. The hash has been removed, and it's been moved to the root of the build target folder, not inside the `chunks/` directory. Moving files like this has not historically increased review times or triggered in-depth reviews when submitting updates to the stores.
@@ -618,12 +738,12 @@ This effects all HTML files, not just the Popup. The hash has been removed, and
### 🚀 Enhancements
- **zip:** ⚠️ Add `includeSources` and rename `ignoredSources` to `excludeSources` ([#378](https://github.com/wxt-dev/wxt/pull/378))
- **zip:** ⚠️ Add `includeSources` and rename `ignoredSources` to `excludeSources` ([#378](https://github.com/wxt-dev/wxt/pull/378))
### 🩹 Fixes
- Generate missing sourcemap in `wxt:unimport` plugin ([#381](https://github.com/wxt-dev/wxt/pull/381))
- ⚠️ Move browser constants to `import.meta.env` ([#380](https://github.com/wxt-dev/wxt/pull/380))
- ⚠️ Move browser constants to `import.meta.env` ([#380](https://github.com/wxt-dev/wxt/pull/380))
- Enable inline sourcemaps by default during development ([#382](https://github.com/wxt-dev/wxt/pull/382))
### 📖 Documentation
@@ -773,7 +893,7 @@ Renamed undocumented constants for detecting the build config at runtime in [#38
### 🚀 Enhancements
- ⚠️ Refactor content script UI functions and add helper for "integrated" UIs ([#333](https://github.com/wxt-dev/wxt/pull/333))
- ⚠️ Refactor content script UI functions and add helper for "integrated" UIs ([#333](https://github.com/wxt-dev/wxt/pull/333))
#### ⚠️ Breaking Changes
@@ -782,7 +902,7 @@ Renamed undocumented constants for detecting the build config at runtime in [#38
- `createContentScriptUi({ ... })` &rarr; `createShadowRootUi({ ... })`
- `createContentScriptIframe({ ... })` &rarr; `createIframeUi({ ... })`
- `type: "inline" | "overlay" | "modal"` has been changed to `position: "inline" | "overlay" | "modal"`
- `onRemove` is now called ***before*** the UI is removed from the DOM, previously it was called after the UI was removed
- `onRemove` is now called **_before_** the UI is removed from the DOM, previously it was called after the UI was removed
- `mount` option has been renamed to `onMount`, to better match the related option, `onRemove`.
## v0.13.5
@@ -878,7 +998,7 @@ Renamed undocumented constants for detecting the build config at runtime in [#38
### 🚀 Enhancements
- ⚠️ New `wxt/storage` APIs ([#300](https://github.com/wxt-dev/wxt/pull/300))
- ⚠️ New `wxt/storage` APIs ([#300](https://github.com/wxt-dev/wxt/pull/300))
#### ⚠️ Breaking Changes
@@ -935,7 +1055,7 @@ Renamed undocumented constants for detecting the build config at runtime in [#38
### 🚀 Enhancements
- ⚠️ Add support for "main world" content scripts ([#284](https://github.com/wxt-dev/wxt/pull/284))
- ⚠️ Add support for "main world" content scripts ([#284](https://github.com/wxt-dev/wxt/pull/284))
### 🩹 Fixes
@@ -957,10 +1077,10 @@ Renamed undocumented constants for detecting the build config at runtime in [#38
- If you use auto-imports, no changes are required.
- If you have disabled auto-imports, you'll need to manually update your import statements:
```diff
- import { defineBackground, defineContentScript } from 'wxt/client';
+ import { defineBackground, defineContentScript } from 'wxt/sandbox';
```
```diff
- import { defineBackground, defineContentScript } from 'wxt/client';
+ import { defineBackground, defineContentScript } from 'wxt/sandbox';
```
## v0.11.2
@@ -998,7 +1118,7 @@ Renamed undocumented constants for detecting the build config at runtime in [#38
### 🚀 Enhancements
- ⚠️ Vite 5 support ([#261](https://github.com/wxt-dev/wxt/pull/261))
- ⚠️ Vite 5 support ([#261](https://github.com/wxt-dev/wxt/pull/261))
### 📖 Documentation
@@ -1090,7 +1210,7 @@ Renamed undocumented constants for detecting the build config at runtime in [#38
### 🚀 Enhancements
- List `bun` as an experimental option in `wxt init` ([#233](https://github.com/wxt-dev/wxt/pull/233))
- ⚠️ Allow plural directory and only png's for manifest icons ([#237](https://github.com/wxt-dev/wxt/pull/237))
- ⚠️ Allow plural directory and only png's for manifest icons ([#237](https://github.com/wxt-dev/wxt/pull/237))
- Add `wxt/storage` API ([#234](https://github.com/wxt-dev/wxt/pull/234))
### 🩹 Fixes
@@ -1162,7 +1282,7 @@ Renamed undocumented constants for detecting the build config at runtime in [#38
### 🩹 Fixes
- ⚠️ Remove `lib` from `.wxt/tsconfig.json` ([#209](https://github.com/wxt-dev/wxt/pull/209))
- ⚠️ Remove `lib` from `.wxt/tsconfig.json` ([#209](https://github.com/wxt-dev/wxt/pull/209))
### 📖 Documentation
@@ -1175,15 +1295,15 @@ Renamed undocumented constants for detecting the build config at runtime in [#38
#### ⚠️ Breaking Changes
- ⚠️ Removed [`"WebWorker"` types](https://www.typescriptlang.org/tsconfig/lib.html) from `.wxt/tsconfig.json` ([#209](https://github.com/wxt-dev/wxt/pull/209)). These types are useful for MV3 projects using a service worker. To add them back to your project, add the following to your project's TSConfig:
```diff
{
"extends": "./.wxt/tsconfig.json",
+ "compilerOptions": {
+ "lib": ["ESNext", "DOM", "WebWorker"]
+ }
}
```
- ⚠️ Removed [`"WebWorker"` types](https://www.typescriptlang.org/tsconfig/lib.html) from `.wxt/tsconfig.json` ([#209](https://github.com/wxt-dev/wxt/pull/209)). These types are useful for MV3 projects using a service worker. To add them back to your project, add the following to your project's TSConfig:
```diff
{
"extends": "./.wxt/tsconfig.json",
+ "compilerOptions": {
+ "lib": ["ESNext", "DOM", "WebWorker"]
+ }
}
```
### ❤️ Contributors
@@ -1297,7 +1417,7 @@ Renamed undocumented constants for detecting the build config at runtime in [#38
### 🚀 Enhancements
- ⚠️ Use `defineUnlistedScript` to define unlisted scripts ([#167](https://github.com/wxt-dev/wxt/pull/167))
- ⚠️ Use `defineUnlistedScript` to define unlisted scripts ([#167](https://github.com/wxt-dev/wxt/pull/167))
### 📖 Documentation
@@ -1305,12 +1425,12 @@ Renamed undocumented constants for detecting the build config at runtime in [#38
### 🌊 Types
- ⚠️ Rename `BackgroundScriptDefintition` to `BackgroundDefinition` ([446f265](https://github.com/wxt-dev/wxt/commit/446f265))
- ⚠️ Rename `BackgroundScriptDefintition` to `BackgroundDefinition` ([446f265](https://github.com/wxt-dev/wxt/commit/446f265))
#### ⚠️ Breaking Changes
- ⚠️ Unlisted scripts must now `export default defineUnlistedScript(...)` ([#167](https://github.com/wxt-dev/wxt/pull/167))
- ⚠️ Rename `BackgroundScriptDefintition` to `BackgroundDefinition` ([446f265](https://github.com/wxt-dev/wxt/commit/446f265))
- ⚠️ Unlisted scripts must now `export default defineUnlistedScript(...)` ([#167](https://github.com/wxt-dev/wxt/pull/167))
- ⚠️ Rename `BackgroundScriptDefintition` to `BackgroundDefinition` ([446f265](https://github.com/wxt-dev/wxt/commit/446f265))
### ❤️ Contributors
@@ -1403,7 +1523,7 @@ Renamed undocumented constants for detecting the build config at runtime in [#38
### 🩹 Fixes
- Validate transformed manifest correctly ([4b2012c](https://github.com/wxt-dev/wxt/commit/4b2012c))
- ⚠️ Output content script CSS to `content-scripts/<name>.css` ([#140](https://github.com/wxt-dev/wxt/pull/140))
- ⚠️ Output content script CSS to `content-scripts/<name>.css` ([#140](https://github.com/wxt-dev/wxt/pull/140))
- Reorder typescript paths to give priority to `@` and `~` over `@@` and `~~` ([#142](https://github.com/wxt-dev/wxt/pull/142))
### 🏡 Chore
@@ -1501,7 +1621,7 @@ Renamed undocumented constants for detecting the build config at runtime in [#38
### 🚀 Enhancements
- Export `ContentScriptContext` from `wxt/client` ([1f448d1](https://github.com/wxt-dev/wxt/commit/1f448d1))
- ⚠️ Require a function for `vite` configuration ([#121](https://github.com/wxt-dev/wxt/pull/121))
- ⚠️ Require a function for `vite` configuration ([#121](https://github.com/wxt-dev/wxt/pull/121))
### 🩹 Fixes
@@ -1510,7 +1630,7 @@ Renamed undocumented constants for detecting the build config at runtime in [#38
#### ⚠️ Breaking Changes
- ⚠️ The `vite` config option must now be a function. If you were using an object before, change it from `vite: { ... }` to `vite: () => ({ ... })`. ([#121](https://github.com/wxt-dev/wxt/pull/121))
- ⚠️ The `vite` config option must now be a function. If you were using an object before, change it from `vite: { ... }` to `vite: () => ({ ... })`. ([#121](https://github.com/wxt-dev/wxt/pull/121))
## v0.5.6
@@ -1577,7 +1697,7 @@ Renamed undocumented constants for detecting the build config at runtime in [#38
### 🩹 Fixes
- **types:** Don't write to files if nothing changes ([#107](https://github.com/wxt-dev/wxt/pull/107))
- ⚠️ Change default `publicDir` to `<srcDir>/public` ([5f15f9c](https://github.com/wxt-dev/wxt/commit/5f15f9c))
- ⚠️ Change default `publicDir` to `<srcDir>/public` ([5f15f9c](https://github.com/wxt-dev/wxt/commit/5f15f9c))
### 📖 Documentation
@@ -1597,7 +1717,7 @@ Renamed undocumented constants for detecting the build config at runtime in [#38
#### ⚠️ Breaking Changes
- ⚠️ Change default `publicDir` to `<srcDir>/public` ([5f15f9c](https://github.com/wxt-dev/wxt/commit/5f15f9c))
- ⚠️ Change default `publicDir` to `<srcDir>/public` ([5f15f9c](https://github.com/wxt-dev/wxt/commit/5f15f9c))
## v0.4.1
@@ -1625,7 +1745,7 @@ Renamed undocumented constants for detecting the build config at runtime in [#38
- Allow adding custom content scripts ([b428a62](https://github.com/wxt-dev/wxt/commit/b428a62))
- Don't overwrite `wxt.config.ts` content scripts, append entrypoints to it ([5f5f1d9](https://github.com/wxt-dev/wxt/commit/5f5f1d9))
- ⚠️ Use relative path aliases inside `.wxt/tsconfig.json` ([#102](https://github.com/wxt-dev/wxt/pull/102))
- ⚠️ Use relative path aliases inside `.wxt/tsconfig.json` ([#102](https://github.com/wxt-dev/wxt/pull/102))
### 📖 Documentation
@@ -1658,7 +1778,7 @@ Renamed undocumented constants for detecting the build config at runtime in [#38
#### ⚠️ Breaking Changes
- ⚠️ Use relative path aliases inside `.wxt/tsconfig.json` ([#102](https://github.com/wxt-dev/wxt/pull/102))
- ⚠️ Use relative path aliases inside `.wxt/tsconfig.json` ([#102](https://github.com/wxt-dev/wxt/pull/102))
## v0.3.2
@@ -1730,8 +1850,8 @@ Renamed undocumented constants for detecting the build config at runtime in [#38
### 🚀 Enhancements
- ⚠️ Add type safety to `browser.runtime.getURL` ([58a84ec](https://github.com/wxt-dev/wxt/commit/58a84ec))
- ⚠️ Change default `publicDir` to `<rootDir>/public` ([19c0948](https://github.com/wxt-dev/wxt/commit/19c0948))
- ⚠️ Add type safety to `browser.runtime.getURL` ([58a84ec](https://github.com/wxt-dev/wxt/commit/58a84ec))
- ⚠️ Change default `publicDir` to `<rootDir>/public` ([19c0948](https://github.com/wxt-dev/wxt/commit/19c0948))
- Windows support ([#50](https://github.com/wxt-dev/wxt/pull/50))
### 🩹 Fixes
@@ -1750,10 +1870,10 @@ Renamed undocumented constants for detecting the build config at runtime in [#38
- Improve checks against `demo/` extension ([9cc464f](https://github.com/wxt-dev/wxt/commit/9cc464f))
#### ⚠️ Breaking Changes
#### ⚠️ Breaking Changes
- ⚠️ Add type safety to `browser.runtime.getURL` ([58a84ec](https://github.com/wxt-dev/wxt/commit/58a84ec))
- ⚠️ Change default `publicDir` to `<rootDir>/public` ([19c0948](https://github.com/wxt-dev/wxt/commit/19c0948))
- ⚠️ Add type safety to `browser.runtime.getURL` ([58a84ec](https://github.com/wxt-dev/wxt/commit/58a84ec))
- ⚠️ Change default `publicDir` to `<rootDir>/public` ([19c0948](https://github.com/wxt-dev/wxt/commit/19c0948))
## v0.2.5
+70
View File
@@ -0,0 +1,70 @@
<h1 align="center">
<img style="vertical-align:middle" width="44" src="./docs/public/hero-logo.svg" alt="WXT Logo">
<span>WXT</span>
</h1>
<p align="center">
<a href="https://www.npmjs.com/package/wxt" target="_blank"><img alt="npm" src="https://img.shields.io/npm/v/wxt?labelColor=black&color=%234fa048"></a>
<span> </span>
<a href="https://www.npmjs.com/package/wxt" target="_blank"><img alt="npm" src="https://img.shields.io/npm/dm/wxt?labelColor=black&color=%234fa048"></a>
<span> </span>
<a href="https://github.com/wxt-dev/wxt/blob/main/LICENSE" target="_blank"><img alt="NPM" src="https://img.shields.io/npm/l/wxt?labelColor=black&color=%234fa048"></a>
<span> </span>
<a href="https://codecov.io/github/wxt-dev/wxt" target="_blank"><img alt="Codecov" src="https://img.shields.io/codecov/c/github/wxt-dev/wxt?labelColor=black&color=%234fa048"></a>
</p>
<p align="center">
<span>Next-gen framework for developing web extensions.</span>
<br/>
<span>⚡</span>
<br/>
<q><i>It's like Nuxt, but for Chrome Extensions</i></q>
</p>
<p align="center">
<a href="https://wxt.dev" target="_blank">Get Started</a>
&bull;
<a href="https://wxt.dev/guide/installation.html" target="_blank">Installation</a>
&bull;
<a href="https://wxt.dev/api/config.html" target="_blank">Configuration</a>
&bull;
<a href="https://wxt.dev/examples.html" target="_blank">Examples</a>
&bull;
<a href="https://discord.gg/ZFsZqGery9" target="_blank">Discord</a>
</p>
![Example CLI Output](./docs/assets/cli-output.png)
## Demo
https://github.com/wxt-dev/wxt/assets/10101283/4d678939-1bdb-495c-9c36-3aa281d84c94
## Quick Start
Bootstrap a new project:
```sh
pnpm dlx wxt@latest init <project-name>
```
Or see the [installation guide](https://wxt.dev/guide/installation.html) to get started with WXT.
## Features
- 🌐 Supports all browsers
- ✅ Supports both MV2 and MV3
- ⚡ Dev mode with HMR & fast reload
- 📂 File based entrypoints
- 🚔 TypeScript
- 🦾 Auto-imports
- 🤖 Automated publishing
- 🎨 Frontend framework agnostic: works with Vue, React, Svelte, etc
- 🖍️ Quickly bootstrap a new project
- 📏 Bundle analysis
- ⬇️ Download and bundle remote URL imports
## Contributors
<a href="https://github.com/wxt-dev/wxt/graphs/contributors">
<img src="https://contrib.rocks/image?repo=wxt-dev/wxt" />
</a>
@@ -9,16 +9,21 @@ const hooks: WxtHooks = {
'build:manifestGenerated': vi.fn(),
'entrypoints:resolved': vi.fn(),
'entrypoints:grouped': vi.fn(),
'vite:build:extendConfig': vi.fn(),
'vite:devServer:extendConfig': vi.fn(),
};
function expectHooksToBeCalled(called: Record<keyof WxtHooks, boolean>) {
function expectHooksToBeCalled(
called: Record<keyof WxtHooks, boolean | number>,
) {
Object.keys(hooks).forEach((key) => {
const hookName = key as keyof WxtHooks;
const times = called[hookName] ? 1 : 0;
const value = called[hookName];
const times = typeof value === 'number' ? value : value ? 1 : 0;
expect(
hooks[hookName],
`Expected "${hookName}" to be called ${times} time(s)`,
).toBeCalledTimes(called[hookName] ? 1 : 0);
).toBeCalledTimes(times);
});
}
@@ -40,6 +45,8 @@ describe('Hooks', () => {
'build:manifestGenerated': false,
'entrypoints:grouped': false,
'entrypoints:resolved': true,
'vite:build:extendConfig': false,
'vite:devServer:extendConfig': false,
});
});
@@ -56,6 +63,8 @@ describe('Hooks', () => {
'build:manifestGenerated': true,
'entrypoints:grouped': true,
'entrypoints:resolved': true,
'vite:build:extendConfig': 1,
'vite:devServer:extendConfig': false,
});
});
@@ -72,6 +81,8 @@ describe('Hooks', () => {
'build:manifestGenerated': true,
'entrypoints:grouped': true,
'entrypoints:resolved': true,
'vite:build:extendConfig': 1,
'vite:devServer:extendConfig': false,
});
});
@@ -94,6 +105,8 @@ describe('Hooks', () => {
'build:manifestGenerated': true,
'entrypoints:grouped': true,
'entrypoints:resolved': true,
'vite:build:extendConfig': 2,
'vite:devServer:extendConfig': 1,
});
});
});
@@ -3,6 +3,7 @@ import { TestProject } 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 () => {
@@ -11,6 +12,7 @@ describe('Init command', () => {
await execaCommand(`pnpm -s wxt init ${project.root} -t vue --pm npm`, {
env: { ...process.env, CI: 'true' },
stdio: 'ignore',
cwd: WXT_PACKAGE_DIR,
});
const files = await glob('**/*', {
cwd: project.root,
@@ -46,13 +48,14 @@ describe('Init command', () => {
it('should throw an error if the directory is not empty', async () => {
const project = new TestProject();
await mkdir(project.root);
await mkdir(project.root, { recursive: true });
await writeJson(project.resolvePath('package.json'), {});
await expect(() =>
execaCommand(`pnpm -s wxt init ${project.root} -t vue --pm npm`, {
env: { ...process.env, CI: 'true' },
stdio: 'ignore',
cwd: WXT_PACKAGE_DIR,
}),
).rejects.toThrowError('Command failed with exit code 1:');
});
@@ -0,0 +1,36 @@
import { describe, it, expect } from 'vitest';
import { TestProject } from '../utils';
describe.each([true, false])(
'Manifest Content (Vite runtime? %s)',
(viteRuntime) => {
it.each([
{ browser: undefined, outDir: 'chrome-mv3', expected: undefined },
{ browser: 'chrome', outDir: 'chrome-mv3', expected: undefined },
{ browser: 'firefox', outDir: 'firefox-mv2', expected: true },
{ browser: 'safari', outDir: 'safari-mv2', expected: false },
])(
'should respect the per-browser entrypoint option with %j',
async ({ browser, expected, outDir }) => {
const project = new TestProject();
project.addFile(
'entrypoints/background.ts',
`export default defineBackground({
persistent: {
firefox: true,
safari: false,
},
main: () => {},
})`,
);
await project.build({ browser, experimental: { viteRuntime } });
const safariManifest = await project.getOutputManifest(
`.output/${outDir}/manifest.json`,
);
expect(safariManifest.background.persistent).toBe(expected);
},
);
},
);
@@ -272,7 +272,7 @@ describe('Output Directory Structure', () => {
.toMatchInlineSnapshot(`
".output/chrome-mv3/background.js
----------------------------------------
import { l as logHello } from "./chunks/log-bezs0tt4.js";
import { l as logHello } from "./chunks/log-BsZv2eRn.js";
function defineBackground(arg) {
if (typeof arg === "function")
return { main: arg };
@@ -294,9 +294,10 @@ describe('Output Directory Structure', () => {
warn: (...args) => print(console.warn, ...args),
error: (...args) => print(console.error, ...args)
};
var result;
try {
const res = definition.main();
if (res instanceof Promise) {
result = definition.main();
if (result instanceof Promise) {
console.warn(
"The background's main() function return a promise, but it must be synchronous"
);
@@ -352,7 +353,7 @@ describe('Output Directory Structure', () => {
.toMatchInlineSnapshot(`
".output/chrome-mv3/background.js
----------------------------------------
(function() {
var _background = function() {
"use strict";
function defineBackground(arg) {
if (typeof arg === "function")
@@ -362,11 +363,13 @@ describe('Output Directory Structure', () => {
function logHello(name) {
console.log(\`Hello \${name}!\`);
}
_background;
const definition = defineBackground({
main() {
logHello("background");
}
});
_background;
chrome;
function print(method, ...args) {
return;
@@ -377,9 +380,10 @@ describe('Output Directory Structure', () => {
warn: (...args) => print(console.warn, ...args),
error: (...args) => print(console.error, ...args)
};
var result;
try {
const res = definition.main();
if (res instanceof Promise) {
result = definition.main();
if (result instanceof Promise) {
console.warn(
"The background's main() function return a promise, but it must be synchronous"
);
@@ -388,7 +392,10 @@ describe('Output Directory Structure', () => {
logger.error("The background crashed on startup!");
throw err;
}
})();
var background_entrypoint_default = result;
return background_entrypoint_default;
}();
_background;
"
`);
});
@@ -119,7 +119,7 @@ describe('User Config', () => {
project.addFile(
'test.config.ts',
`import { defineConfig } from 'wxt';
export default defineConfig({
outDir: ".custom-output",
srcDir: "src",
+14 -6
View File
@@ -1,5 +1,5 @@
import { dirname, join, relative, resolve } from 'path';
import fs from 'fs-extra';
import { dirname, relative, resolve } from 'path';
import fs, { mkdir } from 'fs-extra';
import glob from 'fast-glob';
import { execaCommand } from 'execa';
import {
@@ -13,6 +13,13 @@ import {
import { normalizePath } from '../src/core/utils/paths';
import merge from 'lodash.merge';
// Run "pnpm wxt" to use the "wxt" dev script, not the "wxt" binary from the
// wxt package. This uses the TS files instead of the compiled JS package
// files.
export const WXT_PACKAGE_DIR = resolve(__dirname, '..');
export const E2E_DIR = resolve(WXT_PACKAGE_DIR, 'e2e');
export class TestProject {
files: Array<[string, string]> = [];
config: UserConfig | undefined;
@@ -23,7 +30,7 @@ export class TestProject {
// file is cached and cannot be different between each test. Instead, we add a random ID to the
// end to make each test's path unique.
const id = Math.random().toString(32).substring(3);
this.root = join('e2e/dist', id);
this.root = resolve(E2E_DIR, 'dist', id);
this.files.push([
'package.json',
JSON.stringify(
@@ -113,6 +120,9 @@ export class TestProject {
await execaCommand('pnpm --ignore-workspace i --ignore-scripts', {
cwd: this.root,
});
await mkdir(resolve(this.root, 'public'), { recursive: true }).catch(
() => {},
);
}
/**
@@ -131,9 +141,7 @@ export class TestProject {
* that can be used in a snapshot.
*/
serializeWxtDir(): Promise<string> {
return this.serializeDir(
resolve(this.config?.srcDir ?? this.root, '.wxt/types'),
);
return this.serializeDir(resolve(this.root, '.wxt/types'));
}
/**
+157
View File
@@ -0,0 +1,157 @@
{
"name": "wxt",
"type": "module",
"version": "0.18.2",
"description": "Next gen framework for developing web extensions",
"repository": {
"type": "git",
"url": "https://github.com/wxt-dev/wxt"
},
"homepage": "https://wxt.dev",
"keywords": [
"vite",
"chrome",
"web",
"extension",
"browser",
"bundler",
"framework"
],
"author": {
"name": "Aaron Klinker",
"email": "aaronklinker1+wxt@gmail.com"
},
"license": "MIT",
"files": [
"bin",
"dist"
],
"bin": {
"wxt": "./bin/wxt.mjs",
"wxt-publish-extension": "./bin/wxt-publish-extension.cjs"
},
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"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"
}
},
"./client": {
"types": "./dist/client.d.ts",
"import": "./dist/client.js"
},
"./sandbox": {
"types": "./dist/sandbox.d.ts",
"import": "./dist/sandbox.js"
},
"./browser": {
"types": "./dist/browser.d.ts",
"import": "./dist/browser.js"
},
"./testing": {
"import": {
"types": "./dist/testing.d.ts",
"default": "./dist/testing.js"
},
"require": {
"types": "./dist/testing.d.cts",
"default": "./dist/testing.cjs"
}
},
"./storage": {
"import": {
"types": "./dist/storage.d.ts",
"default": "./dist/storage.js"
},
"require": {
"types": "./dist/storage.d.cts",
"default": "./dist/storage.cjs"
}
},
"./vite-builder-env": {
"types": "./dist/vite-builder-env.d.ts"
}
},
"scripts": {
"wxt": "tsx src/cli/index.ts",
"build": "tsx scripts/build.ts",
"check": "run-s -c check:*",
"check:default": "check",
"check:tsc-virtual": "tsc --noEmit -p src/virtual",
"test": "vitest",
"test:e2e": "vitest -r e2e",
"sync-releases": "pnpx changelogen@latest gh release"
},
"dependencies": {
"@aklinker1/rollup-plugin-visualizer": "5.12.0",
"@types/webextension-polyfill": "^0.10.5",
"@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.0",
"c12": "^1.5.1",
"cac": "^6.7.14",
"chokidar": "^3.5.3",
"ci-info": "^4.0.0",
"defu": "^6.1.3",
"dequal": "^2.0.3",
"esbuild": "^0.19.5",
"fast-glob": "^3.3.1",
"filesize": "^10.0.8",
"fs-extra": "^11.1.1",
"get-port": "^7.0.0",
"giget": "^1.1.3",
"hookable": "^5.5.3",
"is-wsl": "^3.0.0",
"jiti": "^1.21.0",
"json5": "^2.2.3",
"jszip": "^3.10.1",
"linkedom": "^0.16.1",
"magicast": "^0.3.4",
"minimatch": "^9.0.3",
"natural-compare": "^1.4.0",
"normalize-path": "^3.0.0",
"nypm": "^0.3.6",
"open": "^10.1.0",
"ora": "^7.0.1",
"picocolors": "^1.0.0",
"prompts": "^2.4.2",
"publish-browser-extension": "^2.1.3",
"unimport": "^3.4.0",
"vite": "^5.2.8",
"web-ext-run": "^0.2.0",
"webextension-polyfill": "^0.10.0"
},
"devDependencies": {
"@aklinker1/check": "^1.1.1",
"@faker-js/faker": "^8.3.1",
"@types/fs-extra": "^11.0.4",
"@types/lodash.merge": "^4.6.9",
"@types/natural-compare": "^1.4.3",
"@types/node": "^20.10.3",
"@types/normalize-path": "^3.0.2",
"@types/prompts": "^2.4.9",
"execa": "^8.0.1",
"extract-zip": "^2.0.1",
"happy-dom": "^13.3.8",
"lodash.merge": "^4.6.2",
"p-map": "^7.0.0",
"publint": "^0.2.6",
"tsup": "^8.0.1",
"tsx": "^4.6.2",
"typescript": "^5.3.2"
},
"changelog": {
"excludeAuthors": [
"aaronklinker1@gmail.com"
]
}
}
@@ -72,7 +72,7 @@ describe('Content Script UIs', () => {
it('should load a shadow root to the page', async () => {
const ui = await createShadowRootUi(ctx, {
position: 'inline',
name: 'test',
name: 'test-component',
onMount(uiContainer) {
appendTestApp(uiContainer);
},
@@ -80,7 +80,7 @@ describe('Content Script UIs', () => {
ui.mount();
expect(
document.querySelector('test[data-wxt-shadow-root]'),
document.querySelector('test-component[data-wxt-shadow-root]'),
).not.toBeNull();
expect(ui.shadow.querySelector('app')).not.toBeNull();
});
@@ -94,7 +94,7 @@ describe('Content Script UIs', () => {
async (input, expected) => {
const ui = await createShadowRootUi(ctx, {
position: 'inline',
name: 'test',
name: 'test-component',
mode: input,
onMount: appendTestApp,
});
@@ -404,4 +404,62 @@ describe('Content Script UIs', () => {
});
});
});
describe('mounted value', () => {
describe('integrated', () => {
it('should set the mounted value based on the onMounted return value', () => {
const expected = Symbol();
const ui = createIntegratedUi(new ContentScriptContext('test'), {
position: 'inline',
onMount: () => expected,
});
expect(ui.mounted).toBeUndefined();
ui.mount();
expect(ui.mounted).toBe(expected);
ui.remove();
expect(ui.mounted).toBeUndefined();
});
});
describe('iframe', () => {
it('should set the mounted value based on the onMounted return value', async () => {
const expected = Symbol();
const ui = createIframeUi(new ContentScriptContext('test'), {
page: '',
position: 'inline',
onMount: () => expected,
});
expect(ui.mounted).toBeUndefined();
ui.mount();
expect(ui.mounted).toBe(expected);
ui.remove();
expect(ui.mounted).toBeUndefined();
});
});
describe('shadow-root', () => {
it('should set the mounted value based on the onMounted return value', async () => {
const expected = Symbol();
const ui = await createShadowRootUi(new ContentScriptContext('test'), {
name: 'test-component',
position: 'inline',
onMount: () => expected,
});
expect(ui.mounted).toBeUndefined();
ui.mount();
expect(ui.mounted).toBe(expected);
ui.remove();
expect(ui.mounted).toBeUndefined();
});
});
});
});
@@ -35,12 +35,15 @@ export function createIntegratedUi<TMounted>(
const remove = () => {
options.onRemove?.(mounted);
wrapper.remove();
mounted = undefined;
};
ctx.onInvalidated(remove);
return {
mounted,
get mounted() {
return mounted;
},
wrapper,
mount,
remove,
@@ -71,12 +74,15 @@ export function createIframeUi<TMounted>(
const remove = () => {
options.onRemove?.(mounted);
wrapper.remove();
mounted = undefined;
};
ctx.onInvalidated(remove);
return {
mounted,
get mounted() {
return mounted;
},
iframe,
wrapper,
mount,
@@ -116,7 +122,7 @@ export async function createShadowRootUi<TMounted>(
});
shadowHost.setAttribute('data-wxt-shadow-root', '');
let mounted: TMounted;
let mounted: TMounted | undefined;
const mount = () => {
// Add shadow root element to DOM
@@ -134,6 +140,8 @@ export async function createShadowRootUi<TMounted>(
// Remove children from uiContainer
while (uiContainer.lastChild)
uiContainer.removeChild(uiContainer.lastChild);
// Clear mounted value
mounted = undefined;
};
ctx.onInvalidated(remove);
@@ -144,7 +152,9 @@ export async function createShadowRootUi<TMounted>(
uiContainer,
mount,
remove,
mounted: mounted!,
get mounted() {
return mounted;
},
};
}
@@ -0,0 +1,12 @@
import { a } from './test';
function defineSomething<T>(config: T): T {
return config;
}
export default defineSomething({
option: 'some value',
main: () => {
console.log('main', a);
},
});
@@ -0,0 +1,2 @@
console.log('Side-effect in test.ts');
export const a = 'a';
@@ -0,0 +1,22 @@
import { describe, it, expect } from 'vitest';
import { createViteBuilder } from '../index';
import { fakeResolvedConfig } from '~/core/utils/testing/fake-objects';
import { createHooks } from 'hookable';
describe('Vite Builder', () => {
describe('importEntrypoint', () => {
it('should import entrypoints, removing runtime values (like the main function)', async () => {
const {
default: { main: _, ...expected },
} = await import('./fixtures/module');
const builder = await createViteBuilder(
fakeResolvedConfig({ root: __dirname }),
createHooks(),
);
const actual = await builder.importEntrypoint<{ default: any }>(
'./fixtures/module.ts',
);
expect(actual).toEqual(expected);
});
});
});
@@ -6,6 +6,7 @@ import {
WxtBuilder,
WxtBuilderServer,
WxtDevServer,
WxtHooks,
} from '~/types';
import * as wxtPlugins from './plugins';
import {
@@ -16,9 +17,13 @@ import {
VirtualEntrypointType,
VirtualModuleId,
} from '~/core/utils/virtual-modules';
import { Hookable } from 'hookable';
import { toArray } from '~/core/utils/arrays';
import { safeVarName } from '~/core/utils/strings';
export async function createViteBuilder(
wxtConfig: ResolvedConfig,
hooks: Hookable<WxtHooks>,
server?: WxtDevServer,
): Promise<WxtBuilder> {
const vite = await import('vite');
@@ -83,14 +88,22 @@ export async function createViteBuilder(
plugins.push(wxtPlugins.cssEntrypoints(entrypoint, wxtConfig));
}
const iifeReturnValueName = safeVarName(entrypoint.name);
const libMode: vite.UserConfig = {
mode: wxtConfig.mode,
plugins,
esbuild: {
// Add a footer with the returned value so it can return values to `scripting.executeScript`
// Footer is added apart of esbuild to make sure it's not minified. It
// get's removed if added to `build.rollupOptions.output.footer`
// See https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/scripting/executeScript#return_value
footer: iifeReturnValueName + ';',
},
build: {
lib: {
entry,
formats: ['iife'],
name: '_',
name: iifeReturnValueName,
fileName: entrypoint.name,
},
rollupOptions: {
@@ -190,6 +203,22 @@ export async function createViteBuilder(
return {
name: 'Vite',
version: vite.version,
async importEntrypoint(url) {
const baseConfig = await getBaseConfig();
const envConfig: vite.InlineConfig = {
plugins: [
wxtPlugins.webextensionPolyfillMock(wxtConfig),
wxtPlugins.removeEntrypointMainFunction(wxtConfig, url),
],
};
const config = vite.mergeConfig(baseConfig, envConfig);
const server = await vite.createServer(config);
await server.listen();
const runtime = await vite.createViteRuntime(server, { hmr: false });
const module = await runtime.executeUrl(url);
await server.close();
return module.default;
},
async build(group) {
let entryConfig;
if (Array.isArray(group)) entryConfig = getMultiPageConfig(group);
@@ -198,6 +227,11 @@ export async function createViteBuilder(
else entryConfig = getLibModeConfig(group);
const buildConfig = vite.mergeConfig(await getBaseConfig(), entryConfig);
await hooks.callHook(
'vite:build:extendConfig',
toArray(group),
buildConfig,
);
const result = await vite.build(buildConfig);
return {
entrypoints: group,
@@ -214,9 +248,9 @@ export async function createViteBuilder(
},
};
const baseConfig = await getBaseConfig();
const viteServer = await vite.createServer(
vite.mergeConfig(baseConfig, serverConfig),
);
const finalConfig = vite.mergeConfig(baseConfig, serverConfig);
await hooks.callHook('vite:devServer:extendConfig', finalConfig);
const viteServer = await vite.createServer(finalConfig);
const server: WxtBuilderServer = {
async listen() {
@@ -5,9 +5,7 @@ import path from 'node:path';
let increment = 0;
export function bundleAnalysis(
config: Omit<ResolvedConfig, 'builder'>,
): vite.Plugin {
export function bundleAnalysis(config: ResolvedConfig): vite.Plugin {
return visualizer({
template: 'raw-data',
filename: path.resolve(
@@ -14,7 +14,7 @@ import { getEntrypointBundlePath } from '~/core/utils/entrypoints';
*/
export function cssEntrypoints(
entrypoint: Entrypoint,
config: Omit<ResolvedConfig, 'builder'>,
config: ResolvedConfig,
): vite.Plugin {
return {
name: 'wxt:css-entrypoint',
@@ -12,7 +12,7 @@ let reactRefreshPreamble = '';
* Pre-renders the HTML entrypoints when building the extension to connect to the dev server.
*/
export function devHtmlPrerender(
config: Omit<ResolvedConfig, 'builder'>,
config: ResolvedConfig,
server: WxtDevServer | undefined,
): vite.PluginOption {
const htmlReloadId = '@wxt/reload-html';
@@ -133,7 +133,7 @@ export function devHtmlPrerender(
}
export function pointToDevServer(
config: Omit<ResolvedConfig, 'builder'>,
config: ResolvedConfig,
server: WxtDevServer,
id: string,
document: Document,
@@ -5,7 +5,7 @@ import { ResolvedConfig, WxtDevServer } from '~/types';
* Defines global constants about the dev server. Helps scripts connect to the server's web socket.
*/
export function devServerGlobals(
config: Omit<ResolvedConfig, 'builder'>,
config: ResolvedConfig,
server: WxtDevServer | undefined,
): Plugin {
return {
@@ -9,7 +9,7 @@ import { fetchCached } from '~/core/utils/network';
* @example
* import "url:https://google-tagmanager.com/gtag?id=XYZ";
*/
export function download(config: Omit<ResolvedConfig, 'builder'>): Plugin {
export function download(config: ResolvedConfig): Plugin {
return {
name: 'wxt:download',
resolveId(id) {

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