Compare commits
163 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f32cdafdf6 | |||
| 2e2272d07a | |||
| 27ffff7e0a | |||
| 305cebe0d0 | |||
| 4602a068f8 | |||
| 3a947d72c6 | |||
| 1940e3530f | |||
| dd549dc686 | |||
| 3417bd3ed2 | |||
| 9470d2b696 | |||
| f523a7d31d | |||
| ea4c2b035b | |||
| c5bfba837f | |||
| c5ad957b25 | |||
| cc849e7cea | |||
| 22428da54d | |||
| f6071f7e2d | |||
| 08e8560865 | |||
| 75f01db543 | |||
| 5a028d2551 | |||
| 07a4ba8bc5 | |||
| f84921f735 | |||
| 872494e490 | |||
| d0848b0be5 | |||
| c848956777 | |||
| 296997d10e | |||
| ffdb22238c | |||
| a63c320403 | |||
| aa86ed78a3 | |||
| 19456ec855 | |||
| 2c57840c44 | |||
| 26b7927f62 | |||
| d4267af725 | |||
| 16a2aedcd0 | |||
| 755f04f777 | |||
| cf9539ddab | |||
| 99d558f33c | |||
| 1fe073004b | |||
| 6ae5fb5edb | |||
| 3a3953edf6 | |||
| c8e788eaf8 | |||
| 088a44496d | |||
| 60a57c5abc | |||
| 482466bbbf | |||
| 65deb7317b | |||
| 00ae061822 | |||
| 9bd7fc1bd5 | |||
| 98ddb83f1d | |||
| 6dd8b9d072 | |||
| 1e3482a878 | |||
| 734846843f | |||
| f1eac66494 | |||
| b4c3280f58 | |||
| b2f2998767 | |||
| 720eb93c67 | |||
| cdf8611e0b | |||
| 905d797b65 | |||
| 6ca8ccc332 | |||
| 76496e8865 | |||
| f38fec8588 | |||
| 4351ac9657 | |||
| f3834ac0e2 | |||
| 48891a7ca5 | |||
| 3b6a4aa635 | |||
| b20f0471c2 | |||
| 0f9e66e1e8 | |||
| 6fb4cee43f | |||
| 0e8afbbf56 | |||
| 83decf7bf5 | |||
| 5c77cf23b8 | |||
| 606fd3164c | |||
| 71308d0d6f | |||
| 8bbea7cda4 | |||
| a87d3e4809 | |||
| 1f3db58254 | |||
| 43f6c06271 | |||
| 04ae542b13 | |||
| f97c81df0d | |||
| b7b3fc53eb | |||
| 4b44fb849d | |||
| 5d0a266e9c | |||
| 24667861db | |||
| 25cc403886 | |||
| 923312c482 | |||
| adeef6eb73 | |||
| 6f84d45960 | |||
| 938c25cab4 | |||
| 0404637da8 | |||
| 98d95e4b7f | |||
| 2687a35781 | |||
| 886dae28fa | |||
| 8c9bc8cdbc | |||
| 5414a0aa34 | |||
| 223cf8613b | |||
| 4f1776befc | |||
| 38473b9f6c | |||
| 41b428c75f | |||
| d8d754658f | |||
| e52ebf1d53 | |||
| 535c7a5f92 | |||
| 99b2bd784a | |||
| 31ebf966fd | |||
| 6036c6e8e0 | |||
| 597151b5dd | |||
| 29aeaed223 | |||
| edf87952c7 | |||
| 78f8434a06 | |||
| 7eaccad683 | |||
| bfa9c1e1c8 | |||
| a2d6577579 | |||
| 0e8191488f | |||
| a1510bb081 | |||
| 1eaca30f97 | |||
| bc79987ed5 | |||
| 36a501506e | |||
| e1d47f5f63 | |||
| 7faa9b5a64 | |||
| 295bee708c | |||
| 9e917481c4 | |||
| c5a8b9fb3d | |||
| 3f4e32f8da | |||
| f630098f1d | |||
| 608d6e2b54 | |||
| fad5ab6c44 | |||
| d4cb7997fe | |||
| 28364b8be1 | |||
| d28a5c7d5e | |||
| df707aef4c | |||
| 77af2e58ec | |||
| f738e56337 | |||
| f2fe2584e0 | |||
| 02673ae017 | |||
| 8dd294a163 | |||
| 469e735d53 | |||
| b02001796e | |||
| 0d4d2fdd7e | |||
| b65e5446fa | |||
| f75fe3ce5b | |||
| 59ba2712cf | |||
| fefe601541 | |||
| 7291c60413 | |||
| bb679102b1 | |||
| 16027c8971 | |||
| 84405a33e3 | |||
| bdf795c3f2 | |||
| ab73084bb5 | |||
| e9fb4c5414 | |||
| bc54f525e4 | |||
| 9170159bc1 | |||
| fa657a0366 | |||
| 24920ddd52 | |||
| eb0b372113 | |||
| 8f5f4f674e | |||
| 38c1dae9c7 | |||
| f92bcd1d14 | |||
| df09b86d23 | |||
| bd5cfa10ad | |||
| 94914dd1ad | |||
| dfbb58a2f1 | |||
| 54a1c3576f | |||
| 9ddf73b4fe | |||
| 4ceec1a6ab | |||
| ba314d7434 |
@@ -18,7 +18,7 @@ runs:
|
||||
uses: pnpm/action-setup@f2b2b233b538f500472c7274c7012f57857d8ce0 # v4.1.0
|
||||
|
||||
- name: 🛠️ Setup NodeJS
|
||||
uses: actions/setup-node@b7234cc9fe124f0f4932554b4e5284543083ae7b # v4.4.0
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
with:
|
||||
node-version: 20
|
||||
cache: pnpm
|
||||
|
||||
@@ -1,32 +1,35 @@
|
||||
name: 🔔 Notify Unreleased Commits
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 20 * * 1' # Weekly at 8 PM UTC (3 PM CT)
|
||||
|
||||
jobs:
|
||||
notify:
|
||||
runs-on: ubuntu-22.04
|
||||
if: github.repository_owner == 'wxt-dev'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: List Commits
|
||||
id: list-commits
|
||||
run: |
|
||||
OUTPUT="$(./scripts/list-unreleased-commits.sh)"
|
||||
echo "::set-output name=summary::${OUTPUT}"
|
||||
./scripts/list-unreleased-commits.sh > summary.txt
|
||||
|
||||
- name: Discord notification
|
||||
uses: Ilshidur/action-discord@d2594079a10f1d6739ee50a2471f0ca57418b554
|
||||
run: |
|
||||
PAYLOAD=$(jq -n --arg content "${{ env.MESSAGE }}" '{"content": $content}')
|
||||
curl -X POST \
|
||||
-F "payload_json=${PAYLOAD}" \
|
||||
-F "file1=@summary.txt" \
|
||||
$DISCORD_WEBHOOK
|
||||
env:
|
||||
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK_UNRELEASED_COMMITS }}
|
||||
with:
|
||||
args: |
|
||||
```
|
||||
{{ steps.list-commits.outputs.summary }}
|
||||
```
|
||||
|
||||
If a package needs released, please [run the workflow](https://github.com/wxt-dev/wxt/actions/workflows/release.yml).
|
||||
MESSAGE: |
|
||||
If a package needs released, please [run the workflow](<https://github.com/wxt-dev/wxt/actions/workflows/release.yml>).
|
||||
|
||||
Before running, consider:
|
||||
- Are there any breaking changes? If so, prepare a list of breaking changes and update the changelog and release notes after the release.
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
if: ${{ github.repository == 'wxt-dev/wxt' }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Setup
|
||||
uses: ./.github/actions/setup
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Post Thank You Comment
|
||||
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
||||
env:
|
||||
comment: Thanks for helping make WXT better!
|
||||
with:
|
||||
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
# Only fetch the config file from the repository
|
||||
sparse-checkout-cone-mode: false
|
||||
|
||||
@@ -23,13 +23,13 @@ jobs:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Setup
|
||||
uses: ./.github/actions/setup
|
||||
|
||||
- name: Login to Docker Registry
|
||||
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
|
||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
|
||||
with:
|
||||
registry: https://${{ secrets.DOCKER_REGISTRY_HOSTNAME }}
|
||||
username: ${{ secrets.DOCKER_REGISTRY_USERNAME }}
|
||||
|
||||
@@ -31,14 +31,15 @@ jobs:
|
||||
|
||||
publish:
|
||||
name: Publish
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
contents: write
|
||||
contents: write # Push version changes
|
||||
id-token: write # OIDC for NPM publishing
|
||||
needs:
|
||||
- validate
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ssh-key: ${{ secrets.DEPLOY_KEY }} # https://github.com/sbellone/release-workflow-example
|
||||
@@ -61,9 +62,9 @@ jobs:
|
||||
- name: Publish to NPM
|
||||
working-directory: packages/${{ inputs.package }}
|
||||
run: |
|
||||
echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_AUTH_TOKEN }}" > ~/.npmrc
|
||||
pnpm build
|
||||
pnpm publish
|
||||
pnpm pack
|
||||
sudo npm i -g npm@latest
|
||||
/usr/local/bin/npm publish *.tgz
|
||||
|
||||
- name: Create GitHub release
|
||||
run: pnpm tsx scripts/create-github-release.ts ${{ inputs.package }}
|
||||
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Setup
|
||||
uses: ./.github/actions/setup
|
||||
|
||||
@@ -11,11 +11,15 @@ jobs:
|
||||
sync:
|
||||
name: 'Sync with @types/chrome'
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository_owner == 'wxt-dev'
|
||||
permissions:
|
||||
contents: write
|
||||
contents: write # Push version changes
|
||||
id-token: write # OIDC for NPM publishing
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
ssh-key: ${{ secrets.DEPLOY_KEY }}
|
||||
|
||||
- name: Setup
|
||||
uses: ./.github/actions/setup
|
||||
@@ -32,15 +36,16 @@ jobs:
|
||||
|
||||
- name: Commit Changes
|
||||
id: commit
|
||||
uses: stefanzweifel/git-auto-commit-action@01d77ca6cb089da1360e540865f7d035c95aa199 # v6.0.1
|
||||
uses: stefanzweifel/git-auto-commit-action@04702edda442b2e678b25b537cec683a1493fcb9 # v7.1.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
commit_message: 'fix: Upgrade `@wxt-dev/browser` to latest `@types/chrome` version'
|
||||
|
||||
- name: Publish Package
|
||||
- name: Publish to NPM
|
||||
if: steps.commit.outputs.changes_detected == 'true'
|
||||
working-directory: packages/browser
|
||||
run: |
|
||||
echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_AUTH_TOKEN }}" > ~/.npmrc
|
||||
pnpm publish
|
||||
pnpm pack
|
||||
sudo npm i -g npm@latest
|
||||
/usr/local/bin/npm publish *.tgz
|
||||
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Setup
|
||||
uses: ./.github/actions/setup
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Setup
|
||||
uses: ./.github/actions/setup
|
||||
@@ -41,7 +41,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Setup
|
||||
uses: ./.github/actions/setup
|
||||
@@ -68,13 +68,13 @@ jobs:
|
||||
coverage: false
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Setup
|
||||
uses: ./.github/actions/setup
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@22457c87c1b161cf7dde222c3e82b2b5f8d2bed2 # v2.0.2
|
||||
uses: oven-sh/setup-bun@3d267786b128fe76c2f16a390aa2448b815359f3 # v2.1.2
|
||||
|
||||
- name: Run Tests
|
||||
if: ${{ ! matrix.coverage }}
|
||||
@@ -86,7 +86,7 @@ jobs:
|
||||
|
||||
- name: Upload Coverage
|
||||
if: matrix.coverage
|
||||
uses: codecov/codecov-action@fdcc8476540edceab3de004e990f80d881c6cc00 # v5.5.0
|
||||
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
@@ -104,7 +104,7 @@ jobs:
|
||||
- vue
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Setup
|
||||
uses: ./.github/actions/setup
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Setup
|
||||
uses: ./.github/actions/setup
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
path: 'docs/tapes/init-demo.tape'
|
||||
|
||||
- name: Save recorded GIF
|
||||
uses: stefanzweifel/git-auto-commit-action@01d77ca6cb089da1360e540865f7d035c95aa199 # v6.0.1
|
||||
uses: stefanzweifel/git-auto-commit-action@04702edda442b2e678b25b537cec683a1493fcb9 # v7.1.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
|
||||
Vendored
+2
-1
@@ -10,5 +10,6 @@
|
||||
// Additional guidelines for Copilot
|
||||
"github.copilot.chat.codeGeneration.instructions": [
|
||||
{ "file": "CONTRIBUTING.md" }
|
||||
]
|
||||
],
|
||||
"oxc.enable": true
|
||||
}
|
||||
|
||||
@@ -6,6 +6,19 @@ If you are changing the docs or fixing a bug, feel free to fork and open a PR.
|
||||
|
||||
If you want to add a new feature, please create an issue or discussion first so we can decide if the feature is inline with the vision for WXT.
|
||||
|
||||
## WXT's Vision
|
||||
|
||||
WXT is two things:
|
||||
|
||||
1. A build tool
|
||||
2. A set of runtime utilities
|
||||
|
||||
The long term goal of WXT is provide an opinionated build tool that keeps WXT projects standard, while providing light-weight runtime utils that simplify a lot of the boilerplate/overhead when setting up a new extension.
|
||||
|
||||
I also want to provide a way for developers to use either one of those two things independently, and not require them to use both. This is why all of WXT's runtime utils are shipped as their own NPM packages, most of them not bundled inside the core `wxt` package. If you just want to use the packages, they're availalbe, and if you just want to use WXT's built tool, you don't have to import any of WXT's utilities, you can use your own.
|
||||
|
||||
> The few runtime utils shipped inside WXT are things that should be used by 90% of extensions. That said, they're also legacy utils left in from before I started creating separate NPM packages, and in the future, they may be removed from the core package.
|
||||
|
||||
## Conventional Commits
|
||||
|
||||
This project uses [Conventional Commit format](https://www.conventionalcommits.org/en/v1.0.0/) to automatically generate a changelog and better understand the changes in the project
|
||||
@@ -20,6 +33,19 @@ Here are some examples of conventional commit messages:
|
||||
|
||||
The title of your pull request should follow the [conventional commit format](#conventional-commits). When a pull request is merged to the main branch, all changes are going to be squashed into a single commit. The message of this commit will be the title of the pull request. And for every release, the commit messages are used to generate the changelog.
|
||||
|
||||
## Breaking Changes Policy
|
||||
|
||||
A quick word on WXT's breaking changes policy. I am willing to make breaking changes, but they have to be for a good enough reason - they have to make WXT better as a whole, they can't be based on one opinion.
|
||||
|
||||
Breaking changes also require a major release. Major releases have happened once or twice a year, so after you merge your PR, you'll have to wait a little bit before it is released.
|
||||
|
||||
To make a breaking change:
|
||||
|
||||
1. Make sure you're PR is targeting the `major` branch
|
||||
2. Add `!` after the conventional commit type (`fix!: ...`, `feat!: ...`, `chore!: ...`, etc) to indicate that it is a breaking change
|
||||
3. At the top of the PR, provide documentation that will inform developers about the breaking change, why it was done, and how to migrate their extension so nothing breaks.
|
||||
- This documentation will be put ["Upgrading WXT"](https://wxt.dev/guide/resources/upgrading.html) page in the docs, read through previous breaking change docs for an idea of what is required.
|
||||
|
||||
## Setup
|
||||
|
||||
WXT uses `pnpm`, so make sure you have it installed.
|
||||
@@ -188,3 +214,9 @@ Anyone is welcome to submit a blog post on <https://wxt.dev/blog>!
|
||||
|
||||
- **English only**: Blog posts should be written in English. Unfortunately, our maintainers don't have the bandwidth right now to translate our docs, let alone blog posts. Sorry 😓
|
||||
- **AI**: Please only use AI to translate or proof-read your blog post. Don't generate the whole thing... We don't want to publish that.
|
||||
|
||||
## Become a Maintainer
|
||||
|
||||
If you're interested in becoming a maintainer, send an email to Aaron at <aaronklinker1@gmail.com> with your github username saying you're interested. The process is very informal, I will add you quickly if you've contributed code or answered questions and helped out the community!
|
||||
|
||||
Maintainers don't have to just write code - they can manage issues, answer questsions, review PRs, organize and prioritize work - there's lots of ways for you to help out.
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
# Maintainers
|
||||
|
||||
A couple of things for you to consider before merging a PR or giving the go-ahead on a feature proposal.
|
||||
|
||||
## Be picky about new features and packages
|
||||
|
||||
We are responsible for maintaining them and fixing related bugs after the PR is merged. The community can always release their own WXT modules or packages, not everything needs to be built into WXT.
|
||||
|
||||
## Prefer standards over customization
|
||||
|
||||
Don't merge PRs that just add another way to do something, like [this one](https://github.com/wxt-dev/wxt/pull/2053#issuecomment-3857010196).
|
||||
|
||||
WXT is opinionated, if you have questions about what is WXT's opinion or we need to create a new one, create an issue and @ me to discuss.
|
||||
|
||||
## PRs should be small and targeted
|
||||
|
||||
A PR should make one change. They should not make any unrelated changes outside of accomplishing the one thing. This makes PRs easier to review and they get merged more quickly - a win-win for everyone.
|
||||
|
||||
## `@wxt-dev/*` packages are separate
|
||||
|
||||
We can't make changes to these packages assuming people are using them only with WXT. For example, I almost missed [this PR](https://github.com/wxt-dev/wxt/pull/2049#issuecomment-3861251599).
|
||||
|
||||
I want these packages to be usable on their own so if people don't like WXT's build tool, they can still use our other awesome packages.
|
||||
|
||||
## Minimize dependencies
|
||||
|
||||
I don't like how heavy lots of frameworks are. It's unavoidable to a certain extent, but if you can do something without another dependency, try to.
|
||||
|
||||
If you need a dependency, look for one with zero dependencies and that's respectable.
|
||||
|
||||
## Look at milestones
|
||||
|
||||
I've organized WXT's long term plans into [milestones](https://github.com/wxt-dev/wxt/milestones), check those out to get an idea of my priorities for some of the larger features.
|
||||
|
||||
## Require tests
|
||||
|
||||
If someone opens a PR to fix a bug but doesn't include tests, don't merge the PR. Tests are required to prevent regressions and maintain a codebase long term.
|
||||
|
||||
## Ask for reproductions for bugs
|
||||
|
||||
You don't need to triage bugs if someone doesn't give you enough information. You can always ask for a repo with a reproduction or wait for more details.
|
||||
|
||||
If there's not an easy way to reproduce a bug, you're wasting your time triaging it. Just be mindful of your own time!
|
||||
|
||||
Here's an example of how to ask for a reproduction: <https://github.com/wxt-dev/wxt/issues/2064#issuecomment-3862579110>. You could be more blunt than this.
|
||||
|
||||
## Add yourself as a code owner
|
||||
|
||||
If you want to be responsible for a specific package or directory, add yourself to the [`.github/CODEOWNERS`](https://github.com/wxt-dev/wxt/blob/main/.github/CODEOWNERS) file to get added as a reviewer to PRs automatically. You can also add yourself to the default list to be added as a reviewer on all PRs.
|
||||
@@ -102,6 +102,21 @@ const chromeExtensionIds = [
|
||||
'ehmoihnjgkdimihkhokkmfjdgomohjgm', // Filmbudd Pro - Simple, private – and synced ratings and watch notes across all your devices
|
||||
'alglchohmdikgdjhafiicilegegieafa', // MultiField CopyCat - Copy, Paste & Autofill Web Forms Instantly
|
||||
'aamihahiiogceidpbnfgehacgiecephe', // ChatSight - Add Table of Contents to ChatGPT
|
||||
'cndibmoanboadcifjkjbdpjgfedanolh', // BetterCampus (prev. BetterCanvas)
|
||||
'hinfimgacobnellbncbcpdlpaapcofaa', // Leetcode Fonts - Change fonts in leetcode effortlessly
|
||||
'kbkbfefhhabpkibojinapkkgciiacggg', // TranslateManga - Manga Translator & Manga Tracker
|
||||
'emeakbgdecgmdjgegnejpppcnkcnoaen', // SiteData - Free Website Traffic Checker & Reverse AdSense Tool
|
||||
'gpnckbhgpnjciklpoehkmligeaebigaa', // Livestream Chat Reader - Text-to-Speech for YouTube/Twitch chat
|
||||
'fjlalaedpfcojcfpkgkglbjjbbkofgnl', // ChatGPT Token Counter - Count tokens in real time on chatgpt conversation
|
||||
'fbgblmjbeebanackldpbmpacppflgmlj', // LinuxDo Scripts - 为 linux.do 用户提供了一些增强功能
|
||||
'dfacnjidgbagicaekenjgclfnhdnjjdi', // Zen Virtual Piano - https://zen-piano.web.app/
|
||||
'naeibcegmgpofimedkmfgjgphfhfhlab', // Crypto Pulse price tracker - https://get-crypto-pulse.web.app/
|
||||
'ffglckbhfbfmdkefdmjbhpnffkcmlhdh', // Redirect Web - Automatically redirect pages or open them in another app
|
||||
'eglpfhbhmelampoihamjomgkeobgdofl', // Capture It - Capture & Edit Screenshots
|
||||
'jmghclbfbbapimhbgnpffbimphlpolnm', // Teams Chat Exporter
|
||||
'jdcppdokgfbnhiacbeplahgnciahnhck', // Lofi BGM Player - Free lofi focus music for work & study
|
||||
'cgpmbiiagnehkikhcbnhiagfomajncpa', // Margin - Annotate and highlight any webpage, with your notes saved to the decentralized AT Protocol.
|
||||
'mfjdonmgmgcijagclnkfhmjiblbfjaid', // KeyFloat - Floating multilingual keyboard with native key mappings, drag, dark mode, sounds, and dynamic layouts for macOS & Windows
|
||||
];
|
||||
|
||||
const { data, err, isLoading } = useListExtensionDetails(chromeExtensionIds);
|
||||
|
||||
@@ -25,6 +25,7 @@ import {
|
||||
import { Feed } from 'feed';
|
||||
import { writeFile } from 'node:fs/promises';
|
||||
import { join } from 'node:path';
|
||||
import llmstxt from 'vitepress-plugin-llms';
|
||||
|
||||
const origin = 'https://wxt.dev';
|
||||
|
||||
@@ -71,6 +72,7 @@ export default defineConfig({
|
||||
vite: {
|
||||
clearScreen: false,
|
||||
plugins: [
|
||||
llmstxt(),
|
||||
groupIconVitePlugin({
|
||||
customIcon: {
|
||||
'wxt.config.ts': localIconLoader(
|
||||
|
||||
@@ -32,6 +32,8 @@ You can configure browser startup in 3 places:
|
||||
To set or customize the browser opened during development:
|
||||
|
||||
```ts [web-ext.config.ts]
|
||||
import { defineWebExtConfig } from 'wxt';
|
||||
|
||||
export default defineWebExtConfig({
|
||||
binaries: {
|
||||
chrome: '/path/to/chrome-beta', // Use Chrome Beta instead of regular Chrome
|
||||
@@ -41,6 +43,18 @@ export default defineWebExtConfig({
|
||||
});
|
||||
```
|
||||
|
||||
```ts [wxt.config.ts]
|
||||
export default defineConfig({
|
||||
webExt: {
|
||||
binaries: {
|
||||
chrome: '/path/to/chrome-beta', // Use Chrome Beta instead of regular Chrome
|
||||
firefox: 'firefoxdeveloperedition', // Use Firefox Developer Edition instead of regular Firefox
|
||||
edge: '/path/to/edge', // Open MS Edge when running "wxt -b edge"
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
By default, WXT will try to automatically discover where Chrome/Firefox are installed. However, if you have chrome installed in a non-standard location, you need to set it manually as shown above.
|
||||
|
||||
### Persist Data
|
||||
@@ -49,11 +63,13 @@ By default, to keep from modifying your browser's existing profiles, `web-ext` c
|
||||
|
||||
Right now, Chromium based browsers are the only browsers that support overriding this behavior and persisting data when running the `dev` script multiple times.
|
||||
|
||||
To persist data, set the `--user-data-dir` flag:
|
||||
To persist data, set the `--user-data-dir` flag in any of the config files mentioned above:
|
||||
|
||||
:::code-group
|
||||
|
||||
```ts [Mac/Linux]
|
||||
import { defineWebExtConfig } from 'wxt';
|
||||
|
||||
export default defineWebExtConfig({
|
||||
chromiumArgs: ['--user-data-dir=./.wxt/chrome-data'],
|
||||
});
|
||||
@@ -61,6 +77,7 @@ export default defineWebExtConfig({
|
||||
|
||||
```ts [Windows]
|
||||
import { resolve } from 'node:path';
|
||||
import { defineWebExtConfig } from 'wxt';
|
||||
|
||||
export default defineWebExtConfig({
|
||||
// On Windows, the path must be absolute
|
||||
@@ -82,7 +99,30 @@ You can use any directory you'd like for `--user-data-dir`, the examples above c
|
||||
If you prefer to load the extension into your browser manually, you can disable the auto-open behavior:
|
||||
|
||||
```ts [web-ext.config.ts]
|
||||
import { defineWebExtConfig } from 'wxt';
|
||||
|
||||
export default defineWebExtConfig({
|
||||
disabled: true,
|
||||
});
|
||||
```
|
||||
|
||||
### Enabling Chrome Features
|
||||
|
||||
Some APIs are disabled in Chrome during development because of the default flags `web-ext` uses to launch Chrome, like the [Prompt API](https://developer.chrome.com/docs/ai/prompt-api).
|
||||
|
||||
If your extension depends on new features or services, you can enable them via `chromiumArgs`:
|
||||
|
||||
```ts
|
||||
import { defineWebExtConfig } from 'wxt';
|
||||
|
||||
export default defineWebExtConfig({
|
||||
chromiumArgs: [
|
||||
// For example, this flag enables the Prompt API
|
||||
'--disable-features=DisableLoadExtensionCommandLineSwitch',
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
There is no comprehensive list of what feature flags enable what APIs and services.
|
||||
|
||||
Alternatively, if you can't find a flag that enables a feature you're looking for, [disable the opening the browser during development](#disable-opening-browser) and use your regular chrome profile for development.
|
||||
|
||||
@@ -11,7 +11,7 @@ export default defineConfig({
|
||||
hooks: {
|
||||
'build:manifestGenerated': (wxt, manifest) => {
|
||||
if (wxt.config.mode === 'development') {
|
||||
manifest.title += ' (DEV)';
|
||||
manifest.name += ' (DEV)';
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -20,6 +20,8 @@ export default defineConfig({
|
||||
|
||||
Most hooks provide the `wxt` object as the first argument. It contains the resolved config and other info about the current build. The other arguments can be modified by reference to change different parts of the build system.
|
||||
|
||||
You can find the [list of all available hooks](/api/reference/wxt/interfaces/WxtHooks) in the API reference.
|
||||
|
||||
Putting one-off hooks like this in your config file is simple, but if you find yourself writing lots of hooks, you should extract them into [WXT Modules](/guide/essentials/wxt-modules) instead.
|
||||
|
||||
## Execution Order
|
||||
|
||||
@@ -591,6 +591,76 @@ For MV3, `injectScript` is synchronous and the injected script will be evaluated
|
||||
However for MV2, `injectScript` has to `fetch` the script's text content and create an inline `<script>` block. This means for MV2, your script is injected asynchronously and it will not be evaluated at the same time as your content script's `run_at`.
|
||||
:::
|
||||
|
||||
The `script` element can be modified just before it is added to the DOM by using the `modifyScript` option. This can be used to e.g. modify `script.async`/`script.defer`, add event listeners to the element, or pass data to the script via `script.dataset`. An example:
|
||||
|
||||
```ts
|
||||
// entrypoints/example.content.ts
|
||||
export default defineContentScript({
|
||||
matches: ['*://*/*'],
|
||||
async main() {
|
||||
await injectScript('/example-main-world.js', {
|
||||
modifyScript(script) {
|
||||
script.dataset['greeting'] = 'Hello there';
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
```ts
|
||||
// entrypoints/example-main-world.ts
|
||||
export default defineUnlistedScript(() => {
|
||||
console.log(document.currentScript?.dataset['greeting']);
|
||||
});
|
||||
```
|
||||
|
||||
`injectScript` returns the created script element. It can be used to e.g. send messages to the script in the form of custom events. The script can add an event listener for them via `document.currentScript`. An example of bidirectional communication:
|
||||
|
||||
```ts
|
||||
// entrypoints/example.content.ts
|
||||
export default defineContentScript({
|
||||
matches: ['*://*/*'],
|
||||
async main() {
|
||||
const { script } = await injectScript('/example-main-world.js', {
|
||||
modifyScript(script) {
|
||||
// Add a listener before the injected script is loaded.
|
||||
script.addEventListener('from-injected-script', (event) => {
|
||||
if (event instanceof CustomEvent) {
|
||||
console.log(`${event.type}:`, event.detail);
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
// Send an event after the injected script is loaded.
|
||||
script.dispatchEvent(
|
||||
new CustomEvent('from-content-script', {
|
||||
detail: 'General Kenobi',
|
||||
}),
|
||||
);
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
```ts
|
||||
// entrypoints/example-main-world.ts
|
||||
export default defineUnlistedScript(() => {
|
||||
const script = document.currentScript;
|
||||
|
||||
script?.addEventListener('from-content-script', (event) => {
|
||||
if (event instanceof CustomEvent) {
|
||||
console.log(`${event.type}:`, event.detail);
|
||||
}
|
||||
});
|
||||
|
||||
script?.dispatchEvent(
|
||||
new CustomEvent('from-injected-script', {
|
||||
detail: 'Hello there',
|
||||
}),
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
## Mounting UI to dynamic element
|
||||
|
||||
In many cases, you may need to mount a UI to a DOM element that does not exist at the time the web page is initially loaded. To handle this, use the `autoMount` API to automatically mount the UI when the target element appears dynamically and unmount it when the element disappears. In WXT, the `anchor` option is used to target the element, enabling automatic mounting and unmounting based on its appearance and removal.
|
||||
|
||||
@@ -470,6 +470,19 @@ When you define a Newtab entrypoint, WXT will automatically update the manifest
|
||||
/>
|
||||
<meta name="manifest.type" content="page_action|browser_action" />
|
||||
<meta name="manifest.browser_style" content="true|false" />
|
||||
<!-- Firefox only: where to place the action button -->
|
||||
<meta
|
||||
name="manifest.default_area"
|
||||
content="navbar|menupanel|tabstrip|personaltoolbar"
|
||||
/>
|
||||
<!-- Firefox only: icons for light/dark themes -->
|
||||
<meta
|
||||
name="manifest.theme_icons"
|
||||
content="[
|
||||
{ light: '/icon-light-16.png', dark: '/icon-dark-16.png', size: 16 },
|
||||
{ light: '/icon-light-32.png', dark: '/icon-dark-32.png', size: 32 }
|
||||
]"
|
||||
/>
|
||||
|
||||
<!-- Set include/exclude if the page should be removed from some builds -->
|
||||
<meta name="manifest.include" content="['chrome', ...]" />
|
||||
|
||||
@@ -9,7 +9,7 @@ WXT provides first class support for Vitest for unit testing:
|
||||
```ts
|
||||
// vitest.config.ts
|
||||
import { defineConfig } from 'vitest/config';
|
||||
import { WxtVitest } from 'wxt/testing';
|
||||
import { WxtVitest } from 'wxt/testing/vitest-plugin';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [WxtVitest()],
|
||||
@@ -36,7 +36,7 @@ This example demonstrates that you don't have to mock `browser.storage` (used by
|
||||
|
||||
```ts
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { fakeBrowser } from 'wxt/testing';
|
||||
import { fakeBrowser } from 'wxt/testing/fake-browser';
|
||||
|
||||
const accountStorage = storage.defineItem<Account>('local:account');
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ Each module's setup function is executed after the `wxt.config.ts` file is loade
|
||||
|
||||
Refer to the [API reference](/api/reference/wxt/interfaces/Wxt) for a complete list of properties and functions available.
|
||||
|
||||
Also to make sure and read about all the [hooks that are available](https://wxt.dev/api/reference/wxt/interfaces/WxtHooks) - they are essential to writing modules.
|
||||
Also make sure to read about [all the hooks that are available](/api/reference/wxt/interfaces/WxtHooks) - they are essential to writing modules.
|
||||
|
||||
### Recipes
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ This page is dedicated to all the awesome people how have made something for WXT
|
||||
## Blog Posts
|
||||
|
||||
- [Building Modern Cross Browser Web Extensions](https://aabidk.dev/tags/wxt/) by Aabid ([@aabidk20](https://github.com/aabidk20))
|
||||
- [Building Browser Extensions with WXT](https://rxliuli.com/blog/browser-extension-dev-01-introduction-to-basic-concepts/) by rxliuli ([@rxliuli](https://github.com/rxliuli))
|
||||
|
||||
## NPM Packages
|
||||
|
||||
|
||||
@@ -164,6 +164,10 @@ Both issues have the same cause: the library puts something outside the `ShadowR
|
||||
|
||||
Both issues have the same fix: tell the library to put elements inside the `ShadowRoot`, not outside it. See the details above for more information and example fixes for each problem.
|
||||
|
||||
## Does WXT provide docs for LLMs?
|
||||
|
||||
Yes, WXT's documentation provides markdown files based on the [the /llms.txt proposal](https://llmstxt.org/).
|
||||
|
||||
## Is there an LLM trained on WXT's docs that I chat with?
|
||||
|
||||
Yes! There's a "Ask AI" button in the bottom right of the page, try it out! Or visit <https://knowledge.wxt.dev/> for a fullscreen experience.
|
||||
@@ -186,3 +190,33 @@ To run the WXT dev server in a devcontainer, but load the dev build of your exte
|
||||
|
||||
3. **Tell WXT to listen on all network interfaces**
|
||||
To enable hot-reloading, your extension has to connect to the WXT dev server running inside your container. WXT will only listen on `localhost` by default, which prevents connections from outside the devcontainer. To fix this you can instruct WXT to listen on all interfaces with `wxt --host 0.0.0.0`.
|
||||
|
||||
## How do I use the new Prompt API in Chrome?
|
||||
|
||||
The service responsible for the [Prompt API](https://developer.chrome.com/docs/ai/prompt-api) is not enabled by default if you let WXT open the browser during dev mode. When checking `LanguageModel.availability`, you will always receive "unavailable".
|
||||
|
||||
You have two options:
|
||||
|
||||
1. Pass the `--disable-features=DisableLoadExtensionCommandLineSwitch` feature flag to enable the service in the browser WXT opens:
|
||||
|
||||
```ts
|
||||
// wxt.config.ts
|
||||
export default defineConfig({
|
||||
webExt: {
|
||||
chromiumArgs: [
|
||||
'--disable-features=DisableLoadExtensionCommandLineSwitch',
|
||||
],
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
2. Disable the runner and install your extension in your regular chrome profile manually:
|
||||
|
||||
```ts
|
||||
// wxt.config.ts
|
||||
export default defineConfig({
|
||||
webExt: {
|
||||
disabled: true,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
@@ -15,6 +15,11 @@ cd path/to/your/project
|
||||
pnpm dlx wxt@latest init example-wxt --template vanilla
|
||||
```
|
||||
|
||||
:::tip
|
||||
We recommend reviewing [project structure](/guide/essentials/project-structure.md) before you get started.
|
||||
You can customize directory names in `wxt.config.ts` to match your project's needs.
|
||||
:::
|
||||
|
||||
In general, you'll need to:
|
||||
|
||||
 <input type="checkbox" /> Install `wxt`<br />
|
||||
|
||||
+21
-30
@@ -4,49 +4,51 @@
|
||||
"engines": {
|
||||
"node": ">=18.20.3"
|
||||
},
|
||||
"packageManager": "pnpm@10.15.1",
|
||||
"packageManager": "pnpm@10.29.2+sha512.bef43fa759d91fd2da4b319a5a0d13ef7a45bb985a3d7342058470f9d2051a3ba8674e629672654686ef9443ad13a82da2beb9eeb3e0221c87b8154fff9d74b8",
|
||||
"scripts": {
|
||||
"check": "check && pnpm -r --sequential run check",
|
||||
"test": "pnpm -r --sequential run test run",
|
||||
"test:coverage": "pnpm -r --sequential run test:coverage",
|
||||
"prepare": "simple-git-hooks",
|
||||
"prepublish": "pnpm -s build",
|
||||
"docs:gen": "typedoc --options docs/typedoc.json",
|
||||
"docs:dev": "pnpm -s docs:gen && vitepress dev docs",
|
||||
"docs:build": "pnpm -s docs:gen && vitepress build docs",
|
||||
"docs:preview": "pnpm -s docs:gen && vitepress preview docs"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@aklinker1/buildc": "^1.1.5",
|
||||
"@aklinker1/check": "^2.1.0",
|
||||
"@commitlint/config-conventional": "^19.8.1",
|
||||
"@commitlint/types": "^19.8.1",
|
||||
"@aklinker1/buildc": "^1.1.6",
|
||||
"@aklinker1/check": "^2.2.0",
|
||||
"@commitlint/config-conventional": "^20.4.1",
|
||||
"@commitlint/types": "^20.4.0",
|
||||
"@types/fs-extra": "^11.0.4",
|
||||
"@types/semver": "^7.7.1",
|
||||
"@vitest/coverage-v8": "^3.2.4",
|
||||
"@vitest/coverage-v8": "^4.0.18",
|
||||
"changelogen": "^0.6.2",
|
||||
"consola": "^3.4.2",
|
||||
"fast-glob": "^3.3.3",
|
||||
"feed": "^5.1.0",
|
||||
"fs-extra": "^11.3.1",
|
||||
"lint-staged": "^16.1.6",
|
||||
"feed": "^5.2.0",
|
||||
"fs-extra": "^11.3.3",
|
||||
"lint-staged": "^16.2.7",
|
||||
"markdown-it-footnote": "^4.0.0",
|
||||
"markdownlint-cli": "^0.45.0",
|
||||
"nano-spawn": "^1.0.2",
|
||||
"prettier": "^3.6.2",
|
||||
"semver": "^7.7.2",
|
||||
"markdownlint-cli": "^0.47.0",
|
||||
"nano-spawn": "^2.0.0",
|
||||
"p-map": "^7.0.4",
|
||||
"prettier": "^3.8.1",
|
||||
"semver": "^7.7.4",
|
||||
"simple-git-hooks": "^2.13.1",
|
||||
"tsx": "4.20.5",
|
||||
"tsdown": "^0.20.3",
|
||||
"tsx": "4.21.0",
|
||||
"typedoc": "^0.25.4",
|
||||
"typedoc-plugin-frontmatter": "^1.3.0",
|
||||
"typedoc-plugin-frontmatter": "^1.3.1",
|
||||
"typedoc-plugin-markdown": "4.0.0-next.23",
|
||||
"typedoc-vitepress-theme": "1.0.0-next.3",
|
||||
"typescript": "^5.9.2",
|
||||
"typescript": "^5.9.3",
|
||||
"vitepress": "^1.6.4",
|
||||
"vitepress-knowledge": "^0.4.1",
|
||||
"vitepress-plugin-group-icons": "^1.6.3",
|
||||
"vitepress-plugin-group-icons": "^1.7.1",
|
||||
"vitepress-plugin-llms": "^1.11.0",
|
||||
"vitest-mock-extended": "^3.1.0",
|
||||
"vue": "^3.5.21",
|
||||
"vue": "^3.5.27",
|
||||
"wxt": "workspace:*"
|
||||
},
|
||||
"simple-git-hooks": {
|
||||
@@ -54,16 +56,5 @@
|
||||
},
|
||||
"lint-staged": {
|
||||
"*": "prettier --ignore-unknown --write"
|
||||
},
|
||||
"pnpm": {
|
||||
"peerDependencyRules": {
|
||||
"ignoreMissing": [
|
||||
"@algolia/client-search",
|
||||
"search-insights"
|
||||
]
|
||||
},
|
||||
"patchedDependencies": {
|
||||
"markdown-it-footnote": "patches/markdown-it-footnote.patch"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,32 @@
|
||||
# Changelog
|
||||
|
||||
## v0.5.2
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/analytics-v0.5.1...analytics-v0.5.2)
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Normalize path for createAnalytics of analytics/index.ts ([#2013](https://github.com/wxt-dev/wxt/pull/2013))
|
||||
- Allow custom API URL in Google Analytics 4 provider options ([#1653](https://github.com/wxt-dev/wxt/pull/1653))
|
||||
|
||||
### 💅 Refactors
|
||||
|
||||
- Code cleanup in analytics package ([#2084](https://github.com/wxt-dev/wxt/pull/2084))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- Fix other type error after `chrome` types update ([31ebf966](https://github.com/wxt-dev/wxt/commit/31ebf966))
|
||||
- Upgrade dev and non-major prod dependencies ([#2000](https://github.com/wxt-dev/wxt/pull/2000))
|
||||
- Use `tsdown` to build packages ([#2006](https://github.com/wxt-dev/wxt/pull/2006))
|
||||
- Move script-only dev dependencies to top-level `package.json` ([#2007](https://github.com/wxt-dev/wxt/pull/2007))
|
||||
- Update dependencies ([#2069](https://github.com/wxt-dev/wxt/pull/2069))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Honwhy Wang <honwhy.wang@gmail.com>
|
||||
- Aaron ([@aklinker1](https://github.com/aklinker1))
|
||||
- Patryk Kuniczak ([@PatrykKuniczak](https://github.com/PatrykKuniczak))
|
||||
|
||||
## v0.5.1
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/analytics-v0.5.0...analytics-v0.5.1)
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
import { defineBuildConfig } from 'unbuild';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
// Build module and plugins
|
||||
export default defineBuildConfig({
|
||||
rootDir: resolve(__dirname, 'modules/analytics'),
|
||||
outDir: resolve(__dirname, 'dist'),
|
||||
entries: [
|
||||
{ input: 'index.ts', name: 'module' },
|
||||
{ input: 'client.ts', name: 'index' },
|
||||
'background-plugin.ts',
|
||||
'types.ts',
|
||||
'providers/google-analytics-4.ts',
|
||||
'providers/umami.ts',
|
||||
],
|
||||
externals: ['#analytics'],
|
||||
replace: {
|
||||
'import.meta.env.NPM': 'true',
|
||||
},
|
||||
declaration: true,
|
||||
});
|
||||
@@ -13,6 +13,22 @@ import { browser } from '@wxt-dev/browser';
|
||||
|
||||
const ANALYTICS_PORT = '@wxt-dev/analytics';
|
||||
|
||||
const INTERACTIVE_TAGS = new Set([
|
||||
'A',
|
||||
'BUTTON',
|
||||
'INPUT',
|
||||
'SELECT',
|
||||
'TEXTAREA',
|
||||
]);
|
||||
const INTERACTIVE_ROLES = new Set([
|
||||
'button',
|
||||
'link',
|
||||
'checkbox',
|
||||
'menuitem',
|
||||
'tab',
|
||||
'radio',
|
||||
]);
|
||||
|
||||
export function createAnalytics(config?: AnalyticsConfig): Analytics {
|
||||
if (!browser?.runtime?.id)
|
||||
throw Error(
|
||||
@@ -62,8 +78,8 @@ function createBackgroundAnalytics(
|
||||
|
||||
const getBackgroundMeta = () => ({
|
||||
timestamp: Date.now(),
|
||||
// Don't track sessions for the background, it can be running
|
||||
// indefinitely, and will inflate session duration stats.
|
||||
// Don't track sessions for the background, it can be running indefinitely
|
||||
// and will inflate session duration stats.
|
||||
sessionId: undefined,
|
||||
language: navigator.language,
|
||||
referrer: undefined,
|
||||
@@ -75,7 +91,7 @@ function createBackgroundAnalytics(
|
||||
const getBaseEvent = async (
|
||||
meta: AnalyticsEventMetadata,
|
||||
): Promise<BaseAnalyticsEvent> => {
|
||||
const platform = await platformInfo;
|
||||
const { arch, os } = await platformInfo;
|
||||
return {
|
||||
meta,
|
||||
user: {
|
||||
@@ -84,8 +100,8 @@ function createBackgroundAnalytics(
|
||||
version: config?.version ?? manifest.version_name ?? manifest.version,
|
||||
wxtMode: import.meta.env.MODE,
|
||||
wxtBrowser: import.meta.env.BROWSER,
|
||||
arch: platform.arch,
|
||||
os: platform.os,
|
||||
arch,
|
||||
os,
|
||||
browser: userAgent.browser.name,
|
||||
browserVersion: userAgent.browser.version,
|
||||
...(await userProperties),
|
||||
@@ -253,27 +269,12 @@ function defineStorageItem<T>(
|
||||
): AnalyticsStorageItem<T> {
|
||||
return {
|
||||
getValue: async () =>
|
||||
(await browser.storage.local.get(key))[key] ?? defaultValue,
|
||||
(await browser.storage.local.get<Record<string, any>>(key))[key] ??
|
||||
defaultValue,
|
||||
setValue: (newValue) => browser.storage.local.set({ [key]: newValue }),
|
||||
};
|
||||
}
|
||||
|
||||
const INTERACTIVE_TAGS = new Set([
|
||||
'A',
|
||||
'BUTTON',
|
||||
'INPUT',
|
||||
'SELECT',
|
||||
'TEXTAREA',
|
||||
]);
|
||||
const INTERACTIVE_ROLES = new Set([
|
||||
'button',
|
||||
'link',
|
||||
'checkbox',
|
||||
'menuitem',
|
||||
'tab',
|
||||
'radio',
|
||||
]);
|
||||
|
||||
export function defineAnalyticsProvider<T = never>(
|
||||
definition: (
|
||||
/** The analytics object. */
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
} from 'wxt/modules';
|
||||
import { relative, resolve } from 'node:path';
|
||||
import type { AnalyticsConfig } from './types';
|
||||
import { normalizePath } from 'wxt';
|
||||
|
||||
declare module 'wxt/utils/define-app-config' {
|
||||
export interface WxtAppConfig {
|
||||
@@ -22,10 +23,10 @@ export default defineWxtModule({
|
||||
// Paths
|
||||
const wxtAnalyticsFolder = resolve(wxt.config.wxtDir, 'analytics');
|
||||
const wxtAnalyticsIndex = resolve(wxtAnalyticsFolder, 'index.ts');
|
||||
const clientModuleId = import.meta.env.NPM
|
||||
const clientModuleId = process.env.NPM
|
||||
? '@wxt-dev/analytics'
|
||||
: resolve(wxt.config.modulesDir, 'analytics/client');
|
||||
const pluginModuleId = import.meta.env.NPM
|
||||
const pluginModuleId = process.env.NPM
|
||||
? '@wxt-dev/analytics/background-plugin'
|
||||
: resolve(wxt.config.modulesDir, 'analytics/background-plugin');
|
||||
|
||||
@@ -38,17 +39,15 @@ export default defineWxtModule({
|
||||
});
|
||||
|
||||
// Generate #analytics module
|
||||
const wxtAnalyticsCode = [
|
||||
`import { createAnalytics } from '${
|
||||
import.meta.env.NPM
|
||||
? clientModuleId
|
||||
: relative(wxtAnalyticsFolder, clientModuleId)
|
||||
}';`,
|
||||
`import { useAppConfig } from '#imports';`,
|
||||
``,
|
||||
`export const analytics = createAnalytics(useAppConfig().analytics);`,
|
||||
``,
|
||||
].join('\n');
|
||||
const wxtAnalyticsCode = `import { createAnalytics } from '${
|
||||
process.env.NPM
|
||||
? clientModuleId
|
||||
: normalizePath(relative(wxtAnalyticsFolder, clientModuleId))
|
||||
}';
|
||||
import { useAppConfig } from '#imports';
|
||||
|
||||
export const analytics = createAnalytics(useAppConfig().analytics);
|
||||
`;
|
||||
addAlias(wxt, '#analytics', wxtAnalyticsIndex);
|
||||
wxt.hook('prepare:types', async (_, entries) => {
|
||||
entries.push({
|
||||
|
||||
@@ -4,6 +4,7 @@ import type { BaseAnalyticsEvent } from '../types';
|
||||
const DEFAULT_ENGAGEMENT_TIME_IN_MSEC = 100;
|
||||
|
||||
export interface GoogleAnalytics4ProviderOptions {
|
||||
apiUrl?: string;
|
||||
apiSecret: string;
|
||||
measurementId: string;
|
||||
}
|
||||
@@ -18,7 +19,7 @@ export const googleAnalytics4 =
|
||||
): Promise<void> => {
|
||||
const url = new URL(
|
||||
config?.debug ? '/debug/mp/collect' : '/mp/collect',
|
||||
'https://www.google-analytics.com',
|
||||
options.apiUrl ?? 'https://www.google-analytics.com',
|
||||
);
|
||||
if (options.apiSecret)
|
||||
url.searchParams.set('api_secret', options.apiSecret);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wxt-dev/analytics",
|
||||
"version": "0.5.1",
|
||||
"version": "0.5.2",
|
||||
"description": "Add analytics to your web extension",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -35,7 +35,7 @@
|
||||
}
|
||||
},
|
||||
"module": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"types": "./dist/index.d.mts",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
@@ -43,7 +43,7 @@
|
||||
"dev": "buildc --deps-only -- wxt",
|
||||
"dev:build": "buildc --deps-only -- wxt build",
|
||||
"check": "pnpm build && check",
|
||||
"build": "buildc -- unbuild",
|
||||
"build": "buildc -- tsdown",
|
||||
"prepack": "pnpm -s build",
|
||||
"prepare": "buildc --deps-only -- wxt prepare"
|
||||
},
|
||||
@@ -51,11 +51,9 @@
|
||||
"wxt": ">=0.20.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@aklinker1/check": "^2.1.0",
|
||||
"@types/ua-parser-js": "^0.7.39",
|
||||
"publint": "^0.3.12",
|
||||
"typescript": "^5.9.2",
|
||||
"unbuild": "^3.6.1",
|
||||
"publint": "^0.3.17",
|
||||
"typescript": "^5.9.3",
|
||||
"wxt": "workspace:*"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import { defineConfig } from 'tsdown';
|
||||
|
||||
export default defineConfig({
|
||||
entry: {
|
||||
index: './modules/analytics/client.ts',
|
||||
module: './modules/analytics/index.ts',
|
||||
'background-plugin': './modules/analytics/background-plugin.ts',
|
||||
types: './modules/analytics/types.ts',
|
||||
'providers/google-analytics-4':
|
||||
'./modules/analytics/providers/google-analytics-4.ts',
|
||||
'providers/umami': './modules/analytics/providers/umami.ts',
|
||||
},
|
||||
external: ['#analytics'],
|
||||
define: {
|
||||
'process.env.NPM': 'true',
|
||||
},
|
||||
});
|
||||
@@ -27,7 +27,7 @@
|
||||
"version": "1.1.0",
|
||||
"type": "module",
|
||||
"module": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"types": "./dist/index.d.mts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.mts",
|
||||
@@ -38,7 +38,7 @@
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "buildc -- unbuild",
|
||||
"build": "buildc -- tsdown",
|
||||
"check": "pnpm build && check"
|
||||
},
|
||||
"peerDependencies": {
|
||||
@@ -46,15 +46,13 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"defu": "^6.1.4",
|
||||
"fs-extra": "^11.3.1",
|
||||
"sharp": "^0.34.1"
|
||||
"fs-extra": "^11.3.3",
|
||||
"sharp": "^0.34.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@aklinker1/check": "^2.1.0",
|
||||
"oxlint": "^1.14.0",
|
||||
"publint": "^0.3.12",
|
||||
"typescript": "^5.9.2",
|
||||
"unbuild": "^3.6.1",
|
||||
"oxlint": "^1.43.0",
|
||||
"publint": "^0.3.17",
|
||||
"typescript": "^5.9.3",
|
||||
"wxt": "workspace:*"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { defineWxtModule } from 'wxt/modules';
|
||||
import { resolve, relative } from 'node:path';
|
||||
import defu from 'defu';
|
||||
import sharp from 'sharp';
|
||||
import { ensureDir, exists } from 'fs-extra';
|
||||
import { ensureDir, pathExists } from 'fs-extra';
|
||||
|
||||
export default defineWxtModule<AutoIconsOptions>({
|
||||
name: '@wxt-dev/auto-icons',
|
||||
@@ -37,7 +37,7 @@ export default defineWxtModule<AutoIconsOptions>({
|
||||
if (!parsedOptions.enabled)
|
||||
return wxt.logger.warn(`\`[auto-icons]\` ${this.name} disabled`);
|
||||
|
||||
if (!(await exists(resolvedPath))) {
|
||||
if (!(await pathExists(resolvedPath))) {
|
||||
return wxt.logger.warn(
|
||||
`\`[auto-icons]\` Skipping icon generation, no base icon found at ${relative(process.cwd(), resolvedPath)}`,
|
||||
);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@wxt-dev/browser",
|
||||
"description": "Provides a cross-browser API for using extension APIs and types based on @types/chrome",
|
||||
"version": "0.1.4",
|
||||
"version": "0.1.36",
|
||||
"type": "module",
|
||||
"main": "src/index.mjs",
|
||||
"types": "src/index.d.ts",
|
||||
@@ -23,12 +23,11 @@
|
||||
"src"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@types/chrome": "0.1.6",
|
||||
"fs-extra": "^11.3.1",
|
||||
"nano-spawn": "^1.0.2",
|
||||
"tsx": "4.20.5",
|
||||
"typescript": "^5.9.2",
|
||||
"vitest": "^3.2.4"
|
||||
"@types/chrome": "0.1.36",
|
||||
"fs-extra": "^11.3.3",
|
||||
"nano-spawn": "^2.0.0",
|
||||
"typescript": "^5.9.3",
|
||||
"vitest": "^4.0.18"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/filesystem": "*",
|
||||
|
||||
@@ -60,9 +60,7 @@ for (const { file, srcPath, destPath } of declarationFileMapping) {
|
||||
|
||||
// Done!
|
||||
|
||||
console.log(
|
||||
'\x1b[32m✔\x1b[0m Done in ' + performance.now().toFixed(0) + ' ms',
|
||||
);
|
||||
console.log('\x1b[32m✔\x1b[0m Done in ' + performance.now().toFixed(0) + ' ms');
|
||||
|
||||
// Transformations
|
||||
|
||||
|
||||
+2712
-2389
File diff suppressed because it is too large
Load Diff
@@ -24,10 +24,9 @@
|
||||
],
|
||||
"devDependencies": {
|
||||
"@types/chrome": "{{chromeTypesVersion}}",
|
||||
"fs-extra": "^11.3.1",
|
||||
"nano-spawn": "^1.0.2",
|
||||
"tsx": "4.19.4",
|
||||
"typescript": "^5.9.2",
|
||||
"vitest": "^3.1.2"
|
||||
"fs-extra": "^11.3.3",
|
||||
"nano-spawn": "^2.0.0",
|
||||
"typescript": "^5.9.3",
|
||||
"vitest": "^4.0.18"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,13 +21,13 @@
|
||||
"license": "MIT",
|
||||
"funding": "https://github.com/sponsors/wxt-dev",
|
||||
"scripts": {
|
||||
"build": "buildc -- unbuild",
|
||||
"build": "buildc -- tsdown",
|
||||
"check": "buildc --deps-only -- check",
|
||||
"test": "buildc --deps-only -- vitest"
|
||||
},
|
||||
"dependencies": {
|
||||
"@wxt-dev/browser": "workspace:^",
|
||||
"chokidar": "^4.0.3",
|
||||
"chokidar": "^5.0.0",
|
||||
"confbox": "^0.1.8 || ^0.2.2",
|
||||
"fast-glob": "^3.3.3"
|
||||
},
|
||||
@@ -40,19 +40,17 @@
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@aklinker1/check": "^2.1.0",
|
||||
"@types/node": "^20.17.6",
|
||||
"oxlint": "^1.14.0",
|
||||
"publint": "^0.3.12",
|
||||
"typescript": "^5.9.2",
|
||||
"unbuild": "^3.6.1",
|
||||
"vitest": "^3.2.4",
|
||||
"vitest-plugin-random-seed": "^1.1.1",
|
||||
"oxlint": "^1.43.0",
|
||||
"publint": "^0.3.17",
|
||||
"typescript": "^5.9.3",
|
||||
"vitest": "^4.0.18",
|
||||
"vitest-plugin-random-seed": "^1.1.2",
|
||||
"wxt": "workspace:*"
|
||||
},
|
||||
"main": "./dist/index.cjs",
|
||||
"module": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"types": "./dist/index.d.mts",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": {
|
||||
|
||||
@@ -44,7 +44,7 @@ export default defineWxtModule<I18nOptions>({
|
||||
options ?? {};
|
||||
|
||||
const getLocalizationFiles = async () => {
|
||||
const files = await glob('*.{json,json5,yml,yaml,toml}', {
|
||||
const files = await glob('*.{json,json5,jsonc,yml,yaml,toml}', {
|
||||
cwd: localesDir,
|
||||
absolute: true,
|
||||
});
|
||||
@@ -88,7 +88,7 @@ export default defineWxtModule<I18nOptions>({
|
||||
)!;
|
||||
if (defaultLocaleFile == null) {
|
||||
throw Error(
|
||||
`\`[i18n]\` Required localization file does not exist: \`<localesDir>/${wxt.config.manifest.default_locale}.{json|json5|yml|yaml|toml}\``,
|
||||
`\`[i18n]\` Required localization file does not exist: \`<localesDir>/${wxt.config.manifest.default_locale}.{json|json5|jsonc|yml|yaml|toml}\``,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import { defineConfig } from 'tsdown';
|
||||
|
||||
const entry = ['src/index.ts', 'src/build.ts', 'src/module.ts'];
|
||||
|
||||
export default defineConfig([
|
||||
{
|
||||
entry,
|
||||
},
|
||||
{
|
||||
entry,
|
||||
format: 'cjs',
|
||||
},
|
||||
]);
|
||||
@@ -1,5 +1,17 @@
|
||||
# Changelog
|
||||
|
||||
## v1.1.5
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/module-react-v1.1.4...module-react-v1.1.5)
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- **deps:** Support @vitejs/plugin-react@5 ([9170159b](https://github.com/wxt-dev/wxt/commit/9170159b))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Aaron ([@aklinker1](https://github.com/aklinker1))
|
||||
|
||||
## v1.1.4
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/module-react-v1.1.3...module-react-v1.1.4)
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
import { defineBuildConfig } from 'unbuild';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
export default defineBuildConfig({
|
||||
rootDir: resolve(__dirname, 'modules'),
|
||||
outDir: resolve(__dirname, 'dist'),
|
||||
entries: [{ input: 'react.ts', name: 'index' }],
|
||||
rollup: {
|
||||
emitCJS: true,
|
||||
},
|
||||
declaration: true,
|
||||
});
|
||||
@@ -18,11 +18,11 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"funding": "https://github.com/sponsors/wxt-dev",
|
||||
"version": "1.1.4",
|
||||
"version": "1.1.5",
|
||||
"type": "module",
|
||||
"main": "./dist/index.cjs",
|
||||
"module": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"types": "./dist/index.d.mts",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": {
|
||||
@@ -41,24 +41,22 @@
|
||||
"scripts": {
|
||||
"dev": "wxt",
|
||||
"check": "pnpm build && check",
|
||||
"build": "buildc -- unbuild",
|
||||
"build": "buildc -- tsdown",
|
||||
"prepare": "buildc --deps-only -- wxt prepare"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"wxt": ">=0.19.16"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vitejs/plugin-react": "^4.4.1"
|
||||
"@vitejs/plugin-react": "^4.4.1 || ^5.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@aklinker1/check": "^2.1.0",
|
||||
"@types/react": "^19.1.12",
|
||||
"@types/react-dom": "^19.1.9",
|
||||
"publint": "^0.3.12",
|
||||
"react": "^19.1.1",
|
||||
"react-dom": "^19.1.1",
|
||||
"typescript": "^5.9.2",
|
||||
"unbuild": "^3.6.1",
|
||||
"@types/react": "^19.2.13",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"publint": "^0.3.17",
|
||||
"react": "^19.2.4",
|
||||
"react-dom": "^19.2.4",
|
||||
"typescript": "^5.9.3",
|
||||
"wxt": "workspace:*"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import { defineConfig } from 'tsdown';
|
||||
|
||||
const entry = {
|
||||
index: './modules/react.ts',
|
||||
};
|
||||
|
||||
export default defineConfig([
|
||||
{
|
||||
entry,
|
||||
},
|
||||
{
|
||||
entry,
|
||||
format: 'cjs',
|
||||
},
|
||||
]);
|
||||
@@ -1,12 +0,0 @@
|
||||
import { defineBuildConfig } from 'unbuild';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
export default defineBuildConfig({
|
||||
rootDir: resolve(__dirname, 'modules'),
|
||||
outDir: resolve(__dirname, 'dist'),
|
||||
entries: [{ input: 'solid.ts', name: 'index' }],
|
||||
rollup: {
|
||||
emitCJS: true,
|
||||
},
|
||||
declaration: true,
|
||||
});
|
||||
@@ -22,7 +22,7 @@
|
||||
"type": "module",
|
||||
"main": "./dist/index.cjs",
|
||||
"module": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"types": "./dist/index.d.mts",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": {
|
||||
@@ -41,21 +41,19 @@
|
||||
"scripts": {
|
||||
"dev": "wxt",
|
||||
"check": "pnpm build && check",
|
||||
"build": "buildc -- unbuild",
|
||||
"build": "buildc -- tsdown",
|
||||
"prepare": "buildc --deps-only -- wxt prepare"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"wxt": ">=0.19.16"
|
||||
},
|
||||
"dependencies": {
|
||||
"vite-plugin-solid": "^2.11.6"
|
||||
"vite-plugin-solid": "^2.11.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@aklinker1/check": "^2.1.0",
|
||||
"publint": "^0.3.12",
|
||||
"solid-js": "^1.9.9",
|
||||
"typescript": "^5.9.2",
|
||||
"unbuild": "^3.6.1",
|
||||
"publint": "^0.3.17",
|
||||
"solid-js": "^1.9.11",
|
||||
"typescript": "^5.9.3",
|
||||
"wxt": "workspace:*"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import { defineConfig } from 'tsdown';
|
||||
|
||||
const entry = {
|
||||
index: './modules/solid.ts',
|
||||
};
|
||||
|
||||
export default defineConfig([
|
||||
{
|
||||
entry,
|
||||
},
|
||||
{
|
||||
entry,
|
||||
format: 'cjs',
|
||||
},
|
||||
]);
|
||||
@@ -22,7 +22,7 @@
|
||||
"type": "module",
|
||||
"main": "./dist/index.cjs",
|
||||
"module": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"types": "./dist/index.d.mts",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": {
|
||||
@@ -39,7 +39,7 @@
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "buildc -- unbuild",
|
||||
"build": "buildc -- tsdown",
|
||||
"check": "pnpm build && check"
|
||||
},
|
||||
"peerDependencies": {
|
||||
@@ -50,10 +50,8 @@
|
||||
"@sveltejs/vite-plugin-svelte": "^4.0.0 || ^5.0.0 || ^6.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@aklinker1/check": "^2.1.0",
|
||||
"publint": "^0.3.12",
|
||||
"typescript": "^5.9.2",
|
||||
"unbuild": "^3.6.1",
|
||||
"publint": "^0.3.17",
|
||||
"typescript": "^5.9.3",
|
||||
"wxt": "workspace:*"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import { defineConfig } from 'tsdown';
|
||||
|
||||
const entry = {
|
||||
index: './src/index.ts',
|
||||
};
|
||||
|
||||
export default defineConfig([
|
||||
{
|
||||
entry,
|
||||
},
|
||||
{
|
||||
entry,
|
||||
format: 'cjs',
|
||||
},
|
||||
]);
|
||||
@@ -22,7 +22,7 @@
|
||||
"type": "module",
|
||||
"main": "./dist/index.cjs",
|
||||
"module": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"types": "./dist/index.d.mts",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": {
|
||||
@@ -39,7 +39,7 @@
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "buildc -- unbuild",
|
||||
"build": "buildc -- tsdown",
|
||||
"check": "pnpm build && check"
|
||||
},
|
||||
"peerDependencies": {
|
||||
@@ -49,10 +49,8 @@
|
||||
"@vitejs/plugin-vue": "^5.2.3 || ^6.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@aklinker1/check": "^2.1.0",
|
||||
"publint": "^0.3.12",
|
||||
"typescript": "^5.9.2",
|
||||
"unbuild": "^3.6.1",
|
||||
"publint": "^0.3.17",
|
||||
"typescript": "^5.9.3",
|
||||
"wxt": "workspace:*"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import { defineConfig } from 'tsdown';
|
||||
|
||||
const entry = {
|
||||
index: './src/index.ts',
|
||||
};
|
||||
|
||||
export default defineConfig([
|
||||
{
|
||||
entry,
|
||||
},
|
||||
{
|
||||
entry,
|
||||
format: 'cjs',
|
||||
},
|
||||
]);
|
||||
@@ -1,5 +1,33 @@
|
||||
# Changelog
|
||||
|
||||
## v0.1.2
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/runner-v0.1.1...runner-v0.1.2)
|
||||
|
||||
### 🚀 Enhancements
|
||||
|
||||
- **config:** Add browser path for Zen via Homebrew ([#1813](https://github.com/wxt-dev/wxt/pull/1813))
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Improve Chrome path search ([#1823](https://github.com/wxt-dev/wxt/pull/1823))
|
||||
- **paths:** Add browser paths for Arc & Dia on macos ([#1814](https://github.com/wxt-dev/wxt/pull/1814))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- Fix auto-fixable `markdownlint` errors ([#1710](https://github.com/wxt-dev/wxt/pull/1710))
|
||||
- Manually fix markdownlint errors ([#1711](https://github.com/wxt-dev/wxt/pull/1711))
|
||||
- **deps:** Upgrade oxlint from 0.16.8 to 1.14.0 ([a01928e0](https://github.com/wxt-dev/wxt/commit/a01928e0))
|
||||
- **deps:** Upgrade typescript from 5.8.3 to 5.9.2 ([a6eef643](https://github.com/wxt-dev/wxt/commit/a6eef643))
|
||||
- Create script for managing dependency upgrades ([#1875](https://github.com/wxt-dev/wxt/pull/1875))
|
||||
- **deps:** Upgrade all dev dependencies ([#1876](https://github.com/wxt-dev/wxt/pull/1876))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Aaron ([@aklinker1](https://github.com/aklinker1))
|
||||
- Sam Carlton ([@ThatGuySam](https://github.com/ThatGuySam))
|
||||
- Alexander Kachkaev <alexander@kachkaev.ru>
|
||||
|
||||
## v0.1.1
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/runner-v0.1.0...runner-v0.1.1)
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@wxt-dev/runner",
|
||||
"description": "Launch Chrome and Firefox with a web extension installed",
|
||||
"version": "0.1.1",
|
||||
"version": "0.1.2",
|
||||
"type": "module",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -24,21 +24,17 @@
|
||||
"check": "pnpm build && check",
|
||||
"test": "buildc --deps-only -- vitest",
|
||||
"dev": "tsx --trace-warnings dev.ts",
|
||||
"build": "buildc -- unbuild",
|
||||
"build": "buildc -- tsdown",
|
||||
"prepublishOnly": "pnpm build"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@aklinker1/check": "^2.1.0",
|
||||
"oxlint": "^1.14.0",
|
||||
"publint": "^0.3.12",
|
||||
"tsx": "4.20.5",
|
||||
"typescript": "^5.9.2",
|
||||
"unbuild": "^3.6.1",
|
||||
"vitest": "^3.2.4"
|
||||
"oxlint": "^1.43.0",
|
||||
"publint": "^0.3.17",
|
||||
"typescript": "^5.9.3",
|
||||
"vitest": "^4.0.18"
|
||||
},
|
||||
"main": "dist/index.mjs",
|
||||
"types": "dist/index.d.ts",
|
||||
"types": "dist/index.d.mts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.mts",
|
||||
|
||||
@@ -114,7 +114,7 @@ async function findBrowserBinary(target: string): Promise<string | undefined> {
|
||||
for (const target of targets) {
|
||||
const potentialPaths = KNOWN_BROWSER_PATHS[target]?.[platform] ?? [];
|
||||
for (const path of potentialPaths) {
|
||||
if (await exists(path)) return path;
|
||||
if (await pathExists(path)) return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -207,7 +207,7 @@ function deduplicateArgs(
|
||||
return args;
|
||||
}
|
||||
|
||||
async function exists(path: string): Promise<boolean> {
|
||||
async function pathExists(path: string): Promise<boolean> {
|
||||
try {
|
||||
await open(path, 'r');
|
||||
return true;
|
||||
|
||||
@@ -1,5 +1,60 @@
|
||||
# Changelog
|
||||
|
||||
## v1.2.6
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/storage-v1.2.5...storage-v1.2.6)
|
||||
|
||||
## v1.2.5
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/storage-v1.2.4...storage-v1.2.5)
|
||||
|
||||
## v1.2.4
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/storage-v1.2.3...storage-v1.2.4)
|
||||
|
||||
## v1.2.3
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/storage-v1.2.2...storage-v1.2.3)
|
||||
|
||||
## v1.2.2
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/storage-v1.2.1...storage-v1.2.2)
|
||||
|
||||
## v1.2.1
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/storage-v1.2.0...storage-v1.2.1)
|
||||
|
||||
## v1.2.0
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/storage-v1.1.1...storage-v1.2.0)
|
||||
|
||||
### 🚀 Enhancements
|
||||
|
||||
- **storage:** Add `onMigrationComplete` callback ([#1514](https://github.com/wxt-dev/wxt/pull/1514))
|
||||
- **storage:** Add `debug` option to enable migration logs ([#1513](https://github.com/wxt-dev/wxt/pull/1513))
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Fix typescript error on `defineItem` fallback ([#1601](https://github.com/wxt-dev/wxt/pull/1601))
|
||||
- Use `@wxt-dev/browser` instead of `@types/chrome` ([#1645](https://github.com/wxt-dev/wxt/pull/1645))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- **deps:** Update all dependencies ([#1568](https://github.com/wxt-dev/wxt/pull/1568))
|
||||
- Stop using PNPM catalog ([#1644](https://github.com/wxt-dev/wxt/pull/1644))
|
||||
- Upgrade `@aklinker1/check` to v2 ([#1647](https://github.com/wxt-dev/wxt/pull/1647))
|
||||
- Change browser workspace dependency to `^` ([c7335add](https://github.com/wxt-dev/wxt/commit/c7335add))
|
||||
- **deps:** Upgrade oxlint from 0.16.8 to 1.14.0 ([a01928e0](https://github.com/wxt-dev/wxt/commit/a01928e0))
|
||||
- **deps:** Upgrade typescript from 5.8.3 to 5.9.2 ([a6eef643](https://github.com/wxt-dev/wxt/commit/a6eef643))
|
||||
- Create script for managing dependency upgrades ([#1875](https://github.com/wxt-dev/wxt/pull/1875))
|
||||
- **deps:** Upgrade all dev dependencies ([#1876](https://github.com/wxt-dev/wxt/pull/1876))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Aaron ([@aklinker1](https://github.com/aklinker1))
|
||||
- Anh71me ([@iyume](https://github.com/iyume))
|
||||
- Ergou <ma2808203259@hotmail.com>
|
||||
|
||||
## v1.1.1
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/storage-v1.1.0...storage-v1.1.1)
|
||||
@@ -69,4 +124,4 @@ It's still shipped inside WXT and accessible via `wxt/storage`, but now:
|
||||
|
||||
[Read the docs](https://wxt.dev/storage.html) for more details.
|
||||
|
||||
> This is apart of the v1.0 initiative for WXT.
|
||||
> This is apart of the v1.0 initiative for WXT.
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@wxt-dev/storage",
|
||||
"description": "Web extension storage API provided by WXT, supports all browsers.",
|
||||
"version": "1.1.1",
|
||||
"version": "1.2.6",
|
||||
"type": "module",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -25,7 +25,7 @@
|
||||
"license": "MIT",
|
||||
"funding": "https://github.com/sponsors/wxt-dev",
|
||||
"scripts": {
|
||||
"build": "buildc -- unbuild",
|
||||
"build": "buildc -- tsdown",
|
||||
"check": "buildc --deps-only -- check",
|
||||
"test": "buildc --deps-only -- vitest"
|
||||
},
|
||||
@@ -35,16 +35,14 @@
|
||||
"dequal": "^2.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@aklinker1/check": "^2.1.0",
|
||||
"@webext-core/fake-browser": "^1.3.2",
|
||||
"oxlint": "^1.14.0",
|
||||
"publint": "^0.3.12",
|
||||
"typescript": "^5.9.2",
|
||||
"unbuild": "^3.6.1",
|
||||
"vitest": "^3.2.4"
|
||||
"@webext-core/fake-browser": "^1.3.4",
|
||||
"oxlint": "^1.43.0",
|
||||
"publint": "^0.3.17",
|
||||
"typescript": "^5.9.3",
|
||||
"vitest": "^4.0.18"
|
||||
},
|
||||
"module": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"types": "./dist/index.d.mts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.mts",
|
||||
|
||||
@@ -706,6 +706,47 @@ describe('Storage Utils', () => {
|
||||
expect(migrateToV3).toBeCalledWith(4);
|
||||
});
|
||||
|
||||
it('should set the version without running migrations for empty storage items', async () => {
|
||||
const migrate = vi.fn((n: number) => n * 2);
|
||||
|
||||
const item = storage.defineItem<number>('local:key', {
|
||||
init: () => 1,
|
||||
version: 2,
|
||||
migrations: {
|
||||
2: migrate,
|
||||
},
|
||||
});
|
||||
const value = await item.getValue();
|
||||
const meta = await item.getMeta();
|
||||
|
||||
expect(value).toEqual(1);
|
||||
expect(meta).toEqual({ v: 2 });
|
||||
expect(migrate).toBeCalledTimes(0);
|
||||
});
|
||||
|
||||
it('should set the version and run migrations if a storage value already exists and v2 is added', async () => {
|
||||
const key = 'local:key';
|
||||
|
||||
// Mimic as if an initial value was set by a previous version. We expect
|
||||
// this value to be migrated and doubled to V2.
|
||||
await storage.setItem(key, 1);
|
||||
|
||||
const migrate = vi.fn((n: number) => n * 2);
|
||||
const item = storage.defineItem<number>(key, {
|
||||
init: () => 1,
|
||||
version: 2,
|
||||
migrations: {
|
||||
2: migrate,
|
||||
},
|
||||
});
|
||||
const value = await item.getValue();
|
||||
const meta = await item.getMeta();
|
||||
|
||||
expect(value).toEqual(2);
|
||||
expect(meta).toEqual({ v: 2 });
|
||||
expect(migrate).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should call onMigrationComplete callback function if defined', async () => {
|
||||
await fakeBrowser.storage.local.set({
|
||||
count: 2,
|
||||
@@ -1315,6 +1356,18 @@ describe('Storage Utils', () => {
|
||||
});
|
||||
expectTypeOf(item).toEqualTypeOf<WxtStorageItem<number | null, {}>>();
|
||||
});
|
||||
|
||||
it('should define a non-null value when options are passed with a non-null init function', () => {
|
||||
const item = storage.defineItem(`local:test`, {
|
||||
init: () => 123,
|
||||
});
|
||||
expectTypeOf(item).toEqualTypeOf<WxtStorageItem<number, {}>>();
|
||||
|
||||
const item2 = storage.defineItem(`local:test`, {
|
||||
init: () => Promise.resolve(123),
|
||||
});
|
||||
expectTypeOf(item2).toEqualTypeOf<WxtStorageItem<number, {}>>();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
+146
-23
@@ -17,6 +17,7 @@ function createStorage(): WxtStorage {
|
||||
sync: createDriver('sync'),
|
||||
managed: createDriver('managed'),
|
||||
};
|
||||
|
||||
const getDriver = (area: StorageArea) => {
|
||||
const driver = drivers[area];
|
||||
if (driver == null) {
|
||||
@@ -25,14 +26,17 @@ function createStorage(): WxtStorage {
|
||||
}
|
||||
return driver;
|
||||
};
|
||||
|
||||
const resolveKey = (key: StorageItemKey) => {
|
||||
const deliminatorIndex = key.indexOf(':');
|
||||
const driverArea = key.substring(0, deliminatorIndex) as StorageArea;
|
||||
|
||||
const driverKey = key.substring(deliminatorIndex + 1);
|
||||
if (driverKey == null)
|
||||
if (driverKey == null) {
|
||||
throw Error(
|
||||
`Storage key should be in the form of "area:key", but received "${key}"`,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
driverArea,
|
||||
@@ -40,17 +44,23 @@ function createStorage(): WxtStorage {
|
||||
driver: getDriver(driverArea),
|
||||
};
|
||||
};
|
||||
|
||||
const getMetaKey = (key: string) => key + '$';
|
||||
|
||||
const mergeMeta = (oldMeta: any, newMeta: any): any => {
|
||||
const newFields = { ...oldMeta };
|
||||
|
||||
Object.entries(newMeta).forEach(([key, value]) => {
|
||||
if (value == null) delete newFields[key];
|
||||
else newFields[key] = value;
|
||||
});
|
||||
|
||||
return newFields;
|
||||
};
|
||||
|
||||
const getValueOrFallback = (value: any, fallback: any) =>
|
||||
value ?? fallback ?? null;
|
||||
|
||||
const getMetaValue = (properties: any) =>
|
||||
typeof properties === 'object' && !Array.isArray(properties)
|
||||
? properties
|
||||
@@ -64,11 +74,13 @@ function createStorage(): WxtStorage {
|
||||
const res = await driver.getItem<any>(driverKey);
|
||||
return getValueOrFallback(res, opts?.fallback ?? opts?.defaultValue);
|
||||
};
|
||||
|
||||
const getMeta = async (driver: WxtStorageDriver, driverKey: string) => {
|
||||
const metaKey = getMetaKey(driverKey);
|
||||
const res = await driver.getItem<any>(metaKey);
|
||||
return getMetaValue(res);
|
||||
};
|
||||
|
||||
const setItem = async (
|
||||
driver: WxtStorageDriver,
|
||||
driverKey: string,
|
||||
@@ -76,6 +88,7 @@ function createStorage(): WxtStorage {
|
||||
) => {
|
||||
await driver.setItem(driverKey, value ?? null);
|
||||
};
|
||||
|
||||
const setMeta = async (
|
||||
driver: WxtStorageDriver,
|
||||
driverKey: string,
|
||||
@@ -85,23 +98,27 @@ function createStorage(): WxtStorage {
|
||||
const existingFields = getMetaValue(await driver.getItem(metaKey));
|
||||
await driver.setItem(metaKey, mergeMeta(existingFields, properties));
|
||||
};
|
||||
|
||||
const removeItem = async (
|
||||
driver: WxtStorageDriver,
|
||||
driverKey: string,
|
||||
opts: RemoveItemOptions | undefined,
|
||||
) => {
|
||||
await driver.removeItem(driverKey);
|
||||
|
||||
if (opts?.removeMeta) {
|
||||
const metaKey = getMetaKey(driverKey);
|
||||
await driver.removeItem(metaKey);
|
||||
}
|
||||
};
|
||||
|
||||
const removeMeta = async (
|
||||
driver: WxtStorageDriver,
|
||||
driverKey: string,
|
||||
properties: string | string[] | undefined,
|
||||
) => {
|
||||
const metaKey = getMetaKey(driverKey);
|
||||
|
||||
if (properties == null) {
|
||||
await driver.removeItem(metaKey);
|
||||
} else {
|
||||
@@ -110,19 +127,19 @@ function createStorage(): WxtStorage {
|
||||
await driver.setItem(metaKey, newFields);
|
||||
}
|
||||
};
|
||||
|
||||
const watch = (
|
||||
driver: WxtStorageDriver,
|
||||
driverKey: string,
|
||||
cb: WatchCallback<any>,
|
||||
) => {
|
||||
return driver.watch(driverKey, cb);
|
||||
};
|
||||
) => driver.watch(driverKey, cb);
|
||||
|
||||
const storage: WxtStorage = {
|
||||
return {
|
||||
getItem: async (key, opts) => {
|
||||
const { driver, driverKey } = resolveKey(key);
|
||||
return await getItem(driver, driverKey, opts);
|
||||
},
|
||||
|
||||
getItems: async (keys) => {
|
||||
const areaToKeyMap = new Map<StorageArea, string[]>();
|
||||
const keyToOptsMap = new Map<string, GetItemOptions<any> | undefined>();
|
||||
@@ -131,6 +148,7 @@ function createStorage(): WxtStorage {
|
||||
keys.forEach((key) => {
|
||||
let keyStr: StorageItemKey;
|
||||
let opts: GetItemOptions<any> | undefined;
|
||||
|
||||
if (typeof key === 'string') {
|
||||
// key: string
|
||||
keyStr = key;
|
||||
@@ -143,9 +161,11 @@ function createStorage(): WxtStorage {
|
||||
keyStr = key.key;
|
||||
opts = key.options;
|
||||
}
|
||||
|
||||
orderedKeys.push(keyStr);
|
||||
const { driverArea, driverKey } = resolveKey(keyStr);
|
||||
const areaKeys = areaToKeyMap.get(driverArea) ?? [];
|
||||
|
||||
areaToKeyMap.set(driverArea, areaKeys.concat(driverKey));
|
||||
keyToOptsMap.set(keyStr, opts);
|
||||
});
|
||||
@@ -154,6 +174,7 @@ function createStorage(): WxtStorage {
|
||||
await Promise.all(
|
||||
Array.from(areaToKeyMap.entries()).map(async ([driverArea, keys]) => {
|
||||
const driverResults = await drivers[driverArea].getItems(keys);
|
||||
|
||||
driverResults.forEach((driverResult) => {
|
||||
const key = `${driverArea}:${driverResult.key}` as StorageItemKey;
|
||||
const opts = keyToOptsMap.get(key);
|
||||
@@ -161,6 +182,7 @@ function createStorage(): WxtStorage {
|
||||
driverResult.value,
|
||||
opts?.fallback ?? opts?.defaultValue,
|
||||
);
|
||||
|
||||
resultsMap.set(key, value);
|
||||
});
|
||||
}),
|
||||
@@ -171,14 +193,17 @@ function createStorage(): WxtStorage {
|
||||
value: resultsMap.get(key),
|
||||
}));
|
||||
},
|
||||
|
||||
getMeta: async (key) => {
|
||||
const { driver, driverKey } = resolveKey(key);
|
||||
return await getMeta(driver, driverKey);
|
||||
},
|
||||
|
||||
getMetas: async (args) => {
|
||||
const keys = args.map((arg) => {
|
||||
const key = typeof arg === 'string' ? arg : arg.key;
|
||||
const { driverArea, driverKey } = resolveKey(key);
|
||||
|
||||
return {
|
||||
key,
|
||||
driverArea,
|
||||
@@ -186,6 +211,7 @@ function createStorage(): WxtStorage {
|
||||
driverMetaKey: getMetaKey(driverKey),
|
||||
};
|
||||
});
|
||||
|
||||
const areaToDriverMetaKeysMap = keys.reduce<
|
||||
Partial<Record<StorageArea, (typeof keys)[number][]>>
|
||||
>((map, key) => {
|
||||
@@ -211,10 +237,12 @@ function createStorage(): WxtStorage {
|
||||
meta: resultsMap[key.key],
|
||||
}));
|
||||
},
|
||||
|
||||
setItem: async (key, value) => {
|
||||
const { driver, driverKey } = resolveKey(key);
|
||||
await setItem(driver, driverKey, value);
|
||||
},
|
||||
|
||||
setItems: async (items) => {
|
||||
const areaToKeyValueMap: Partial<
|
||||
Record<StorageArea, Array<{ key: string; value: any }>>
|
||||
@@ -229,6 +257,7 @@ function createStorage(): WxtStorage {
|
||||
value: item.value,
|
||||
});
|
||||
});
|
||||
|
||||
await Promise.all(
|
||||
Object.entries(areaToKeyValueMap).map(async ([driverArea, values]) => {
|
||||
const driver = getDriver(driverArea as StorageArea);
|
||||
@@ -236,10 +265,12 @@ function createStorage(): WxtStorage {
|
||||
}),
|
||||
);
|
||||
},
|
||||
|
||||
setMeta: async (key, properties) => {
|
||||
const { driver, driverKey } = resolveKey(key);
|
||||
await setMeta(driver, driverKey, properties);
|
||||
},
|
||||
|
||||
setMetas: async (items) => {
|
||||
const areaToMetaUpdatesMap: Partial<
|
||||
Record<StorageArea, { key: string; properties: any }[]>
|
||||
@@ -278,16 +309,19 @@ function createStorage(): WxtStorage {
|
||||
),
|
||||
);
|
||||
},
|
||||
|
||||
removeItem: async (key, opts) => {
|
||||
const { driver, driverKey } = resolveKey(key);
|
||||
await removeItem(driver, driverKey, opts);
|
||||
},
|
||||
|
||||
removeItems: async (keys) => {
|
||||
const areaToKeysMap: Partial<Record<StorageArea, string[]>> = {};
|
||||
|
||||
keys.forEach((key) => {
|
||||
let keyStr: StorageItemKey;
|
||||
let opts: RemoveItemOptions | undefined;
|
||||
|
||||
if (typeof key === 'string') {
|
||||
// key: string
|
||||
keyStr = key;
|
||||
@@ -303,9 +337,11 @@ function createStorage(): WxtStorage {
|
||||
keyStr = key.key;
|
||||
opts = key.options;
|
||||
}
|
||||
|
||||
const { driverArea, driverKey } = resolveKey(keyStr);
|
||||
areaToKeysMap[driverArea] ??= [];
|
||||
areaToKeysMap[driverArea].push(driverKey);
|
||||
|
||||
if (opts?.removeMeta) {
|
||||
areaToKeysMap[driverArea].push(getMetaKey(driverKey));
|
||||
}
|
||||
@@ -318,36 +354,45 @@ function createStorage(): WxtStorage {
|
||||
}),
|
||||
);
|
||||
},
|
||||
|
||||
clear: async (base) => {
|
||||
const driver = getDriver(base);
|
||||
await driver.clear();
|
||||
},
|
||||
|
||||
removeMeta: async (key, properties) => {
|
||||
const { driver, driverKey } = resolveKey(key);
|
||||
await removeMeta(driver, driverKey, properties);
|
||||
},
|
||||
|
||||
snapshot: async (base, opts) => {
|
||||
const driver = getDriver(base);
|
||||
const data = await driver.snapshot();
|
||||
|
||||
opts?.excludeKeys?.forEach((key) => {
|
||||
delete data[key];
|
||||
delete data[getMetaKey(key)];
|
||||
});
|
||||
|
||||
return data;
|
||||
},
|
||||
|
||||
restoreSnapshot: async (base, data) => {
|
||||
const driver = getDriver(base);
|
||||
await driver.restoreSnapshot(data);
|
||||
},
|
||||
|
||||
watch: (key, cb) => {
|
||||
const { driver, driverKey } = resolveKey(key);
|
||||
return watch(driver, driverKey, cb);
|
||||
},
|
||||
|
||||
unwatch() {
|
||||
Object.values(drivers).forEach((driver) => {
|
||||
driver.unwatch();
|
||||
});
|
||||
},
|
||||
|
||||
defineItem: (key, opts?: WxtStorageItemOptions<any>) => {
|
||||
const { driver, driverKey } = resolveKey(key);
|
||||
|
||||
@@ -357,12 +402,14 @@ function createStorage(): WxtStorage {
|
||||
onMigrationComplete,
|
||||
debug = false,
|
||||
} = opts ?? {};
|
||||
|
||||
if (targetVersion < 1) {
|
||||
throw Error(
|
||||
'Storage item version cannot be less than 1. Initial versions should be set to 1, not 0.',
|
||||
);
|
||||
}
|
||||
const migrate = async () => {
|
||||
|
||||
const migrate: WxtStorageItem<any, any>['migrate'] = async () => {
|
||||
const driverMetaKey = getMetaKey(driverKey);
|
||||
const [{ value }, { value: meta }] = await driver.getItems([
|
||||
driverKey,
|
||||
@@ -376,11 +423,12 @@ function createStorage(): WxtStorage {
|
||||
`Version downgrade detected (v${currentVersion} -> v${targetVersion}) for "${key}"`,
|
||||
);
|
||||
}
|
||||
|
||||
if (currentVersion === targetVersion) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (debug === true) {
|
||||
if (debug) {
|
||||
console.debug(
|
||||
`[@wxt-dev/storage] Running storage migration for ${key}: v${currentVersion} -> v${targetVersion}`,
|
||||
);
|
||||
@@ -395,7 +443,7 @@ function createStorage(): WxtStorage {
|
||||
migratedValue =
|
||||
(await migrations?.[migrateToVersion]?.(migratedValue)) ??
|
||||
migratedValue;
|
||||
if (debug === true) {
|
||||
if (debug) {
|
||||
console.debug(
|
||||
`[@wxt-dev/storage] Storage migration processed for version: v${migrateToVersion}`,
|
||||
);
|
||||
@@ -411,14 +459,16 @@ function createStorage(): WxtStorage {
|
||||
{ key: driverMetaKey, value: { ...meta, v: targetVersion } },
|
||||
]);
|
||||
|
||||
if (debug === true) {
|
||||
if (debug) {
|
||||
console.debug(
|
||||
`[@wxt-dev/storage] Storage migration completed for ${key} v${targetVersion}`,
|
||||
{ migratedValue },
|
||||
);
|
||||
}
|
||||
|
||||
onMigrationComplete?.(migratedValue, targetVersion);
|
||||
};
|
||||
|
||||
const migrationsDone =
|
||||
opts?.migrations == null
|
||||
? Promise.resolve()
|
||||
@@ -441,6 +491,9 @@ function createStorage(): WxtStorage {
|
||||
|
||||
const newValue = await opts.init();
|
||||
await driver.setItem<any>(driverKey, newValue);
|
||||
if (value == null && targetVersion > 1) {
|
||||
await setMeta(driver, driverKey, { v: targetVersion });
|
||||
}
|
||||
return newValue;
|
||||
});
|
||||
|
||||
@@ -449,62 +502,75 @@ function createStorage(): WxtStorage {
|
||||
|
||||
return {
|
||||
key,
|
||||
|
||||
get defaultValue() {
|
||||
return getFallback();
|
||||
},
|
||||
get fallback() {
|
||||
return getFallback();
|
||||
},
|
||||
|
||||
getValue: async () => {
|
||||
await migrationsDone;
|
||||
|
||||
if (opts?.init) {
|
||||
return await getOrInitValue();
|
||||
} else {
|
||||
return await getItem(driver, driverKey, opts);
|
||||
}
|
||||
},
|
||||
|
||||
getMeta: async () => {
|
||||
await migrationsDone;
|
||||
|
||||
return await getMeta(driver, driverKey);
|
||||
},
|
||||
|
||||
setValue: async (value) => {
|
||||
await migrationsDone;
|
||||
|
||||
return await setItem(driver, driverKey, value);
|
||||
},
|
||||
|
||||
setMeta: async (properties) => {
|
||||
await migrationsDone;
|
||||
|
||||
return await setMeta(driver, driverKey, properties);
|
||||
},
|
||||
|
||||
removeValue: async (opts) => {
|
||||
await migrationsDone;
|
||||
|
||||
return await removeItem(driver, driverKey, opts);
|
||||
},
|
||||
|
||||
removeMeta: async (properties) => {
|
||||
await migrationsDone;
|
||||
|
||||
return await removeMeta(driver, driverKey, properties);
|
||||
},
|
||||
|
||||
watch: (cb) =>
|
||||
watch(driver, driverKey, (newValue, oldValue) =>
|
||||
cb(newValue ?? getFallback(), oldValue ?? getFallback()),
|
||||
),
|
||||
|
||||
migrate,
|
||||
};
|
||||
},
|
||||
};
|
||||
return storage;
|
||||
}
|
||||
|
||||
function createDriver(storageArea: StorageArea): WxtStorageDriver {
|
||||
const getStorageArea = () => {
|
||||
if (browser.runtime == null) {
|
||||
throw Error(
|
||||
[
|
||||
"'wxt/storage' must be loaded in a web extension environment",
|
||||
'\n - If thrown during a build, see https://github.com/wxt-dev/wxt/issues/371',
|
||||
" - If thrown during tests, mock 'wxt/browser' correctly. See https://wxt.dev/guide/go-further/testing.html\n",
|
||||
].join('\n'),
|
||||
);
|
||||
throw Error(`'wxt/storage' must be loaded in a web extension environment
|
||||
|
||||
- If thrown during a build, see https://github.com/wxt-dev/wxt/issues/371
|
||||
- If thrown during tests, mock 'wxt/browser' correctly. See https://wxt.dev/guide/go-further/testing.html
|
||||
`);
|
||||
}
|
||||
|
||||
if (browser.storage == null) {
|
||||
throw Error(
|
||||
"You must add the 'storage' permission to your manifest to use 'wxt/storage'",
|
||||
@@ -514,18 +580,23 @@ function createDriver(storageArea: StorageArea): WxtStorageDriver {
|
||||
const area = browser.storage[storageArea];
|
||||
if (area == null)
|
||||
throw Error(`"browser.storage.${storageArea}" is undefined`);
|
||||
|
||||
return area;
|
||||
};
|
||||
|
||||
const watchListeners = new Set<(changes: StorageAreaChanges) => void>();
|
||||
|
||||
return {
|
||||
getItem: async (key) => {
|
||||
const res = await getStorageArea().get(key);
|
||||
const res = await getStorageArea().get<Record<string, any>>(key);
|
||||
return res[key];
|
||||
},
|
||||
|
||||
getItems: async (keys) => {
|
||||
const result = await getStorageArea().get(keys);
|
||||
return keys.map((key) => ({ key, value: result[key] ?? null }));
|
||||
},
|
||||
|
||||
setItem: async (key, value) => {
|
||||
if (value == null) {
|
||||
await getStorageArea().remove(key);
|
||||
@@ -533,6 +604,7 @@ function createDriver(storageArea: StorageArea): WxtStorageDriver {
|
||||
await getStorageArea().set({ [key]: value });
|
||||
}
|
||||
},
|
||||
|
||||
setItems: async (values) => {
|
||||
const map = values.reduce<Record<string, unknown>>(
|
||||
(map, { key, value }) => {
|
||||
@@ -541,37 +613,51 @@ function createDriver(storageArea: StorageArea): WxtStorageDriver {
|
||||
},
|
||||
{},
|
||||
);
|
||||
|
||||
await getStorageArea().set(map);
|
||||
},
|
||||
|
||||
removeItem: async (key) => {
|
||||
await getStorageArea().remove(key);
|
||||
},
|
||||
|
||||
removeItems: async (keys) => {
|
||||
await getStorageArea().remove(keys);
|
||||
},
|
||||
|
||||
clear: async () => {
|
||||
await getStorageArea().clear();
|
||||
},
|
||||
|
||||
snapshot: async () => {
|
||||
return await getStorageArea().get();
|
||||
},
|
||||
|
||||
restoreSnapshot: async (data) => {
|
||||
await getStorageArea().set(data);
|
||||
},
|
||||
|
||||
watch(key, cb) {
|
||||
const listener = (changes: StorageAreaChanges) => {
|
||||
const change = changes[key];
|
||||
if (change == null) return;
|
||||
if (dequal(change.newValue, change.oldValue)) return;
|
||||
const change = changes[key] as {
|
||||
newValue?: any;
|
||||
oldValue?: any | null;
|
||||
} | null;
|
||||
|
||||
if (change == null || dequal(change.newValue, change.oldValue)) return;
|
||||
|
||||
cb(change.newValue ?? null, change.oldValue ?? null);
|
||||
};
|
||||
|
||||
getStorageArea().onChanged.addListener(listener);
|
||||
watchListeners.add(listener);
|
||||
|
||||
return () => {
|
||||
getStorageArea().onChanged.removeListener(listener);
|
||||
watchListeners.delete(listener);
|
||||
};
|
||||
},
|
||||
|
||||
unwatch() {
|
||||
watchListeners.forEach((listener) => {
|
||||
getStorageArea().onChanged.removeListener(listener);
|
||||
@@ -612,6 +698,7 @@ export interface WxtStorage {
|
||||
| { key: StorageItemKey; options?: GetItemOptions<any> }
|
||||
>,
|
||||
): Promise<Array<{ key: StorageItemKey; value: any }>>;
|
||||
|
||||
/**
|
||||
* Return an object containing metadata about the key. Object is stored at `key + "$"`. If value
|
||||
* is not an object, it returns an empty object.
|
||||
@@ -620,15 +707,17 @@ export interface WxtStorage {
|
||||
* await storage.getMeta("local:installDate");
|
||||
*/
|
||||
getMeta<T extends Record<string, unknown>>(key: StorageItemKey): Promise<T>;
|
||||
|
||||
/**
|
||||
* Get the metadata of multiple storage items.
|
||||
*
|
||||
* @param items List of keys or items to get the metadata of.
|
||||
* @param keys List of keys or items to get the metadata of.
|
||||
* @returns An array containing storage keys and their metadata.
|
||||
*/
|
||||
getMetas(
|
||||
keys: Array<StorageItemKey | WxtStorageItem<any, any>>,
|
||||
): Promise<Array<{ key: StorageItemKey; meta: any }>>;
|
||||
|
||||
/**
|
||||
* Set a value in storage. Setting a value to `null` or `undefined` is equivalent to calling
|
||||
* `removeItem`.
|
||||
@@ -637,6 +726,7 @@ export interface WxtStorage {
|
||||
* await storage.setItem<number>("local:installDate", Date.now());
|
||||
*/
|
||||
setItem<T>(key: StorageItemKey, value: T | null): Promise<void>;
|
||||
|
||||
/**
|
||||
* Set multiple values in storage. If a value is set to `null` or `undefined`, the key is removed.
|
||||
*
|
||||
@@ -652,6 +742,7 @@ export interface WxtStorage {
|
||||
| { item: WxtStorageItem<any, any>; value: any }
|
||||
>,
|
||||
): Promise<void>;
|
||||
|
||||
/**
|
||||
* Sets metadata properties. If some properties are already set, but are not included in the
|
||||
* `properties` parameter, they will not be removed.
|
||||
@@ -663,10 +754,11 @@ export interface WxtStorage {
|
||||
key: StorageItemKey,
|
||||
properties: T | null,
|
||||
): Promise<void>;
|
||||
|
||||
/**
|
||||
* Set the metadata of multiple storage items.
|
||||
*
|
||||
* @param items List of storage keys or items and metadata to set for each.
|
||||
* @param metas List of storage keys or items and metadata to set for each.
|
||||
*/
|
||||
setMetas(
|
||||
metas: Array<
|
||||
@@ -674,6 +766,7 @@ export interface WxtStorage {
|
||||
| { item: WxtStorageItem<any, any>; meta: Record<string, any> }
|
||||
>,
|
||||
): Promise<void>;
|
||||
|
||||
/**
|
||||
* Removes an item from storage.
|
||||
*
|
||||
@@ -681,6 +774,7 @@ export interface WxtStorage {
|
||||
* await storage.removeItem("local:installDate");
|
||||
*/
|
||||
removeItem(key: StorageItemKey, opts?: RemoveItemOptions): Promise<void>;
|
||||
|
||||
/**
|
||||
* Remove a list of keys from storage.
|
||||
*/
|
||||
@@ -712,6 +806,7 @@ export interface WxtStorage {
|
||||
key: StorageItemKey,
|
||||
properties?: string | string[],
|
||||
): Promise<void>;
|
||||
|
||||
/**
|
||||
* Return all the items in storage.
|
||||
*/
|
||||
@@ -719,15 +814,18 @@ export interface WxtStorage {
|
||||
base: StorageArea,
|
||||
opts?: SnapshotOptions,
|
||||
): Promise<Record<string, unknown>>;
|
||||
|
||||
/**
|
||||
* Restores the results of `snapshot`. If new properties have been saved since the snapshot, they are
|
||||
* not overridden. Only values existing in the snapshot are overridden.
|
||||
*/
|
||||
restoreSnapshot(base: StorageArea, data: any): Promise<void>;
|
||||
|
||||
/**
|
||||
* Watch for changes to a specific key in storage.
|
||||
*/
|
||||
watch<T>(key: StorageItemKey, cb: WatchCallback<T | null>): Unwatch;
|
||||
|
||||
/**
|
||||
* Remove all watch listeners.
|
||||
*/
|
||||
@@ -749,6 +847,12 @@ export interface WxtStorage {
|
||||
key: StorageItemKey,
|
||||
options: WxtStorageItemOptions<TValue> & { defaultValue: TValue },
|
||||
): WxtStorageItem<TValue, TMetadata>;
|
||||
defineItem<TValue, TMetadata extends Record<string, unknown> = {}>(
|
||||
key: StorageItemKey,
|
||||
options: WxtStorageItemOptions<TValue> & {
|
||||
init: () => TValue | Promise<TValue>;
|
||||
},
|
||||
): WxtStorageItem<TValue, TMetadata>;
|
||||
defineItem<TValue, TMetadata extends Record<string, unknown> = {}>(
|
||||
key: StorageItemKey,
|
||||
options: WxtStorageItemOptions<TValue>,
|
||||
@@ -777,42 +881,52 @@ export interface WxtStorageItem<
|
||||
* The storage key passed when creating the storage item.
|
||||
*/
|
||||
key: StorageItemKey;
|
||||
|
||||
/**
|
||||
* @deprecated Renamed to fallback, use it instead.
|
||||
*/
|
||||
defaultValue: TValue;
|
||||
|
||||
/**
|
||||
* The value provided by the `fallback` option.
|
||||
*/
|
||||
fallback: TValue;
|
||||
|
||||
/**
|
||||
* Get the latest value from storage.
|
||||
*/
|
||||
getValue(): Promise<TValue>;
|
||||
|
||||
/**
|
||||
* Get metadata.
|
||||
*/
|
||||
getMeta(): Promise<NullablePartial<TMetadata>>;
|
||||
|
||||
/**
|
||||
* Set the value in storage.
|
||||
*/
|
||||
setValue(value: TValue): Promise<void>;
|
||||
|
||||
/**
|
||||
* Set metadata properties.
|
||||
*/
|
||||
setMeta(properties: NullablePartial<TMetadata>): Promise<void>;
|
||||
|
||||
/**
|
||||
* Remove the value from storage.
|
||||
*/
|
||||
removeValue(opts?: RemoveItemOptions): Promise<void>;
|
||||
|
||||
/**
|
||||
* Remove all metadata or certain properties from metadata.
|
||||
*/
|
||||
removeMeta(properties?: string[]): Promise<void>;
|
||||
|
||||
/**
|
||||
* Listen for changes to the value in storage.
|
||||
*/
|
||||
watch(cb: WatchCallback<TValue>): Unwatch;
|
||||
|
||||
/**
|
||||
* If there are migrations defined on the storage item, migrate to the latest version.
|
||||
*
|
||||
@@ -830,6 +944,7 @@ export interface GetItemOptions<T> {
|
||||
* @deprecated Renamed to `fallback`, use it instead.
|
||||
*/
|
||||
defaultValue?: T;
|
||||
|
||||
/**
|
||||
* Default value returned when `getItem` would otherwise return `null`.
|
||||
*/
|
||||
@@ -858,10 +973,12 @@ export interface WxtStorageItemOptions<T> {
|
||||
* @deprecated Renamed to `fallback`, use it instead.
|
||||
*/
|
||||
defaultValue?: T;
|
||||
|
||||
/**
|
||||
* Default value returned when `getValue` would otherwise return `null`.
|
||||
*/
|
||||
fallback?: T;
|
||||
|
||||
/**
|
||||
* If passed, a value in storage will be initialized immediately after
|
||||
* defining the storage item. This function returns the value that will be
|
||||
@@ -869,20 +986,24 @@ export interface WxtStorageItemOptions<T> {
|
||||
* already exist.
|
||||
*/
|
||||
init?: () => T | Promise<T>;
|
||||
|
||||
/**
|
||||
* Provide a version number for the storage item to enable migrations. When changing the version
|
||||
* in the future, migration functions will be ran on application startup.
|
||||
*/
|
||||
version?: number;
|
||||
|
||||
/**
|
||||
* A map of version numbers to the functions used to migrate the data to that version.
|
||||
*/
|
||||
migrations?: Record<number, (oldValue: any) => any>;
|
||||
|
||||
/**
|
||||
* Print debug logs, such as migration process.
|
||||
* @default false
|
||||
*/
|
||||
debug?: boolean;
|
||||
|
||||
/**
|
||||
* A callback function that runs on migration complete.
|
||||
*/
|
||||
@@ -900,10 +1021,12 @@ export type StorageAreaChanges = {
|
||||
type NullablePartial<T> = {
|
||||
[key in keyof T]+?: T[key] | undefined | null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback called when a value in storage is changed.
|
||||
*/
|
||||
export type WatchCallback<T> = (newValue: T, oldValue: T) => void;
|
||||
|
||||
/**
|
||||
* Call to remove a watch listener
|
||||
*/
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"module": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"types": "./dist/index.d.mts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.mts",
|
||||
@@ -32,7 +32,7 @@
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "buildc -- unbuild",
|
||||
"build": "buildc -- tsdown",
|
||||
"check": "buildc --deps-only -- check"
|
||||
},
|
||||
"peerDependencies": {
|
||||
@@ -40,11 +40,9 @@
|
||||
"wxt": ">=0.19.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@aklinker1/check": "^2.1.0",
|
||||
"oxlint": "^1.14.0",
|
||||
"publint": "^0.3.12",
|
||||
"typescript": "^5.9.2",
|
||||
"unbuild": "^3.6.1",
|
||||
"oxlint": "^1.43.0",
|
||||
"publint": "^0.3.17",
|
||||
"typescript": "^5.9.3",
|
||||
"unocss": "^0.64.0 || ^0.65.0 || ^65.0.0 || ^66.0.0",
|
||||
"wxt": "workspace:*"
|
||||
},
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
import { defineBuildConfig } from 'unbuild';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
export default defineBuildConfig({
|
||||
rootDir: resolve(__dirname, 'modules/webextension-polyfill'),
|
||||
outDir: resolve(__dirname, 'dist'),
|
||||
entries: [
|
||||
{ input: 'index.ts', name: 'index' },
|
||||
{ input: 'browser.ts', name: 'browser' },
|
||||
],
|
||||
replace: {
|
||||
'process.env.NPM': 'true',
|
||||
},
|
||||
declaration: true,
|
||||
});
|
||||
@@ -20,7 +20,7 @@
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"main": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"types": "./dist/index.d.mts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.mts",
|
||||
@@ -37,7 +37,7 @@
|
||||
"scripts": {
|
||||
"dev": "wxt",
|
||||
"check": "pnpm build && check",
|
||||
"build": "buildc -- unbuild",
|
||||
"build": "buildc -- tsdown",
|
||||
"prepare": "buildc --deps-only -- wxt prepare"
|
||||
},
|
||||
"peerDependencies": {
|
||||
@@ -45,11 +45,9 @@
|
||||
"wxt": ">=0.20.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@aklinker1/check": "^2.1.0",
|
||||
"@types/webextension-polyfill": "^0.12.3",
|
||||
"publint": "^0.3.12",
|
||||
"typescript": "^5.9.2",
|
||||
"unbuild": "^3.6.1",
|
||||
"@types/webextension-polyfill": "^0.12.4",
|
||||
"publint": "^0.3.17",
|
||||
"typescript": "^5.9.3",
|
||||
"webextension-polyfill": "^0.12.0",
|
||||
"wxt": "workspace:*"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import { defineConfig } from 'tsdown';
|
||||
|
||||
export default defineConfig({
|
||||
entry: {
|
||||
index: 'modules/webextension-polyfill/index.ts',
|
||||
browser: 'modules/webextension-polyfill/browser.ts',
|
||||
},
|
||||
define: {
|
||||
'process.env.NPM': 'true',
|
||||
},
|
||||
});
|
||||
@@ -18,19 +18,19 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@wxt-dev/i18n": "workspace:*",
|
||||
"react": "^19.1.1",
|
||||
"react-dom": "^19.1.1"
|
||||
"react": "^19.2.4",
|
||||
"react-dom": "^19.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^19.1.12",
|
||||
"@types/react-dom": "^19.1.9",
|
||||
"@types/react": "^19.2.13",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@wxt-dev/auto-icons": "workspace:*",
|
||||
"@wxt-dev/unocss": "workspace:*",
|
||||
"sass": "^1.92.0",
|
||||
"typescript": "^5.9.2",
|
||||
"sass": "^1.97.3",
|
||||
"typescript": "^5.9.3",
|
||||
"unocss": "^0.64.0 || ^0.65.0 || ^65.0.0 || ^66.0.0",
|
||||
"vitest": "^3.2.4",
|
||||
"vitest-plugin-random-seed": "^1.1.1",
|
||||
"vitest": "^4.0.18",
|
||||
"vitest-plugin-random-seed": "^1.1.2",
|
||||
"wxt": "workspace:*"
|
||||
},
|
||||
"buildc": {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { defineConfig } from 'wxt';
|
||||
import { presetUno } from 'unocss';
|
||||
import { presetWind3 } from 'unocss';
|
||||
|
||||
export default defineConfig({
|
||||
srcDir: 'src',
|
||||
@@ -53,7 +53,7 @@ export default defineConfig({
|
||||
],
|
||||
},
|
||||
},
|
||||
presets: [presetUno()],
|
||||
presets: [presetWind3()],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,5 +1,218 @@
|
||||
# Changelog
|
||||
|
||||
## v0.20.16
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.20.15...wxt-v0.20.16)
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Revert "rename `name` to `names` prop of `rollup` to fix deprecated warning " ([#2106](https://github.com/wxt-dev/wxt/pull/2106))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- Speed up E2E tests by skipping `pnpm install` when possible ([#2113](https://github.com/wxt-dev/wxt/pull/2113))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Aaron ([@aklinker1](https://github.com/aklinker1))
|
||||
|
||||
## v0.20.15
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.20.14...wxt-v0.20.15)
|
||||
|
||||
### 🚀 Enhancements
|
||||
|
||||
- Export `normalizePath` from `wxt` module ([#2080](https://github.com/wxt-dev/wxt/pull/2080))
|
||||
- **popup:** Add Firefox `default_area` and `theme_icons` support ([#2097](https://github.com/wxt-dev/wxt/pull/2097))
|
||||
- Add log `--level` cli option ([#1973](https://github.com/wxt-dev/wxt/pull/1973))
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Content script is incorrectly invalidated when injected multiple times ([#2035](https://github.com/wxt-dev/wxt/pull/2035))
|
||||
- Use `uiContainer` to apply position when creating shadow root ui ([#2036](https://github.com/wxt-dev/wxt/pull/2036))
|
||||
- Make `ExtensionRunner#closeBrowser` optional ([#2092](https://github.com/wxt-dev/wxt/pull/2092))
|
||||
- Rename `name` to `names` prop of `rollup` to fix deprecated warning ([#2106](https://github.com/wxt-dev/wxt/pull/2106))
|
||||
|
||||
### 💅 Refactors
|
||||
|
||||
- Standardize file existence checks to `pathExists` ([#2083](https://github.com/wxt-dev/wxt/pull/2083))
|
||||
- Cleanup esm ([#1950](https://github.com/wxt-dev/wxt/pull/1950))
|
||||
- `async`/`await` cleanup ([#2088](https://github.com/wxt-dev/wxt/pull/2088))
|
||||
- Cleanup unnecssary checks ([#2089](https://github.com/wxt-dev/wxt/pull/2089))
|
||||
- Simplify import paths ([#2093](https://github.com/wxt-dev/wxt/pull/2093))
|
||||
|
||||
### 📖 Documentation
|
||||
|
||||
- Fix JSDoc ([6ae5fb5e](https://github.com/wxt-dev/wxt/commit/6ae5fb5e))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- Cleanup comment line lengths ([#2090](https://github.com/wxt-dev/wxt/pull/2090))
|
||||
- Cleanup `@ts-*` comments ([#2094](https://github.com/wxt-dev/wxt/pull/2094))
|
||||
- Update JSDoc to use `@internal` ([#2091](https://github.com/wxt-dev/wxt/pull/2091))
|
||||
- Fix typos ([#2086](https://github.com/wxt-dev/wxt/pull/2086))
|
||||
- Remove unused code ([#2087](https://github.com/wxt-dev/wxt/pull/2087))
|
||||
- Simplify imports of `cli/__tests__/index.ts` ([#2104](https://github.com/wxt-dev/wxt/pull/2104))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Nick Doan ([@nickbar01234](https://github.com/nickbar01234))
|
||||
- Patryk Kuniczak ([@PatrykKuniczak](https://github.com/PatrykKuniczak))
|
||||
- Aaron ([@aklinker1](https://github.com/aklinker1))
|
||||
- Wotan-allfather <wotan-ai@proton.me>
|
||||
- Namu ([@namuorg](https://github.com/namuorg))
|
||||
- Eli ([@lishaduck](https://github.com/lishaduck))
|
||||
|
||||
## v0.20.14
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.20.13...wxt-v0.20.14)
|
||||
|
||||
### 🚀 Enhancements
|
||||
|
||||
- Add `onBeforeMount` callback to `createIframeUi` options ([#1899](https://github.com/wxt-dev/wxt/pull/1899))
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Remove failing test ([6fb4cee4](https://github.com/wxt-dev/wxt/commit/6fb4cee4))
|
||||
- Rename and make firefoxPrefs in web-ext.config.ts work ([#2068](https://github.com/wxt-dev/wxt/pull/2068))
|
||||
- **content-script-context:** Handle undefined browser.runtime ([#2042](https://github.com/wxt-dev/wxt/pull/2042))
|
||||
- `MaxListenersExceededWarning` ([#2058](https://github.com/wxt-dev/wxt/pull/2058))
|
||||
|
||||
### 📖 Documentation
|
||||
|
||||
- Fix alignment of 2 last comments of regex patterns ([#2012](https://github.com/wxt-dev/wxt/pull/2012))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- Use `tsdown` to build packages ([#2006](https://github.com/wxt-dev/wxt/pull/2006))
|
||||
- Move script-only dev dependencies to top-level `package.json` ([#2007](https://github.com/wxt-dev/wxt/pull/2007))
|
||||
- Update dependencies ([#2069](https://github.com/wxt-dev/wxt/pull/2069))
|
||||
- Upgrade major deps ([#2070](https://github.com/wxt-dev/wxt/pull/2070))
|
||||
- Refresh lockfile and upgrade subdependencies ([#2071](https://github.com/wxt-dev/wxt/pull/2071))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Dareka ([@darekadareka](https://github.com/darekadareka))
|
||||
- Mark ([@mjfaga](https://github.com/mjfaga))
|
||||
- ariasuni ([@ariasuni](https://github.com/ariasuni))
|
||||
- Aaron ([@aklinker1](https://github.com/aklinker1))
|
||||
- Patryk Kuniczak ([@PatrykKuniczak](https://github.com/PatrykKuniczak))
|
||||
- Bohuslavsemenov ([@bohuslavsemenov](https://github.com/bohuslavsemenov))
|
||||
|
||||
## v0.20.13
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.20.12...wxt-v0.20.13)
|
||||
|
||||
### 🚀 Enhancements
|
||||
|
||||
- Remove script element immediately in injectScript ([#1761](https://github.com/wxt-dev/wxt/pull/1761))
|
||||
- Add `modifyScript` option to `injectScript` ([#1762](https://github.com/wxt-dev/wxt/pull/1762))
|
||||
- Make `injectScript` return the created script element ([#1838](https://github.com/wxt-dev/wxt/pull/1838))
|
||||
- Support `.wxtrc` config file ([#1833](https://github.com/wxt-dev/wxt/pull/1833))
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Make `injectScript` wait until script is actually loaded ([#1763](https://github.com/wxt-dev/wxt/pull/1763))
|
||||
- Don't return promises from unlisted scripts that do not have an async `main` function ([#1907](https://github.com/wxt-dev/wxt/pull/1907))
|
||||
|
||||
### 💅 Refactors
|
||||
|
||||
- Use `script.text` instead of `innerHTML` in `injectScript` ([#1764](https://github.com/wxt-dev/wxt/pull/1764))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Rxliuli ([@rxliuli](https://github.com/rxliuli))
|
||||
- Sebastian Landwehr <info@sebastianlandwehr.com>
|
||||
- Johan Kiviniemi ([@ion1](https://github.com/ion1))
|
||||
|
||||
## v0.20.12
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.20.11...wxt-v0.20.12)
|
||||
|
||||
### 🚀 Enhancements
|
||||
|
||||
- Remove `data-wxt-*` attributes ([#1913](https://github.com/wxt-dev/wxt/pull/1913))
|
||||
- Default to using `use_dynamic_url: true` for content script css files ([#1993](https://github.com/wxt-dev/wxt/pull/1993))
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Wxt normal logs are drowned by `dotenv@17.0.0` ads ([#1883](https://github.com/wxt-dev/wxt/pull/1883))
|
||||
- Optimize `splitShadowRootCss` ([#1934](https://github.com/wxt-dev/wxt/pull/1934))
|
||||
- `wxt prepare` fails with the error "__vite_ssr_exportName__ is not defined" when using Vite 7 ([#1884](https://github.com/wxt-dev/wxt/pull/1884))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- Use `linkedom` a test instead of `happy-dom` ([#1957](https://github.com/wxt-dev/wxt/pull/1957))
|
||||
- Add support for `vite-node` v5 ([#2001](https://github.com/wxt-dev/wxt/pull/2001))
|
||||
- Upgrade dev and non-major prod dependencies ([#2000](https://github.com/wxt-dev/wxt/pull/2000))
|
||||
- **dev-deps:** Upgrade `happy-dom` to address CVE-2025-61927 ([#2002](https://github.com/wxt-dev/wxt/pull/2002))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Aaron ([@aklinker1](https://github.com/aklinker1))
|
||||
- Jaguar Zhou ([@aiktb](https://github.com/aiktb))
|
||||
- Alexander Harding <noreply@harding.dev>
|
||||
- Florian Kühne ([@ZerGo0](https://github.com/ZerGo0))
|
||||
|
||||
## v0.20.11
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.20.10...wxt-v0.20.11)
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Split `wxt/testing` into separate modules to fix issues with `jsdom` and `happy-dom` ([#1844](https://github.com/wxt-dev/wxt/pull/1844))
|
||||
- `input_components` is supported by mv3 ([#1881](https://github.com/wxt-dev/wxt/pull/1881))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- **deps:** Upgrade project subdependencies ([#1882](https://github.com/wxt-dev/wxt/pull/1882))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Aaron ([@aklinker1](https://github.com/aklinker1))
|
||||
- Qijia Liu <liumeo@pku.edu.cn>
|
||||
- Marcellino Ornelas ([@marcellino-ornelas](https://github.com/marcellino-ornelas))
|
||||
|
||||
## v0.20.10
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.20.9...wxt-v0.20.10)
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- **deps:** Upgrade non-breaking production dependencies ([#1877](https://github.com/wxt-dev/wxt/pull/1877))
|
||||
- **deps:** Upgrade web-ext-run to support CDP ([#1879](https://github.com/wxt-dev/wxt/pull/1879))
|
||||
- **deps:** `publish-browser-extension` upgrade ([#1880](https://github.com/wxt-dev/wxt/pull/1880))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Aaron ([@aklinker1](https://github.com/aklinker1))
|
||||
|
||||
## v0.20.9
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.20.8...wxt-v0.20.9)
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- **types:** Use TType for DocumentEventMap key in ctx.addEventListener ([#1863](https://github.com/wxt-dev/wxt/pull/1863))
|
||||
- Prevent Unlisted CSS from being excluded in the build when using CSS preprocessor ([#1590](https://github.com/wxt-dev/wxt/pull/1590))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- **deps:** Upgrade oxlint from 0.16.8 to 1.14.0 ([a01928e0](https://github.com/wxt-dev/wxt/commit/a01928e0))
|
||||
- **deps:** Upgrade typescript from 5.8.3 to 5.9.2 ([a6eef643](https://github.com/wxt-dev/wxt/commit/a6eef643))
|
||||
- Upgrade nano-spawn to v1 ([5fefd8e0](https://github.com/wxt-dev/wxt/commit/5fefd8e0))
|
||||
- Upgrade faker to v10 ([984568e0](https://github.com/wxt-dev/wxt/commit/984568e0))
|
||||
- Upgrade dotenv to v17.2.2 ([380a9630](https://github.com/wxt-dev/wxt/commit/380a9630))
|
||||
- Upgrade happy-dom to v18.0.1 ([c1c3d3b7](https://github.com/wxt-dev/wxt/commit/c1c3d3b7))
|
||||
- Create script for managing dependency upgrades ([#1875](https://github.com/wxt-dev/wxt/pull/1875))
|
||||
- **deps:** Upgrade all dev dependencies ([#1876](https://github.com/wxt-dev/wxt/pull/1876))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Aaron ([@aklinker1](https://github.com/aklinker1))
|
||||
- Kim Gyeongjae ([@PortalCube](https://github.com/PortalCube))
|
||||
- Atomie CHEN <atomic_cwh@163.com>
|
||||
|
||||
## v0.20.8
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.20.7...wxt-v0.20.8)
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
import { defineBuildConfig } from 'unbuild';
|
||||
import { version, exports } from './package.json';
|
||||
import { readFile, writeFile } from 'fs/promises';
|
||||
import {
|
||||
virtualEntrypointModuleNames,
|
||||
virtualModuleNames,
|
||||
} from './src/core/utils/virtual-modules';
|
||||
|
||||
export default defineBuildConfig([
|
||||
// Non-virtual modules can be transpiled with mkdist
|
||||
{
|
||||
entries: [
|
||||
{
|
||||
builder: 'mkdist',
|
||||
input: 'src',
|
||||
pattern: ['**/*', '!**/__tests__', '!**/*.md', '!virtual', '!@types'],
|
||||
declaration: true,
|
||||
},
|
||||
],
|
||||
hooks: {
|
||||
async 'build:done'() {
|
||||
// Replace any template variables in output files
|
||||
await replaceVars('dist/version.mjs', { version });
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// Virtual modules must be bundled individually
|
||||
...virtualModuleNames.map((moduleName) => ({
|
||||
entries: [`src/virtual/${moduleName}.ts`],
|
||||
externals: [
|
||||
...virtualEntrypointModuleNames.map((name) => `virtual:user-${name}`),
|
||||
'virtual:wxt-plugins',
|
||||
'virtual:app-config',
|
||||
...Object.keys(exports).map((path) => 'wxt' + path.slice(1)), // ./utils/storage => wxt/utils/storage
|
||||
],
|
||||
})),
|
||||
]);
|
||||
|
||||
async function replaceVars(file: string, vars: Record<string, string>) {
|
||||
let text = await readFile(file, 'utf8');
|
||||
Object.entries(vars).forEach(([name, value]) => {
|
||||
text = text.replaceAll(`{{${name}}}`, value);
|
||||
});
|
||||
await writeFile(file, text, 'utf8');
|
||||
}
|
||||
@@ -30,8 +30,8 @@ describe('Analysis', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(await project.fileExists('stats.html')).toBe(true);
|
||||
expect(await project.fileExists('.output/chrome-mv3/stats-0.json')).toBe(
|
||||
expect(await project.pathExists('stats.html')).toBe(true);
|
||||
expect(await project.pathExists('.output/chrome-mv3/stats-0.json')).toBe(
|
||||
false,
|
||||
);
|
||||
});
|
||||
@@ -52,9 +52,9 @@ describe('Analysis', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(await project.fileExists('stats.html')).toBe(true);
|
||||
expect(await project.fileExists('stats-0.json')).toBe(true);
|
||||
expect(await project.fileExists('stats-1.json')).toBe(true);
|
||||
expect(await project.pathExists('stats.html')).toBe(true);
|
||||
expect(await project.pathExists('stats-0.json')).toBe(true);
|
||||
expect(await project.pathExists('stats-1.json')).toBe(true);
|
||||
});
|
||||
|
||||
it('should support customizing the stats output directory', async () => {
|
||||
@@ -73,7 +73,7 @@ describe('Analysis', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(await project.fileExists('stats/bundle.html')).toBe(true);
|
||||
expect(await project.pathExists('stats/bundle.html')).toBe(true);
|
||||
});
|
||||
|
||||
it('should place artifacts next to the custom output file', async () => {
|
||||
@@ -93,9 +93,9 @@ describe('Analysis', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(await project.fileExists('stats/bundle.html')).toBe(true);
|
||||
expect(await project.fileExists('stats/bundle-0.json')).toBe(true);
|
||||
expect(await project.fileExists('stats/bundle-1.json')).toBe(true);
|
||||
expect(await project.pathExists('stats/bundle.html')).toBe(true);
|
||||
expect(await project.pathExists('stats/bundle-0.json')).toBe(true);
|
||||
expect(await project.pathExists('stats/bundle-1.json')).toBe(true);
|
||||
});
|
||||
|
||||
it('should open the stats in the browser when requested', async () => {
|
||||
|
||||
@@ -17,22 +17,22 @@ describe('Auto Imports', () => {
|
||||
// Generated by wxt
|
||||
export {}
|
||||
declare global {
|
||||
const ContentScriptContext: typeof import('wxt/utils/content-script-context')['ContentScriptContext']
|
||||
const InvalidMatchPattern: typeof import('wxt/utils/match-patterns')['InvalidMatchPattern']
|
||||
const MatchPattern: typeof import('wxt/utils/match-patterns')['MatchPattern']
|
||||
const browser: typeof import('wxt/browser')['browser']
|
||||
const createIframeUi: typeof import('wxt/utils/content-script-ui/iframe')['createIframeUi']
|
||||
const createIntegratedUi: typeof import('wxt/utils/content-script-ui/integrated')['createIntegratedUi']
|
||||
const createShadowRootUi: typeof import('wxt/utils/content-script-ui/shadow-root')['createShadowRootUi']
|
||||
const defineAppConfig: typeof import('wxt/utils/define-app-config')['defineAppConfig']
|
||||
const defineBackground: typeof import('wxt/utils/define-background')['defineBackground']
|
||||
const defineContentScript: typeof import('wxt/utils/define-content-script')['defineContentScript']
|
||||
const defineUnlistedScript: typeof import('wxt/utils/define-unlisted-script')['defineUnlistedScript']
|
||||
const defineWxtPlugin: typeof import('wxt/utils/define-wxt-plugin')['defineWxtPlugin']
|
||||
const fakeBrowser: typeof import('wxt/testing')['fakeBrowser']
|
||||
const injectScript: typeof import('wxt/utils/inject-script')['injectScript']
|
||||
const storage: typeof import('wxt/utils/storage')['storage']
|
||||
const useAppConfig: typeof import('wxt/utils/app-config')['useAppConfig']
|
||||
const ContentScriptContext: typeof import('wxt/utils/content-script-context').ContentScriptContext
|
||||
const InvalidMatchPattern: typeof import('wxt/utils/match-patterns').InvalidMatchPattern
|
||||
const MatchPattern: typeof import('wxt/utils/match-patterns').MatchPattern
|
||||
const browser: typeof import('wxt/browser').browser
|
||||
const createIframeUi: typeof import('wxt/utils/content-script-ui/iframe').createIframeUi
|
||||
const createIntegratedUi: typeof import('wxt/utils/content-script-ui/integrated').createIntegratedUi
|
||||
const createShadowRootUi: typeof import('wxt/utils/content-script-ui/shadow-root').createShadowRootUi
|
||||
const defineAppConfig: typeof import('wxt/utils/define-app-config').defineAppConfig
|
||||
const defineBackground: typeof import('wxt/utils/define-background').defineBackground
|
||||
const defineContentScript: typeof import('wxt/utils/define-content-script').defineContentScript
|
||||
const defineUnlistedScript: typeof import('wxt/utils/define-unlisted-script').defineUnlistedScript
|
||||
const defineWxtPlugin: typeof import('wxt/utils/define-wxt-plugin').defineWxtPlugin
|
||||
const fakeBrowser: typeof import('wxt/testing').fakeBrowser
|
||||
const injectScript: typeof import('wxt/utils/inject-script').injectScript
|
||||
const storage: typeof import('wxt/utils/storage').storage
|
||||
const useAppConfig: typeof import('wxt/utils/app-config').useAppConfig
|
||||
}
|
||||
// for type re-export
|
||||
declare global {
|
||||
@@ -142,7 +142,7 @@ describe('Auto Imports', () => {
|
||||
|
||||
await project.prepare();
|
||||
|
||||
expect(await project.fileExists('.wxt/types/imports.d.ts')).toBe(false);
|
||||
expect(await project.pathExists('.wxt/types/imports.d.ts')).toBe(false);
|
||||
});
|
||||
|
||||
it('should only include imports-module.d.ts in the the project', async () => {
|
||||
@@ -280,24 +280,10 @@ describe('Auto Imports', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(await project.fileExists('.wxt/eslint-auto-imports.mjs')).toBe(
|
||||
expect(await project.pathExists('.wxt/eslint-auto-imports.mjs')).toBe(
|
||||
false,
|
||||
);
|
||||
expect(await project.fileExists('.wxt/eslintrc-auto-import.json')).toBe(
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
it('should NOT output an ESlint config file by default', async () => {
|
||||
const project = new TestProject();
|
||||
project.addFile('entrypoints/popup.html', `<html></html>`);
|
||||
|
||||
await project.prepare();
|
||||
|
||||
expect(await project.fileExists('.wxt/eslint-auto-imports.mjs')).toBe(
|
||||
false,
|
||||
);
|
||||
expect(await project.fileExists('.wxt/eslintrc-auto-import.json')).toBe(
|
||||
expect(await project.pathExists('.wxt/eslintrc-auto-import.json')).toBe(
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -77,7 +77,7 @@ describe('Module Helpers', () => {
|
||||
|
||||
await project.build(config);
|
||||
|
||||
expect(await project.fileExists('.output/chrome-mv3/injected.js')).toBe(
|
||||
expect(await project.pathExists('.output/chrome-mv3/injected.js')).toBe(
|
||||
true,
|
||||
);
|
||||
});
|
||||
@@ -118,10 +118,10 @@ describe('Module Helpers', () => {
|
||||
fileName: 'module.txt',
|
||||
});
|
||||
await expect(
|
||||
project.fileExists('.output/chrome-mv3/module.txt'),
|
||||
project.pathExists('.output/chrome-mv3/module.txt'),
|
||||
).resolves.toBe(true);
|
||||
await expect(
|
||||
project.fileExists('.output/chrome-mv3/example/generated.txt'),
|
||||
project.pathExists('.output/chrome-mv3/example/generated.txt'),
|
||||
).resolves.toBe(true);
|
||||
});
|
||||
|
||||
@@ -298,7 +298,7 @@ describe('Module Helpers', () => {
|
||||
|
||||
await expect(
|
||||
project.serializeFile('.wxt/types/imports.d.ts'),
|
||||
).resolves.toContain("const ref: typeof import('vue')['ref']");
|
||||
).resolves.toContain("const ref: typeof import('vue').ref");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -126,7 +126,7 @@ describe('Output Directory Structure', () => {
|
||||
|
||||
await project.build({ browser: 'firefox' });
|
||||
|
||||
expect(await project.fileExists('.output/firefox-mv2/background.js')).toBe(
|
||||
expect(await project.pathExists('.output/firefox-mv2/background.js')).toBe(
|
||||
false,
|
||||
);
|
||||
});
|
||||
@@ -146,7 +146,7 @@ describe('Output Directory Structure', () => {
|
||||
|
||||
await project.build({ browser: 'chrome' });
|
||||
|
||||
expect(await project.fileExists('.output/firefox-mv2/background.js')).toBe(
|
||||
expect(await project.pathExists('.output/firefox-mv2/background.js')).toBe(
|
||||
false,
|
||||
);
|
||||
});
|
||||
@@ -174,7 +174,7 @@ describe('Output Directory Structure', () => {
|
||||
|
||||
await project.build();
|
||||
|
||||
expect(await project.fileExists('stats.html')).toBe(true);
|
||||
expect(await project.pathExists('stats.html')).toBe(true);
|
||||
});
|
||||
|
||||
it('should support JavaScript entrypoints', async () => {
|
||||
@@ -210,14 +210,14 @@ describe('Output Directory Structure', () => {
|
||||
----------------------------------------
|
||||
{"manifest_version":3,"name":"E2E Extension","description":"Example description","version":"0.0.0","background":{"service_worker":"background.js"},"content_scripts":[{"matches":["*://*.google.com/*"],"js":["content-scripts/content.js"]},{"matches":["*://*.duckduckgo.com/*"],"js":["content-scripts/named.js"]}]}"
|
||||
`);
|
||||
expect(await project.fileExists('.output/chrome-mv3/background.js'));
|
||||
expect(await project.pathExists('.output/chrome-mv3/background.js'));
|
||||
expect(
|
||||
await project.fileExists('.output/chrome-mv3/content-scripts/content.js'),
|
||||
await project.pathExists('.output/chrome-mv3/content-scripts/content.js'),
|
||||
);
|
||||
expect(
|
||||
await project.fileExists('.output/chrome-mv3/content-scripts/named.js'),
|
||||
await project.pathExists('.output/chrome-mv3/content-scripts/named.js'),
|
||||
);
|
||||
expect(await project.fileExists('.output/chrome-mv3/unlisted.js'));
|
||||
expect(await project.pathExists('.output/chrome-mv3/unlisted.js'));
|
||||
});
|
||||
|
||||
it('should support CSS entrypoints', async () => {
|
||||
@@ -300,7 +300,7 @@ describe('Output Directory Structure', () => {
|
||||
|
||||
await project.build();
|
||||
|
||||
expect(await project.fileExists('dist/chrome-mv3/manifest.json')).toBe(
|
||||
expect(await project.pathExists('dist/chrome-mv3/manifest.json')).toBe(
|
||||
true,
|
||||
);
|
||||
});
|
||||
@@ -335,7 +335,7 @@ describe('Output Directory Structure', () => {
|
||||
await project.build({
|
||||
vite: () => ({
|
||||
build: {
|
||||
// Make output for snapshot readible
|
||||
// Make output for the snapshot readable
|
||||
minify: false,
|
||||
},
|
||||
}),
|
||||
@@ -343,45 +343,40 @@ describe('Output Directory Structure', () => {
|
||||
|
||||
expect(await project.serializeFile('.output/chrome-mv3/background.js'))
|
||||
.toMatchInlineSnapshot(`
|
||||
".output/chrome-mv3/background.js
|
||||
----------------------------------------
|
||||
var _a, _b;
|
||||
import { l as logHello, i as initPlugins } from "./chunks/_virtual_wxt-plugins-OjKtWpmY.js";
|
||||
function defineBackground(arg) {
|
||||
if (arg == null || typeof arg === "function") return { main: arg };
|
||||
return arg;
|
||||
}
|
||||
const definition = defineBackground({
|
||||
type: "module",
|
||||
main() {
|
||||
logHello("background");
|
||||
".output/chrome-mv3/background.js
|
||||
----------------------------------------
|
||||
import { l as logHello, i as initPlugins } from "./chunks/_virtual_wxt-plugins-OjKtWpmY.js";
|
||||
function defineBackground(arg) {
|
||||
if (arg == null || typeof arg === "function") return { main: arg };
|
||||
return arg;
|
||||
}
|
||||
});
|
||||
((_b = (_a = globalThis.browser) == null ? void 0 : _a.runtime) == null ? void 0 : _b.id) ? globalThis.browser : globalThis.chrome;
|
||||
function print(method, ...args) {
|
||||
return;
|
||||
}
|
||||
const logger = {
|
||||
debug: (...args) => print(console.debug, ...args),
|
||||
log: (...args) => print(console.log, ...args),
|
||||
warn: (...args) => print(console.warn, ...args),
|
||||
error: (...args) => print(console.error, ...args)
|
||||
};
|
||||
let result;
|
||||
try {
|
||||
initPlugins();
|
||||
result = definition.main();
|
||||
if (result instanceof Promise) {
|
||||
console.warn(
|
||||
"The background's main() function return a promise, but it must be synchronous"
|
||||
);
|
||||
const definition = defineBackground({
|
||||
type: "module",
|
||||
main() {
|
||||
logHello("background");
|
||||
}
|
||||
});
|
||||
globalThis.browser?.runtime?.id ? globalThis.browser : globalThis.chrome;
|
||||
function print(method, ...args) {
|
||||
return;
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error("The background crashed on startup!");
|
||||
throw err;
|
||||
}
|
||||
"
|
||||
`);
|
||||
const logger = {
|
||||
debug: (...args) => print(console.debug, ...args),
|
||||
log: (...args) => print(console.log, ...args),
|
||||
warn: (...args) => print(console.warn, ...args),
|
||||
error: (...args) => print(console.error, ...args)
|
||||
};
|
||||
let result;
|
||||
try {
|
||||
initPlugins();
|
||||
result = definition.main();
|
||||
if (result instanceof Promise) console.warn("The background's main() function return a promise, but it must be synchronous");
|
||||
} catch (err) {
|
||||
logger.error("The background crashed on startup!");
|
||||
throw err;
|
||||
}
|
||||
"
|
||||
`);
|
||||
});
|
||||
|
||||
it('should generate IIFE background script when type=undefined', async () => {
|
||||
@@ -413,7 +408,7 @@ describe('Output Directory Structure', () => {
|
||||
await project.build({
|
||||
vite: () => ({
|
||||
build: {
|
||||
// Make output for snapshot readible
|
||||
// Make output for the snapshot readable
|
||||
minify: false,
|
||||
},
|
||||
}),
|
||||
@@ -421,52 +416,47 @@ describe('Output Directory Structure', () => {
|
||||
|
||||
expect(await project.serializeFile('.output/chrome-mv3/background.js'))
|
||||
.toMatchInlineSnapshot(`
|
||||
".output/chrome-mv3/background.js
|
||||
----------------------------------------
|
||||
var background = function() {
|
||||
"use strict";
|
||||
var _a, _b;
|
||||
function defineBackground(arg) {
|
||||
if (arg == null || typeof arg === "function") return { main: arg };
|
||||
return arg;
|
||||
".output/chrome-mv3/background.js
|
||||
----------------------------------------
|
||||
var background = (function() {
|
||||
"use strict";
|
||||
function defineBackground(arg) {
|
||||
if (arg == null || typeof arg === "function") return { main: arg };
|
||||
return arg;
|
||||
}
|
||||
function logHello(name) {
|
||||
console.log(\`Hello \${name}!\`);
|
||||
}
|
||||
const definition = defineBackground({
|
||||
main() {
|
||||
logHello("background");
|
||||
}
|
||||
function logHello(name) {
|
||||
console.log(\`Hello \${name}!\`);
|
||||
}
|
||||
const definition = defineBackground({
|
||||
main() {
|
||||
logHello("background");
|
||||
}
|
||||
});
|
||||
function initPlugins() {
|
||||
}
|
||||
((_b = (_a = globalThis.browser) == null ? void 0 : _a.runtime) == null ? void 0 : _b.id) ? globalThis.browser : globalThis.chrome;
|
||||
function print(method, ...args) {
|
||||
return;
|
||||
}
|
||||
const logger = {
|
||||
debug: (...args) => print(console.debug, ...args),
|
||||
log: (...args) => print(console.log, ...args),
|
||||
warn: (...args) => print(console.warn, ...args),
|
||||
error: (...args) => print(console.error, ...args)
|
||||
};
|
||||
let result;
|
||||
try {
|
||||
initPlugins();
|
||||
result = definition.main();
|
||||
if (result instanceof Promise) {
|
||||
console.warn(
|
||||
"The background's main() function return a promise, but it must be synchronous"
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error("The background crashed on startup!");
|
||||
throw err;
|
||||
}
|
||||
const result$1 = result;
|
||||
return result$1;
|
||||
}();
|
||||
"
|
||||
`);
|
||||
});
|
||||
function initPlugins() {
|
||||
}
|
||||
globalThis.browser?.runtime?.id ? globalThis.browser : globalThis.chrome;
|
||||
function print(method, ...args) {
|
||||
return;
|
||||
}
|
||||
const logger = {
|
||||
debug: (...args) => print(console.debug, ...args),
|
||||
log: (...args) => print(console.log, ...args),
|
||||
warn: (...args) => print(console.warn, ...args),
|
||||
error: (...args) => print(console.error, ...args)
|
||||
};
|
||||
let result;
|
||||
try {
|
||||
initPlugins();
|
||||
result = definition.main();
|
||||
if (result instanceof Promise) console.warn("The background's main() function return a promise, but it must be synchronous");
|
||||
} catch (err) {
|
||||
logger.error("The background crashed on startup!");
|
||||
throw err;
|
||||
}
|
||||
var background_entrypoint_default = result;
|
||||
return background_entrypoint_default;
|
||||
})();
|
||||
"
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -31,7 +31,7 @@ describe('React', () => {
|
||||
await project.build();
|
||||
|
||||
expect(
|
||||
await project.fileExists('.output/chrome-mv3/content-scripts/demo.js'),
|
||||
await project.pathExists('.output/chrome-mv3/content-scripts/demo.js'),
|
||||
).toBe(true);
|
||||
expect(await project.serializeFile('.output/chrome-mv3/manifest.json'))
|
||||
.toMatchInlineSnapshot(`
|
||||
|
||||
@@ -16,11 +16,11 @@ describe('Remote Code', () => {
|
||||
const output = await project.serializeFile('.output/chrome-mv3/popup.js');
|
||||
expect(output).toContain(
|
||||
// Some text that will hopefully be in future versions of this script
|
||||
'lodash.com',
|
||||
'__lodash_placeholder__',
|
||||
);
|
||||
expect(output).not.toContain(url);
|
||||
expect(
|
||||
await project.fileExists(`.wxt/cache/${encodeURIComponent(url)}`),
|
||||
await project.pathExists(`.wxt/cache/${encodeURIComponent(url)}`),
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -108,7 +108,7 @@ describe('User Config', () => {
|
||||
await project.build({ configFile: 'test.config.ts' });
|
||||
|
||||
expect(
|
||||
await project.fileExists('.custom-output/chrome-mv3/background.js'),
|
||||
await project.pathExists('.custom-output/chrome-mv3/background.js'),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
@@ -129,27 +129,25 @@ describe('User Config', () => {
|
||||
await project.build();
|
||||
|
||||
expect(
|
||||
await project.fileExists('.output/test-chrome-mv3-production-build'),
|
||||
await project.pathExists('.output/test-chrome-mv3-production-build'),
|
||||
).toBe(true);
|
||||
|
||||
await project.build({ mode: 'development' });
|
||||
|
||||
expect(
|
||||
await project.fileExists('.output/test-chrome-mv3-development-dev-build'),
|
||||
await project.pathExists('.output/test-chrome-mv3-development-dev-build'),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('should throw error when config file not exist', async () => {
|
||||
it('should not throw error when config file not exist', async () => {
|
||||
const project = new TestProject();
|
||||
project.addFile(
|
||||
'src/entrypoints/background.ts',
|
||||
'entrypoints/background.ts',
|
||||
`export default defineBackground(
|
||||
() => console.log('Hello background'),
|
||||
);`,
|
||||
);
|
||||
|
||||
await expect(
|
||||
project.build({ configFile: 'foo.config.ts' }),
|
||||
).rejects.toThrowError(/not found/);
|
||||
await project.build({ configFile: 'foo.config.ts' });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -26,7 +26,7 @@ describe('Zipping', () => {
|
||||
browser: 'firefox',
|
||||
zip: { downloadPackages: ['flatten'] },
|
||||
});
|
||||
expect(await project.fileExists('.output/')).toBe(true);
|
||||
expect(await project.pathExists('.output/')).toBe(true);
|
||||
|
||||
await extract(sourcesZip, { dir: unzipDir });
|
||||
// Update package json wxt path
|
||||
@@ -51,7 +51,7 @@ describe('Zipping', () => {
|
||||
}),
|
||||
).resolves.not.toHaveProperty('exitCode');
|
||||
|
||||
await expect(project.fileExists(unzipDir, '.output')).resolves.toBe(true);
|
||||
await expect(project.pathExists(unzipDir, '.output')).resolves.toBe(true);
|
||||
expect(
|
||||
await project.serializeFile(
|
||||
project.resolvePath(unzipDir, 'package.json'),
|
||||
@@ -95,8 +95,8 @@ describe('Zipping', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(await project.fileExists(artifactZip)).toBe(true);
|
||||
expect(await project.fileExists(sourcesZip)).toBe(true);
|
||||
expect(await project.pathExists(artifactZip)).toBe(true);
|
||||
expect(await project.pathExists(sourcesZip)).toBe(true);
|
||||
});
|
||||
|
||||
it('should not zip hidden files into sources by default', async () => {
|
||||
@@ -117,8 +117,8 @@ describe('Zipping', () => {
|
||||
browser: 'firefox',
|
||||
});
|
||||
await extract(sourcesZip, { dir: unzipDir });
|
||||
expect(await project.fileExists(unzipDir, '.env')).toBe(false);
|
||||
expect(await project.fileExists(unzipDir, '.hidden-dir/file')).toBe(false);
|
||||
expect(await project.pathExists(unzipDir, '.env')).toBe(false);
|
||||
expect(await project.pathExists(unzipDir, '.hidden-dir/file')).toBe(false);
|
||||
});
|
||||
|
||||
it('should not zip files inside hidden directories if only the directory is specified', async () => {
|
||||
@@ -142,8 +142,8 @@ describe('Zipping', () => {
|
||||
},
|
||||
});
|
||||
await extract(sourcesZip, { dir: unzipDir });
|
||||
expect(await project.fileExists(unzipDir, '.hidden-dir/file')).toBe(false);
|
||||
expect(await project.fileExists(unzipDir, '.hidden-dir/nested/file')).toBe(
|
||||
expect(await project.pathExists(unzipDir, '.hidden-dir/file')).toBe(false);
|
||||
expect(await project.pathExists(unzipDir, '.hidden-dir/nested/file')).toBe(
|
||||
false,
|
||||
);
|
||||
});
|
||||
@@ -171,12 +171,12 @@ describe('Zipping', () => {
|
||||
},
|
||||
});
|
||||
await extract(sourcesZip, { dir: unzipDir });
|
||||
expect(await project.fileExists(unzipDir, '.env')).toBe(true);
|
||||
expect(await project.fileExists(unzipDir, '.hidden-dir/file')).toBe(true);
|
||||
expect(await project.fileExists(unzipDir, '.hidden-dir/nested/file1')).toBe(
|
||||
expect(await project.pathExists(unzipDir, '.env')).toBe(true);
|
||||
expect(await project.pathExists(unzipDir, '.hidden-dir/file')).toBe(true);
|
||||
expect(await project.pathExists(unzipDir, '.hidden-dir/nested/file1')).toBe(
|
||||
true,
|
||||
);
|
||||
expect(await project.fileExists(unzipDir, '.hidden-dir/nested/file2')).toBe(
|
||||
expect(await project.pathExists(unzipDir, '.hidden-dir/nested/file2')).toBe(
|
||||
true,
|
||||
);
|
||||
});
|
||||
@@ -210,10 +210,10 @@ describe('Zipping', () => {
|
||||
});
|
||||
await extract(sourcesZip, { dir: unzipDir });
|
||||
expect(
|
||||
await project.fileExists(unzipDir, 'entrypoints/not-firefox.content.ts'),
|
||||
await project.pathExists(unzipDir, 'entrypoints/not-firefox.content.ts'),
|
||||
).toBe(false);
|
||||
expect(
|
||||
await project.fileExists(unzipDir, 'entrypoints/all.content.ts'),
|
||||
await project.pathExists(unzipDir, 'entrypoints/all.content.ts'),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
@@ -234,7 +234,7 @@ describe('Zipping', () => {
|
||||
browser,
|
||||
});
|
||||
|
||||
expect(await project.fileExists(sourcesZip)).toBe(true);
|
||||
expect(await project.pathExists(sourcesZip)).toBe(true);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -258,7 +258,7 @@ describe('Zipping', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(await project.fileExists(sourcesZip)).toBe(true);
|
||||
expect(await project.pathExists(sourcesZip)).toBe(true);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -282,7 +282,7 @@ describe('Zipping', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(await project.fileExists(sourcesZip)).toBe(false);
|
||||
expect(await project.pathExists(sourcesZip)).toBe(false);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -305,6 +305,6 @@ describe('Zipping', () => {
|
||||
});
|
||||
|
||||
await extract(sourcesZip, { dir: unzipDir });
|
||||
expect(await project.fileExists(unzipDir, 'manifest.json')).toBe(true);
|
||||
expect(await project.pathExists(unzipDir, 'manifest.json')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
+24
-19
@@ -1,7 +1,8 @@
|
||||
import { dirname, relative, resolve } from 'path';
|
||||
import fs, { mkdir } from 'fs-extra';
|
||||
import glob from 'fast-glob';
|
||||
import fs, { mkdir } from 'fs-extra';
|
||||
import merge from 'lodash.merge';
|
||||
import spawn from 'nano-spawn';
|
||||
import { dirname, relative, resolve } from 'path';
|
||||
import {
|
||||
InlineConfig,
|
||||
UserConfig,
|
||||
@@ -10,8 +11,7 @@ import {
|
||||
prepare,
|
||||
zip,
|
||||
} from '../src';
|
||||
import { normalizePath } from '../src/core/utils/paths';
|
||||
import merge from 'lodash.merge';
|
||||
import { normalizePath } from '../src/core/utils';
|
||||
|
||||
// Run "pnpm wxt" to use the "wxt" dev script, not the "wxt" binary from the
|
||||
// wxt package. This uses the TS files instead of the compiled JS package
|
||||
@@ -24,6 +24,7 @@ export class TestProject {
|
||||
files: Array<[string, string]> = [];
|
||||
config: UserConfig | undefined;
|
||||
readonly root: string;
|
||||
readonly hasCustomDependencies: boolean;
|
||||
|
||||
constructor(packageJson: any = {}) {
|
||||
// We can't put each test's project inside e2e/dist directly, otherwise the wxt.config.ts
|
||||
@@ -31,6 +32,13 @@ export class TestProject {
|
||||
// end to make each test's path unique.
|
||||
const id = Math.random().toString(32).substring(3);
|
||||
this.root = resolve(E2E_DIR, 'dist', id);
|
||||
|
||||
this.hasCustomDependencies =
|
||||
Object.keys({
|
||||
...packageJson.dependencies,
|
||||
...packageJson.devDependencies,
|
||||
}).length > 0;
|
||||
|
||||
this.files.push([
|
||||
'package.json',
|
||||
JSON.stringify(
|
||||
@@ -119,9 +127,14 @@ export class TestProject {
|
||||
await fs.writeFile(filePath, content ?? '', 'utf-8');
|
||||
}
|
||||
|
||||
await spawn('pnpm', ['--ignore-workspace', 'i', '--ignore-scripts'], {
|
||||
cwd: this.root,
|
||||
});
|
||||
// Only install dependencies if the project has custom ones - otherwise the
|
||||
// project will reuse the ones in `packages/wxt/node_modules`!
|
||||
if (this.hasCustomDependencies) {
|
||||
await spawn('pnpm', ['--ignore-workspace', 'i', '--ignore-scripts'], {
|
||||
cwd: this.root,
|
||||
});
|
||||
}
|
||||
|
||||
await mkdir(resolve(this.root, 'public'), { recursive: true }).catch(
|
||||
() => {},
|
||||
);
|
||||
@@ -138,14 +151,6 @@ export class TestProject {
|
||||
return this.serializeDir('.output', ignoreContentsOfFilenames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read all the files from the test project's `.wxt` directory and combine them into a string
|
||||
* that can be used in a snapshot.
|
||||
*/
|
||||
serializeWxtDir(): Promise<string> {
|
||||
return this.serializeDir(resolve(this.root, '.wxt/types'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Deeply print the filename and contents of all files in a directory.
|
||||
*
|
||||
@@ -185,13 +190,13 @@ export class TestProject {
|
||||
].join(`\n${''.padEnd(40, '-')}\n`);
|
||||
}
|
||||
|
||||
fileExists(...path: string[]): Promise<boolean> {
|
||||
return fs.exists(this.resolvePath(...path));
|
||||
pathExists(...path: string[]): Promise<boolean> {
|
||||
return fs.pathExists(this.resolvePath(...path));
|
||||
}
|
||||
|
||||
async getOutputManifest(
|
||||
getOutputManifest(
|
||||
path: string = '.output/chrome-mv3/manifest.json',
|
||||
): Promise<any> {
|
||||
return await fs.readJson(this.resolvePath(path));
|
||||
return fs.readJson(this.resolvePath(path));
|
||||
}
|
||||
}
|
||||
|
||||
+71
-57
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "wxt",
|
||||
"type": "module",
|
||||
"version": "0.20.8",
|
||||
"version": "0.20.16",
|
||||
"description": "⚡ Next-gen Web Extension Framework",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"wxt": "tsx src/cli/index.ts",
|
||||
"build": "buildc -- unbuild",
|
||||
"build": "buildc -- tsdown --config-loader unrun",
|
||||
"check": "pnpm build && pnpm run --reporter-hide-prefix /^check:.*/",
|
||||
"check:default": "check",
|
||||
"check:tsc-virtual": "tsc --noEmit -p src/virtual",
|
||||
@@ -18,69 +18,75 @@
|
||||
"dependencies": {
|
||||
"@1natsu/wait-element": "^4.1.2",
|
||||
"@aklinker1/rollup-plugin-visualizer": "5.12.0",
|
||||
"@webext-core/fake-browser": "^1.3.2",
|
||||
"@webext-core/isolated-element": "^1.1.2",
|
||||
"@webext-core/fake-browser": "^1.3.4",
|
||||
"@webext-core/isolated-element": "^1.1.3",
|
||||
"@webext-core/match-patterns": "^1.0.3",
|
||||
"@wxt-dev/browser": "workspace:^",
|
||||
"@wxt-dev/storage": "workspace:^1.0.0",
|
||||
"async-mutex": "^0.5.0",
|
||||
"c12": "^3.0.3",
|
||||
"c12": "^3.3.3",
|
||||
"cac": "^6.7.14",
|
||||
"chokidar": "^4.0.3",
|
||||
"ci-info": "^4.2.0",
|
||||
"chokidar": "^5.0.0",
|
||||
"ci-info": "^4.4.0",
|
||||
"consola": "^3.4.2",
|
||||
"defu": "^6.1.4",
|
||||
"dotenv": "^17.2.2",
|
||||
"dotenv-expand": "^12.0.2",
|
||||
"esbuild": "^0.25.0",
|
||||
"dotenv": "^17.2.4",
|
||||
"dotenv-expand": "^12.0.3",
|
||||
"esbuild": "^0.27.1",
|
||||
"fast-glob": "^3.3.3",
|
||||
"filesize": "^10.1.6",
|
||||
"fs-extra": "^11.3.1",
|
||||
"get-port-please": "^3.1.2",
|
||||
"giget": "^1.2.3 || ^2.0.0",
|
||||
"hookable": "^5.5.3",
|
||||
"import-meta-resolve": "^4.1.0",
|
||||
"filesize": "^11.0.13",
|
||||
"fs-extra": "^11.3.3",
|
||||
"get-port-please": "^3.2.0",
|
||||
"giget": "^1.2.3 || ^2.0.0 || ^3.0.0",
|
||||
"hookable": "^6.0.1",
|
||||
"import-meta-resolve": "^4.2.0",
|
||||
"is-wsl": "^3.1.0",
|
||||
"json5": "^2.2.3",
|
||||
"jszip": "^3.10.1",
|
||||
"linkedom": "^0.18.10",
|
||||
"magicast": "^0.3.5",
|
||||
"minimatch": "^10.0.1",
|
||||
"nano-spawn": "^1.0.2",
|
||||
"linkedom": "^0.18.12",
|
||||
"magicast": "^0.5.2",
|
||||
"minimatch": "^10.1.2",
|
||||
"nano-spawn": "^2.0.0",
|
||||
"normalize-path": "^3.0.0",
|
||||
"nypm": "^0.6.0",
|
||||
"nypm": "^0.6.5",
|
||||
"ohash": "^2.0.11",
|
||||
"open": "^10.1.2",
|
||||
"ora": "^8.2.0",
|
||||
"perfect-debounce": "^1.0.0",
|
||||
"open": "^11.0.0",
|
||||
"ora": "^9.3.0",
|
||||
"perfect-debounce": "^2.1.0",
|
||||
"picocolors": "^1.1.1",
|
||||
"prompts": "^2.4.2",
|
||||
"publish-browser-extension": "^2.3.0 || ^3.0.0",
|
||||
"publish-browser-extension": "^2.3.0 || ^3.0.2 || ^4.0.0",
|
||||
"scule": "^1.3.0",
|
||||
"unimport": "^3.13.1 || ^4.0.0 || ^5.0.0",
|
||||
"vite": "^5.4.19 || ^6.3.4 || ^7.0.0",
|
||||
"vite-node": "^2.1.4 || ^3.1.2",
|
||||
"web-ext-run": "^0.2.3"
|
||||
"vite-node": "^3.2.4 || ^5.0.0",
|
||||
"web-ext-run": "^0.2.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.57.0 || ^9.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"eslint": {
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@aklinker1/check": "^2.1.0",
|
||||
"@faker-js/faker": "^10.0.0",
|
||||
"@faker-js/faker": "^10.2.0",
|
||||
"@types/fs-extra": "^11.0.4",
|
||||
"@types/lodash.merge": "^4.6.9",
|
||||
"@types/node": "^20.17.6",
|
||||
"@types/normalize-path": "^3.0.2",
|
||||
"@types/prompts": "^2.4.9",
|
||||
"eslint": "^9.38.0",
|
||||
"extract-zip": "^2.0.1",
|
||||
"happy-dom": "^18.0.1",
|
||||
"happy-dom": "^20.5.0",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"oxlint": "^1.14.0",
|
||||
"publint": "^0.3.12",
|
||||
"typescript": "^5.9.2",
|
||||
"unbuild": "^3.6.1",
|
||||
"vitest": "^3.2.4",
|
||||
"vitest-plugin-random-seed": "^1.1.1"
|
||||
"oxlint": "^1.43.0",
|
||||
"publint": "^0.3.17",
|
||||
"typescript": "^5.9.3",
|
||||
"vitest": "^4.0.18",
|
||||
"vitest-plugin-random-seed": "^1.1.2"
|
||||
},
|
||||
"peerDependenciesMeta": {},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/wxt-dev/wxt.git"
|
||||
@@ -109,85 +115,93 @@
|
||||
"wxt-publish-extension": "./bin/wxt-publish-extension.cjs"
|
||||
},
|
||||
"module": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"types": "./dist/index.d.mts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"types": "./dist/index.d.mts",
|
||||
"default": "./dist/index.mjs"
|
||||
},
|
||||
"./utils/app-config": {
|
||||
"types": "./dist/utils/app-config.d.ts",
|
||||
"types": "./dist/utils/app-config.d.mts",
|
||||
"default": "./dist/utils/app-config.mjs"
|
||||
},
|
||||
"./utils/inject-script": {
|
||||
"types": "./dist/utils/inject-script.d.ts",
|
||||
"types": "./dist/utils/inject-script.d.mts",
|
||||
"default": "./dist/utils/inject-script.mjs"
|
||||
},
|
||||
"./utils/content-script-context": {
|
||||
"types": "./dist/utils/content-script-context.d.ts",
|
||||
"types": "./dist/utils/content-script-context.d.mts",
|
||||
"default": "./dist/utils/content-script-context.mjs"
|
||||
},
|
||||
"./utils/content-script-ui/types": {
|
||||
"types": "./dist/utils/content-script-ui/types.d.ts",
|
||||
"types": "./dist/utils/content-script-ui/types.d.mts",
|
||||
"default": "./dist/utils/content-script-ui/types.mjs"
|
||||
},
|
||||
"./utils/content-script-ui/integrated": {
|
||||
"types": "./dist/utils/content-script-ui/integrated.d.ts",
|
||||
"types": "./dist/utils/content-script-ui/integrated.d.mts",
|
||||
"default": "./dist/utils/content-script-ui/integrated.mjs"
|
||||
},
|
||||
"./utils/content-script-ui/shadow-root": {
|
||||
"types": "./dist/utils/content-script-ui/shadow-root.d.ts",
|
||||
"types": "./dist/utils/content-script-ui/shadow-root.d.mts",
|
||||
"default": "./dist/utils/content-script-ui/shadow-root.mjs"
|
||||
},
|
||||
"./utils/content-script-ui/iframe": {
|
||||
"types": "./dist/utils/content-script-ui/iframe.d.ts",
|
||||
"types": "./dist/utils/content-script-ui/iframe.d.mts",
|
||||
"default": "./dist/utils/content-script-ui/iframe.mjs"
|
||||
},
|
||||
"./utils/define-app-config": {
|
||||
"types": "./dist/utils/define-app-config.d.ts",
|
||||
"types": "./dist/utils/define-app-config.d.mts",
|
||||
"default": "./dist/utils/define-app-config.mjs"
|
||||
},
|
||||
"./utils/define-background": {
|
||||
"types": "./dist/utils/define-background.d.ts",
|
||||
"types": "./dist/utils/define-background.d.mts",
|
||||
"default": "./dist/utils/define-background.mjs"
|
||||
},
|
||||
"./utils/define-content-script": {
|
||||
"types": "./dist/utils/define-content-script.d.ts",
|
||||
"types": "./dist/utils/define-content-script.d.mts",
|
||||
"default": "./dist/utils/define-content-script.mjs"
|
||||
},
|
||||
"./utils/define-unlisted-script": {
|
||||
"types": "./dist/utils/define-unlisted-script.d.ts",
|
||||
"types": "./dist/utils/define-unlisted-script.d.mts",
|
||||
"default": "./dist/utils/define-unlisted-script.mjs"
|
||||
},
|
||||
"./utils/define-wxt-plugin": {
|
||||
"types": "./dist/utils/define-wxt-plugin.d.ts",
|
||||
"types": "./dist/utils/define-wxt-plugin.d.mts",
|
||||
"default": "./dist/utils/define-wxt-plugin.mjs"
|
||||
},
|
||||
"./utils/match-patterns": {
|
||||
"types": "./dist/utils/match-patterns.d.ts",
|
||||
"types": "./dist/utils/match-patterns.d.mts",
|
||||
"default": "./dist/utils/match-patterns.mjs"
|
||||
},
|
||||
"./utils/split-shadow-root-css": {
|
||||
"types": "./dist/utils/split-shadow-root-css.d.ts",
|
||||
"types": "./dist/utils/split-shadow-root-css.d.mts",
|
||||
"default": "./dist/utils/split-shadow-root-css.mjs"
|
||||
},
|
||||
"./utils/storage": {
|
||||
"types": "./dist/utils/storage.d.ts",
|
||||
"types": "./dist/utils/storage.d.mts",
|
||||
"default": "./dist/utils/storage.mjs"
|
||||
},
|
||||
"./browser": {
|
||||
"types": "./dist/browser.d.ts",
|
||||
"types": "./dist/browser.d.mts",
|
||||
"default": "./dist/browser.mjs"
|
||||
},
|
||||
"./testing/fake-browser": {
|
||||
"types": "./dist/testing/fake-browser.d.mts",
|
||||
"default": "./dist/testing/fake-browser.mjs"
|
||||
},
|
||||
"./testing/vitest-plugin": {
|
||||
"types": "./dist/testing/wxt-vitest-plugin.d.mts",
|
||||
"default": "./dist/testing/wxt-vitest-plugin.mjs"
|
||||
},
|
||||
"./testing": {
|
||||
"types": "./dist/testing/index.d.ts",
|
||||
"types": "./dist/testing/index.d.mts",
|
||||
"default": "./dist/testing/index.mjs"
|
||||
},
|
||||
"./vite-builder-env": {
|
||||
"types": "./dist/vite-builder-env.d.ts"
|
||||
},
|
||||
"./modules": {
|
||||
"types": "./dist/modules.d.ts",
|
||||
"types": "./dist/modules.d.mts",
|
||||
"default": "./dist/modules.mjs"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ export default defineWxtModule({
|
||||
// Only create global types when user has enabled auto-imports
|
||||
entries.push(await getImportsDeclarationEntry(unimport));
|
||||
|
||||
if (wxt.config.imports.eslintrc.enabled === false) return;
|
||||
if (!wxt.config.imports.eslintrc.enabled) return;
|
||||
|
||||
// Only generate ESLint config if that feature is enabled
|
||||
entries.push(
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import { describe, it, vi, beforeEach, expect } from 'vitest';
|
||||
import { build } from '../../core/build';
|
||||
import { createServer } from '../../core/create-server';
|
||||
import { zip } from '../../core/zip';
|
||||
import { prepare } from '../../core/prepare';
|
||||
import { clean } from '../../core/clean';
|
||||
import { initialize } from '../../core/initialize';
|
||||
import {
|
||||
build,
|
||||
createServer,
|
||||
zip,
|
||||
prepare,
|
||||
clean,
|
||||
initialize,
|
||||
} from '../../core';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
import consola from 'consola';
|
||||
import consola, { LogLevels } from 'consola';
|
||||
|
||||
vi.mock('../../core/build');
|
||||
const buildMock = vi.mocked(build);
|
||||
@@ -137,6 +139,21 @@ describe('CLI', () => {
|
||||
expect(createServerMock).toBeCalledWith({
|
||||
debug: true,
|
||||
});
|
||||
expect(consola.level).toBe(LogLevels.debug);
|
||||
});
|
||||
|
||||
it('should set log --level', async () => {
|
||||
mockArgv('--level', 'warn');
|
||||
await importCli();
|
||||
|
||||
expect(consola.level).toBe(LogLevels.warn);
|
||||
});
|
||||
|
||||
it('--debug should override --level', async () => {
|
||||
mockArgv('--debug', '--level', 'silent');
|
||||
await importCli();
|
||||
|
||||
expect(consola.level).toBe(LogLevels.debug);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -229,6 +246,21 @@ describe('CLI', () => {
|
||||
expect(buildMock).toBeCalledWith({
|
||||
debug: true,
|
||||
});
|
||||
expect(consola.level).toBe(LogLevels.debug);
|
||||
});
|
||||
|
||||
it('should set log --level', async () => {
|
||||
mockArgv('build', '--level', 'warn');
|
||||
await importCli();
|
||||
|
||||
expect(consola.level).toBe(LogLevels.warn);
|
||||
});
|
||||
|
||||
it('--debug should override --level', async () => {
|
||||
mockArgv('build', '--debug', '--level', 'silent');
|
||||
await importCli();
|
||||
|
||||
expect(consola.level).toBe(LogLevels.debug);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -310,6 +342,21 @@ describe('CLI', () => {
|
||||
debug: true,
|
||||
zip: {},
|
||||
});
|
||||
expect(consola.level).toBe(LogLevels.debug);
|
||||
});
|
||||
|
||||
it('should set log --level', async () => {
|
||||
mockArgv('zip', '--level', 'warn');
|
||||
await importCli();
|
||||
|
||||
expect(consola.level).toBe(LogLevels.warn);
|
||||
});
|
||||
|
||||
it('--debug should override --level', async () => {
|
||||
mockArgv('zip', '--debug', '--level', 'silent');
|
||||
await importCli();
|
||||
|
||||
expect(consola.level).toBe(LogLevels.debug);
|
||||
});
|
||||
|
||||
it('should pass undefined for zipSources when --sources is not passed', async () => {
|
||||
@@ -379,6 +426,21 @@ describe('CLI', () => {
|
||||
expect(prepareMock).toBeCalledWith({
|
||||
debug: true,
|
||||
});
|
||||
expect(consola.level).toBe(LogLevels.debug);
|
||||
});
|
||||
|
||||
it('should set log --level', async () => {
|
||||
mockArgv('prepare', '--level', 'warn');
|
||||
await importCli();
|
||||
|
||||
expect(consola.level).toBe(LogLevels.warn);
|
||||
});
|
||||
|
||||
it('--debug should override --level', async () => {
|
||||
mockArgv('prepare', '--debug', '--level', 'silent');
|
||||
await importCli();
|
||||
|
||||
expect(consola.level).toBe(LogLevels.debug);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -413,6 +475,21 @@ describe('CLI', () => {
|
||||
expect(cleanMock).toBeCalledWith({
|
||||
debug: true,
|
||||
});
|
||||
expect(consola.level).toBe(LogLevels.debug);
|
||||
});
|
||||
|
||||
it('should set log --level', async () => {
|
||||
mockArgv('clean', '--level', 'warn');
|
||||
await importCli();
|
||||
|
||||
expect(consola.level).toBe(LogLevels.warn);
|
||||
});
|
||||
|
||||
it('--debug should override --level', async () => {
|
||||
mockArgv('clean', '--debug', '--level', 'silent');
|
||||
await importCli();
|
||||
|
||||
expect(consola.level).toBe(LogLevels.debug);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CAC, Command } from 'cac';
|
||||
import consola, { LogLevels } from 'consola';
|
||||
import consola, { LogLevels, LogType } from 'consola';
|
||||
import { filterTruthy, toArray } from '../core/utils/arrays';
|
||||
import { printHeader } from '../core/utils/log';
|
||||
import { formatDuration } from '../core/utils/time';
|
||||
@@ -19,8 +19,13 @@ export function wrapAction(
|
||||
},
|
||||
) {
|
||||
return async (...args: any[]) => {
|
||||
// Enable consola's debug mode globally at the start of all commands when the `--debug` flag is
|
||||
// passed
|
||||
const level: LogType | undefined = args.find((arg) => arg?.level)?.level;
|
||||
if (level && Object.keys(LogLevels).includes(level)) {
|
||||
consola.level = LogLevels[level];
|
||||
}
|
||||
|
||||
// Enable consola's debug mode globally at the start of all commands when
|
||||
// the `--debug` flag is passed
|
||||
const isDebug = !!args.find((arg) => arg?.debug);
|
||||
if (isDebug) {
|
||||
consola.level = LogLevels.debug;
|
||||
@@ -40,9 +45,7 @@ export function wrapAction(
|
||||
consola.fail(
|
||||
`Command failed after ${formatDuration(Date.now() - startTime)}`,
|
||||
);
|
||||
if (err instanceof ValidationError) {
|
||||
// Don't log these errors, they've already been logged
|
||||
} else {
|
||||
if (!(err instanceof ValidationError)) {
|
||||
consola.error(err);
|
||||
}
|
||||
process.exit(1);
|
||||
|
||||
@@ -9,6 +9,10 @@ import {
|
||||
const cli = cac('wxt');
|
||||
|
||||
cli.option('--debug', 'enable debug mode');
|
||||
cli.option(
|
||||
'--level <level>',
|
||||
'specify log level ("silent" | "fatal" | "error" | "warn" | "log" | "info" | "success" | "fail" | "ready" | "start" | "box" | "debug" | "trace" | "verbose")',
|
||||
);
|
||||
|
||||
// DEV
|
||||
cli
|
||||
|
||||
@@ -27,7 +27,7 @@ import { installSourcemapsSupport } from 'vite-node/source-map';
|
||||
import { createExtensionEnvironment } from '../../utils/environments';
|
||||
import { dirname, extname, join, relative } from 'node:path';
|
||||
import fs from 'fs-extra';
|
||||
import { normalizePath } from '../../utils/paths';
|
||||
import { normalizePath } from '../../utils';
|
||||
|
||||
export async function createViteBuilder(
|
||||
wxtConfig: ResolvedConfig,
|
||||
@@ -453,7 +453,7 @@ async function moveHtmlFiles(
|
||||
);
|
||||
|
||||
// TODO: Optimize and only delete old path directories
|
||||
removeEmptyDirs(config.outDir);
|
||||
await removeEmptyDirs(config.outDir);
|
||||
|
||||
return movedChunks;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { Window } from 'happy-dom';
|
||||
import { pointToDevServer } from '../devHtmlPrerender';
|
||||
import {
|
||||
fakeDevServer,
|
||||
fakeResolvedConfig,
|
||||
} from '../../../../utils/testing/fake-objects';
|
||||
import { normalizePath } from '../../../../utils/paths';
|
||||
import { normalizePath } from '../../../../utils';
|
||||
import { resolve } from 'node:path';
|
||||
import { parseHTML } from 'linkedom';
|
||||
|
||||
describe('Dev HTML Prerender Plugin', () => {
|
||||
describe('pointToDevServer', () => {
|
||||
@@ -32,9 +32,7 @@ describe('Dev HTML Prerender Plugin', () => {
|
||||
// URLs should not be changed
|
||||
['https://example.com/style.css', 'https://example.com/style.css'],
|
||||
])('should transform "%s" into "%s"', (input, expected) => {
|
||||
const { document } = new Window({
|
||||
url: 'http://localhost',
|
||||
});
|
||||
const { document } = parseHTML('<html></html>');
|
||||
const root = '/some/root';
|
||||
const config = fakeResolvedConfig({
|
||||
root,
|
||||
@@ -55,7 +53,7 @@ describe('Dev HTML Prerender Plugin', () => {
|
||||
const id = root + '/entrypoints/popup/index.html';
|
||||
|
||||
document.head.innerHTML = `<link rel="stylesheet" href="${input}" />`;
|
||||
pointToDevServer(config, server, id, document as any, 'link', 'href');
|
||||
pointToDevServer(config, server, id, document, 'link', 'href');
|
||||
|
||||
const actual = document.querySelector('link')!;
|
||||
expect(actual.getAttribute('href')).toBe(expected);
|
||||
|
||||
@@ -16,7 +16,7 @@ export function bundleAnalysis(config: ResolvedConfig): vite.Plugin {
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated FOR TESTING ONLY.
|
||||
* @internal FOR TESTING ONLY.
|
||||
*/
|
||||
export function resetBundleIncrement() {
|
||||
increment = 0;
|
||||
|
||||
@@ -3,7 +3,7 @@ import { ResolvedConfig, WxtDevServer } from '../../../../types';
|
||||
import { getEntrypointName } from '../../../utils/entrypoints';
|
||||
import { parseHTML } from 'linkedom';
|
||||
import { dirname, relative, resolve } from 'node:path';
|
||||
import { normalizePath } from '../../../utils/paths';
|
||||
import { normalizePath } from '../../../utils';
|
||||
import { hash } from 'ohash';
|
||||
|
||||
// Stored outside the plugin to effect all instances of the devHtmlPrerender plugin.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Plugin } from 'vite';
|
||||
import { ResolvedConfig, WxtDevServer } from '../../../../types';
|
||||
import type { Plugin } from 'vite';
|
||||
import type { ResolvedConfig, WxtDevServer } from '../../../../types';
|
||||
|
||||
/**
|
||||
* Defines global constants about the dev server. Helps scripts connect to the server's web socket.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Plugin } from 'vite';
|
||||
import { ResolvedConfig } from '../../../../types';
|
||||
import type { Plugin } from 'vite';
|
||||
import type { ResolvedConfig } from '../../../../types';
|
||||
import { fetchCached } from '../../../utils/network';
|
||||
|
||||
/**
|
||||
@@ -15,12 +15,12 @@ export function download(config: ResolvedConfig): Plugin {
|
||||
resolveId(id) {
|
||||
if (id.startsWith('url:')) return '\0' + id;
|
||||
},
|
||||
async load(id) {
|
||||
load(id) {
|
||||
if (!id.startsWith('\0url:')) return;
|
||||
|
||||
// Load file from network or cache
|
||||
const url = id.replace('\0url:', '');
|
||||
return await fetchCached(url, config);
|
||||
return fetchCached(url, config);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ export function extensionApiMock(config: ResolvedConfig): vite.PluginOption {
|
||||
],
|
||||
},
|
||||
ssr: {
|
||||
// Inline all WXT modules subdependencies can be mocked
|
||||
// Inline all WXT modules sub-dependencies can be mocked
|
||||
noExternal: ['wxt'],
|
||||
},
|
||||
};
|
||||
@@ -43,7 +43,7 @@ export function extensionApiMock(config: ResolvedConfig): vite.PluginOption {
|
||||
|
||||
const setupTemplate = `
|
||||
import { vi } from 'vitest';
|
||||
import { fakeBrowser } from 'wxt/testing';
|
||||
import { fakeBrowser } from 'wxt/testing/fake-browser';
|
||||
|
||||
vi.stubGlobal("chrome", fakeBrowser);
|
||||
vi.stubGlobal("browser", fakeBrowser);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Plugin } from 'vite';
|
||||
import type { Plugin } from 'vite';
|
||||
import { VIRTUAL_NOOP_BACKGROUND_MODULE_ID } from '../../../utils/constants';
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ResolvedConfig } from '../../../../types';
|
||||
import * as vite from 'vite';
|
||||
import { normalizePath } from '../../../utils/paths';
|
||||
import type * as vite from 'vite';
|
||||
import { normalizePath } from '../../../utils';
|
||||
import { removeMainFunctionCode } from '../../../utils/transform';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { exists } from 'fs-extra';
|
||||
import { pathExists } from 'fs-extra';
|
||||
import { resolve } from 'node:path';
|
||||
import type * as vite from 'vite';
|
||||
import { ResolvedConfig } from '../../../../types';
|
||||
@@ -25,7 +25,7 @@ export function resolveAppConfig(config: ResolvedConfig): vite.Plugin {
|
||||
async resolveId(id) {
|
||||
if (id !== virtualModuleId) return;
|
||||
|
||||
return (await exists(appConfigFile))
|
||||
return (await pathExists(appConfigFile))
|
||||
? appConfigFile
|
||||
: resolvedVirtualModuleId;
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Plugin } from 'vite';
|
||||
import type { Plugin } from 'vite';
|
||||
import { ResolvedConfig } from '../../../../types';
|
||||
import { normalizePath } from '../../../utils/paths';
|
||||
import { normalizePath } from '../../../utils';
|
||||
import {
|
||||
VirtualModuleId,
|
||||
virtualModuleNames,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { parseHTML } from 'linkedom';
|
||||
import type * as vite from 'vite';
|
||||
import { normalizePath } from '../../../utils/paths';
|
||||
import { normalizePath } from '../../../utils';
|
||||
import { ResolvedConfig } from '../../../../types';
|
||||
|
||||
/**
|
||||
|
||||
@@ -126,7 +126,7 @@ async function createServerInternal(): Promise<WxtDevServer> {
|
||||
async stop() {
|
||||
wasStopped = true;
|
||||
keyboardShortcuts.stop();
|
||||
await runner.closeBrowser();
|
||||
await runner.closeBrowser?.();
|
||||
await builderServer.close();
|
||||
await wxt.hooks.callHook('server:closed', wxt, server);
|
||||
|
||||
@@ -150,7 +150,7 @@ async function createServerInternal(): Promise<WxtDevServer> {
|
||||
server.ws.send('wxt:reload-extension');
|
||||
},
|
||||
async restartBrowser() {
|
||||
await runner.closeBrowser();
|
||||
await runner.closeBrowser?.();
|
||||
keyboardShortcuts.stop();
|
||||
await wxt.reloadConfig();
|
||||
runner = await createExtensionRunner();
|
||||
|
||||
@@ -3,7 +3,7 @@ import fs from 'fs-extra';
|
||||
import { dirname, relative, resolve } from 'node:path';
|
||||
import { getEntrypointBundlePath, isHtmlEntrypoint } from './utils/entrypoints';
|
||||
import { getEntrypointGlobals, getGlobals } from './utils/globals';
|
||||
import { normalizePath } from './utils/paths';
|
||||
import { normalizePath } from './utils';
|
||||
import path from 'node:path';
|
||||
import { Message, parseI18nMessages } from './utils/i18n';
|
||||
import { writeFileIfDifferent, getPublicFiles } from './utils/fs';
|
||||
@@ -136,7 +136,7 @@ declare module "wxt/browser" {
|
||||
'messages.json',
|
||||
);
|
||||
let messages: Message[];
|
||||
if (await fs.exists(defaultLocalePath)) {
|
||||
if (await fs.pathExists(defaultLocalePath)) {
|
||||
const content = JSON.parse(await fs.readFile(defaultLocalePath, 'utf-8'));
|
||||
messages = parseI18nMessages(content);
|
||||
} else {
|
||||
@@ -166,7 +166,8 @@ declare module "wxt/browser" {
|
||||
};
|
||||
|
||||
const overrides = [
|
||||
// Generate individual overloads for each message so JSDoc contains description and base translation.
|
||||
// Generate individual overloads for each message so JSDoc contains
|
||||
// description and base translation.
|
||||
...messages.map((message) =>
|
||||
renderGetMessageOverload(
|
||||
`"${message.name}"`,
|
||||
@@ -174,7 +175,8 @@ declare module "wxt/browser" {
|
||||
message.message,
|
||||
),
|
||||
),
|
||||
// Include a final union-based override so TS accepts valid string templates or concatenations
|
||||
// Include a final union-based override so TS accepts valid string
|
||||
// templates or concatenations.
|
||||
// ie: browser.i18n.getMessage(`some_enum_${enumValue}`)
|
||||
renderGetMessageOverload(
|
||||
messages.map((message) => `"${message.name}"`).join(' | '),
|
||||
|
||||
@@ -6,3 +6,4 @@ export * from './create-server';
|
||||
export * from './initialize';
|
||||
export * from './prepare';
|
||||
export * from './zip';
|
||||
export * from './utils';
|
||||
|
||||
@@ -26,6 +26,8 @@ export function createKeyboardShortcuts(
|
||||
|
||||
return {
|
||||
start() {
|
||||
this.stop();
|
||||
|
||||
rl ??= readline.createInterface({
|
||||
input: process.stdin,
|
||||
terminal: false, // Don't intercept ctrl+C, ctrl+Z, etc
|
||||
|
||||
@@ -2,7 +2,7 @@ import { beforeAll, describe, expect, it } from 'vitest';
|
||||
import path from 'node:path';
|
||||
import { npm } from '../npm';
|
||||
import spawn from 'nano-spawn';
|
||||
import { exists } from 'fs-extra';
|
||||
import { pathExists } from 'fs-extra';
|
||||
|
||||
describe('NPM Package Management Utils', () => {
|
||||
describe('listDependencies', () => {
|
||||
@@ -41,7 +41,7 @@ describe('NPM Package Management Utils', () => {
|
||||
const actual = await npm.downloadDependency(id, downloadDir);
|
||||
|
||||
expect(actual).toEqual(expected);
|
||||
expect(await exists(actual)).toBe(true);
|
||||
expect(await pathExists(actual)).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -21,7 +21,7 @@ import consola, { LogLevels } from 'consola';
|
||||
import defu from 'defu';
|
||||
import { NullablyRequired } from './utils/types';
|
||||
import fs from 'fs-extra';
|
||||
import { normalizePath } from './utils/paths';
|
||||
import { normalizePath } from './utils';
|
||||
import glob from 'fast-glob';
|
||||
import { builtinModules } from '../builtin-modules';
|
||||
import { getEslintVersion } from './utils/eslint';
|
||||
@@ -50,11 +50,7 @@ export async function resolveConfig(
|
||||
configFile: inlineConfig.configFile,
|
||||
name: 'wxt',
|
||||
cwd: inlineConfig.root ?? process.cwd(),
|
||||
rcFile: false,
|
||||
});
|
||||
if (inlineConfig.configFile && metadata.layers?.length === 0) {
|
||||
throw Error(`Config file "${inlineConfig.configFile}" not found`);
|
||||
}
|
||||
userConfig = loadedConfig ?? {};
|
||||
userConfigMetadata = metadata;
|
||||
}
|
||||
@@ -536,17 +532,10 @@ async function getUnimportEslintOptions(
|
||||
* Returns the path to `node_modules/wxt`.
|
||||
*/
|
||||
function resolveWxtModuleDir() {
|
||||
// TODO: Drop the __filename expression once we're fully running in ESM
|
||||
// (see https://github.com/wxt-dev/wxt/issues/277)
|
||||
const importer =
|
||||
typeof __filename === 'string'
|
||||
? pathToFileURL(__filename).href
|
||||
: import.meta.url;
|
||||
|
||||
// TODO: Switch to import.meta.resolve() once the parent argument is unflagged
|
||||
// (e.g. --experimental-import-meta-resolve) and all Node.js versions we support
|
||||
// have it.
|
||||
const url = esmResolve('wxt', importer);
|
||||
const url = esmResolve('wxt', import.meta.url);
|
||||
|
||||
// esmResolve() returns the "wxt/dist/index.mjs" file, not the package's root
|
||||
// directory, which we want to return from this function.
|
||||
@@ -554,7 +543,7 @@ function resolveWxtModuleDir() {
|
||||
}
|
||||
|
||||
async function isDirMissing(dir: string) {
|
||||
return !(await fs.exists(dir));
|
||||
return !(await fs.pathExists(dir));
|
||||
}
|
||||
|
||||
function logMissingDir(logger: Logger, name: string, expected: string) {
|
||||
@@ -584,8 +573,8 @@ export async function mergeBuilderConfig(
|
||||
if (vite) {
|
||||
return {
|
||||
vite: async (env) => {
|
||||
const resolvedInlineConfig = (await inlineConfig.vite?.(env)) ?? {};
|
||||
const resolvedUserConfig = (await userConfig.vite?.(env)) ?? {};
|
||||
const [resolvedInlineConfig = {}, resolvedUserConfig = {}] =
|
||||
await Promise.all([inlineConfig.vite?.(env), userConfig.vite?.(env)]);
|
||||
return vite.mergeConfig(resolvedUserConfig, resolvedInlineConfig);
|
||||
},
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user