Compare commits
59 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ca5a52c6f1 | |||
| 982c69f8ae | |||
| 6fc7d9254a | |||
| 2e0e104d48 | |||
| 02430fd7b8 | |||
| 2e6d35d193 | |||
| 7cf412ac1f | |||
| 9398cbb596 | |||
| ca9b96142e | |||
| db57c8e079 | |||
| 7e37e11caf | |||
| bb90029c54 | |||
| d3b14afbce | |||
| ba2197a609 | |||
| 4c558d3eb6 | |||
| dcd175444a | |||
| 16fc58404a | |||
| 28c7e7d9ed | |||
| 5a3b42a4b0 | |||
| c9c5d721ec | |||
| 1556b9ad73 | |||
| ca15b1f321 | |||
| 448436cb08 | |||
| c9ddc3d0f2 | |||
| 6b72f883b6 | |||
| cd3446bd7f | |||
| 829b371bba | |||
| 36b399dd49 | |||
| 08f32aa685 | |||
| 05db264e02 | |||
| de5a01834c | |||
| 1d260dbacb | |||
| 53c63b4556 | |||
| 816878bc15 | |||
| e087a0d6ef | |||
| 56b71491a6 | |||
| 121b521157 | |||
| 16c2e3218b | |||
| d9cba55d34 | |||
| 832cd5d640 | |||
| bb95e08d71 | |||
| 35269dad9e | |||
| 64d1498460 | |||
| 0d540a6df9 | |||
| b47c150daa | |||
| 38345481df | |||
| da92449e0f | |||
| 23b3980645 | |||
| 81b4b629c9 | |||
| 4f7e9cb050 | |||
| b226d9b947 | |||
| aabba41e86 | |||
| f19e6908b0 | |||
| 5f651cc3fe | |||
| 8a6acbaaf2 | |||
| 13ab8e4d01 | |||
| bd039dcbab | |||
| 9cd4e8342b | |||
| c9633cefec |
@@ -7,24 +7,12 @@ on:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
formatting:
|
||||
checks:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./.github/actions/setup
|
||||
- run: pnpm format:check
|
||||
lint:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./.github/actions/setup
|
||||
- run: pnpm lint
|
||||
type-check:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./.github/actions/setup
|
||||
- run: pnpm compile
|
||||
- run: pnpm check
|
||||
validate-demo:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
|
||||
+162
@@ -1,5 +1,167 @@
|
||||
# Changelog
|
||||
|
||||
## 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)
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Resolve absolute paths from the public directory properly ([#583](https://github.com/wxt-dev/wxt/pull/583))
|
||||
|
||||
### 📖 Documentation
|
||||
|
||||
- Fix `zip.includeSources` example ([16fc584](https://github.com/wxt-dev/wxt/commit/16fc584))
|
||||
- Add "GitHub Custom Notifier" to homepage ([#580](https://github.com/wxt-dev/wxt/pull/580))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- Simplify virtual module setup ([#581](https://github.com/wxt-dev/wxt/pull/581))
|
||||
- Add some array utils ([#582](https://github.com/wxt-dev/wxt/pull/582))
|
||||
- Extract helper function ([d3b14af](https://github.com/wxt-dev/wxt/commit/d3b14af))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Qiwei Yang ([@qiweiii](http://github.com/qiweiii))
|
||||
|
||||
## v0.17.10
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.17.9...v0.17.10)
|
||||
|
||||
### 🚀 Enhancements
|
||||
|
||||
- Add `dev.server.port` config ([#577](https://github.com/wxt-dev/wxt/pull/577))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- Use `@aklinker1/check` to simplify checks setup ([#550](https://github.com/wxt-dev/wxt/pull/550))
|
||||
- Refactor order of config resolution ([#578](https://github.com/wxt-dev/wxt/pull/578))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Zizheng Tai ([@zizhengtai](http://github.com/zizhengtai))
|
||||
|
||||
## v0.17.9
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.17.8...v0.17.9)
|
||||
|
||||
### 🚀 Enhancements
|
||||
|
||||
- Add `{{mode}}` Template Variable ([#566](https://github.com/wxt-dev/wxt/pull/566))
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Don't override `wxt.config.ts` options when CLI flags are not passed ([#567](https://github.com/wxt-dev/wxt/pull/567))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- Merge user config using `defu` ([#568](https://github.com/wxt-dev/wxt/pull/568))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Guillaume ([@GuiEpi](http://github.com/GuiEpi))
|
||||
|
||||
## v0.17.8
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.17.7...v0.17.8)
|
||||
|
||||
### 🚀 Enhancements
|
||||
|
||||
- **analysis:** Open `stats.html` file automatically ([#564](https://github.com/wxt-dev/wxt/pull/564))
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- **init:** Better error logging when templates fail to load ([b47c150](https://github.com/wxt-dev/wxt/commit/b47c150))
|
||||
- Remove deprecated extension from Vue template ([#534](https://github.com/wxt-dev/wxt/pull/534))
|
||||
- Append option description error ([#546](https://github.com/wxt-dev/wxt/pull/546))
|
||||
- **init:** Don't overwrite existing files when initializing a new project ([#556](https://github.com/wxt-dev/wxt/pull/556))
|
||||
- **dev:** Don't crash dev mode when rebuild fails ([#565](https://github.com/wxt-dev/wxt/pull/565))
|
||||
|
||||
### 📖 Documentation
|
||||
|
||||
- Replace `pnpx` with `pnpm dlx` ([#527](https://github.com/wxt-dev/wxt/pull/527))
|
||||
- Update homepage demo video ([35269da](https://github.com/wxt-dev/wxt/commit/35269da))
|
||||
- Update README demo video ([#539](https://github.com/wxt-dev/wxt/pull/539))
|
||||
- Add Plex skipper to "Using WXT" section ([#541](https://github.com/wxt-dev/wxt/pull/541))
|
||||
- Add documentation for Bun.sh ([#543](https://github.com/wxt-dev/wxt/pull/543))
|
||||
- Mention adding unlisted scripts and pages to `web_accessible_resources` ([121b521](https://github.com/wxt-dev/wxt/commit/121b521))
|
||||
- Add examples for GitHub Actions ([#540](https://github.com/wxt-dev/wxt/pull/540))
|
||||
- Fixed "Reload the Extension" section ([#559](https://github.com/wxt-dev/wxt/pull/559))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- Increase unit test timeout ([d9cba55](https://github.com/wxt-dev/wxt/commit/d9cba55))
|
||||
- Increase hook timeout for Windows/NPM tests ([56b7149](https://github.com/wxt-dev/wxt/commit/56b7149))
|
||||
- Switch to seed plugin for testing ([#547](https://github.com/wxt-dev/wxt/pull/547))
|
||||
- **vue-template:** Upgrade to `vue-tsc` v2 ([#549](https://github.com/wxt-dev/wxt/pull/549))
|
||||
- Add a test covering `wxt init` in a non-empty directory ([#563](https://github.com/wxt-dev/wxt/pull/563))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Btea ([@btea](http://github.com/btea))
|
||||
- Vlad Fedosov ([@StyleT](http://github.com/StyleT))
|
||||
- Lpmvb ([@Lpmvb](http://github.com/Lpmvb))
|
||||
- Guillaume ([@GuiEpi](http://github.com/GuiEpi))
|
||||
- Sunshio ([@MPB-Tech](http://github.com/MPB-Tech))
|
||||
- Luca Dalli ([@lucadalli](http://github.com/lucadalli))
|
||||
|
||||
## v0.17.7
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.17.6...v0.17.7)
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- **zip:** List `.wxt/local_modules` overrides relative to the `package.json` they're added to ([#526](https://github.com/wxt-dev/wxt/pull/526))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- Bump templates to v0.17 ([#524](https://github.com/wxt-dev/wxt/pull/524))
|
||||
- Increase test timeout for windows NPM tests ([#525](https://github.com/wxt-dev/wxt/pull/525))
|
||||
|
||||
## v0.17.6
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.17.5...v0.17.6)
|
||||
|
||||
### 🚀 Enhancements
|
||||
|
||||
- Add warnings when important directories are missing ([#516](https://github.com/wxt-dev/wxt/pull/516))
|
||||
- Automatically remove top-level MV2-only or MV3-only keys ([#518](https://github.com/wxt-dev/wxt/pull/518))
|
||||
- Automatically generate `browser_action` based on `action` for MV2 ([#519](https://github.com/wxt-dev/wxt/pull/519))
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- **zip:** List all private packages correctly in a PNPM workspace ([#520](https://github.com/wxt-dev/wxt/pull/520))
|
||||
|
||||
### 📖 Documentation
|
||||
|
||||
- Mentions moving folders into `srcDir` ([9cd4e83](https://github.com/wxt-dev/wxt/commit/9cd4e83))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- **deps-dev:** Bump @types/react from 18.2.34 to 18.2.61 ([#510](https://github.com/wxt-dev/wxt/pull/510))
|
||||
|
||||
## v0.17.5
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.17.4...v0.17.5)
|
||||
|
||||
@@ -29,20 +29,22 @@
|
||||
<a href="https://wxt.dev/api/config.html" target="_blank">Configuration</a>
|
||||
•
|
||||
<a href="https://wxt.dev/examples.html" target="_blank">Examples</a>
|
||||
•
|
||||
<a href="https://discord.gg/ZFsZqGery9" target="_blank">Discord</a>
|
||||
</p>
|
||||
|
||||

|
||||
|
||||
## Demo
|
||||
|
||||
https://github.com/wxt-dev/wxt/assets/10101283/07359e53-f491-43b6-8e8f-fae94aec8063
|
||||
https://github.com/wxt-dev/wxt/assets/10101283/4d678939-1bdb-495c-9c36-3aa281d84c94
|
||||
|
||||
## Quick Start
|
||||
|
||||
Bootstrap a new project:
|
||||
|
||||
```sh
|
||||
pnpx wxt@latest init <project-name>
|
||||
pnpm dlx wxt@latest init <project-name>
|
||||
```
|
||||
|
||||
Or see the [installation guide](https://wxt.dev/guide/installation.html) to get started with WXT.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import messages from 'public/_locales/en/messages.json';
|
||||
import messages from '~/public/_locales/en/messages.json';
|
||||
|
||||
export default defineBackground({
|
||||
// type: 'module',
|
||||
|
||||
+3
-3
@@ -12,10 +12,10 @@ export default defineConfig({
|
||||
},
|
||||
],
|
||||
},
|
||||
alias: {
|
||||
public: 'src/public',
|
||||
},
|
||||
zip: {
|
||||
downloadPackages: ['sass'],
|
||||
},
|
||||
analysis: {
|
||||
open: true,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -20,6 +20,8 @@ const chromeExtensionIds = [
|
||||
'agjnjboanicjcpenljmaaigopkgdnihi', // PreMiD
|
||||
'aiakblgmlabokilgljkglggnpflljdgp', // Markdown Sticky Notes
|
||||
'nomnkbngkijpffepcgbbofhcnafpkiep', // DocVersionRedirector
|
||||
'ceicccfeikoipigeghddpocceifjelph', // Plex Skipper
|
||||
'aelkipgppclpfimeamgmlonimflbhlgf', // GitHub Custom Notifier
|
||||
];
|
||||
|
||||
const { data, err, isLoading } = useListExtensionDetails(chromeExtensionIds);
|
||||
|
||||
@@ -146,6 +146,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' },
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
HTML pages that are bundled and shipped with the extension, but are not included in the manifest.
|
||||
|
||||
If you plan on using the page in an iframe, don't forget to add the page to [`web_accessible_resources`](https://developer.chrome.com/docs/extensions/reference/manifest/web-accessible-resources).
|
||||
|
||||
### Examples
|
||||
|
||||
- Onboarding
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
TypeScript files that are bundled and shipped with the extension, but are not included in the manifest.
|
||||
|
||||
You are responsible for loading/running these scripts where needed.
|
||||
You are responsible for loading/running these scripts where needed. If necessary, don't forget to add the script and/or any related stylesheets to [`web_accessible_resources`](https://developer.chrome.com/docs/extensions/reference/manifest/web-accessible-resources).
|
||||
|
||||
## Filenames
|
||||
|
||||
|
||||
@@ -99,7 +99,17 @@ For a full list of options, see the [API Reference](/api/wxt/interfaces/Extensio
|
||||
|
||||
Normally, to manually reload an extension, you have to visit `chrome://extensions` and click the reload button for your extension.
|
||||
|
||||
When running `wxt` command to start the dev server, WXT adds a keyboard shortcut, `ctrl+E` for Windows/Linux and `cmd+E` for Mac, that reloads the extension when pressed, without visiting `chrome://extensions`.
|
||||
When running `wxt` command to start the dev server, WXT adds a keyboard shortcut `Alt+R`, that reloads the extension when pressed, without visiting `chrome://extensions`. This can also be customized or disabled:
|
||||
|
||||
```ts [wxt.config.ts]
|
||||
import { defineConfig } from 'wxt';
|
||||
|
||||
export default defineConfig({
|
||||
dev: {
|
||||
reloadCommand: 'Alt+T', // false, to disable
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
:::info
|
||||
This shortcut is only available during development, and is not be added to your extension when running `wxt build` or `wxt-zip`.
|
||||
|
||||
@@ -7,13 +7,17 @@ Bootstrap a new project, start from scratch, or [migrate an existing project](/g
|
||||
:::code-group
|
||||
|
||||
```sh [pnpm]
|
||||
pnpx wxt@latest init <project-name>
|
||||
pnpm dlx wxt@latest init <project-name>
|
||||
```
|
||||
|
||||
```sh [npm]
|
||||
npx wxt@latest init <project-name>
|
||||
```
|
||||
|
||||
```sh [bun]
|
||||
bunx wxt@latest init <project-name>
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
There are several starting templates available.
|
||||
@@ -55,6 +59,12 @@ cd project-name
|
||||
yarn init
|
||||
```
|
||||
|
||||
```sh [bun]
|
||||
mkdir project-name
|
||||
cd project-name
|
||||
bun init
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
Then install `wxt`:
|
||||
@@ -73,6 +83,10 @@ npm i --save-dev wxt
|
||||
yarn add --dev wxt
|
||||
```
|
||||
|
||||
```sh [bun]
|
||||
bun add --dev wxt
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
Add your first entrypoint:
|
||||
@@ -102,7 +116,7 @@ Finally, add scripts to your `package.json`:
|
||||
|
||||
## Migrate an Existing Project
|
||||
|
||||
Before starting the migration, it is recommended to run `pnpx wxt@latest init` to see what a basic project looks like. Once you have an understanding of how WXT projects are structured, you're ready to convert the project, using the initialized project as a reference.
|
||||
Before starting the migration, it is recommended to run `pnpm dlx wxt@latest init` to see what a basic project looks like. Once you have an understanding of how WXT projects are structured, you're ready to convert the project, using the initialized project as a reference.
|
||||
|
||||
Migrating a project to WXT comes down to a few steps:
|
||||
|
||||
|
||||
@@ -130,6 +130,72 @@ See the official localization examples for more details:
|
||||
|
||||
<ExampleList tag="i18n" />
|
||||
|
||||
## Per-Manifest Version Config
|
||||
|
||||
WXT applies several transformations to your manifest to simplify managing both MV2 and MV3 keys in your `wxt.config.ts` file:
|
||||
|
||||
1. Top level MV2-only or MV3-only keys are stripped from the final manifest when targeting the other manifest version
|
||||
2. Some keys, are automatically converted between versions when possible:
|
||||
- Define `web_accessible_resources` in it's MV3 style and it will be converted to the MV2 style automatically
|
||||
- `action` will automatically be converted to `browser_action` for MV3. To use `page_action` instead, add both `action` and `page_action` entries to your manifest
|
||||
|
||||
For example, a `wxt.config.ts` file that looks like this:
|
||||
|
||||
```ts
|
||||
import { defineConfig } from 'wxt';
|
||||
|
||||
export default defineConfig({
|
||||
mainfest: {
|
||||
action: {
|
||||
default_title: 'Some Title',
|
||||
},
|
||||
web_accessible_resources: [
|
||||
{
|
||||
matches: ['*://*.google.com/*'],
|
||||
resources: ['icon/*.png'],
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Will be output differently for each manifest version:
|
||||
|
||||
:::code-group
|
||||
|
||||
```json [MV2]
|
||||
{
|
||||
"manifest_version": 2,
|
||||
// ...
|
||||
"browser_action": {
|
||||
"default_title": "Some Title"
|
||||
},
|
||||
"web_accessible_resources": ["icon/*.png"]
|
||||
}
|
||||
```
|
||||
|
||||
```json [MV3]
|
||||
{
|
||||
"manifest_version": 3,
|
||||
// ...
|
||||
"action": {
|
||||
"default_title": "Some Title"
|
||||
},
|
||||
"web_accessible_resources": [
|
||||
{
|
||||
"matches": ["*://*.google.com/*"],
|
||||
"resources": ["icon/*.png"]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
:::tip
|
||||
If this isn't enough control for your use-case, remember you can use a function for the `manifest` key and generate it however you'd like, or you can use the `build:manifestGenerated` hook to apply additional transformations.
|
||||
:::
|
||||
|
||||
## Per-Browser Configuration
|
||||
|
||||
The `manifest` field can be a function. If you are building and extension for multiple browsers, and need to modify the manifest per browser, using a function instead of an object is very useful.
|
||||
|
||||
@@ -12,7 +12,7 @@ Always start by generating a new vanilla project and merging it into your projec
|
||||
|
||||
```sh
|
||||
cd path/to/your/project
|
||||
pnpx wxt@latest init example-wxt --template vanilla
|
||||
pnpm dlx wxt@latest init example-wxt --template vanilla
|
||||
```
|
||||
|
||||
In general, you'll need to:
|
||||
|
||||
@@ -64,12 +64,59 @@ See the [Firefox Addon Store](#firefox-addon-store) section for more details abo
|
||||
|
||||
## GitHub Action
|
||||
|
||||
Here's an example of a GitHub Action to automate submitting new versions of your extension for review. Ensure that you've added all required secrets used in the workflow to the repo's settings.
|
||||
Here's an example of a GitHub Action that submits new versions of an extension for review. Ensure that you've added all required secrets used in the workflow to the repo's settings.
|
||||
|
||||
```yml
|
||||
# TODO
|
||||
name: Release
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
submit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: pnpm/action-setup@v3
|
||||
with:
|
||||
version: 'latest'
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Zip extensions
|
||||
run: |
|
||||
pnpm zip
|
||||
pnpm zip:firefox
|
||||
|
||||
- name: Submit to stores
|
||||
run: |
|
||||
pnpm wxt submit \
|
||||
--chrome-zip .output/*-chrome.zip \
|
||||
--firefox-zip .output/*-firefox.zip --firefox-sources-zip .output/*-sources.zip
|
||||
env:
|
||||
CHROME_EXTENSION_ID: ${{ secrets.CHROME_EXTENSION_ID }}
|
||||
CHROME_CLIENT_ID: ${{ secrets.CHROME_CLIENT_ID }}
|
||||
CHROME_CLIENT_SECRET: ${{ secrets.CHROME_CLIENT_SECRET }}
|
||||
CHROME_REFRESH_TOKEN: ${{ secrets.CHROME_REFRESH_TOKEN }}
|
||||
FIREFOX_EXTENSION_ID: ${{ secrets.FIREFOX_EXTENSION_ID }}
|
||||
FIREFOX_JWT_ISSUER: ${{ secrets.FIREFOX_JWT_ISSUER }}
|
||||
FIREFOX_JWT_SECRET: ${{ secrets.FIREFOX_JWT_SECRET }}
|
||||
```
|
||||
|
||||
The action above lays the foundation for a basic workflow, including `zip` and `submit` steps. To further enhance your GitHub Action and delve into more complex scenarios, consider exploring the following examples from real projects. They introduce advanced features such as version management, changelog generation, and GitHub releases, tailored for different needs:
|
||||
|
||||
- [`aklinker1/github-better-line-counts`](https://github.com/aklinker1/github-better-line-counts/blob/main/.github/workflows/submit.yml) - Conventional commits, automated version bump and changelog generation, triggered manually, optional dry run for testing
|
||||
- [`GuiEpi/plex-skipper`](https://github.com/GuiEpi/plex-skipper/blob/main/.github/workflows/deploy.yml) - Triggered automatically when `package.json` version is changed, creates and uploads artifacts to GitHub release.
|
||||
|
||||
> These examples are designed to provide clear insights and are a good starting point for customizing your own workflows. Feel free to explore and adapt them to your project needs.
|
||||
|
||||
## Stores
|
||||
|
||||
### Chrome Web Store
|
||||
@@ -124,6 +171,11 @@ yarn
|
||||
yarn zip:firefox
|
||||
```
|
||||
|
||||
```sh [bun]
|
||||
bun i
|
||||
bun zip:firefox
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
Make sure the build output is the exact same when running `wxt build -b firefox` in your main project and inside the zipped sources.
|
||||
|
||||
+2
-2
@@ -70,14 +70,14 @@ features:
|
||||
linkText: Read docs
|
||||
---
|
||||
|
||||
<section class="vp-doc">
|
||||
<section class="vp-doc" style="padding: 0 48px">
|
||||
<div class="container">
|
||||
<h2>Put <span style="color: var(--vp-c-brand-1)">Developer Experience</span> First</h2>
|
||||
<p>
|
||||
WXT's simplifies the chrome extension development process by providing tools for zipping and publishing, the best-in-class dev mode, an opinionated project structure, and more. Iterate faster, develop features not build scripts, and use everything the JS ecosystem has to offer.
|
||||
</p>
|
||||
<div style="margin: auto; width: 100%; max-width: 900px; text-align: center">
|
||||
<video src="https://github.com/wxt-dev/wxt/assets/10101283/b32e6766-ec11-45a4-9677-226ee4718e1c" controls></video>
|
||||
<video src="https://github.com/wxt-dev/wxt/assets/10101283/4d678939-1bdb-495c-9c36-3aa281d84c94" controls></video>
|
||||
<br />
|
||||
<small>
|
||||
And who doesn't appreciate a beautiful CLI?
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
import { TestProject } from '../utils';
|
||||
import { resetBundleIncrement } from '~/core/builders/vite/plugins';
|
||||
import open from 'open';
|
||||
|
||||
vi.mock('open');
|
||||
const openMock = vi.mocked(open);
|
||||
|
||||
vi.mock('ci-info', () => ({
|
||||
isCI: false,
|
||||
}));
|
||||
|
||||
describe('Analysis', () => {
|
||||
beforeEach(() => {
|
||||
@@ -89,4 +97,24 @@ describe('Analysis', () => {
|
||||
expect(await project.fileExists('stats/bundle-0.json')).toBe(true);
|
||||
expect(await project.fileExists('stats/bundle-1.json')).toBe(true);
|
||||
});
|
||||
|
||||
it('should open the stats in the browser when requested', async () => {
|
||||
const project = new TestProject();
|
||||
project.addFile('entrypoints/popup.html');
|
||||
project.addFile('entrypoints/options.html');
|
||||
project.addFile(
|
||||
'entrypoints/background.ts',
|
||||
'export default defineBackground(() => {});',
|
||||
);
|
||||
|
||||
await project.build({
|
||||
analysis: {
|
||||
enabled: true,
|
||||
open: true,
|
||||
},
|
||||
});
|
||||
|
||||
expect(openMock).toBeCalledTimes(1);
|
||||
expect(openMock).toBeCalledWith(project.resolvePath('stats.html'));
|
||||
});
|
||||
});
|
||||
|
||||
+16
-3
@@ -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,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,6 +2,7 @@ import { describe, it, expect } from 'vitest';
|
||||
import { TestProject } from '../utils';
|
||||
import { execaCommand } from 'execa';
|
||||
import glob from 'fast-glob';
|
||||
import { mkdir, writeJson } from 'fs-extra';
|
||||
|
||||
describe('Init command', () => {
|
||||
it('should download and create a template', async () => {
|
||||
@@ -42,4 +43,17 @@ describe('Init command', () => {
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
it('should throw an error if the directory is not empty', async () => {
|
||||
const project = new TestProject();
|
||||
await mkdir(project.root);
|
||||
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',
|
||||
}),
|
||||
).rejects.toThrowError('Command failed with exit code 1:');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -71,4 +71,29 @@ describe('Zipping', () => {
|
||||
}"
|
||||
`);
|
||||
});
|
||||
|
||||
it('should correctly apply template variables for zip file names based on provided config', async () => {
|
||||
const project = new TestProject({
|
||||
name: 'test',
|
||||
version: '1.0.0',
|
||||
});
|
||||
project.addFile(
|
||||
'entrypoints/background.ts',
|
||||
'export default defineBackground(() => {});',
|
||||
);
|
||||
const artifactZip = '.output/test-1.0.0-firefox-development.zip';
|
||||
const sourcesZip = '.output/test-1.0.0-development-sources.zip';
|
||||
|
||||
await project.zip({
|
||||
browser: 'firefox',
|
||||
mode: 'development',
|
||||
zip: {
|
||||
artifactTemplate: '{{name}}-{{version}}-{{browser}}-{{mode}}.zip',
|
||||
sourcesTemplate: '{{name}}-{{version}}-{{mode}}-sources.zip',
|
||||
},
|
||||
});
|
||||
|
||||
expect(await project.fileExists(artifactZip)).toBe(true);
|
||||
expect(await project.fileExists(sourcesZip)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
+8
-9
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "wxt",
|
||||
"type": "module",
|
||||
"version": "0.17.5",
|
||||
"version": "0.17.12",
|
||||
"description": "Next gen framework for developing web extensions",
|
||||
"engines": {
|
||||
"node": ">=18",
|
||||
@@ -87,14 +87,9 @@
|
||||
"scripts": {
|
||||
"wxt": "tsx src/cli/index.ts",
|
||||
"build": "tsx scripts/build.ts",
|
||||
"format": "prettier --write .",
|
||||
"format:check": "prettier --check .",
|
||||
"lint": "run-p -c -s lint:*",
|
||||
"lint:eslint": "echo 'ESLint: TODO'",
|
||||
"lint:package": "publint",
|
||||
"compile": "run-s -c compile:*",
|
||||
"compile:wxt": "tsc --noEmit",
|
||||
"compile:virtual": "tsc --noEmit -p src/virtual",
|
||||
"check": "run-s -c check:*",
|
||||
"check:default": "check",
|
||||
"check:tsc-virtual": "tsc --noEmit -p src/virtual",
|
||||
"test": "vitest",
|
||||
"test:coverage": "vitest run --coverage.enabled \"--coverage.include=src/**\" \"--coverage.exclude=src/core/utils/testing/**\" \"--coverage.exclude=**/*.d.ts\"",
|
||||
"prepare": "simple-git-hooks",
|
||||
@@ -115,6 +110,7 @@
|
||||
"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",
|
||||
@@ -134,6 +130,7 @@
|
||||
"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",
|
||||
@@ -144,6 +141,7 @@
|
||||
"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",
|
||||
@@ -171,6 +169,7 @@
|
||||
"vitepress": "1.0.0-rc.34",
|
||||
"vitest": "^1.2.2",
|
||||
"vitest-mock-extended": "^1.3.1",
|
||||
"vitest-plugin-random-seed": "^1.0.2",
|
||||
"vue": "^3.3.10"
|
||||
},
|
||||
"packageManager": "pnpm@8.6.3",
|
||||
|
||||
Generated
+235
-209
@@ -28,13 +28,16 @@ importers:
|
||||
version: 0.4.0
|
||||
c12:
|
||||
specifier: ^1.5.1
|
||||
version: 1.5.1
|
||||
version: 1.10.0
|
||||
cac:
|
||||
specifier: ^6.7.14
|
||||
version: 6.7.14
|
||||
chokidar:
|
||||
specifier: ^3.5.3
|
||||
version: 3.5.3
|
||||
version: 3.6.0
|
||||
ci-info:
|
||||
specifier: ^4.0.0
|
||||
version: 4.0.0
|
||||
consola:
|
||||
specifier: ^3.2.3
|
||||
version: 3.2.3
|
||||
@@ -79,7 +82,7 @@ importers:
|
||||
version: 3.10.1
|
||||
linkedom:
|
||||
specifier: ^0.16.1
|
||||
version: 0.16.1
|
||||
version: 0.16.8
|
||||
minimatch:
|
||||
specifier: ^9.0.3
|
||||
version: 9.0.3
|
||||
@@ -92,6 +95,9 @@ importers:
|
||||
nypm:
|
||||
specifier: ^0.3.6
|
||||
version: 0.3.6
|
||||
open:
|
||||
specifier: ^10.1.0
|
||||
version: 10.1.0
|
||||
ora:
|
||||
specifier: ^7.0.1
|
||||
version: 7.0.1
|
||||
@@ -117,6 +123,9 @@ importers:
|
||||
specifier: ^0.10.0
|
||||
version: 0.10.0
|
||||
devDependencies:
|
||||
'@aklinker1/check':
|
||||
specifier: ^1.1.1
|
||||
version: 1.2.0(typescript@5.3.3)
|
||||
'@faker-js/faker':
|
||||
specifier: ^8.3.1
|
||||
version: 8.3.1
|
||||
@@ -198,9 +207,12 @@ importers:
|
||||
vitest-mock-extended:
|
||||
specifier: ^1.3.1
|
||||
version: 1.3.1(typescript@5.3.3)(vitest@1.2.2)
|
||||
vitest-plugin-random-seed:
|
||||
specifier: ^1.0.2
|
||||
version: 1.0.2(vite@5.1.3)
|
||||
vue:
|
||||
specifier: ^3.3.10
|
||||
version: 3.3.10(typescript@5.3.3)
|
||||
version: 3.4.21(typescript@5.3.3)
|
||||
|
||||
demo:
|
||||
dependencies:
|
||||
@@ -229,6 +241,18 @@ importers:
|
||||
|
||||
packages:
|
||||
|
||||
/@aklinker1/check@1.2.0(typescript@5.3.3):
|
||||
resolution: {integrity: sha512-8GEoPcifx5f7Yx2t1KCGEQyrLOOb2ErP3cG+H1+TwWBYjkT2HV9ZHCLYy0Ws8CET8VeUcKDvLKmn2DW3HBt+FA==}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
typescript: ^5.0.0
|
||||
dependencies:
|
||||
'@antfu/utils': 0.7.7
|
||||
ci-info: 4.0.0
|
||||
citty: 0.1.6
|
||||
typescript: 5.3.3
|
||||
dev: true
|
||||
|
||||
/@aklinker1/rollup-plugin-visualizer@5.12.0:
|
||||
resolution: {integrity: sha512-X24LvEGw6UFmy0lpGJDmXsMyBD58XmX1bbwsaMLhNoM+UMQfQ3b2RtC+nz4b/NoRK5r6QJSKJHBNVeUdwqybaQ==}
|
||||
engines: {node: '>=14'}
|
||||
@@ -393,6 +417,10 @@ packages:
|
||||
'@jridgewell/trace-mapping': 0.3.18
|
||||
dev: true
|
||||
|
||||
/@antfu/utils@0.7.7:
|
||||
resolution: {integrity: sha512-gFPqTG7otEJ8uP6wrhDv6mqwGWYZKNvAcCq6u9hOj0c+IKCEsY4L1oC9trPq2SaWIzAfHvqfBDxF591JkMf+kg==}
|
||||
dev: true
|
||||
|
||||
/@babel/code-frame@7.22.5:
|
||||
resolution: {integrity: sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
@@ -418,8 +446,8 @@ packages:
|
||||
js-tokens: 4.0.0
|
||||
dev: false
|
||||
|
||||
/@babel/parser@7.23.6:
|
||||
resolution: {integrity: sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==}
|
||||
/@babel/parser@7.24.1:
|
||||
resolution: {integrity: sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
@@ -1155,7 +1183,7 @@ packages:
|
||||
/@types/react-dom@18.2.14:
|
||||
resolution: {integrity: sha512-V835xgdSVmyQmI1KLV2BEIUgqEuinxp9O4G6g3FqO/SqLac049E53aysv0oEFD2kHfejeKU+ZqL2bcFWj9gLAQ==}
|
||||
dependencies:
|
||||
'@types/react': 18.2.34
|
||||
'@types/react': 18.2.61
|
||||
dev: true
|
||||
|
||||
/@types/react@18.2.34:
|
||||
@@ -1166,6 +1194,14 @@ packages:
|
||||
csstype: 3.1.2
|
||||
dev: true
|
||||
|
||||
/@types/react@18.2.61:
|
||||
resolution: {integrity: sha512-NURTN0qNnJa7O/k4XUkEW2yfygA+NxS0V5h1+kp9jPwhzZy95q3ADoGMP0+JypMhrZBTTgjKAUlTctde1zzeQA==}
|
||||
dependencies:
|
||||
'@types/prop-types': 15.7.9
|
||||
'@types/scheduler': 0.16.5
|
||||
csstype: 3.1.3
|
||||
dev: true
|
||||
|
||||
/@types/scheduler@0.16.5:
|
||||
resolution: {integrity: sha512-s/FPdYRmZR8SjLWGMCuax7r3qCWQw9QKHzXVukAuuIJkXkDRwp+Pu5LMIVFi0Fxbav35WURicYr8u1QsoybnQw==}
|
||||
dev: true
|
||||
@@ -1185,7 +1221,7 @@ packages:
|
||||
'@types/node': 20.10.3
|
||||
optional: true
|
||||
|
||||
/@vitejs/plugin-vue@5.0.2(vite@5.1.3)(vue@3.4.3):
|
||||
/@vitejs/plugin-vue@5.0.2(vite@5.1.3)(vue@3.4.21):
|
||||
resolution: {integrity: sha512-kEjJHrLb5ePBvjD0SPZwJlw1QTRcjjCA9sB5VyfonoXVBxTS7TMnqL6EkLt1Eu61RDeiuZ/WN9Hf6PxXhPI2uA==}
|
||||
engines: {node: ^18.0.0 || >=20.0.0}
|
||||
peerDependencies:
|
||||
@@ -1193,7 +1229,7 @@ packages:
|
||||
vue: ^3.2.25
|
||||
dependencies:
|
||||
vite: 5.1.3(@types/node@20.10.3)(sass@1.69.5)
|
||||
vue: 3.4.3(typescript@5.3.3)
|
||||
vue: 3.4.21(typescript@5.3.3)
|
||||
dev: true
|
||||
|
||||
/@vitest/coverage-v8@1.2.2(vitest@1.2.2):
|
||||
@@ -1231,13 +1267,13 @@ packages:
|
||||
dependencies:
|
||||
'@vitest/utils': 1.2.2
|
||||
p-limit: 5.0.0
|
||||
pathe: 1.1.1
|
||||
pathe: 1.1.2
|
||||
|
||||
/@vitest/snapshot@1.2.2:
|
||||
resolution: {integrity: sha512-SmGY4saEw1+bwE1th6S/cZmPxz/Q4JWsl7LvbQIky2tKE35US4gd0Mjzqfr84/4OD0tikGWaWdMja/nWL5NIPA==}
|
||||
dependencies:
|
||||
magic-string: 0.30.5
|
||||
pathe: 1.1.1
|
||||
magic-string: 0.30.8
|
||||
pathe: 1.1.2
|
||||
pretty-format: 29.7.0
|
||||
|
||||
/@vitest/spy@1.2.2:
|
||||
@@ -1253,179 +1289,96 @@ packages:
|
||||
loupe: 2.3.7
|
||||
pretty-format: 29.7.0
|
||||
|
||||
/@vue/compiler-core@3.3.10:
|
||||
resolution: {integrity: sha512-doe0hODR1+i1menPkRzJ5MNR6G+9uiZHIknK3Zn5OcIztu6GGw7u0XUzf3AgB8h/dfsZC9eouzoLo3c3+N/cVA==}
|
||||
/@vue/compiler-core@3.4.21:
|
||||
resolution: {integrity: sha512-MjXawxZf2SbZszLPYxaFCjxfibYrzr3eYbKxwpLR9EQN+oaziSu3qKVbwBERj1IFIB8OLUewxB5m/BFzi613og==}
|
||||
dependencies:
|
||||
'@babel/parser': 7.23.6
|
||||
'@vue/shared': 3.3.10
|
||||
estree-walker: 2.0.2
|
||||
source-map-js: 1.0.2
|
||||
dev: true
|
||||
|
||||
/@vue/compiler-core@3.4.3:
|
||||
resolution: {integrity: sha512-u8jzgFg0EDtSrb/hG53Wwh1bAOQFtc1ZCegBpA/glyvTlgHl+tq13o1zvRfLbegYUw/E4mSTGOiCnAJ9SJ+lsg==}
|
||||
dependencies:
|
||||
'@babel/parser': 7.23.6
|
||||
'@vue/shared': 3.4.3
|
||||
'@babel/parser': 7.24.1
|
||||
'@vue/shared': 3.4.21
|
||||
entities: 4.5.0
|
||||
estree-walker: 2.0.2
|
||||
source-map-js: 1.0.2
|
||||
dev: true
|
||||
|
||||
/@vue/compiler-dom@3.3.10:
|
||||
resolution: {integrity: sha512-NCrqF5fm10GXZIK0GrEAauBqdy+F2LZRt3yNHzrYjpYBuRssQbuPLtSnSNjyR9luHKkWSH8we5LMB3g+4z2HvA==}
|
||||
/@vue/compiler-dom@3.4.21:
|
||||
resolution: {integrity: sha512-IZC6FKowtT1sl0CR5DpXSiEB5ayw75oT2bma1BEhV7RRR1+cfwLrxc2Z8Zq/RGFzJ8w5r9QtCOvTjQgdn0IKmA==}
|
||||
dependencies:
|
||||
'@vue/compiler-core': 3.3.10
|
||||
'@vue/shared': 3.3.10
|
||||
'@vue/compiler-core': 3.4.21
|
||||
'@vue/shared': 3.4.21
|
||||
dev: true
|
||||
|
||||
/@vue/compiler-dom@3.4.3:
|
||||
resolution: {integrity: sha512-oGF1E9/htI6JWj/lTJgr6UgxNCtNHbM6xKVreBWeZL9QhRGABRVoWGAzxmtBfSOd+w0Zi5BY0Es/tlJrN6WgEg==}
|
||||
/@vue/compiler-sfc@3.4.21:
|
||||
resolution: {integrity: sha512-me7epoTxYlY+2CUM7hy9PCDdpMPfIwrOvAXud2Upk10g4YLv9UBW7kL798TvMeDhPthkZ0CONNrK2GoeI1ODiQ==}
|
||||
dependencies:
|
||||
'@vue/compiler-core': 3.4.3
|
||||
'@vue/shared': 3.4.3
|
||||
dev: true
|
||||
|
||||
/@vue/compiler-sfc@3.3.10:
|
||||
resolution: {integrity: sha512-xpcTe7Rw7QefOTRFFTlcfzozccvjM40dT45JtrE3onGm/jBLZ0JhpKu3jkV7rbDFLeeagR/5RlJ2Y9SvyS0lAg==}
|
||||
dependencies:
|
||||
'@babel/parser': 7.23.6
|
||||
'@vue/compiler-core': 3.3.10
|
||||
'@vue/compiler-dom': 3.3.10
|
||||
'@vue/compiler-ssr': 3.3.10
|
||||
'@vue/reactivity-transform': 3.3.10
|
||||
'@vue/shared': 3.3.10
|
||||
'@babel/parser': 7.24.1
|
||||
'@vue/compiler-core': 3.4.21
|
||||
'@vue/compiler-dom': 3.4.21
|
||||
'@vue/compiler-ssr': 3.4.21
|
||||
'@vue/shared': 3.4.21
|
||||
estree-walker: 2.0.2
|
||||
magic-string: 0.30.5
|
||||
postcss: 8.4.32
|
||||
source-map-js: 1.0.2
|
||||
dev: true
|
||||
|
||||
/@vue/compiler-sfc@3.4.3:
|
||||
resolution: {integrity: sha512-NuJqb5is9I4uzv316VRUDYgIlPZCG8D+ARt5P4t5UDShIHKL25J3TGZAUryY/Aiy0DsY7srJnZL5ryB6DD63Zw==}
|
||||
dependencies:
|
||||
'@babel/parser': 7.23.6
|
||||
'@vue/compiler-core': 3.4.3
|
||||
'@vue/compiler-dom': 3.4.3
|
||||
'@vue/compiler-ssr': 3.4.3
|
||||
'@vue/shared': 3.4.3
|
||||
estree-walker: 2.0.2
|
||||
magic-string: 0.30.5
|
||||
magic-string: 0.30.8
|
||||
postcss: 8.4.35
|
||||
source-map-js: 1.0.2
|
||||
dev: true
|
||||
|
||||
/@vue/compiler-ssr@3.3.10:
|
||||
resolution: {integrity: sha512-12iM4jA4GEbskwXMmPcskK5wImc2ohKm408+o9iox3tfN9qua8xL0THIZtoe9OJHnXP4eOWZpgCAAThEveNlqQ==}
|
||||
/@vue/compiler-ssr@3.4.21:
|
||||
resolution: {integrity: sha512-M5+9nI2lPpAsgXOGQobnIueVqc9sisBFexh5yMIMRAPYLa7+5wEJs8iqOZc1WAa9WQbx9GR2twgznU8LTIiZ4Q==}
|
||||
dependencies:
|
||||
'@vue/compiler-dom': 3.3.10
|
||||
'@vue/shared': 3.3.10
|
||||
dev: true
|
||||
|
||||
/@vue/compiler-ssr@3.4.3:
|
||||
resolution: {integrity: sha512-wnYQtMBkeFSxgSSQbYGQeXPhQacQiog2c6AlvMldQH6DB+gSXK/0F6DVXAJfEiuBSgBhUc8dwrrG5JQcqwalsA==}
|
||||
dependencies:
|
||||
'@vue/compiler-dom': 3.4.3
|
||||
'@vue/shared': 3.4.3
|
||||
'@vue/compiler-dom': 3.4.21
|
||||
'@vue/shared': 3.4.21
|
||||
dev: true
|
||||
|
||||
/@vue/devtools-api@6.5.1:
|
||||
resolution: {integrity: sha512-+KpckaAQyfbvshdDW5xQylLni1asvNSGme1JFs8I1+/H5pHEhqUKMEQD/qn3Nx5+/nycBq11qAEi8lk+LXI2dA==}
|
||||
dev: true
|
||||
|
||||
/@vue/reactivity-transform@3.3.10:
|
||||
resolution: {integrity: sha512-0xBdk+CKHWT+Gev8oZ63Tc0qFfj935YZx+UAynlutnrDZ4diFCVFMWixn65HzjE3S1iJppWOo6Tt1OzASH7VEg==}
|
||||
/@vue/reactivity@3.4.21:
|
||||
resolution: {integrity: sha512-UhenImdc0L0/4ahGCyEzc/pZNwVgcglGy9HVzJ1Bq2Mm9qXOpP8RyNTjookw/gOCUlXSEtuZ2fUg5nrHcoqJcw==}
|
||||
dependencies:
|
||||
'@babel/parser': 7.23.6
|
||||
'@vue/compiler-core': 3.3.10
|
||||
'@vue/shared': 3.3.10
|
||||
estree-walker: 2.0.2
|
||||
magic-string: 0.30.5
|
||||
'@vue/shared': 3.4.21
|
||||
dev: true
|
||||
|
||||
/@vue/reactivity@3.3.10:
|
||||
resolution: {integrity: sha512-H5Z7rOY/JLO+e5a6/FEXaQ1TMuOvY4LDVgT+/+HKubEAgs9qeeZ+NhADSeEtrNQeiKLDuzeKc8v0CUFpB6Pqgw==}
|
||||
/@vue/runtime-core@3.4.21:
|
||||
resolution: {integrity: sha512-pQthsuYzE1XcGZznTKn73G0s14eCJcjaLvp3/DKeYWoFacD9glJoqlNBxt3W2c5S40t6CCcpPf+jG01N3ULyrA==}
|
||||
dependencies:
|
||||
'@vue/shared': 3.3.10
|
||||
'@vue/reactivity': 3.4.21
|
||||
'@vue/shared': 3.4.21
|
||||
dev: true
|
||||
|
||||
/@vue/reactivity@3.4.3:
|
||||
resolution: {integrity: sha512-q5f9HLDU+5aBKizXHAx0w4whkIANs1Muiq9R5YXm0HtorSlflqv9u/ohaMxuuhHWCji4xqpQ1eL04WvmAmGnFg==}
|
||||
/@vue/runtime-dom@3.4.21:
|
||||
resolution: {integrity: sha512-gvf+C9cFpevsQxbkRBS1NpU8CqxKw0ebqMvLwcGQrNpx6gqRDodqKqA+A2VZZpQ9RpK2f9yfg8VbW/EpdFUOJw==}
|
||||
dependencies:
|
||||
'@vue/shared': 3.4.3
|
||||
dev: true
|
||||
|
||||
/@vue/runtime-core@3.3.10:
|
||||
resolution: {integrity: sha512-DZ0v31oTN4YHX9JEU5VW1LoIVgFovWgIVb30bWn9DG9a7oA415idcwsRNNajqTx8HQJyOaWfRKoyuP2P2TYIag==}
|
||||
dependencies:
|
||||
'@vue/reactivity': 3.3.10
|
||||
'@vue/shared': 3.3.10
|
||||
dev: true
|
||||
|
||||
/@vue/runtime-core@3.4.3:
|
||||
resolution: {integrity: sha512-C1r6QhB1qY7D591RCSFhMULyzL9CuyrGc+3PpB0h7dU4Qqw6GNyo4BNFjHZVvsWncrUlKX3DIKg0Y7rNNr06NQ==}
|
||||
dependencies:
|
||||
'@vue/reactivity': 3.4.3
|
||||
'@vue/shared': 3.4.3
|
||||
dev: true
|
||||
|
||||
/@vue/runtime-dom@3.3.10:
|
||||
resolution: {integrity: sha512-c/jKb3ny05KJcYk0j1m7Wbhrxq7mZYr06GhKykDMNRRR9S+/dGT8KpHuNQjv3/8U4JshfkAk6TpecPD3B21Ijw==}
|
||||
dependencies:
|
||||
'@vue/runtime-core': 3.3.10
|
||||
'@vue/shared': 3.3.10
|
||||
csstype: 3.1.2
|
||||
dev: true
|
||||
|
||||
/@vue/runtime-dom@3.4.3:
|
||||
resolution: {integrity: sha512-wrsprg7An5Ec+EhPngWdPuzkp0BEUxAKaQtN9dPU/iZctPyD9aaXmVtehPJerdQxQale6gEnhpnfywNw3zOv2A==}
|
||||
dependencies:
|
||||
'@vue/runtime-core': 3.4.3
|
||||
'@vue/shared': 3.4.3
|
||||
'@vue/runtime-core': 3.4.21
|
||||
'@vue/shared': 3.4.21
|
||||
csstype: 3.1.3
|
||||
dev: true
|
||||
|
||||
/@vue/server-renderer@3.3.10(vue@3.3.10):
|
||||
resolution: {integrity: sha512-0i6ww3sBV3SKlF3YTjSVqKQ74xialMbjVYGy7cOTi7Imd8ediE7t72SK3qnvhrTAhOvlQhq6Bk6nFPdXxe0sAg==}
|
||||
/@vue/server-renderer@3.4.21(vue@3.4.21):
|
||||
resolution: {integrity: sha512-aV1gXyKSN6Rz+6kZ6kr5+Ll14YzmIbeuWe7ryJl5muJ4uwSwY/aStXTixx76TwkZFJLm1aAlA/HSWEJ4EyiMkg==}
|
||||
peerDependencies:
|
||||
vue: 3.3.10
|
||||
vue: 3.4.21
|
||||
dependencies:
|
||||
'@vue/compiler-ssr': 3.3.10
|
||||
'@vue/shared': 3.3.10
|
||||
vue: 3.3.10(typescript@5.3.3)
|
||||
'@vue/compiler-ssr': 3.4.21
|
||||
'@vue/shared': 3.4.21
|
||||
vue: 3.4.21(typescript@5.3.3)
|
||||
dev: true
|
||||
|
||||
/@vue/server-renderer@3.4.3(vue@3.4.3):
|
||||
resolution: {integrity: sha512-BUxt8oVGMKKsqSkM1uU3d3Houyfy4WAc2SpSQRebNd+XJGATVkW/rO129jkyL+kpB/2VRKzE63zwf5RtJ3XuZw==}
|
||||
peerDependencies:
|
||||
vue: 3.4.3
|
||||
dependencies:
|
||||
'@vue/compiler-ssr': 3.4.3
|
||||
'@vue/shared': 3.4.3
|
||||
vue: 3.4.3(typescript@5.3.3)
|
||||
/@vue/shared@3.4.21:
|
||||
resolution: {integrity: sha512-PuJe7vDIi6VYSinuEbUIQgMIRZGgM8e4R+G+/dQTk0X1NEdvgvvgv7m+rfmDH1gZzyA1OjjoWskvHlfRNfQf3g==}
|
||||
dev: true
|
||||
|
||||
/@vue/shared@3.3.10:
|
||||
resolution: {integrity: sha512-2y3Y2J1a3RhFa0WisHvACJR2ncvWiVHcP8t0Inxo+NKz+8RKO4ZV8eZgCxRgQoA6ITfV12L4E6POOL9HOU5nqw==}
|
||||
dev: true
|
||||
|
||||
/@vue/shared@3.4.3:
|
||||
resolution: {integrity: sha512-rIwlkkP1n4uKrRzivAKPZIEkHiuwY5mmhMJ2nZKCBLz8lTUlE73rQh4n1OnnMurXt1vcUNyH4ZPfdh8QweTjpQ==}
|
||||
dev: true
|
||||
|
||||
/@vueuse/core@10.7.1(vue@3.4.3):
|
||||
/@vueuse/core@10.7.1(vue@3.4.21):
|
||||
resolution: {integrity: sha512-74mWHlaesJSWGp1ihg76vAnfVq9NTv1YT0SYhAQ6zwFNdBkkP+CKKJmVOEHcdSnLXCXYiL5e7MaewblfiYLP7g==}
|
||||
dependencies:
|
||||
'@types/web-bluetooth': 0.0.20
|
||||
'@vueuse/metadata': 10.7.1
|
||||
'@vueuse/shared': 10.7.1(vue@3.4.3)
|
||||
vue-demi: 0.14.6(vue@3.4.3)
|
||||
'@vueuse/shared': 10.7.1(vue@3.4.21)
|
||||
vue-demi: 0.14.6(vue@3.4.21)
|
||||
transitivePeerDependencies:
|
||||
- '@vue/composition-api'
|
||||
- vue
|
||||
dev: true
|
||||
|
||||
/@vueuse/integrations@10.7.1(focus-trap@7.5.4)(vue@3.4.3):
|
||||
/@vueuse/integrations@10.7.1(focus-trap@7.5.4)(vue@3.4.21):
|
||||
resolution: {integrity: sha512-cKo5LEeKVHdBRBtMTOrDPdR0YNtrmN9IBfdcnY2P3m5LHVrsD0xiHUtAH1WKjHQRIErZG6rJUa6GA4tWZt89Og==}
|
||||
peerDependencies:
|
||||
async-validator: '*'
|
||||
@@ -1466,10 +1419,10 @@ packages:
|
||||
universal-cookie:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@vueuse/core': 10.7.1(vue@3.4.3)
|
||||
'@vueuse/shared': 10.7.1(vue@3.4.3)
|
||||
'@vueuse/core': 10.7.1(vue@3.4.21)
|
||||
'@vueuse/shared': 10.7.1(vue@3.4.21)
|
||||
focus-trap: 7.5.4
|
||||
vue-demi: 0.14.6(vue@3.4.3)
|
||||
vue-demi: 0.14.6(vue@3.4.21)
|
||||
transitivePeerDependencies:
|
||||
- '@vue/composition-api'
|
||||
- vue
|
||||
@@ -1479,10 +1432,10 @@ packages:
|
||||
resolution: {integrity: sha512-jX8MbX5UX067DYVsbtrmKn6eG6KMcXxLRLlurGkZku5ZYT3vxgBjui2zajvUZ18QLIjrgBkFRsu7CqTAg18QFw==}
|
||||
dev: true
|
||||
|
||||
/@vueuse/shared@10.7.1(vue@3.4.3):
|
||||
/@vueuse/shared@10.7.1(vue@3.4.21):
|
||||
resolution: {integrity: sha512-v0jbRR31LSgRY/C5i5X279A/WQjD6/JsMzGa+eqt658oJ75IvQXAeONmwvEMrvJQKnRElq/frzBR7fhmWY5uLw==}
|
||||
dependencies:
|
||||
vue-demi: 0.14.6(vue@3.4.3)
|
||||
vue-demi: 0.14.6(vue@3.4.21)
|
||||
transitivePeerDependencies:
|
||||
- '@vue/composition-api'
|
||||
- vue
|
||||
@@ -1506,8 +1459,8 @@ packages:
|
||||
resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==}
|
||||
engines: {node: '>=0.4.0'}
|
||||
|
||||
/acorn@8.11.2:
|
||||
resolution: {integrity: sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==}
|
||||
/acorn@8.11.3:
|
||||
resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==}
|
||||
engines: {node: '>=0.4.0'}
|
||||
hasBin: true
|
||||
|
||||
@@ -1736,6 +1689,13 @@ packages:
|
||||
run-applescript: 5.0.0
|
||||
dev: false
|
||||
|
||||
/bundle-name@4.1.0:
|
||||
resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==}
|
||||
engines: {node: '>=18'}
|
||||
dependencies:
|
||||
run-applescript: 7.0.0
|
||||
dev: false
|
||||
|
||||
/bundle-require@4.0.1(esbuild@0.19.8):
|
||||
resolution: {integrity: sha512-9NQkRHlNdNpDBGmLpngF3EFDcwodhMUuLz9PaWYciVcQF9SE4LFjM2DB/xV1Li5JiuDMv7ZUWuC3rGbqR0MAXQ==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
@@ -1757,22 +1717,21 @@ packages:
|
||||
safe-json-stringify: 1.2.0
|
||||
dev: false
|
||||
|
||||
/c12@1.5.1:
|
||||
resolution: {integrity: sha512-BWZRJgDEveT8uI+cliCwvYSSSSvb4xKoiiu5S0jaDbKBopQLQF7E+bq9xKk1pTcG+mUa3yXuFO7bD9d8Lr9Xxg==}
|
||||
/c12@1.10.0:
|
||||
resolution: {integrity: sha512-0SsG7UDhoRWcuSvKWHaXmu5uNjDCDN3nkQLRL4Q42IlFy+ze58FcCoI3uPwINXinkz7ZinbhEgyzYFw9u9ZV8g==}
|
||||
dependencies:
|
||||
chokidar: 3.5.3
|
||||
chokidar: 3.6.0
|
||||
confbox: 0.1.3
|
||||
defu: 6.1.4
|
||||
dotenv: 16.3.1
|
||||
giget: 1.1.3
|
||||
dotenv: 16.4.5
|
||||
giget: 1.2.3
|
||||
jiti: 1.21.0
|
||||
mlly: 1.4.2
|
||||
mlly: 1.6.1
|
||||
ohash: 1.1.3
|
||||
pathe: 1.1.1
|
||||
pathe: 1.1.2
|
||||
perfect-debounce: 1.0.0
|
||||
pkg-types: 1.0.3
|
||||
rc9: 2.1.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/cac@6.7.14:
|
||||
@@ -1846,8 +1805,8 @@ packages:
|
||||
dependencies:
|
||||
get-func-name: 2.0.2
|
||||
|
||||
/chokidar@3.5.3:
|
||||
resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
|
||||
/chokidar@3.6.0:
|
||||
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
|
||||
engines: {node: '>= 8.10.0'}
|
||||
dependencies:
|
||||
anymatch: 3.1.3
|
||||
@@ -1883,11 +1842,14 @@ packages:
|
||||
engines: {node: '>=8'}
|
||||
dev: false
|
||||
|
||||
/ci-info@4.0.0:
|
||||
resolution: {integrity: sha512-TdHqgGf9odd8SXNuxtUBVx8Nv+qZOejE6qyqiy5NtbYYQOeFa6zmHkxlPzmaLxWWHsU6nJmB7AETdVPi+2NBUg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
/citty@0.1.6:
|
||||
resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==}
|
||||
dependencies:
|
||||
consola: 3.2.3
|
||||
dev: false
|
||||
|
||||
/cli-boxes@3.0.0:
|
||||
resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==}
|
||||
@@ -2004,6 +1966,10 @@ packages:
|
||||
typedarray: 0.0.6
|
||||
dev: false
|
||||
|
||||
/confbox@0.1.3:
|
||||
resolution: {integrity: sha512-eH3ZxAihl1PhKfpr4VfEN6/vUd87fmgb6JkldHgg/YR6aEBhW63qUDgzP2Y6WM0UumdsYp5H3kibalXAdHfbgg==}
|
||||
dev: false
|
||||
|
||||
/config-chain@1.1.13:
|
||||
resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==}
|
||||
dependencies:
|
||||
@@ -2025,7 +1991,6 @@ packages:
|
||||
/consola@3.2.3:
|
||||
resolution: {integrity: sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==}
|
||||
engines: {node: ^14.18.0 || >=16.10.0}
|
||||
dev: false
|
||||
|
||||
/convert-source-map@2.0.0:
|
||||
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
|
||||
@@ -2140,6 +2105,11 @@ packages:
|
||||
untildify: 4.0.0
|
||||
dev: false
|
||||
|
||||
/default-browser-id@5.0.0:
|
||||
resolution: {integrity: sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==}
|
||||
engines: {node: '>=18'}
|
||||
dev: false
|
||||
|
||||
/default-browser@4.0.0:
|
||||
resolution: {integrity: sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==}
|
||||
engines: {node: '>=14.16'}
|
||||
@@ -2150,6 +2120,14 @@ packages:
|
||||
titleize: 3.0.0
|
||||
dev: false
|
||||
|
||||
/default-browser@5.2.1:
|
||||
resolution: {integrity: sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==}
|
||||
engines: {node: '>=18'}
|
||||
dependencies:
|
||||
bundle-name: 4.1.0
|
||||
default-browser-id: 5.0.0
|
||||
dev: false
|
||||
|
||||
/defaults@1.0.4:
|
||||
resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==}
|
||||
dependencies:
|
||||
@@ -2242,6 +2220,11 @@ packages:
|
||||
engines: {node: '>=12'}
|
||||
dev: false
|
||||
|
||||
/dotenv@16.4.5:
|
||||
resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==}
|
||||
engines: {node: '>=12'}
|
||||
dev: false
|
||||
|
||||
/dtrace-provider@0.8.8:
|
||||
resolution: {integrity: sha512-b7Z7cNtHPhH9EJhNNbbeqTcXB8LGFFZhq1PGgEvpeHlzd36bhbdTWoE/Ba/YguqpBSlAPKnARWhVlhunCMwfxg==}
|
||||
engines: {node: '>=0.10'}
|
||||
@@ -2705,6 +2688,20 @@ packages:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/giget@1.2.3:
|
||||
resolution: {integrity: sha512-8EHPljDvs7qKykr6uw8b+lqLiUc/vUg+KVTI0uND4s63TdsZM2Xus3mflvF0DDG9SiM4RlCkFGL+7aAjRmV7KA==}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
citty: 0.1.6
|
||||
consola: 3.2.3
|
||||
defu: 6.1.4
|
||||
node-fetch-native: 1.6.4
|
||||
nypm: 0.3.8
|
||||
ohash: 1.1.3
|
||||
pathe: 1.1.2
|
||||
tar: 6.2.0
|
||||
dev: false
|
||||
|
||||
/glob-parent@5.1.2:
|
||||
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
|
||||
engines: {node: '>= 6'}
|
||||
@@ -3394,8 +3391,8 @@ packages:
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
dev: false
|
||||
|
||||
/linkedom@0.16.1:
|
||||
resolution: {integrity: sha512-kbK4txFSjGstS8aHkYo3sRSD7viQbE1TAlYRqiqU13oihzzQFp23D1OwW3VdAQJuzqzBB+1qo9Qvp0xOeoVKig==}
|
||||
/linkedom@0.16.8:
|
||||
resolution: {integrity: sha512-+HtHVHBb3yZKlP9pgcJdi1AIG9tsAuo+Qtlz+79cCTsxgQwDzajsZjYvpp+DEckCK/zoGVhzkADniYZQ57KcFQ==}
|
||||
dependencies:
|
||||
css-select: 5.1.0
|
||||
cssom: 0.5.0
|
||||
@@ -3471,7 +3468,7 @@ packages:
|
||||
resolution: {integrity: sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==}
|
||||
engines: {node: '>=14'}
|
||||
dependencies:
|
||||
mlly: 1.4.2
|
||||
mlly: 1.6.1
|
||||
pkg-types: 1.0.3
|
||||
|
||||
/lodash.camelcase@4.3.0:
|
||||
@@ -3544,10 +3541,16 @@ packages:
|
||||
dependencies:
|
||||
'@jridgewell/sourcemap-codec': 1.4.15
|
||||
|
||||
/magic-string@0.30.8:
|
||||
resolution: {integrity: sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==}
|
||||
engines: {node: '>=12'}
|
||||
dependencies:
|
||||
'@jridgewell/sourcemap-codec': 1.4.15
|
||||
|
||||
/magicast@0.3.3:
|
||||
resolution: {integrity: sha512-ZbrP1Qxnpoes8sz47AM0z08U+jW6TyRgZzcWy3Ma3vDhJttwMwAFDMMQFobwdBxByBD46JYmxRzeF7w2+wJEuw==}
|
||||
dependencies:
|
||||
'@babel/parser': 7.23.6
|
||||
'@babel/parser': 7.24.1
|
||||
'@babel/types': 7.23.9
|
||||
source-map-js: 1.0.2
|
||||
dev: true
|
||||
@@ -3678,7 +3681,16 @@ packages:
|
||||
/mlly@1.4.2:
|
||||
resolution: {integrity: sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg==}
|
||||
dependencies:
|
||||
acorn: 8.11.2
|
||||
acorn: 8.11.3
|
||||
pathe: 1.1.2
|
||||
pkg-types: 1.0.3
|
||||
ufo: 1.4.0
|
||||
dev: false
|
||||
|
||||
/mlly@1.6.1:
|
||||
resolution: {integrity: sha512-vLgaHvaeunuOXHSmEbZ9izxPx3USsk8KCQ8iC+aTlp5sKRSoZvwhHh5L9VbKSaVC6sJDqbyohIS76E2VmHIPAA==}
|
||||
dependencies:
|
||||
acorn: 8.11.3
|
||||
pathe: 1.1.2
|
||||
pkg-types: 1.0.3
|
||||
ufo: 1.4.0
|
||||
@@ -3763,6 +3775,10 @@ packages:
|
||||
resolution: {integrity: sha512-NsXBU0UgBxo2rQLOeWNZqS3fvflWePMECr8CoSWoSTqCqGbVVsvl9vZu1HfQicYN0g5piV9Gh8RTEvo/uP752w==}
|
||||
dev: false
|
||||
|
||||
/node-fetch-native@1.6.4:
|
||||
resolution: {integrity: sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ==}
|
||||
dev: false
|
||||
|
||||
/node-forge@1.3.1:
|
||||
resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==}
|
||||
engines: {node: '>= 6.13.0'}
|
||||
@@ -3865,6 +3881,18 @@ packages:
|
||||
ufo: 1.4.0
|
||||
dev: false
|
||||
|
||||
/nypm@0.3.8:
|
||||
resolution: {integrity: sha512-IGWlC6So2xv6V4cIDmoV0SwwWx7zLG086gyqkyumteH2fIgCAM4nDVFB2iDRszDvmdSVW9xb1N+2KjQ6C7d4og==}
|
||||
engines: {node: ^14.16.0 || >=16.10.0}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
citty: 0.1.6
|
||||
consola: 3.2.3
|
||||
execa: 8.0.1
|
||||
pathe: 1.1.2
|
||||
ufo: 1.4.0
|
||||
dev: false
|
||||
|
||||
/object-assign@4.1.1:
|
||||
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -3892,7 +3920,7 @@ packages:
|
||||
resolution: {integrity: sha512-s1ZCMmQWXy4b5K/TW9i/DtiN8Ku+xCiHcjQ6/J/nDdssirrQNOoB165Zu8EqLMA2lln1JUth9a0aW9Ap2ctrUg==}
|
||||
dependencies:
|
||||
destr: 2.0.2
|
||||
node-fetch-native: 1.4.1
|
||||
node-fetch-native: 1.6.4
|
||||
ufo: 1.4.0
|
||||
dev: false
|
||||
|
||||
@@ -3917,6 +3945,16 @@ packages:
|
||||
dependencies:
|
||||
mimic-fn: 4.0.0
|
||||
|
||||
/open@10.1.0:
|
||||
resolution: {integrity: sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==}
|
||||
engines: {node: '>=18'}
|
||||
dependencies:
|
||||
default-browser: 5.2.1
|
||||
define-lazy-prop: 3.0.0
|
||||
is-inside-container: 1.0.0
|
||||
is-wsl: 3.1.0
|
||||
dev: false
|
||||
|
||||
/open@8.4.2:
|
||||
resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -4116,7 +4154,7 @@ packages:
|
||||
resolution: {integrity: sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==}
|
||||
dependencies:
|
||||
jsonc-parser: 3.2.0
|
||||
mlly: 1.4.2
|
||||
mlly: 1.6.1
|
||||
pathe: 1.1.2
|
||||
|
||||
/postcss-load-config@4.0.1:
|
||||
@@ -4135,15 +4173,6 @@ packages:
|
||||
yaml: 2.3.4
|
||||
dev: true
|
||||
|
||||
/postcss@8.4.32:
|
||||
resolution: {integrity: sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
dependencies:
|
||||
nanoid: 3.3.7
|
||||
picocolors: 1.0.0
|
||||
source-map-js: 1.0.2
|
||||
dev: true
|
||||
|
||||
/postcss@8.4.35:
|
||||
resolution: {integrity: sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
@@ -4444,6 +4473,11 @@ packages:
|
||||
execa: 5.1.1
|
||||
dev: false
|
||||
|
||||
/run-applescript@7.0.0:
|
||||
resolution: {integrity: sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==}
|
||||
engines: {node: '>=18'}
|
||||
dev: false
|
||||
|
||||
/run-parallel@1.2.0:
|
||||
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
|
||||
dependencies:
|
||||
@@ -4479,7 +4513,7 @@ packages:
|
||||
engines: {node: '>=14.0.0'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
chokidar: 3.5.3
|
||||
chokidar: 3.6.0
|
||||
immutable: 4.3.4
|
||||
source-map-js: 1.0.2
|
||||
|
||||
@@ -4834,7 +4868,7 @@ packages:
|
||||
/strip-literal@1.3.0:
|
||||
resolution: {integrity: sha512-PugKzOsyXpArk0yWmUwqOZecSO0GH0bPoctLcqNDH9J04pVW3lflYE0ujElBGTloevcxF5MofAOZ7C5l2b+wLg==}
|
||||
dependencies:
|
||||
acorn: 8.11.2
|
||||
acorn: 8.11.3
|
||||
|
||||
/sucrase@3.32.0:
|
||||
resolution: {integrity: sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ==}
|
||||
@@ -4989,7 +5023,7 @@ packages:
|
||||
dependencies:
|
||||
bundle-require: 4.0.1(esbuild@0.19.8)
|
||||
cac: 6.7.14
|
||||
chokidar: 3.5.3
|
||||
chokidar: 3.6.0
|
||||
debug: 4.3.4
|
||||
esbuild: 0.19.8
|
||||
execa: 5.1.1
|
||||
@@ -5147,8 +5181,8 @@ packages:
|
||||
/unplugin@1.5.0:
|
||||
resolution: {integrity: sha512-9ZdRwbh/4gcm1JTOkp9lAkIDrtOyOxgHmY7cjuwI8L/2RTikMcVG25GsZwNAgRuap3iDw2jeq7eoqtAsz5rW3A==}
|
||||
dependencies:
|
||||
acorn: 8.11.2
|
||||
chokidar: 3.5.3
|
||||
acorn: 8.11.3
|
||||
chokidar: 3.6.0
|
||||
webpack-sources: 3.2.3
|
||||
webpack-virtual-modules: 0.5.0
|
||||
dev: false
|
||||
@@ -5210,7 +5244,7 @@ packages:
|
||||
dependencies:
|
||||
cac: 6.7.14
|
||||
debug: 4.3.4
|
||||
pathe: 1.1.1
|
||||
pathe: 1.1.2
|
||||
picocolors: 1.0.0
|
||||
vite: 5.1.3(@types/node@20.10.3)(sass@1.69.5)
|
||||
transitivePeerDependencies:
|
||||
@@ -5274,10 +5308,10 @@ packages:
|
||||
'@docsearch/css': 3.5.2
|
||||
'@docsearch/js': 3.5.2
|
||||
'@types/markdown-it': 13.0.7
|
||||
'@vitejs/plugin-vue': 5.0.2(vite@5.1.3)(vue@3.4.3)
|
||||
'@vitejs/plugin-vue': 5.0.2(vite@5.1.3)(vue@3.4.21)
|
||||
'@vue/devtools-api': 6.5.1
|
||||
'@vueuse/core': 10.7.1(vue@3.4.3)
|
||||
'@vueuse/integrations': 10.7.1(focus-trap@7.5.4)(vue@3.4.3)
|
||||
'@vueuse/core': 10.7.1(vue@3.4.21)
|
||||
'@vueuse/integrations': 10.7.1(focus-trap@7.5.4)(vue@3.4.21)
|
||||
focus-trap: 7.5.4
|
||||
mark.js: 8.11.1
|
||||
minisearch: 6.3.0
|
||||
@@ -5286,7 +5320,7 @@ packages:
|
||||
shikiji-core: 0.9.16
|
||||
shikiji-transformers: 0.9.16
|
||||
vite: 5.1.3(@types/node@20.10.3)(sass@1.69.5)
|
||||
vue: 3.4.3(typescript@5.3.3)
|
||||
vue: 3.4.21(typescript@5.3.3)
|
||||
transitivePeerDependencies:
|
||||
- '@algolia/client-search'
|
||||
- '@types/node'
|
||||
@@ -5326,6 +5360,14 @@ packages:
|
||||
vitest: 1.2.2(@types/node@20.10.3)(happy-dom@13.3.8)(sass@1.69.5)
|
||||
dev: true
|
||||
|
||||
/vitest-plugin-random-seed@1.0.2(vite@5.1.3):
|
||||
resolution: {integrity: sha512-Kt5QHmx7I1p2WShsmgJSK/L8hNPZpyNu85zSml5yv/fHDe7gJspcKc7kNYrLVVwZdGcqcZxyHAeH503szzQ95g==}
|
||||
peerDependencies:
|
||||
vite: ^4.0.0 || ^5.0.0
|
||||
dependencies:
|
||||
vite: 5.1.3(@types/node@20.10.3)(sass@1.69.5)
|
||||
dev: true
|
||||
|
||||
/vitest@1.2.2(@types/node@20.10.3)(happy-dom@13.3.8)(sass@1.69.5):
|
||||
resolution: {integrity: sha512-d5Ouvrnms3GD9USIK36KG8OZ5bEvKEkITFtnGv56HFaSlbItJuYr7hv2Lkn903+AvRAgSixiamozUVfORUekjw==}
|
||||
engines: {node: ^18.0.0 || >=20.0.0}
|
||||
@@ -5391,7 +5433,7 @@ packages:
|
||||
resolution: {integrity: sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==}
|
||||
dev: true
|
||||
|
||||
/vue-demi@0.14.6(vue@3.4.3):
|
||||
/vue-demi@0.14.6(vue@3.4.21):
|
||||
resolution: {integrity: sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==}
|
||||
engines: {node: '>=12'}
|
||||
hasBin: true
|
||||
@@ -5403,38 +5445,22 @@ packages:
|
||||
'@vue/composition-api':
|
||||
optional: true
|
||||
dependencies:
|
||||
vue: 3.4.3(typescript@5.3.3)
|
||||
vue: 3.4.21(typescript@5.3.3)
|
||||
dev: true
|
||||
|
||||
/vue@3.3.10(typescript@5.3.3):
|
||||
resolution: {integrity: sha512-zg6SIXZdTBwiqCw/1p+m04VyHjLfwtjwz8N57sPaBhEex31ND0RYECVOC1YrRwMRmxFf5T1dabl6SGUbMKKuVw==}
|
||||
/vue@3.4.21(typescript@5.3.3):
|
||||
resolution: {integrity: sha512-5hjyV/jLEIKD/jYl4cavMcnzKwjMKohureP8ejn3hhEjwhWIhWeuzL2kJAjzl/WyVsgPY56Sy4Z40C3lVshxXA==}
|
||||
peerDependencies:
|
||||
typescript: '*'
|
||||
peerDependenciesMeta:
|
||||
typescript:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@vue/compiler-dom': 3.3.10
|
||||
'@vue/compiler-sfc': 3.3.10
|
||||
'@vue/runtime-dom': 3.3.10
|
||||
'@vue/server-renderer': 3.3.10(vue@3.3.10)
|
||||
'@vue/shared': 3.3.10
|
||||
typescript: 5.3.3
|
||||
dev: true
|
||||
|
||||
/vue@3.4.3(typescript@5.3.3):
|
||||
resolution: {integrity: sha512-GjN+culMAGv/mUbkIv8zMKItno8npcj5gWlXkSxf1SPTQf8eJ4A+YfHIvQFyL1IfuJcMl3soA7SmN1fRxbf/wA==}
|
||||
peerDependencies:
|
||||
typescript: '*'
|
||||
peerDependenciesMeta:
|
||||
typescript:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@vue/compiler-dom': 3.4.3
|
||||
'@vue/compiler-sfc': 3.4.3
|
||||
'@vue/runtime-dom': 3.4.3
|
||||
'@vue/server-renderer': 3.4.3(vue@3.4.3)
|
||||
'@vue/shared': 3.4.3
|
||||
'@vue/compiler-dom': 3.4.21
|
||||
'@vue/compiler-sfc': 3.4.21
|
||||
'@vue/runtime-dom': 3.4.21
|
||||
'@vue/server-renderer': 3.4.21(vue@3.4.21)
|
||||
'@vue/shared': 3.4.21
|
||||
typescript: 5.3.3
|
||||
dev: true
|
||||
|
||||
|
||||
+12
-17
@@ -8,6 +8,10 @@ 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();
|
||||
@@ -20,12 +24,7 @@ const preset = {
|
||||
dts: true,
|
||||
silent: true,
|
||||
sourcemap: false,
|
||||
external: [
|
||||
'virtual:user-unlisted-script',
|
||||
'virtual:user-content-script-isolated-world',
|
||||
'virtual:user-content-script-main-world',
|
||||
'virtual:user-background',
|
||||
],
|
||||
external: virtualEntrypointModuleNames.map((name) => `virtual:user-${name}`),
|
||||
} satisfies tsup.Options;
|
||||
|
||||
function spinnerPMap(configs: tsup.Options[]) {
|
||||
@@ -74,17 +73,13 @@ const config: tsup.Options[] = [
|
||||
},
|
||||
{
|
||||
...preset,
|
||||
entry: {
|
||||
'virtual/background-entrypoint': 'src/virtual/background-entrypoint.ts',
|
||||
'virtual/content-script-isolated-world-entrypoint':
|
||||
'src/virtual/content-script-isolated-world-entrypoint.ts',
|
||||
'virtual/content-script-main-world-entrypoint':
|
||||
'src/virtual/content-script-main-world-entrypoint.ts',
|
||||
'virtual/mock-browser': 'src/virtual/mock-browser.ts',
|
||||
'virtual/reload-html': 'src/virtual/reload-html.ts',
|
||||
'virtual/unlisted-script-entrypoint':
|
||||
'src/virtual/unlisted-script-entrypoint.ts',
|
||||
},
|
||||
entry: virtualModuleNames.reduce<Record<string, string>>(
|
||||
(acc, moduleName) => {
|
||||
acc[`virtual/${moduleName}`] = `src/virtual/${moduleName}.ts`;
|
||||
return acc;
|
||||
},
|
||||
{},
|
||||
),
|
||||
format: ['esm'],
|
||||
splitting: false,
|
||||
dts: false,
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ export type {
|
||||
Identity,
|
||||
Idle,
|
||||
Management,
|
||||
Manifest,
|
||||
Manifest, // TODO: Export custom manifest types that are valid for both Chrome and Firefox.
|
||||
ContextMenus,
|
||||
Menus,
|
||||
NetworkStatus,
|
||||
|
||||
@@ -116,6 +116,20 @@ describe('CLI', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should respect passing --port', async () => {
|
||||
const expectedPort = 3100;
|
||||
mockArgv('--port', String(expectedPort));
|
||||
await importCli();
|
||||
|
||||
expect(createServerMock).toBeCalledWith({
|
||||
dev: {
|
||||
server: {
|
||||
port: expectedPort,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should respect passing --debug', async () => {
|
||||
mockArgv('--debug');
|
||||
await importCli();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
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';
|
||||
@@ -56,8 +57,8 @@ export function getArrayFromFlags<T>(
|
||||
flags: any,
|
||||
name: string,
|
||||
): T[] | undefined {
|
||||
const array = [flags[name]].flat() as Array<T | undefined>;
|
||||
const result = array.filter((item) => item != null) as T[];
|
||||
const array = toArray<T | undefined>(flags[name]);
|
||||
const result = filterTruthy(array);
|
||||
return result.length ? result : undefined;
|
||||
}
|
||||
|
||||
|
||||
+16
-1
@@ -16,6 +16,7 @@ cli
|
||||
.option('-c, --config <file>', 'use specified config file')
|
||||
.option('-m, --mode <mode>', 'set env mode')
|
||||
.option('-b, --browser <browser>', 'specify a browser')
|
||||
.option('-p, --port <port>', 'specify a port for the dev server')
|
||||
.option(
|
||||
'-e, --filter-entrypoint <entrypoint>',
|
||||
'only build specific entrypoints',
|
||||
@@ -35,6 +36,14 @@ cli
|
||||
configFile: flags.config,
|
||||
debug: flags.debug,
|
||||
filterEntrypoints: getArrayFromFlags(flags, 'filterEntrypoint'),
|
||||
dev:
|
||||
flags.port == null
|
||||
? undefined
|
||||
: {
|
||||
server: {
|
||||
port: parseInt(flags.port),
|
||||
},
|
||||
},
|
||||
});
|
||||
await server.start();
|
||||
return { isOngoing: true };
|
||||
@@ -57,6 +66,7 @@ cli
|
||||
.option('--mv3', 'target manifest v3')
|
||||
.option('--mv2', 'target manifest v2')
|
||||
.option('--analyze', 'visualize extension bundle')
|
||||
.option('--analyze-open', 'automatically open stats.html in browser')
|
||||
.action(
|
||||
wrapAction(async (root, flags) => {
|
||||
await build({
|
||||
@@ -66,7 +76,12 @@ cli
|
||||
manifestVersion: flags.mv3 ? 3 : flags.mv2 ? 2 : undefined,
|
||||
configFile: flags.config,
|
||||
debug: flags.debug,
|
||||
analysis: flags.analyze ? { enabled: true } : undefined,
|
||||
analysis: flags.analyze
|
||||
? {
|
||||
enabled: true,
|
||||
open: flags.analyzeOpen,
|
||||
}
|
||||
: undefined,
|
||||
filterEntrypoints: getArrayFromFlags(flags, 'filterEntrypoint'),
|
||||
});
|
||||
}),
|
||||
|
||||
@@ -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',
|
||||
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;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -207,7 +207,7 @@ export interface ContentScriptAnchoredOptions {
|
||||
* In combination with `anchor`, decide how to add the UI to the DOM.
|
||||
*
|
||||
* - `"last"` (default) - Add the UI as the last child of the `anchor` element
|
||||
* - `"first"` - Add the UI as the last child of the `anchor` element
|
||||
* - `"first"` - Add the UI as the first child of the `anchor` element
|
||||
* - `"replace"` - Replace the `anchor` element with the UI.
|
||||
* - `"before"` - Add the UI as the sibling before the `anchor` element
|
||||
* - `"after"` - Add the UI as the sibling after the `anchor` element
|
||||
|
||||
@@ -2,23 +2,28 @@ import type * as vite from 'vite';
|
||||
import {
|
||||
BuildStepOutput,
|
||||
Entrypoint,
|
||||
InlineConfig,
|
||||
ResolvedConfig,
|
||||
UserConfig,
|
||||
VirtualEntrypointType,
|
||||
WxtBuilder,
|
||||
WxtBuilderServer,
|
||||
WxtDevServer,
|
||||
WxtHooks,
|
||||
} from '~/types';
|
||||
import * as wxtPlugins from './plugins';
|
||||
import {
|
||||
getEntrypointBundlePath,
|
||||
isHtmlEntrypoint,
|
||||
} from '~/core/utils/entrypoints';
|
||||
import {
|
||||
VirtualEntrypointType,
|
||||
VirtualModuleId,
|
||||
} from '~/core/utils/virtual-modules';
|
||||
import { Hookable } from 'hookable';
|
||||
import { toArray } from '~/core/utils/arrays';
|
||||
|
||||
export async function createViteBuilder(
|
||||
inlineConfig: InlineConfig,
|
||||
userConfig: UserConfig,
|
||||
wxtConfig: Omit<ResolvedConfig, 'builder'>,
|
||||
wxtConfig: ResolvedConfig,
|
||||
hooks: Hookable<WxtHooks>,
|
||||
server?: WxtDevServer,
|
||||
): Promise<WxtBuilder> {
|
||||
const vite = await import('vite');
|
||||
|
||||
@@ -26,14 +31,9 @@ export async function createViteBuilder(
|
||||
* Returns the base vite config shared by all builds based on the inline and user config.
|
||||
*/
|
||||
const getBaseConfig = async () => {
|
||||
const resolvedInlineConfig =
|
||||
(await inlineConfig.vite?.(wxtConfig.env)) ?? {};
|
||||
const resolvedUserConfig = (await userConfig.vite?.(wxtConfig.env)) ?? {};
|
||||
|
||||
const config: vite.InlineConfig = vite.mergeConfig(
|
||||
resolvedUserConfig,
|
||||
resolvedInlineConfig,
|
||||
);
|
||||
const config: vite.InlineConfig = await wxtConfig.vite({
|
||||
...wxtConfig.env,
|
||||
});
|
||||
|
||||
config.root = wxtConfig.root;
|
||||
config.configFile = false;
|
||||
@@ -41,6 +41,8 @@ export async function createViteBuilder(
|
||||
config.mode = wxtConfig.mode;
|
||||
|
||||
config.build ??= {};
|
||||
config.publicDir = wxtConfig.publicDir;
|
||||
config.build.copyPublicDir = false;
|
||||
config.build.outDir = wxtConfig.outDir;
|
||||
config.build.emptyOutDir = false;
|
||||
// Disable minification for the dev command
|
||||
@@ -55,13 +57,10 @@ export async function createViteBuilder(
|
||||
config.plugins ??= [];
|
||||
config.plugins.push(
|
||||
wxtPlugins.download(wxtConfig),
|
||||
wxtPlugins.devHtmlPrerender(wxtConfig),
|
||||
wxtPlugins.devHtmlPrerender(wxtConfig, server),
|
||||
wxtPlugins.unimport(wxtConfig),
|
||||
wxtPlugins.virtualEntrypoint('background', wxtConfig),
|
||||
wxtPlugins.virtualEntrypoint('content-script-isolated-world', wxtConfig),
|
||||
wxtPlugins.virtualEntrypoint('content-script-main-world', wxtConfig),
|
||||
wxtPlugins.virtualEntrypoint('unlisted-script', wxtConfig),
|
||||
wxtPlugins.devServerGlobals(wxtConfig),
|
||||
wxtPlugins.resolveVirtualModules(wxtConfig),
|
||||
wxtPlugins.devServerGlobals(wxtConfig, server),
|
||||
wxtPlugins.tsconfigPaths(wxtConfig),
|
||||
wxtPlugins.noopBackground(),
|
||||
wxtPlugins.globals(wxtConfig),
|
||||
@@ -205,6 +204,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,
|
||||
@@ -221,9 +225,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() {
|
||||
@@ -277,7 +281,10 @@ function getRollupEntry(entrypoint: Entrypoint): string {
|
||||
: 'content-script-isolated-world';
|
||||
break;
|
||||
}
|
||||
return virtualEntrypointType
|
||||
? `virtual:wxt-${virtualEntrypointType}?${entrypoint.inputPath}`
|
||||
: entrypoint.inputPath;
|
||||
|
||||
if (virtualEntrypointType) {
|
||||
const moduleId: VirtualModuleId = `virtual:wxt-${virtualEntrypointType}-entrypoint`;
|
||||
return `${moduleId}?${entrypoint.inputPath}`;
|
||||
}
|
||||
return entrypoint.inputPath;
|
||||
}
|
||||
|
||||
@@ -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,8 @@ 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';
|
||||
const resolvedHtmlReloadId = resolve(
|
||||
@@ -38,7 +39,6 @@ export function devHtmlPrerender(
|
||||
// Convert scripts like src="./main.tsx" -> src="http://localhost:3000/entrypoints/popup/main.tsx"
|
||||
// before the paths are replaced with their bundled path
|
||||
transform(code, id) {
|
||||
const server = config.server;
|
||||
if (
|
||||
config.command !== 'serve' ||
|
||||
server == null ||
|
||||
@@ -68,7 +68,6 @@ export function devHtmlPrerender(
|
||||
|
||||
// Pass the HTML through the dev server to add dev-mode specific code
|
||||
async transformIndexHtml(html, ctx) {
|
||||
const server = config.server;
|
||||
if (config.command !== 'serve' || server == null) return;
|
||||
|
||||
const originalUrl = `${server.origin}${ctx.path}`;
|
||||
@@ -134,7 +133,7 @@ export function devHtmlPrerender(
|
||||
}
|
||||
|
||||
export function pointToDevServer(
|
||||
config: Omit<ResolvedConfig, 'builder'>,
|
||||
config: ResolvedConfig,
|
||||
server: WxtDevServer,
|
||||
id: string,
|
||||
document: Document,
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
import { Plugin } from 'vite';
|
||||
import { ResolvedConfig } from '~/types';
|
||||
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 {
|
||||
name: 'wxt:dev-server-globals',
|
||||
config() {
|
||||
if (config.server == null || config.command == 'build') return;
|
||||
if (server == null || config.command == 'build') return;
|
||||
|
||||
return {
|
||||
define: {
|
||||
__DEV_SERVER_PROTOCOL__: JSON.stringify('ws:'),
|
||||
__DEV_SERVER_HOSTNAME__: JSON.stringify(config.server.hostname),
|
||||
__DEV_SERVER_PORT__: JSON.stringify(config.server.port),
|
||||
__DEV_SERVER_HOSTNAME__: JSON.stringify(server.hostname),
|
||||
__DEV_SERVER_PORT__: JSON.stringify(server.port),
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -6,9 +6,7 @@ import type * as vite from 'vite';
|
||||
* `webextension-polyfill` module to a virtual module and exporting the `chrome` global from the
|
||||
* virtual module.
|
||||
*/
|
||||
export function excludeBrowserPolyfill(
|
||||
config: Omit<ResolvedConfig, 'builder'>,
|
||||
): vite.Plugin {
|
||||
export function excludeBrowserPolyfill(config: ResolvedConfig): vite.Plugin {
|
||||
const virtualId = 'virtual:wxt-webextension-polyfill-disabled';
|
||||
|
||||
return {
|
||||
|
||||
@@ -2,9 +2,7 @@ import type * as vite from 'vite';
|
||||
import { ResolvedConfig } from '~/types';
|
||||
import { getGlobals } from '~/core/utils/globals';
|
||||
|
||||
export function globals(
|
||||
config: Omit<ResolvedConfig, 'builder'>,
|
||||
): vite.PluginOption {
|
||||
export function globals(config: ResolvedConfig): vite.PluginOption {
|
||||
return {
|
||||
name: 'wxt:globals',
|
||||
config() {
|
||||
|
||||
@@ -3,7 +3,7 @@ export * from './devServerGlobals';
|
||||
export * from './download';
|
||||
export * from './multipageMove';
|
||||
export * from './unimport';
|
||||
export * from './virtualEntrypoint';
|
||||
export * from './resolveVirtualModules';
|
||||
export * from './tsconfigPaths';
|
||||
export * from './noopBackground';
|
||||
export * from './cssEntrypoints';
|
||||
|
||||
@@ -20,7 +20,7 @@ import { normalizePath } from '~/core/utils/paths';
|
||||
*/
|
||||
export function multipageMove(
|
||||
entrypoints: Entrypoint[],
|
||||
config: Omit<ResolvedConfig, 'builder'>,
|
||||
config: ResolvedConfig,
|
||||
): vite.Plugin {
|
||||
return {
|
||||
name: 'wxt:multipage-move',
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import { Plugin } from 'vite';
|
||||
import { ResolvedConfig } from '~/types';
|
||||
import { normalizePath } from '~/core/utils/paths';
|
||||
import {
|
||||
VirtualModuleId,
|
||||
virtualModuleNames,
|
||||
} from '~/core/utils/virtual-modules';
|
||||
import fs from 'fs-extra';
|
||||
import { resolve } from 'path';
|
||||
|
||||
/**
|
||||
* Resolve all the virtual modules to the `node_modules/wxt/dist/virtual` directory.
|
||||
*/
|
||||
export function resolveVirtualModules(config: ResolvedConfig): Plugin[] {
|
||||
return virtualModuleNames.map((name) => {
|
||||
const virtualId: `${VirtualModuleId}?` = `virtual:wxt-${name}?`;
|
||||
const resolvedVirtualId = '\0' + virtualId;
|
||||
return {
|
||||
name: `wxt:resolve-virtual-${name}`,
|
||||
resolveId(id) {
|
||||
// Id doesn't start with prefix, it looks like this:
|
||||
// /path/to/project/virtual:wxt-background?/path/to/project/entrypoints/background.ts
|
||||
const index = id.indexOf(virtualId);
|
||||
if (index === -1) return;
|
||||
|
||||
const inputPath = normalizePath(id.substring(index + virtualId.length));
|
||||
return resolvedVirtualId + inputPath;
|
||||
},
|
||||
async load(id) {
|
||||
if (!id.startsWith(resolvedVirtualId)) return;
|
||||
|
||||
const inputPath = id.replace(resolvedVirtualId, '');
|
||||
const template = await fs.readFile(
|
||||
resolve(config.wxtModuleDir, `dist/virtual/${name}.js`),
|
||||
'utf-8',
|
||||
);
|
||||
return template.replace(`virtual:user-${name}`, inputPath);
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
import { ResolvedConfig } from '~/types';
|
||||
import type * as vite from 'vite';
|
||||
|
||||
export function tsconfigPaths(
|
||||
config: Omit<ResolvedConfig, 'builder'>,
|
||||
): vite.Plugin {
|
||||
export function tsconfigPaths(config: ResolvedConfig): vite.Plugin {
|
||||
return {
|
||||
name: 'wxt:aliases',
|
||||
async config() {
|
||||
|
||||
@@ -15,9 +15,7 @@ const ENABLED_EXTENSIONS = new Set([
|
||||
/**
|
||||
* Inject any global imports defined by unimport
|
||||
*/
|
||||
export function unimport(
|
||||
config: Omit<ResolvedConfig, 'builder'>,
|
||||
): vite.PluginOption {
|
||||
export function unimport(config: ResolvedConfig): vite.PluginOption {
|
||||
const options = config.imports;
|
||||
if (options === false) return [];
|
||||
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
import { Plugin } from 'vite';
|
||||
import { ResolvedConfig, VirtualEntrypointType } from '~/types';
|
||||
import fs from 'fs-extra';
|
||||
import { resolve } from 'path';
|
||||
import { normalizePath } from '~/core/utils/paths';
|
||||
|
||||
/**
|
||||
* Wraps a user's entrypoint with a vitual version with additional logic.
|
||||
*/
|
||||
export function virtualEntrypoint(
|
||||
type: VirtualEntrypointType,
|
||||
config: Omit<ResolvedConfig, 'builder'>,
|
||||
): Plugin {
|
||||
const virtualId = `virtual:wxt-${type}?`;
|
||||
const resolvedVirtualId = `\0${virtualId}`;
|
||||
|
||||
return {
|
||||
name: `wxt:virtual-entrypoint`,
|
||||
resolveId(id) {
|
||||
// Id doesn't start with prefix, it looks like this:
|
||||
// /path/to/project/virtual:background?/path/to/project/entrypoints/background.ts
|
||||
const index = id.indexOf(virtualId);
|
||||
if (index === -1) return;
|
||||
|
||||
const inputPath = normalizePath(id.substring(index + virtualId.length));
|
||||
return resolvedVirtualId + inputPath;
|
||||
},
|
||||
async load(id) {
|
||||
if (!id.startsWith(resolvedVirtualId)) return;
|
||||
|
||||
const inputPath = id.replace(resolvedVirtualId, '');
|
||||
const template = await fs.readFile(
|
||||
resolve(config.wxtModuleDir, `dist/virtual/${type}-entrypoint.js`),
|
||||
'utf-8',
|
||||
);
|
||||
return template.replace(`virtual:user-${type}`, inputPath);
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -16,7 +16,7 @@ import { ResolvedConfig } from '~/types';
|
||||
* `npm list` and inline them automatically.
|
||||
*/
|
||||
export function webextensionPolyfillMock(
|
||||
config: Omit<ResolvedConfig, 'builder'>,
|
||||
config: ResolvedConfig,
|
||||
): vite.PluginOption {
|
||||
return {
|
||||
name: 'wxt:testing-inline-deps',
|
||||
|
||||
+93
-91
@@ -26,7 +26,10 @@ import pc from 'picocolors';
|
||||
import { relative } from 'node:path';
|
||||
import { registerWxt, wxt } from './wxt';
|
||||
import { unnormalizePath } from './utils/paths';
|
||||
import { mapWxtOptionsToRegisteredContentScript } from './utils/content-scripts';
|
||||
import {
|
||||
getContentScriptJs,
|
||||
mapWxtOptionsToRegisteredContentScript,
|
||||
} from './utils/content-scripts';
|
||||
|
||||
/**
|
||||
* Creates a dev server and pre-builds all the files that need to exist before loading the extension.
|
||||
@@ -40,14 +43,63 @@ import { mapWxtOptionsToRegisteredContentScript } from './utils/content-scripts'
|
||||
export async function createServer(
|
||||
inlineConfig?: InlineConfig,
|
||||
): Promise<WxtDevServer> {
|
||||
const port = await getPort();
|
||||
const hostname = 'localhost';
|
||||
const origin = `http://${hostname}:${port}`;
|
||||
const serverInfo: ServerInfo = {
|
||||
port,
|
||||
hostname,
|
||||
origin,
|
||||
};
|
||||
await registerWxt('serve', inlineConfig, async (config) => {
|
||||
const { port, hostname } = config.dev.server!;
|
||||
const serverInfo: ServerInfo = {
|
||||
port,
|
||||
hostname,
|
||||
origin: `http://${hostname}:${port}`,
|
||||
};
|
||||
|
||||
// Server instance must be created first so its reference can be added to the internal config used
|
||||
// to pre-render entrypoints
|
||||
const server: WxtDevServer = {
|
||||
...serverInfo,
|
||||
get watcher() {
|
||||
return builderServer.watcher;
|
||||
},
|
||||
get ws() {
|
||||
return builderServer.ws;
|
||||
},
|
||||
currentOutput: undefined,
|
||||
async start() {
|
||||
await builderServer.listen();
|
||||
wxt.logger.success(`Started dev server @ ${serverInfo.origin}`);
|
||||
await buildAndOpenBrowser();
|
||||
},
|
||||
async stop() {
|
||||
await runner.closeBrowser();
|
||||
await builderServer.close();
|
||||
},
|
||||
async restart() {
|
||||
await closeAndRecreateRunner();
|
||||
await buildAndOpenBrowser();
|
||||
},
|
||||
transformHtml(url, html, originalUrl) {
|
||||
return builderServer.transformHtml(url, html, originalUrl);
|
||||
},
|
||||
reloadContentScript(payload) {
|
||||
server.ws.send('wxt:reload-content-script', payload);
|
||||
},
|
||||
reloadPage(path) {
|
||||
server.ws.send('wxt:reload-page', path);
|
||||
},
|
||||
reloadExtension() {
|
||||
server.ws.send('wxt:reload-extension');
|
||||
},
|
||||
async restartBrowser() {
|
||||
await closeAndRecreateRunner();
|
||||
await runner.openBrowser();
|
||||
},
|
||||
};
|
||||
return server;
|
||||
});
|
||||
|
||||
const server = wxt.server!;
|
||||
let [runner, builderServer] = await Promise.all([
|
||||
createExtensionRunner(),
|
||||
wxt.builder.createServer(server),
|
||||
]);
|
||||
|
||||
const buildAndOpenBrowser = async () => {
|
||||
// Build after starting the dev server so it can be used to transform HTML files
|
||||
@@ -74,55 +126,6 @@ export async function createServer(
|
||||
runner = await createExtensionRunner();
|
||||
};
|
||||
|
||||
// Server instance must be created first so its reference can be added to the internal config used
|
||||
// to pre-render entrypoints
|
||||
const server: WxtDevServer = {
|
||||
...serverInfo,
|
||||
get watcher() {
|
||||
return builderServer.watcher;
|
||||
},
|
||||
get ws() {
|
||||
return builderServer.ws;
|
||||
},
|
||||
currentOutput: undefined,
|
||||
async start() {
|
||||
await builderServer.listen();
|
||||
wxt.logger.success(`Started dev server @ ${serverInfo.origin}`);
|
||||
await buildAndOpenBrowser();
|
||||
},
|
||||
async stop() {
|
||||
await runner.closeBrowser();
|
||||
await builderServer.close();
|
||||
},
|
||||
async restart() {
|
||||
await closeAndRecreateRunner();
|
||||
await buildAndOpenBrowser();
|
||||
},
|
||||
transformHtml(url, html, originalUrl) {
|
||||
return builderServer.transformHtml(url, html, originalUrl);
|
||||
},
|
||||
reloadContentScript(payload) {
|
||||
server.ws.send('wxt:reload-content-script', payload);
|
||||
},
|
||||
reloadPage(path) {
|
||||
server.ws.send('wxt:reload-page', path);
|
||||
},
|
||||
reloadExtension() {
|
||||
server.ws.send('wxt:reload-extension');
|
||||
},
|
||||
async restartBrowser() {
|
||||
await closeAndRecreateRunner();
|
||||
await runner.openBrowser();
|
||||
},
|
||||
};
|
||||
|
||||
await registerWxt('serve', inlineConfig, server);
|
||||
|
||||
let [runner, builderServer] = await Promise.all([
|
||||
createExtensionRunner(),
|
||||
wxt.config.builder.createServer(server),
|
||||
]);
|
||||
|
||||
// Register content scripts for the first time after the background starts up since they're not
|
||||
// listed in the manifest
|
||||
server.ws.on('wxt:background-initialized', () => {
|
||||
@@ -137,11 +140,6 @@ export async function createServer(
|
||||
return server;
|
||||
}
|
||||
|
||||
async function getPort(): Promise<number> {
|
||||
const { default: getPort, portNumbers } = await import('get-port');
|
||||
return await getPort({ port: portNumbers(3000, 3010) });
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a function responsible for reloading different parts of the extension when a file
|
||||
* changes.
|
||||
@@ -189,34 +187,38 @@ function createFileReloader(server: WxtDevServer) {
|
||||
|
||||
// Rebuild entrypoints on change
|
||||
const allEntrypoints = await findEntrypoints();
|
||||
const { output: newOutput } = await rebuild(
|
||||
allEntrypoints,
|
||||
// TODO: this excludes new entrypoints, so they're not built until the dev command is restarted
|
||||
changes.rebuildGroups,
|
||||
changes.cachedOutput,
|
||||
);
|
||||
server.currentOutput = newOutput;
|
||||
try {
|
||||
const { output: newOutput } = await rebuild(
|
||||
allEntrypoints,
|
||||
// TODO: this excludes new entrypoints, so they're not built until the dev command is restarted
|
||||
changes.rebuildGroups,
|
||||
changes.cachedOutput,
|
||||
);
|
||||
server.currentOutput = newOutput;
|
||||
|
||||
// Perform reloads
|
||||
switch (changes.type) {
|
||||
case 'extension-reload':
|
||||
server.reloadExtension();
|
||||
consola.success(`Reloaded extension`);
|
||||
break;
|
||||
case 'html-reload':
|
||||
const { reloadedNames } = reloadHtmlPages(
|
||||
changes.rebuildGroups,
|
||||
server,
|
||||
);
|
||||
consola.success(`Reloaded: ${getFilenameList(reloadedNames)}`);
|
||||
break;
|
||||
case 'content-script-reload':
|
||||
reloadContentScripts(changes.changedSteps, server);
|
||||
const rebuiltNames = changes.rebuildGroups
|
||||
.flat()
|
||||
.map((entry) => entry.name);
|
||||
consola.success(`Reloaded: ${getFilenameList(rebuiltNames)}`);
|
||||
break;
|
||||
// Perform reloads
|
||||
switch (changes.type) {
|
||||
case 'extension-reload':
|
||||
server.reloadExtension();
|
||||
consola.success(`Reloaded extension`);
|
||||
break;
|
||||
case 'html-reload':
|
||||
const { reloadedNames } = reloadHtmlPages(
|
||||
changes.rebuildGroups,
|
||||
server,
|
||||
);
|
||||
consola.success(`Reloaded: ${getFilenameList(reloadedNames)}`);
|
||||
break;
|
||||
case 'content-script-reload':
|
||||
reloadContentScripts(changes.changedSteps, server);
|
||||
const rebuiltNames = changes.rebuildGroups
|
||||
.flat()
|
||||
.map((entry) => entry.name);
|
||||
consola.success(`Reloaded: ${getFilenameList(rebuiltNames)}`);
|
||||
break;
|
||||
}
|
||||
} catch (err) {
|
||||
// Catch build errors instead of crashing. Don't log error either, builder should have already logged it
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -233,7 +235,7 @@ function reloadContentScripts(steps: BuildStepOutput[], server: WxtDevServer) {
|
||||
const entry = step.entrypoints;
|
||||
if (Array.isArray(entry) || entry.type !== 'content-script') return;
|
||||
|
||||
const js = [getEntrypointBundlePath(entry, wxt.config.outDir, '.js')];
|
||||
const js = getContentScriptJs(wxt.config, entry);
|
||||
const cssMap = getContentScriptsCssMap(server.currentOutput, [entry]);
|
||||
const css = getContentScriptCssFiles([entry], cssMap);
|
||||
|
||||
|
||||
+12
-1
@@ -59,6 +59,16 @@ export async function initialize(options: {
|
||||
input.template ??= defaultTemplate;
|
||||
input.packageManager ??= options.packageManager;
|
||||
|
||||
const isExists = await fs.pathExists(input.directory);
|
||||
if (isExists) {
|
||||
const isEmpty = (await fs.readdir(input.directory)).length === 0;
|
||||
if (!isEmpty) {
|
||||
consola.error(
|
||||
`The directory ${path.resolve(input.directory)} is not empty. Aborted.`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
await cloneProject(input);
|
||||
|
||||
const cdPath = path.relative(process.cwd(), path.resolve(input.directory));
|
||||
@@ -117,7 +127,8 @@ async function listTemplates(): Promise<Template[]> {
|
||||
return l.name.localeCompare(r.name);
|
||||
});
|
||||
} catch (err) {
|
||||
throw Error(`Cannot load templates: ${JSON.stringify(err, null, 2)}`);
|
||||
consola.error(err);
|
||||
throw Error(`Failed to load templates`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ describe('NPM Package Management Utils', () => {
|
||||
beforeAll(async () => {
|
||||
// NPM needs the modules installed for 'npm ls' to work
|
||||
await execaCommand('npm i', { cwd });
|
||||
});
|
||||
}, 60e3);
|
||||
|
||||
describe('listDependencies', () => {
|
||||
it('should list direct dependencies', async () => {
|
||||
|
||||
@@ -7,7 +7,7 @@ export const pnpm: WxtPackageManagerImpl = {
|
||||
return npm.downloadDependency(...args);
|
||||
},
|
||||
async listDependencies(options) {
|
||||
const args = ['ls', '--json'];
|
||||
const args = ['ls', '-r', '--json'];
|
||||
if (options?.all) {
|
||||
args.push('--depth', 'Infinity');
|
||||
}
|
||||
|
||||
@@ -111,6 +111,7 @@ describe('Manifest Utils', () => {
|
||||
setFakeWxt({
|
||||
config: {
|
||||
outDir,
|
||||
manifestVersion: 3,
|
||||
manifest: {
|
||||
action: {
|
||||
default_icon: 'icon-16.png',
|
||||
@@ -119,13 +120,83 @@ describe('Manifest Utils', () => {
|
||||
},
|
||||
},
|
||||
});
|
||||
const expected: Partial<Manifest.WebExtensionManifest> = {
|
||||
action: wxt.config.manifest.action,
|
||||
};
|
||||
|
||||
const { manifest: actual } = await generateManifest([], buildOutput);
|
||||
|
||||
expect(actual).toMatchObject(expected);
|
||||
expect(actual.action).toEqual(wxt.config.manifest.action);
|
||||
expect(actual.browser_action).toBeUndefined();
|
||||
expect(actual.page_action).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should generate `browser_action` for MV2 when only `action` is defined', async () => {
|
||||
const buildOutput = fakeBuildOutput();
|
||||
setFakeWxt({
|
||||
config: {
|
||||
outDir,
|
||||
manifestVersion: 2,
|
||||
manifest: {
|
||||
action: {
|
||||
default_title: 'Action',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const { manifest: actual } = await generateManifest([], buildOutput);
|
||||
|
||||
expect(actual.action).toBeUndefined();
|
||||
expect(actual.browser_action).toEqual(wxt.config.manifest.action);
|
||||
expect(actual.page_action).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should keep the `page_action` for MV2 when both `action` and `page_action` are defined', async () => {
|
||||
const buildOutput = fakeBuildOutput();
|
||||
setFakeWxt({
|
||||
config: {
|
||||
outDir,
|
||||
manifestVersion: 2,
|
||||
manifest: {
|
||||
action: {
|
||||
default_title: 'Action',
|
||||
},
|
||||
page_action: {
|
||||
default_title: 'Page Action',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const { manifest: actual } = await generateManifest([], buildOutput);
|
||||
|
||||
expect(actual.action).toBeUndefined();
|
||||
expect(actual.browser_action).toBeUndefined();
|
||||
expect(actual.page_action).toEqual(wxt.config.manifest.page_action);
|
||||
});
|
||||
|
||||
it('should keep the custom `browser_action` for MV2 when both `action` and `browser_action` are defined', async () => {
|
||||
const buildOutput = fakeBuildOutput();
|
||||
setFakeWxt({
|
||||
config: {
|
||||
outDir,
|
||||
manifestVersion: 2,
|
||||
manifest: {
|
||||
action: {
|
||||
default_title: 'Action',
|
||||
},
|
||||
browser_action: {
|
||||
default_title: 'Browser Action',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const { manifest: actual } = await generateManifest([], buildOutput);
|
||||
|
||||
expect(actual.action).toBeUndefined();
|
||||
expect(actual.browser_action).toEqual(
|
||||
wxt.config.manifest.browser_action,
|
||||
);
|
||||
expect(actual.page_action).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1306,6 +1377,76 @@ describe('Manifest Utils', () => {
|
||||
expect(actual.commands).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Stripping keys', () => {
|
||||
const mv2Manifest = {
|
||||
page_action: {},
|
||||
browser_action: {},
|
||||
automation: {},
|
||||
content_capabilities: {},
|
||||
converted_from_user_script: {},
|
||||
current_locale: {},
|
||||
differential_fingerprint: {},
|
||||
event_rules: {},
|
||||
file_browser_handlers: {},
|
||||
file_system_provider_capabilities: {},
|
||||
input_components: {},
|
||||
nacl_modules: {},
|
||||
natively_connectable: {},
|
||||
offline_enabled: {},
|
||||
platforms: {},
|
||||
replacement_web_app: {},
|
||||
system_indicator: {},
|
||||
user_scripts: {},
|
||||
};
|
||||
const mv3Manifest = {
|
||||
action: {},
|
||||
export: {},
|
||||
optional_host_permissions: {},
|
||||
side_panel: {},
|
||||
};
|
||||
const hostPermissionsManifest = {
|
||||
host_permissions: {},
|
||||
};
|
||||
const manifest: any = {
|
||||
...mv2Manifest,
|
||||
...mv3Manifest,
|
||||
...hostPermissionsManifest,
|
||||
};
|
||||
|
||||
it.each([
|
||||
['firefox', 2, mv2Manifest],
|
||||
['chrome', 2, { ...mv2Manifest, ...hostPermissionsManifest }],
|
||||
['safari', 2, { ...mv2Manifest, ...hostPermissionsManifest }],
|
||||
['edge', 2, { ...mv2Manifest, ...hostPermissionsManifest }],
|
||||
['firefox', 3, { ...mv3Manifest, ...hostPermissionsManifest }],
|
||||
['chrome', 3, { ...mv3Manifest, ...hostPermissionsManifest }],
|
||||
['safari', 3, { ...mv3Manifest, ...hostPermissionsManifest }],
|
||||
['edge', 3, { ...mv3Manifest, ...hostPermissionsManifest }],
|
||||
] as const)(
|
||||
"%s MV%s should only include that version's keys",
|
||||
async (browser, manifestVersion, expected) => {
|
||||
setFakeWxt({
|
||||
config: {
|
||||
browser,
|
||||
manifest,
|
||||
manifestVersion,
|
||||
command: 'build',
|
||||
},
|
||||
});
|
||||
const output = fakeBuildOutput();
|
||||
|
||||
const { manifest: actual } = await generateManifest([], output);
|
||||
|
||||
expect(actual).toEqual({
|
||||
name: expect.any(String),
|
||||
version: expect.any(String),
|
||||
manifest_version: manifestVersion,
|
||||
...expected,
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('stripPathFromMatchPattern', () => {
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import { describe, it } from 'vitest';
|
||||
import {
|
||||
VirtualModuleId,
|
||||
VirtualModuleName,
|
||||
VirtualEntrypointType,
|
||||
VirtualEntrypointModuleName,
|
||||
} from '../virtual-modules';
|
||||
|
||||
describe('Virtual Modules', () => {
|
||||
it('should resolve types to litteral values, not string', () => {
|
||||
// @ts-expect-error
|
||||
const _c: VirtualEntrypointType = '';
|
||||
// @ts-expect-error
|
||||
const _d: VirtualEntrypointModuleName = '';
|
||||
// @ts-expect-error
|
||||
const _b: VirtualModuleName = '';
|
||||
// @ts-expect-error
|
||||
const _a: VirtualModuleId = '';
|
||||
});
|
||||
});
|
||||
@@ -21,3 +21,14 @@ export function some<T>(
|
||||
if (predicate(array[i], i)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an item or array to an array.
|
||||
*/
|
||||
export function toArray<T>(a: T | T[]): T[] {
|
||||
return Array.isArray(a) ? a : [a];
|
||||
}
|
||||
|
||||
export function filterTruthy<T>(array: Array<T | undefined>): T[] {
|
||||
return array.filter((item) => !!item) as T[];
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { dirname, resolve } from 'path';
|
||||
import type { Ora } from 'ora';
|
||||
import pc from 'picocolors';
|
||||
import { wxt } from '../../wxt';
|
||||
import { toArray } from '../arrays';
|
||||
|
||||
export async function buildEntrypoints(
|
||||
groups: EntrypointGroup[],
|
||||
@@ -13,13 +14,14 @@ export async function buildEntrypoints(
|
||||
const steps: BuildStepOutput[] = [];
|
||||
for (let i = 0; i < groups.length; i++) {
|
||||
const group = groups[i];
|
||||
const groupNames = [group].flat().map((e) => e.name);
|
||||
const groupNames = toArray(group).map((e) => e.name);
|
||||
const groupNameColored = groupNames.join(pc.dim(', '));
|
||||
spinner.text =
|
||||
pc.dim(`[${i + 1}/${groups.length}]`) + ` ${groupNameColored}`;
|
||||
try {
|
||||
steps.push(await wxt.config.builder.build(group));
|
||||
steps.push(await wxt.builder.build(group));
|
||||
} catch (err) {
|
||||
spinner.stop().clear();
|
||||
wxt.logger.error(err);
|
||||
throw Error(`Failed to build ${groupNames.join(', ')}`, { cause: err });
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
import consola from 'consola';
|
||||
import { wxt } from '../../wxt';
|
||||
import { mergeJsonOutputs } from '@aklinker1/rollup-plugin-visualizer';
|
||||
import { isCI } from 'ci-info';
|
||||
|
||||
/**
|
||||
* Builds the extension based on an internal config. No more config discovery is performed, the
|
||||
@@ -36,7 +37,7 @@ export async function internalBuild(): Promise<BuildOutput> {
|
||||
const target = `${wxt.config.browser}-mv${wxt.config.manifestVersion}`;
|
||||
wxt.logger.info(
|
||||
`${verb} ${pc.cyan(target)} for ${pc.cyan(wxt.config.mode)} with ${pc.green(
|
||||
`${wxt.config.builder.name} ${wxt.config.builder.version}`,
|
||||
`${wxt.builder.name} ${wxt.builder.version}`,
|
||||
)}`,
|
||||
);
|
||||
const startTime = Date.now();
|
||||
@@ -81,6 +82,15 @@ export async function internalBuild(): Promise<BuildOutput> {
|
||||
wxt.logger.info(
|
||||
`Analysis complete:\n ${pc.gray('└─')} ${pc.yellow(statsPath)}`,
|
||||
);
|
||||
if (wxt.config.analysis.open) {
|
||||
if (isCI) {
|
||||
wxt.logger.debug(`Skipped opening ${pc.yellow(statsPath)} in CI`);
|
||||
} else {
|
||||
wxt.logger.info(`Opening ${pc.yellow(statsPath)} in browser...`);
|
||||
const { default: open } = await import('open');
|
||||
open(wxt.config.analysis.outputFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
|
||||
@@ -7,17 +7,18 @@ import {
|
||||
UserManifestFn,
|
||||
UserManifest,
|
||||
ExtensionRunnerConfig,
|
||||
WxtDevServer,
|
||||
WxtResolvedUnimportOptions,
|
||||
Logger,
|
||||
WxtCommand,
|
||||
} from '~/types';
|
||||
import path from 'node:path';
|
||||
import { createFsCache } from '~/core/utils/cache';
|
||||
import consola, { LogLevels } from 'consola';
|
||||
import { createViteBuilder } from '~/core/builders/vite';
|
||||
import defu from 'defu';
|
||||
import { NullablyRequired } from '../types';
|
||||
import { isModuleInstalled } from '../package';
|
||||
import fs from 'fs-extra';
|
||||
import { normalizePath } from '../paths';
|
||||
|
||||
/**
|
||||
* Given an inline config, discover the config file if necessary, merge the results, resolve any
|
||||
@@ -28,8 +29,7 @@ import { isModuleInstalled } from '../package';
|
||||
*/
|
||||
export async function resolveConfig(
|
||||
inlineConfig: InlineConfig,
|
||||
command: 'build' | 'serve',
|
||||
server?: WxtDevServer,
|
||||
command: WxtCommand,
|
||||
): Promise<ResolvedConfig> {
|
||||
// Load user config
|
||||
|
||||
@@ -51,7 +51,7 @@ export async function resolveConfig(
|
||||
|
||||
// Merge it into the inline config
|
||||
|
||||
const mergedConfig = mergeInlineConfig(inlineConfig, userConfig);
|
||||
const mergedConfig = await mergeInlineConfig(inlineConfig, userConfig);
|
||||
|
||||
// Apply defaults to make internal config.
|
||||
|
||||
@@ -63,8 +63,7 @@ export async function resolveConfig(
|
||||
const manifestVersion =
|
||||
mergedConfig.manifestVersion ??
|
||||
(browser === 'firefox' || browser === 'safari' ? 2 : 3);
|
||||
const mode =
|
||||
mergedConfig.mode ?? (command === 'build' ? 'production' : 'development');
|
||||
const mode = mergedConfig.mode ?? COMMAND_MODES[command];
|
||||
const env: ConfigEnv = { browser, command, manifestVersion, mode };
|
||||
|
||||
const root = path.resolve(
|
||||
@@ -77,10 +76,16 @@ export async function resolveConfig(
|
||||
srcDir,
|
||||
mergedConfig.entrypointsDir ?? 'entrypoints',
|
||||
);
|
||||
if (await isDirMissing(entrypointsDir)) {
|
||||
logMissingDir(logger, 'Entrypoints', entrypointsDir);
|
||||
}
|
||||
const filterEntrypoints = !!mergedConfig.filterEntrypoints?.length
|
||||
? new Set(mergedConfig.filterEntrypoints)
|
||||
: undefined;
|
||||
const publicDir = path.resolve(srcDir, mergedConfig.publicDir ?? 'public');
|
||||
if (await isDirMissing(publicDir)) {
|
||||
logMissingDir(logger, 'Public', publicDir);
|
||||
}
|
||||
const typesDir = path.resolve(wxtDir, 'types');
|
||||
const outBaseDir = path.resolve(root, mergedConfig.outDir ?? '.output');
|
||||
const outDir = path.resolve(outBaseDir, `${browser}-mv${manifestVersion}`);
|
||||
@@ -105,14 +110,20 @@ export async function resolveConfig(
|
||||
}).map(([key, value]) => [key, path.resolve(root, value)]),
|
||||
);
|
||||
|
||||
const analysisOutputFile = path.resolve(
|
||||
root,
|
||||
mergedConfig.analysis?.outputFile ?? 'stats.html',
|
||||
);
|
||||
const analysisOutputDir = path.dirname(analysisOutputFile);
|
||||
const analysisOutputName = path.parse(analysisOutputFile).name;
|
||||
let devServerConfig: ResolvedConfig['dev']['server'];
|
||||
if (command === 'serve') {
|
||||
let port = mergedConfig.dev?.server?.port;
|
||||
if (port == null || !isFinite(port)) {
|
||||
const { default: getPort, portNumbers } = await import('get-port');
|
||||
port = await getPort({ port: portNumbers(3000, 3010) });
|
||||
}
|
||||
devServerConfig = {
|
||||
port,
|
||||
hostname: 'localhost',
|
||||
};
|
||||
}
|
||||
|
||||
const finalConfig: Omit<ResolvedConfig, 'builder'> = {
|
||||
return {
|
||||
browser,
|
||||
command,
|
||||
debug,
|
||||
@@ -134,41 +145,20 @@ export async function resolveConfig(
|
||||
srcDir,
|
||||
typesDir,
|
||||
wxtDir,
|
||||
zip: resolveInternalZipConfig(root, mergedConfig),
|
||||
transformManifest(manifest) {
|
||||
userConfig.transformManifest?.(manifest);
|
||||
inlineConfig.transformManifest?.(manifest);
|
||||
},
|
||||
analysis: {
|
||||
enabled: mergedConfig.analysis?.enabled ?? false,
|
||||
template: mergedConfig.analysis?.template ?? 'treemap',
|
||||
outputFile: analysisOutputFile,
|
||||
outputDir: analysisOutputDir,
|
||||
outputName: analysisOutputName,
|
||||
keepArtifacts: mergedConfig.analysis?.keepArtifacts ?? false,
|
||||
},
|
||||
zip: resolveZipConfig(root, mergedConfig),
|
||||
transformManifest: mergedConfig.transformManifest,
|
||||
analysis: resolveAnalysisConfig(root, mergedConfig),
|
||||
userConfigMetadata: userConfigMetadata ?? {},
|
||||
alias,
|
||||
experimental: {
|
||||
includeBrowserPolyfill:
|
||||
mergedConfig.experimental?.includeBrowserPolyfill ?? true,
|
||||
},
|
||||
server,
|
||||
experimental: defu(mergedConfig.experimental, {
|
||||
includeBrowserPolyfill: true,
|
||||
}),
|
||||
dev: {
|
||||
server: devServerConfig,
|
||||
reloadCommand,
|
||||
},
|
||||
hooks: mergedConfig.hooks ?? {},
|
||||
};
|
||||
|
||||
const builder = await createViteBuilder(
|
||||
inlineConfig,
|
||||
userConfig,
|
||||
finalConfig,
|
||||
);
|
||||
|
||||
return {
|
||||
...finalConfig,
|
||||
builder,
|
||||
vite: mergedConfig.vite ?? (() => ({})),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -184,77 +174,45 @@ async function resolveManifestConfig(
|
||||
/**
|
||||
* Merge the inline config and user config. Inline config is given priority. Defaults are not applied here.
|
||||
*/
|
||||
function mergeInlineConfig(
|
||||
async function mergeInlineConfig(
|
||||
inlineConfig: InlineConfig,
|
||||
userConfig: UserConfig,
|
||||
): NullablyRequired<InlineConfig> {
|
||||
let imports: InlineConfig['imports'];
|
||||
if (inlineConfig.imports === false || userConfig.imports === false) {
|
||||
imports = false;
|
||||
} else if (userConfig.imports == null && inlineConfig.imports == null) {
|
||||
imports = undefined;
|
||||
} else {
|
||||
imports = defu(inlineConfig.imports ?? {}, userConfig.imports ?? {});
|
||||
}
|
||||
): Promise<InlineConfig> {
|
||||
// Merge imports option
|
||||
const imports: InlineConfig['imports'] =
|
||||
inlineConfig.imports === false || userConfig.imports === false
|
||||
? false
|
||||
: userConfig.imports == null && inlineConfig.imports == null
|
||||
? undefined
|
||||
: defu(inlineConfig.imports ?? {}, userConfig.imports ?? {});
|
||||
|
||||
// Merge manifest option
|
||||
const manifest: UserManifestFn = async (env) => {
|
||||
const user = await resolveManifestConfig(env, userConfig.manifest);
|
||||
const inline = await resolveManifestConfig(env, inlineConfig.manifest);
|
||||
return defu(inline, user);
|
||||
};
|
||||
const runner: InlineConfig['runner'] = defu(
|
||||
inlineConfig.runner ?? {},
|
||||
userConfig.runner ?? {},
|
||||
);
|
||||
const zip: InlineConfig['zip'] = defu(
|
||||
inlineConfig.zip ?? {},
|
||||
userConfig.zip ?? {},
|
||||
);
|
||||
const hooks: InlineConfig['hooks'] = defu(
|
||||
inlineConfig.hooks ?? {},
|
||||
userConfig.hooks ?? {},
|
||||
);
|
||||
|
||||
// Merge transformManifest option
|
||||
const transformManifest: InlineConfig['transformManifest'] = (manifest) => {
|
||||
userConfig.transformManifest?.(manifest);
|
||||
inlineConfig.transformManifest?.(manifest);
|
||||
};
|
||||
|
||||
// Builders
|
||||
const builderConfig = await mergeBuilderConfig(inlineConfig, userConfig);
|
||||
|
||||
return {
|
||||
root: inlineConfig.root ?? userConfig.root,
|
||||
browser: inlineConfig.browser ?? userConfig.browser,
|
||||
manifestVersion: inlineConfig.manifestVersion ?? userConfig.manifestVersion,
|
||||
configFile: inlineConfig.configFile,
|
||||
debug: inlineConfig.debug ?? userConfig.debug,
|
||||
entrypointsDir: inlineConfig.entrypointsDir ?? userConfig.entrypointsDir,
|
||||
filterEntrypoints:
|
||||
inlineConfig.filterEntrypoints ?? userConfig.filterEntrypoints,
|
||||
...defu(inlineConfig, userConfig),
|
||||
// Custom merge values
|
||||
transformManifest,
|
||||
imports,
|
||||
logger: inlineConfig.logger ?? userConfig.logger,
|
||||
manifest,
|
||||
mode: inlineConfig.mode ?? userConfig.mode,
|
||||
publicDir: inlineConfig.publicDir ?? userConfig.publicDir,
|
||||
runner,
|
||||
srcDir: inlineConfig.srcDir ?? userConfig.srcDir,
|
||||
outDir: inlineConfig.outDir ?? userConfig.outDir,
|
||||
zip,
|
||||
analysis: {
|
||||
...userConfig.analysis,
|
||||
...inlineConfig.analysis,
|
||||
},
|
||||
alias: {
|
||||
...userConfig.alias,
|
||||
...inlineConfig.alias,
|
||||
},
|
||||
experimental: {
|
||||
...userConfig.experimental,
|
||||
...inlineConfig.experimental,
|
||||
},
|
||||
vite: undefined,
|
||||
transformManifest: undefined,
|
||||
dev: {
|
||||
...userConfig.dev,
|
||||
...inlineConfig.dev,
|
||||
},
|
||||
hooks,
|
||||
...builderConfig,
|
||||
};
|
||||
}
|
||||
|
||||
function resolveInternalZipConfig(
|
||||
function resolveZipConfig(
|
||||
root: string,
|
||||
mergedConfig: InlineConfig,
|
||||
): NullablyRequired<ResolvedConfig['zip']> {
|
||||
@@ -283,6 +241,28 @@ function resolveInternalZipConfig(
|
||||
};
|
||||
}
|
||||
|
||||
function resolveAnalysisConfig(
|
||||
root: string,
|
||||
mergedConfig: InlineConfig,
|
||||
): NullablyRequired<ResolvedConfig['analysis']> {
|
||||
const analysisOutputFile = path.resolve(
|
||||
root,
|
||||
mergedConfig.analysis?.outputFile ?? 'stats.html',
|
||||
);
|
||||
const analysisOutputDir = path.dirname(analysisOutputFile);
|
||||
const analysisOutputName = path.parse(analysisOutputFile).name;
|
||||
|
||||
return {
|
||||
enabled: mergedConfig.analysis?.enabled ?? false,
|
||||
open: mergedConfig.analysis?.open ?? false,
|
||||
template: mergedConfig.analysis?.template ?? 'treemap',
|
||||
outputFile: analysisOutputFile,
|
||||
outputDir: analysisOutputDir,
|
||||
outputName: analysisOutputName,
|
||||
keepArtifacts: mergedConfig.analysis?.keepArtifacts ?? false,
|
||||
};
|
||||
}
|
||||
|
||||
async function getUnimportOptions(
|
||||
wxtDir: string,
|
||||
logger: Logger,
|
||||
@@ -339,3 +319,41 @@ async function resolveWxtModuleDir() {
|
||||
// require.resolve returns the wxt/dist/index file, not the package's root directory, which we want to return
|
||||
return path.resolve(requireResolve('wxt'), '../..');
|
||||
}
|
||||
|
||||
async function isDirMissing(dir: string) {
|
||||
return !(await fs.exists(dir));
|
||||
}
|
||||
|
||||
function logMissingDir(logger: Logger, name: string, expected: string) {
|
||||
logger.warn(
|
||||
`${name} directory not found: ./${normalizePath(
|
||||
path.relative(process.cwd(), expected),
|
||||
)}`,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map of `ConfigEnv` commands to their default modes.
|
||||
*/
|
||||
const COMMAND_MODES: Record<WxtCommand, string> = {
|
||||
build: 'production',
|
||||
serve: 'development',
|
||||
};
|
||||
|
||||
export async function mergeBuilderConfig(
|
||||
inlineConfig: InlineConfig,
|
||||
userConfig: UserConfig,
|
||||
): Promise<Pick<InlineConfig, 'vite'>> {
|
||||
const vite = await import('vite').catch(() => void 0);
|
||||
if (vite) {
|
||||
return {
|
||||
vite: async (env) => {
|
||||
const resolvedInlineConfig = (await inlineConfig.vite?.(env)) ?? {};
|
||||
const resolvedUserConfig = (await userConfig.vite?.(env)) ?? {};
|
||||
return vite.mergeConfig(resolvedUserConfig, resolvedInlineConfig);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
throw Error('Builder not found. Make sure vite is installed.');
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { Manifest, Scripting } from '~/browser';
|
||||
import { ContentScriptEntrypoint } from '~/types';
|
||||
import { ContentScriptEntrypoint, ResolvedConfig } from '~/types';
|
||||
import { getEntrypointBundlePath } from './entrypoints';
|
||||
|
||||
/**
|
||||
* Returns a unique and consistent string hash based on a content scripts options.
|
||||
@@ -83,3 +84,10 @@ export function mapWxtOptionsToRegisteredContentScript(
|
||||
world: options.world,
|
||||
};
|
||||
}
|
||||
|
||||
export function getContentScriptJs(
|
||||
config: ResolvedConfig,
|
||||
entrypoint: ContentScriptEntrypoint,
|
||||
): string[] {
|
||||
return [getEntrypointBundlePath(entrypoint, config.outDir, '.js')];
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ResolvedConfig } from '~/types';
|
||||
|
||||
export function getGlobals(
|
||||
config: Omit<ResolvedConfig, 'builder'>,
|
||||
config: ResolvedConfig,
|
||||
): Array<{ name: string; value: any; type: string }> {
|
||||
return [
|
||||
{
|
||||
|
||||
@@ -111,16 +111,20 @@ export async function generateManifest(
|
||||
if (wxt.config.command === 'serve') addDevModePermissions(manifest);
|
||||
|
||||
// TODO: Remove in v1
|
||||
wxt.config.transformManifest(manifest);
|
||||
wxt.config.transformManifest?.(manifest);
|
||||
await wxt.hooks.callHook('build:manifestGenerated', wxt, manifest);
|
||||
|
||||
if (wxt.config.manifestVersion === 2)
|
||||
if (wxt.config.manifestVersion === 2) {
|
||||
convertWebAccessibleResourcesToMv2(manifest);
|
||||
convertActionToMv2(manifest);
|
||||
}
|
||||
|
||||
if (wxt.config.manifestVersion === 3) {
|
||||
validateMv3WebAccessbileResources(manifest);
|
||||
}
|
||||
|
||||
stripKeys(manifest);
|
||||
|
||||
if (manifest.name == null)
|
||||
throw Error(
|
||||
"Manifest 'name' is missing. Either:\n1. Set the name in your <rootDir>/package.json\n2. Set a name via the manifest option in your wxt.config.ts",
|
||||
@@ -451,8 +455,8 @@ function discoverIcons(
|
||||
}
|
||||
|
||||
function addDevModeCsp(manifest: Manifest.WebExtensionManifest): void {
|
||||
const permission = `http://${wxt.config.server?.hostname ?? ''}/*`;
|
||||
const allowedCsp = wxt.config.server?.origin ?? 'http://localhost:*';
|
||||
const permission = `http://${wxt.server?.hostname ?? ''}/*`;
|
||||
const allowedCsp = wxt.server?.origin ?? 'http://localhost:*';
|
||||
|
||||
if (manifest.manifest_version === 3) {
|
||||
addHostPermission(manifest, permission);
|
||||
@@ -469,7 +473,7 @@ function addDevModeCsp(manifest: Manifest.WebExtensionManifest): void {
|
||||
"script-src 'self'; object-src 'self';", // default CSP for MV2
|
||||
);
|
||||
|
||||
if (wxt.config.server) csp.add('script-src', allowedCsp);
|
||||
if (wxt.server) csp.add('script-src', allowedCsp);
|
||||
|
||||
if (manifest.manifest_version === 3) {
|
||||
manifest.content_security_policy ??= {};
|
||||
@@ -613,6 +617,17 @@ export function convertWebAccessibleResourcesToMv2(
|
||||
);
|
||||
}
|
||||
|
||||
function convertActionToMv2(manifest: Manifest.WebExtensionManifest): void {
|
||||
if (
|
||||
manifest.action == null ||
|
||||
manifest.browser_action != null ||
|
||||
manifest.page_action != null
|
||||
)
|
||||
return;
|
||||
|
||||
manifest.browser_action = manifest.action;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure all resources are in MV3 format. If not, add a wanring
|
||||
*/
|
||||
@@ -632,3 +647,50 @@ export function validateMv3WebAccessbileResources(
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove keys from the manifest based on the build target.
|
||||
*/
|
||||
function stripKeys(manifest: Manifest.WebExtensionManifest): void {
|
||||
let keysToRemove: string[] = [];
|
||||
if (wxt.config.manifestVersion === 2) {
|
||||
keysToRemove.push(...mv3OnlyKeys);
|
||||
if (wxt.config.browser === 'firefox')
|
||||
keysToRemove.push(...firefoxMv3OnlyKeys);
|
||||
} else {
|
||||
keysToRemove.push(...mv2OnlyKeys);
|
||||
}
|
||||
|
||||
keysToRemove.forEach((key) => {
|
||||
delete manifest[key as keyof Manifest.WebExtensionManifest];
|
||||
});
|
||||
}
|
||||
|
||||
const mv2OnlyKeys = [
|
||||
'page_action',
|
||||
'browser_action',
|
||||
'automation',
|
||||
'content_capabilities',
|
||||
'converted_from_user_script',
|
||||
'current_locale',
|
||||
'differential_fingerprint',
|
||||
'event_rules',
|
||||
'file_browser_handlers',
|
||||
'file_system_provider_capabilities',
|
||||
'input_components',
|
||||
'nacl_modules',
|
||||
'natively_connectable',
|
||||
'offline_enabled',
|
||||
'platforms',
|
||||
'replacement_web_app',
|
||||
'system_indicator',
|
||||
'user_scripts',
|
||||
];
|
||||
|
||||
const mv3OnlyKeys = [
|
||||
'action',
|
||||
'export',
|
||||
'optional_host_permissions',
|
||||
'side_panel',
|
||||
];
|
||||
const firefoxMv3OnlyKeys = ['host_permissions'];
|
||||
|
||||
@@ -26,7 +26,7 @@ export async function isOnline(): Promise<boolean> {
|
||||
*/
|
||||
export async function fetchCached(
|
||||
url: string,
|
||||
config: Omit<ResolvedConfig, 'builder'>,
|
||||
config: ResolvedConfig,
|
||||
): Promise<string> {
|
||||
let content: string = '';
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ import { mock } from 'vitest-mock-extended';
|
||||
import { vi } from 'vitest';
|
||||
import { setWxtForTesting } from '~/core/wxt';
|
||||
|
||||
faker.seed(__TEST_SEED__);
|
||||
faker.seed(import.meta.test.SEED);
|
||||
|
||||
type DeepPartial<T> = T extends object
|
||||
? {
|
||||
@@ -270,9 +270,9 @@ export const fakeResolvedConfig = fakeObjectCreator<ResolvedConfig>(() => {
|
||||
srcDir: fakeDir(),
|
||||
typesDir: fakeDir(),
|
||||
wxtDir: fakeDir(),
|
||||
server: mock<WxtDevServer>(),
|
||||
analysis: {
|
||||
enabled: false,
|
||||
open: false,
|
||||
template: 'treemap',
|
||||
outputFile: fakeFile(),
|
||||
outputDir: fakeDir(),
|
||||
@@ -295,11 +295,11 @@ export const fakeResolvedConfig = fakeObjectCreator<ResolvedConfig>(() => {
|
||||
experimental: {
|
||||
includeBrowserPolyfill: true,
|
||||
},
|
||||
builder: mock(),
|
||||
dev: {
|
||||
reloadCommand: 'Alt+R',
|
||||
},
|
||||
hooks: {},
|
||||
vite: () => ({}),
|
||||
};
|
||||
});
|
||||
|
||||
@@ -309,11 +309,14 @@ export const fakeWxt = fakeObjectCreator<Wxt>(() => ({
|
||||
logger: mock(),
|
||||
reloadConfig: vi.fn(),
|
||||
pm: mock(),
|
||||
server: faker.helpers.arrayElement([undefined, mock<WxtDevServer>()]),
|
||||
builder: mock(),
|
||||
}));
|
||||
|
||||
export function setFakeWxt(overrides?: DeepPartial<Wxt>) {
|
||||
const wxt = fakeWxt(overrides);
|
||||
setWxtForTesting(wxt);
|
||||
return wxt;
|
||||
}
|
||||
|
||||
export const fakeBuildOutput = fakeObjectCreator<BuildOutput>(() => ({
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
export const virtualEntrypointTypes = [
|
||||
'content-script-main-world' as const,
|
||||
'content-script-isolated-world' as const,
|
||||
'background' as const,
|
||||
'unlisted-script' as const,
|
||||
];
|
||||
export type VirtualEntrypointType = (typeof virtualEntrypointTypes)[0];
|
||||
|
||||
/**
|
||||
* All the names of entrypoint files in the `src/virtual/` and `dist/virtual/` directories, minus the extension.
|
||||
*/
|
||||
export const virtualEntrypointModuleNames = virtualEntrypointTypes.map(
|
||||
(name) => `${name}-entrypoint` as const,
|
||||
);
|
||||
/**
|
||||
* Name of entrypoint files in the `src/virtual/` and `dist/virtual/` directories, minus the extension.
|
||||
*/
|
||||
export type VirtualEntrypointModuleName =
|
||||
(typeof virtualEntrypointModuleNames)[0];
|
||||
|
||||
/**
|
||||
* All the names of files in the `src/virtual/` and `dist/virtual/` directories, minus the extension.
|
||||
*/
|
||||
export const virtualModuleNames = [
|
||||
...virtualEntrypointModuleNames,
|
||||
'mock-browser' as const,
|
||||
'reload-html' as const,
|
||||
];
|
||||
/**
|
||||
* Name of files in the `src/virtual/` and `dist/virtual/` directories, minus the extension.
|
||||
*/
|
||||
export type VirtualModuleName = (typeof virtualModuleNames)[0];
|
||||
|
||||
/**
|
||||
* Import alias used for importing a virtual module
|
||||
*/
|
||||
export type VirtualModuleId = `virtual:wxt-${VirtualModuleName}`;
|
||||
+17
-5
@@ -1,7 +1,15 @@
|
||||
import { InlineConfig, Wxt, WxtDevServer, WxtHooks } from '~/types';
|
||||
import {
|
||||
InlineConfig,
|
||||
ResolvedConfig,
|
||||
Wxt,
|
||||
WxtCommand,
|
||||
WxtDevServer,
|
||||
WxtHooks,
|
||||
} from '~/types';
|
||||
import { resolveConfig } from './utils/building';
|
||||
import { createHooks } from 'hookable';
|
||||
import { createWxtPackageManager } from './package-managers';
|
||||
import { createViteBuilder } from './builders/vite';
|
||||
|
||||
/**
|
||||
* Global variable set once `createWxt` is called once. Since this variable is used everywhere, this
|
||||
@@ -13,12 +21,14 @@ export let wxt: Wxt;
|
||||
* Create and register a global instance of the Wxt interface for use throughout the project.
|
||||
*/
|
||||
export async function registerWxt(
|
||||
command: 'build' | 'serve',
|
||||
command: WxtCommand,
|
||||
inlineConfig: InlineConfig = {},
|
||||
server?: WxtDevServer,
|
||||
getServer?: (config: ResolvedConfig) => Promise<WxtDevServer>,
|
||||
): Promise<void> {
|
||||
const config = await resolveConfig(inlineConfig, command, server);
|
||||
const hooks = createHooks<WxtHooks>();
|
||||
const config = await resolveConfig(inlineConfig, command);
|
||||
const server = await getServer?.(config);
|
||||
const builder = await createViteBuilder(config, hooks, server);
|
||||
const pm = await createWxtPackageManager(config.root);
|
||||
|
||||
wxt = {
|
||||
@@ -28,9 +38,11 @@ export async function registerWxt(
|
||||
return config.logger;
|
||||
},
|
||||
async reloadConfig() {
|
||||
wxt.config = await resolveConfig(inlineConfig, command, server);
|
||||
wxt.config = await resolveConfig(inlineConfig, command);
|
||||
},
|
||||
pm,
|
||||
builder,
|
||||
server,
|
||||
};
|
||||
|
||||
// Initialize hooks
|
||||
|
||||
+15
-11
@@ -38,6 +38,7 @@ export async function zip(config?: InlineConfig): Promise<string[]> {
|
||||
'{{version}}',
|
||||
output.manifest.version_name ?? output.manifest.version,
|
||||
)
|
||||
.replaceAll('{{mode}}', wxt.config.mode)
|
||||
.replaceAll('{{manifestVersion}}', `mv${wxt.config.manifestVersion}`);
|
||||
|
||||
await fs.ensureDir(wxt.config.outBaseDir);
|
||||
@@ -62,9 +63,9 @@ export async function zip(config?: InlineConfig): Promise<string[]> {
|
||||
await zipDir(wxt.config.zip.sourcesRoot, sourcesZipPath, {
|
||||
include: wxt.config.zip.includeSources,
|
||||
exclude: wxt.config.zip.excludeSources,
|
||||
transform(file, content) {
|
||||
if (file.endsWith('package.json')) {
|
||||
return addOverridesToPackageJson(content, overrides);
|
||||
transform(absolutePath, zipPath, content) {
|
||||
if (zipPath.endsWith('package.json')) {
|
||||
return addOverridesToPackageJson(absolutePath, content, overrides);
|
||||
}
|
||||
},
|
||||
additionalFiles: downloadedPackages,
|
||||
@@ -88,7 +89,8 @@ async function zipDir(
|
||||
include?: string[];
|
||||
exclude?: string[];
|
||||
transform?: (
|
||||
file: string,
|
||||
absolutePath: string,
|
||||
zipPath: string,
|
||||
content: string,
|
||||
) => Promise<string | undefined | void> | string | undefined | void;
|
||||
additionalWork?: (archive: JSZip) => Promise<void> | void;
|
||||
@@ -125,7 +127,7 @@ async function zipDir(
|
||||
const content = await fs.readFile(absolutePath, 'utf-8');
|
||||
archive.file(
|
||||
file,
|
||||
(await options?.transform?.(file, content)) || content,
|
||||
(await options?.transform?.(absolutePath, file, content)) || content,
|
||||
);
|
||||
} else {
|
||||
const content = await fs.readFile(absolutePath);
|
||||
@@ -159,8 +161,7 @@ async function downloadPrivatePackages() {
|
||||
wxt.config.zip.downloadedPackagesDir,
|
||||
);
|
||||
files.push(tgzPath);
|
||||
overrides[id] =
|
||||
'file://./' + normalizePath(path.relative(wxt.config.root, tgzPath));
|
||||
overrides[id] = tgzPath;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,18 +169,21 @@ async function downloadPrivatePackages() {
|
||||
}
|
||||
|
||||
function addOverridesToPackageJson(
|
||||
absolutePackageJsonPath: string,
|
||||
content: string,
|
||||
overrides: Record<string, string>,
|
||||
): string {
|
||||
if (Object.keys(overrides).length === 0) return content;
|
||||
|
||||
const packageJsonDir = path.dirname(absolutePackageJsonPath);
|
||||
const oldPackage = JSON.parse(content);
|
||||
const newPackage = {
|
||||
...oldPackage,
|
||||
[wxt.pm.overridesKey]: {
|
||||
...oldPackage[wxt.pm.overridesKey],
|
||||
...overrides,
|
||||
},
|
||||
[wxt.pm.overridesKey]: { ...oldPackage[wxt.pm.overridesKey] },
|
||||
};
|
||||
Object.entries(overrides).forEach(([key, absolutePath]) => {
|
||||
newPackage[wxt.pm.overridesKey][key] =
|
||||
'file://./' + normalizePath(path.relative(packageJsonDir, absolutePath));
|
||||
});
|
||||
return JSON.stringify(newPackage, null, 2);
|
||||
}
|
||||
|
||||
+2
-1
@@ -8,6 +8,7 @@
|
||||
import { Storage, browser } from '~/browser';
|
||||
import { dequal } from 'dequal/lite';
|
||||
import { logger } from './sandbox/utils/logger';
|
||||
import { toArray } from './core/utils/arrays';
|
||||
|
||||
export const storage = createStorage();
|
||||
|
||||
@@ -107,7 +108,7 @@ function createStorage(): WxtStorage {
|
||||
await driver.removeItem(metaKey);
|
||||
} else {
|
||||
const newFields = getMetaValue(await driver.getItem(metaKey));
|
||||
[properties].flat().forEach((field) => delete newFields[field]);
|
||||
toArray(properties).forEach((field) => delete newFields[field]);
|
||||
await driver.setItem(metaKey, newFields);
|
||||
}
|
||||
};
|
||||
|
||||
Vendored
+1
-1
@@ -4,7 +4,7 @@ declare const __DEV_SERVER_PORT__: string;
|
||||
|
||||
// Globals defined by the vite-plugins/devServerGlobals.ts and utils/globals.ts
|
||||
interface ImportMetaEnv {
|
||||
readonly COMMAND: 'build' | 'serve';
|
||||
readonly COMMAND: WxtCommand;
|
||||
readonly MANIFEST_VERSION: 2 | 3;
|
||||
readonly ENTRYPOINT: string;
|
||||
}
|
||||
|
||||
+76
-21
@@ -21,6 +21,9 @@ export interface InlineConfig {
|
||||
* Directory containing all source code. Set to `"src"` to move all source code to a `src/`
|
||||
* directory.
|
||||
*
|
||||
* After changing, don't forget to move the `public/` and `entrypoints/` directories into the new
|
||||
* source dir.
|
||||
*
|
||||
* @default config.root
|
||||
*/
|
||||
srcDir?: string;
|
||||
@@ -114,10 +117,11 @@ export interface InlineConfig {
|
||||
*
|
||||
* Available template variables:
|
||||
*
|
||||
* - `{{name}}` - The project's name converted to kebab-case
|
||||
* - `{{version}}` - The version_name or version from the manifest
|
||||
* - `{{browser}}` - The target browser from the `--browser` CLI flag
|
||||
* - `{{manifestVersion}}` - Either "2" or "3"
|
||||
* - <span v-pre>`{{name}}`</span> - The project's name converted to kebab-case
|
||||
* - <span v-pre>`{{version}}`</span> - The version_name or version from the manifest
|
||||
* - <span v-pre>`{{browser}}`</span> - The target browser from the `--browser` CLI flag
|
||||
* - <span v-pre>`{{mode}}`</span> - The current mode
|
||||
* - <span v-pre>`{{manifestVersion}}`</span> - Either "2" or "3"
|
||||
*
|
||||
* @default "{{name}}-{{version}}-{{browser}}.zip"
|
||||
*/
|
||||
@@ -127,10 +131,11 @@ export interface InlineConfig {
|
||||
*
|
||||
* Available template variables:
|
||||
*
|
||||
* - `{{name}}` - The project's name converted to kebab-case
|
||||
* - `{{version}}` - The version_name or version from the manifest
|
||||
* - `{{browser}}` - The target browser from the `--browser` CLI flag
|
||||
* - `{{manifestVersion}}` - Either "2" or "3"
|
||||
* - <span v-pre>`{{name}}`</span> - The project's name converted to kebab-case
|
||||
* - <span v-pre>`{{version}}`</span> - The version_name or version from the manifest
|
||||
* - <span v-pre>`{{browser}}`</span> - The target browser from the `--browser` CLI flag
|
||||
* - <span v-pre>`{{mode}}`</span> - The current mode
|
||||
* - <span v-pre>`{{manifestVersion}}`</span> - Either "2" or "3"
|
||||
*
|
||||
* @default "{{name}}-{{version}}-sources.zip"
|
||||
*/
|
||||
@@ -168,7 +173,7 @@ export interface InlineConfig {
|
||||
*
|
||||
* @example
|
||||
* [
|
||||
* "coverage", // Ignore the coverage directory in the `sourcesRoot`
|
||||
* "coverage", // Include the coverage directory in the `sourcesRoot`
|
||||
* ]
|
||||
*/
|
||||
excludeSources?: string[];
|
||||
@@ -226,6 +231,12 @@ export interface InlineConfig {
|
||||
* @default false
|
||||
*/
|
||||
enabled?: boolean;
|
||||
/**
|
||||
* Set to true to automatically open the `stats.html` file when the build is finished. When building in CI, the browser will never open.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
open?: boolean;
|
||||
/**
|
||||
* When running `wxt build --analyze` or setting `analysis.enabled` to true, customize how the
|
||||
* bundle will be visualized. See
|
||||
@@ -298,6 +309,12 @@ export interface InlineConfig {
|
||||
* Config effecting dev mode only.
|
||||
*/
|
||||
dev?: {
|
||||
server?: {
|
||||
/**
|
||||
* Port to run the dev server on. Defaults to the first open port from 3000 to 3010.
|
||||
*/
|
||||
port?: number;
|
||||
};
|
||||
/**
|
||||
* Controls whether a custom keyboard shortcut command, `Alt+R`, is added during dev mode to
|
||||
* quickly reload the extension.
|
||||
@@ -333,12 +350,39 @@ export interface InlineConfig {
|
||||
vite?: (env: ConfigEnv) => WxtViteConfig | Promise<WxtViteConfig>;
|
||||
}
|
||||
|
||||
// TODO: Move into @wxt/vite-builder
|
||||
export interface ResolvedConfig {
|
||||
vite: (env: ConfigEnv) => WxtViteConfig | Promise<WxtViteConfig>;
|
||||
}
|
||||
|
||||
// TODO: Move into @wxt/vite-builder
|
||||
export type WxtViteConfig = Omit<
|
||||
vite.UserConfig,
|
||||
'root' | 'configFile' | 'mode'
|
||||
>;
|
||||
|
||||
// TODO: Move into @wxt/vite-builder
|
||||
export interface WxtHooks {
|
||||
/**
|
||||
* Called when WXT has created Vite's config for a build step. Useful if you
|
||||
* want to add plugins or update the vite config per entrypoint group.
|
||||
*
|
||||
* @param entrypoints The list of entrypoints being built with the provided config.
|
||||
* @param viteConfig The config that will be used for the dev server.
|
||||
*/
|
||||
'vite:build:extendConfig': (
|
||||
entrypoints: readonly Entrypoint[],
|
||||
viteConfig: vite.InlineConfig,
|
||||
) => HookResult;
|
||||
/**
|
||||
* Called when WXT has created Vite's config for the dev server. Useful if
|
||||
* you want to add plugins or update the vite config per entrypoint group.
|
||||
*
|
||||
* @param viteConfig The config that will be used to build the entrypoints. Can be updated by reference.
|
||||
*/
|
||||
'vite:devServer:extendConfig': (config: vite.InlineConfig) => HookResult;
|
||||
}
|
||||
|
||||
export interface BuildOutput {
|
||||
manifest: Manifest.WebExtensionManifest;
|
||||
publicAssets: OutputAsset[];
|
||||
@@ -763,7 +807,7 @@ export interface ConfigEnv {
|
||||
/**
|
||||
* The command used to run WXT. `"serve"` during development and `"build"` for any other command.
|
||||
*/
|
||||
command: 'build' | 'serve';
|
||||
command: WxtCommand;
|
||||
/**
|
||||
* Browser passed in from the CLI via the `-b` or `--browser` flag. Defaults to `"chrome"` when not passed.
|
||||
*/
|
||||
@@ -776,6 +820,8 @@ export interface ConfigEnv {
|
||||
manifestVersion: 2 | 3;
|
||||
}
|
||||
|
||||
export type WxtCommand = 'build' | 'serve';
|
||||
|
||||
/**
|
||||
* Configure how the browser starts up.
|
||||
*/
|
||||
@@ -989,6 +1035,14 @@ export interface Wxt {
|
||||
* Package manager utilities.
|
||||
*/
|
||||
pm: WxtPackageManager;
|
||||
/**
|
||||
* If the dev server was started, it will be availble.
|
||||
*/
|
||||
server?: WxtDevServer;
|
||||
/**
|
||||
* The module in charge of executing all the build steps.
|
||||
*/
|
||||
builder: WxtBuilder;
|
||||
}
|
||||
|
||||
export interface ResolvedConfig {
|
||||
@@ -1007,7 +1061,7 @@ export interface ResolvedConfig {
|
||||
*/
|
||||
wxtModuleDir: string;
|
||||
mode: string;
|
||||
command: 'build' | 'serve';
|
||||
command: WxtCommand;
|
||||
browser: TargetBrowser;
|
||||
manifestVersion: TargetManifestVersion;
|
||||
env: ConfigEnv;
|
||||
@@ -1015,7 +1069,6 @@ export interface ResolvedConfig {
|
||||
imports: false | WxtResolvedUnimportOptions;
|
||||
manifest: UserManifest;
|
||||
fsCache: FsCache;
|
||||
server?: WxtDevServer;
|
||||
runnerConfig: C12ResolvedConfig<ExtensionRunnerConfig>;
|
||||
zip: {
|
||||
name?: string;
|
||||
@@ -1027,9 +1080,13 @@ export interface ResolvedConfig {
|
||||
downloadedPackagesDir: string;
|
||||
downloadPackages: string[];
|
||||
};
|
||||
transformManifest: (manifest: Manifest.WebExtensionManifest) => void;
|
||||
/**
|
||||
* @deprecated Use `build:manifestGenerated` hook instead.
|
||||
*/
|
||||
transformManifest?: (manifest: Manifest.WebExtensionManifest) => void;
|
||||
analysis: {
|
||||
enabled: boolean;
|
||||
open: boolean;
|
||||
template: NonNullable<PluginVisualizerOptions['template']>;
|
||||
/** Absolute file path to the `stats.html` file */
|
||||
outputFile: string;
|
||||
@@ -1047,11 +1104,15 @@ export interface ResolvedConfig {
|
||||
experimental: {
|
||||
includeBrowserPolyfill: boolean;
|
||||
};
|
||||
builder: WxtBuilder;
|
||||
dev: {
|
||||
/** Only defined during dev command */
|
||||
server?: {
|
||||
port: number;
|
||||
hostname: string;
|
||||
};
|
||||
reloadCommand: string | false;
|
||||
};
|
||||
hooks: Partial<WxtHooks>;
|
||||
hooks: NestedHooks<WxtHooks>;
|
||||
}
|
||||
|
||||
export interface FsCache {
|
||||
@@ -1064,12 +1125,6 @@ export interface ExtensionRunner {
|
||||
closeBrowser(): Promise<void>;
|
||||
}
|
||||
|
||||
export type VirtualEntrypointType =
|
||||
| 'content-script-main-world'
|
||||
| 'content-script-isolated-world'
|
||||
| 'background'
|
||||
| 'unlisted-script';
|
||||
|
||||
export type EslintGlobalsPropValue =
|
||||
| boolean
|
||||
| 'readonly'
|
||||
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
declare const __TEST_SEED__: number;
|
||||
@@ -1,4 +1,4 @@
|
||||
import definition from 'virtual:user-background';
|
||||
import definition from 'virtual:user-background-entrypoint';
|
||||
import { setupWebSocket } from './utils/setup-web-socket';
|
||||
import { logger } from '../sandbox/utils/logger';
|
||||
import { browser } from 'wxt/browser';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import definition from 'virtual:user-content-script-isolated-world';
|
||||
import definition from 'virtual:user-content-script-isolated-world-entrypoint';
|
||||
import { logger } from '../sandbox/utils/logger';
|
||||
import { ContentScriptContext } from 'wxt/client';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import definition from 'virtual:user-content-script-main-world';
|
||||
import definition from 'virtual:user-content-script-main-world-entrypoint';
|
||||
import { logger } from '../sandbox/utils/logger';
|
||||
|
||||
(async () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import definition from 'virtual:user-unlisted-script';
|
||||
import definition from 'virtual:user-unlisted-script-entrypoint';
|
||||
import { logger } from '../sandbox/utils/logger';
|
||||
|
||||
(async () => {
|
||||
|
||||
+4
-4
@@ -1,11 +1,11 @@
|
||||
// Types required to make the virtual modules happy.
|
||||
|
||||
declare module 'virtual:user-background' {
|
||||
declare module 'virtual:user-background-entrypoint' {
|
||||
const definition: { main: () => void };
|
||||
export default definition;
|
||||
}
|
||||
|
||||
declare module 'virtual:user-content-script-isolated-world' {
|
||||
declare module 'virtual:user-content-script-isolated-world-entrypoint' {
|
||||
const definition: {
|
||||
main: (
|
||||
ctx: import('wxt/client').ContentScriptContext,
|
||||
@@ -14,12 +14,12 @@ declare module 'virtual:user-content-script-isolated-world' {
|
||||
export default definition;
|
||||
}
|
||||
|
||||
declare module 'virtual:user-content-script-main-world' {
|
||||
declare module 'virtual:user-content-script-main-world-entrypoint' {
|
||||
const definition: { main: () => void | Promise<void> };
|
||||
export default definition;
|
||||
}
|
||||
|
||||
declare module 'virtual:user-unlisted-script' {
|
||||
declare module 'virtual:user-unlisted-script-entrypoint' {
|
||||
const definition: { main: () => void | Promise<void> };
|
||||
export default definition;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,6 @@
|
||||
"@types/react-dom": "^18.2.18",
|
||||
"@vitejs/plugin-react": "^4.2.1",
|
||||
"typescript": "^5.3.3",
|
||||
"wxt": "^0.16.0"
|
||||
"wxt": "^0.17.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,6 @@
|
||||
"devDependencies": {
|
||||
"typescript": "^5.3.3",
|
||||
"vite-plugin-solid": "^2.8.0",
|
||||
"wxt": "^0.16.0"
|
||||
"wxt": "^0.17.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,6 @@
|
||||
"svelte-check": "^3.6.2",
|
||||
"tslib": "^2.6.2",
|
||||
"typescript": "^5.3.3",
|
||||
"wxt": "^0.16.0"
|
||||
"wxt": "^0.17.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,6 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.3.3",
|
||||
"wxt": "^0.16.0"
|
||||
"wxt": "^0.17.0"
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"]
|
||||
"recommendations": ["Vue.volar"]
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^5.0.1",
|
||||
"typescript": "^5.3.3",
|
||||
"vue-tsc": "^1.8.27",
|
||||
"wxt": "^0.16.0"
|
||||
"vue-tsc": "^2.0.6",
|
||||
"wxt": "^0.17.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"extends": "./tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"types": ["vitest-plugin-random-seed/types"],
|
||||
"paths": {
|
||||
"~/*": ["./src/*"]
|
||||
}
|
||||
|
||||
+3
-16
@@ -1,20 +1,7 @@
|
||||
import { defineWorkspace } from 'vitest/config';
|
||||
import fs from 'fs-extra';
|
||||
import pc from 'picocolors';
|
||||
import type { Plugin } from 'vite';
|
||||
import path from 'node:path';
|
||||
|
||||
const seed = Math.round(Math.random() * Number.MAX_SAFE_INTEGER);
|
||||
console.info('Test seed: ' + pc.cyan(seed));
|
||||
|
||||
// config.define doesn't work with workspaces, so we have to set it inside a plugin
|
||||
const testSeed = (): Plugin => ({
|
||||
name: 'test-seed',
|
||||
config(config) {
|
||||
config.define ??= {};
|
||||
config.define.__TEST_SEED__ = JSON.stringify(seed);
|
||||
},
|
||||
});
|
||||
import RandomSeed from 'vitest-plugin-random-seed';
|
||||
|
||||
const resolve = {
|
||||
alias: {
|
||||
@@ -36,7 +23,7 @@ export default defineWorkspace([
|
||||
restoreMocks: true,
|
||||
setupFiles: 'vitest.setup.ts',
|
||||
},
|
||||
plugins: [testSeed()],
|
||||
plugins: [RandomSeed()],
|
||||
resolve,
|
||||
},
|
||||
{
|
||||
@@ -45,7 +32,7 @@ export default defineWorkspace([
|
||||
dir: 'e2e',
|
||||
testTimeout: 120e3,
|
||||
},
|
||||
plugins: [testSeed()],
|
||||
plugins: [RandomSeed()],
|
||||
resolve,
|
||||
},
|
||||
]);
|
||||
|
||||
Reference in New Issue
Block a user