Compare commits

...

44 Commits

Author SHA1 Message Date
GitHub Actions 79426671cf chore(release): v0.4.1 2023-09-05 22:15:02 +00:00
Aaron 89b34403ee feat(cli): Add wxt clean command to delete generated files (#106) 2023-09-05 16:21:57 -05:00
Aaron Klinker 749bc38234 Add sync-releases helper script 2023-09-05 10:21:14 -05:00
Aaron Klinker e086374828 fix(init): Don't show cd . when initializing the current directory 2023-09-05 10:21:14 -05:00
Aaron 2c3721e5f4 Upgrade templates to 0.4 (#105) 2023-09-05 10:16:31 -05:00
Aaron Klinker c2946aa1eb Fix changelog contributors 2023-09-05 10:14:22 -05:00
GitHub Actions 4dd6320eae chore(release): v0.4.0 2023-09-05 15:07:59 +00:00
Aaron a8285fff78 feat: Generate types for browser.i18n.getMessage (#103) 2023-09-05 09:55:55 -05:00
Aaron d89be2544d chore: Use import aliases in Vue template (#104) 2023-09-05 09:31:47 -05:00
Aaron f234c85357 fix!: Use relative path aliases inside .wxt/tsconfig.json (#102)
BREAKING CHANGE: Moved .wxt directory from inside srcDir to root to match Nuxt.
2023-09-04 21:48:07 -05:00
Aaron Klinker 93bfee0578 chore: Remove explict icon config from templates
Icons are now automatically discovered thanks to aefc8d3
2023-09-04 15:55:29 -05:00
Aaron Klinker 2c7922ca4c chore: Fix test watcher restarting indefinetly 2023-09-04 15:41:06 -05:00
dependabot[bot] 72ae812c42 chore(deps-dev): bump vitepress from 1.0.0-rc.4 to 1.0.0-rc.10 (#96)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Aaron Klinker <aaronklinker1@gmail.com>
2023-09-03 16:59:04 -05:00
Aaron 2a0842bb62 chore: Increase E2E test timeout because GitHub Actions Window runner is slow 2023-09-02 11:22:34 -05:00
Aaron b301ee324e feat: Replace web-ext with web-ext-run (#101) 2023-09-02 09:47:05 -05:00
dependabot[bot] 4ef3eeaca1 chore(deps-dev): bump vitest from 0.34.1 to 0.34.3 (#99)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-01 17:29:21 -05:00
dependabot[bot] e803bfecb5 chore(deps-dev): bump lint-staged from 14.0.0 to 14.0.1 (#100)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-01 17:06:35 -05:00
dependabot[bot] 0dcf540393 chore(deps): bump linkedom from 0.15.1 to 0.15.2 (#98)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-01 17:05:51 -05:00
dependabot[bot] 062e25d834 chore(deps-dev): bump vitest-mock-extended from 1.2.0 to 1.2.1 (#97)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-01 17:03:19 -05:00
Aaron Klinker b58a15e783 chore: Fix failing demo build 2023-08-29 16:06:43 -05:00
Aaron Klinker 5f5f1d90f8 fix: Don't overwrite wxt.config.ts content scripts, append entrypoints to it 2023-08-29 16:02:47 -05:00
Aaron Klinker 83e62a1d63 chore: Fix remote code E2E test 2023-08-29 16:02:47 -05:00
Aaron Klinker b428a62a90 fix: Allow adding custom content scripts 2023-08-29 15:48:25 -05:00
dependabot[bot] 1fe4eedc9a chore(deps): bump filesize from 10.0.8 to 10.0.12 (#90)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-14 21:07:26 -05:00
dependabot[bot] 39d3192904 chore(deps-dev): bump lint-staged from 13.3.0 to 14.0.0 (#89)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-14 21:07:18 -05:00
dependabot[bot] de30509d94 chore(deps-dev): bump vitest-mock-extended from 1.1.4 to 1.2.0 (#87)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-14 21:07:11 -05:00
dependabot[bot] d5ae2332ca chore(deps): bump linkedom from 0.14.26 to 0.15.1 (#86)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-14 20:59:18 -05:00
dependabot[bot] f8b367dd7b chore(deps): bump unimport from 3.1.0 to 3.1.3 (#88)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-14 20:58:07 -05:00
dependabot[bot] 6bcb71baa0 chore(deps-dev): bump vitepress from 1.0.0-beta.5 to 1.0.0-rc.4 (#85)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Aaron Klinker <aaronklinker1@gmail.com>
2023-08-14 20:56:33 -05:00
dependabot[bot] 54bdf54839 chore(deps-dev): bump @vitest/coverage-v8 from 0.32.4 to 0.34.1 (#84)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-14 20:47:43 -05:00
dependabot[bot] 83f457f40f chore(deps): bump vite from 4.4.7 to 4.4.9 (#82)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Aaron Klinker <aaronklinker1@gmail.com>
2023-08-13 19:30:02 -05:00
dependabot[bot] f9df2d0809 chore(deps-dev): bump tsup from 7.1.0 to 7.2.0 (#80)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-13 15:07:49 -05:00
dependabot[bot] 2b079bb7f6 chore(deps-dev): bump @types/node from 20.4.5 to 20.5.0 (#78)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-13 15:06:03 -05:00
Aaron 0194448af4 Remove generated docs/config.md file (#83) 2023-08-13 14:59:34 -05:00
dependabot[bot] b409def211 chore(deps-dev): bump ora from 6.3.1 to 7.0.1 (#79) 2023-08-13 14:58:02 -05:00
dependabot[bot] 62bbef3487 chore(deps-dev): bump vitest from 0.32.4 to 0.34.1 (#81) 2023-08-13 14:56:47 -05:00
Aaron 87013bc616 Check for updates weekly 2023-08-13 14:52:45 -05:00
Aaron Klinker 4599bf2aa0 Fix dependabot config 2023-08-13 14:41:40 -05:00
Aaron d629acf518 chore: Upgrade to prettier 3 (#77) 2023-08-13 14:39:53 -05:00
Aaron 2bde9175b7 chore: Setup bug and feature issue templates 2023-08-13 14:39:33 -05:00
Aaron 8d5f4f5201 docs: Add contribution guide (#76) 2023-08-13 14:22:17 -05:00
Aaron d05f126eb3 feat: Add --debug flag for printing debug logs for all CLI commands (#75) 2023-08-13 14:04:43 -05:00
Aaron Klinker e164bd51fe chore: Update social preview 2023-08-13 13:18:01 -05:00
Aaron d66293c56e chore: Setup dependabot for upgrading dependencies 2023-08-13 13:15:46 -05:00
81 changed files with 1429 additions and 2268 deletions
-1
View File
@@ -1,3 +1,2 @@
* text=auto eol=lf
pnpm-lock.yaml linguist-generated
docs/config.md linguist-generated
+42
View File
@@ -0,0 +1,42 @@
---
name: Bug report
about: Report an issue with WXT
title: ''
labels: triage
assignees: ''
---
### Describe the bug
A clear and concise description of what the bug is.
### To Reproduce
Upload a ZIP or share a link to a repo representing the minimal reproduction. **_If you don't upload a minimal reproduction, you bug report will be closed._**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
### Expected behavior
A clear and concise description of what you expected to happen.
### Screenshots
If applicable, add screenshots to help explain your problem.
### Environment
<!--- Run `npx envinfo --system --browsers --binaries --npmPackages wxt,vite` and paste the output below -->
```
Paste output here
```
### Additional context
Add any other context about the problem here, otherwise you can delete this section.
+23
View File
@@ -0,0 +1,23 @@
---
name: Feature request
about: Suggest an idea for WXT
title: ''
labels: feature
assignees: ''
---
### Feature Request
Please describe your feature, be clear and concise. If you have a proposal for required type or API changes, list them here.
#### Is your feature request related to a bug?
If so, add a link here. If not, write "N/A"
### What are the alternatives?
A clear and concise description of any alternative solutions or features you've considered.
### Additional context
Add any other context or screenshots about the feature request here.
+11
View File
@@ -0,0 +1,11 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: npm
directory: '/' # Location of package manifests
schedule:
interval: 'monthly'
+1 -1
View File
@@ -10,7 +10,6 @@
/docs/.vitepress/cache
coverage
dist
e2e/project
node_modules
TODOs.md
web-ext.config.js
@@ -18,3 +17,4 @@ web-ext.config.ts
templates/*/pnpm-lock.yaml
templates/*/yarn.lock
templates/*/package-lock.json
docs/config.md
+3 -1
View File
@@ -1,8 +1,10 @@
.output
coverage
dist
e2e/project
.wxt
docs/.vitepress/cache
pnpm-lock.yaml
CHANGELOG.md
.gitattributes
.gitignore
.prettierignore
-1
View File
@@ -1,3 +1,2 @@
singleQuote: true
trailingComma: all
endOfLine: lf
+71 -2
View File
@@ -1,5 +1,75 @@
# Changelog
## v0.4.1
[compare changes](https://github.com/aklinker1/wxt/compare/v0.4.0...v0.4.1)
### 🚀 Enhancements
- **cli:** Add `wxt clean` command to delete generated files ([#106](https://github.com/aklinker1/wxt/pull/106))
### 🩹 Fixes
- **init:** Don't show `cd .` when initializing the current directory ([e086374](https://github.com/aklinker1/wxt/commit/e086374))
### ❤️ Contributors
- Aaron <aaronklinker1@gmail.com>
- Aaron Klinker <aaronklinker1@gmail.com>
## v0.4.0
[compare changes](https://github.com/aklinker1/wxt/compare/v0.3.2...v0.4.0)
### 🚀 Enhancements
- Add `--debug` flag for printing debug logs for all CLI commands ([#75](https://github.com/aklinker1/wxt/pull/75))
- Replace `web-ext` with `web-ext-run` ([#101](https://github.com/aklinker1/wxt/pull/101))
- Generate types for `browser.i18n.getMessage` ([#103](https://github.com/aklinker1/wxt/pull/103))
### 🩹 Fixes
- Allow adding custom content scripts ([b428a62](https://github.com/aklinker1/wxt/commit/b428a62))
- Don't overwrite `wxt.config.ts` content scripts, append entrypoints to it ([5f5f1d9](https://github.com/aklinker1/wxt/commit/5f5f1d9))
- ⚠️ Use relative path aliases inside `.wxt/tsconfig.json` ([#102](https://github.com/aklinker1/wxt/pull/102))
### 📖 Documentation
- Add contribution guide ([#76](https://github.com/aklinker1/wxt/pull/76))
### 🏡 Chore
- Setup dependabot for upgrading dependencies ([d66293c](https://github.com/aklinker1/wxt/commit/d66293c))
- Update social preview ([e164bd5](https://github.com/aklinker1/wxt/commit/e164bd5))
- Setup bug and feature issue templates ([2bde917](https://github.com/aklinker1/wxt/commit/2bde917))
- Upgrade to prettier 3 ([#77](https://github.com/aklinker1/wxt/pull/77))
- **deps-dev:** Bump vitest from 0.32.4 to 0.34.1 ([#81](https://github.com/aklinker1/wxt/pull/81))
- **deps-dev:** Bump ora from 6.3.1 to 7.0.1 ([#79](https://github.com/aklinker1/wxt/pull/79))
- **deps-dev:** Bump @types/node from 20.4.5 to 20.5.0 ([#78](https://github.com/aklinker1/wxt/pull/78))
- **deps-dev:** Bump tsup from 7.1.0 to 7.2.0 ([#80](https://github.com/aklinker1/wxt/pull/80))
- **deps-dev:** Bump @vitest/coverage-v8 from 0.32.4 to 0.34.1 ([#84](https://github.com/aklinker1/wxt/pull/84))
- **deps-dev:** Bump vitepress from 1.0.0-beta.5 to 1.0.0-rc.4 ([#85](https://github.com/aklinker1/wxt/pull/85))
- **deps-dev:** Bump vitest-mock-extended from 1.1.4 to 1.2.0 ([#87](https://github.com/aklinker1/wxt/pull/87))
- **deps-dev:** Bump lint-staged from 13.3.0 to 14.0.0 ([#89](https://github.com/aklinker1/wxt/pull/89))
- Fix remote code E2E test ([83e62a1](https://github.com/aklinker1/wxt/commit/83e62a1))
- Fix failing demo build ([b58a15e](https://github.com/aklinker1/wxt/commit/b58a15e))
- **deps-dev:** Bump vitest-mock-extended from 1.2.0 to 1.2.1 ([#97](https://github.com/aklinker1/wxt/pull/97))
- **deps-dev:** Bump lint-staged from 14.0.0 to 14.0.1 ([#100](https://github.com/aklinker1/wxt/pull/100))
- **deps-dev:** Bump vitest from 0.34.1 to 0.34.3 ([#99](https://github.com/aklinker1/wxt/pull/99))
- Increase E2E test timeout because GitHub Actions Window runner is slow ([2a0842b](https://github.com/aklinker1/wxt/commit/2a0842b))
- **deps-dev:** Bump vitepress from 1.0.0-rc.4 to 1.0.0-rc.10 ([#96](https://github.com/aklinker1/wxt/pull/96))
- Fix test watcher restarting indefinetly ([2c7922c](https://github.com/aklinker1/wxt/commit/2c7922c))
- Remove explict icon config from templates ([93bfee0](https://github.com/aklinker1/wxt/commit/93bfee0))
- Use import aliases in Vue template ([#104](https://github.com/aklinker1/wxt/pull/104))
#### ⚠️ Breaking Changes
- ⚠️ Use relative path aliases inside `.wxt/tsconfig.json` ([#102](https://github.com/aklinker1/wxt/pull/102))
### ❤️ Contributors
- Aaron Klinker ([@aklinker1](https://github.com/aklinker1))
## v0.3.2
[compare changes](https://github.com/aklinker1/wxt/compare/v0.3.1...v0.3.2)
@@ -31,8 +101,7 @@
### ❤️ Contributors
- Aaron <aaronklinker1@gmail.com>
- Aaron Klinker <aaronklinker1@gmail.com>
- Aaron Klinker ([@aklinker1](https://github.com/aklinker1))
## v0.3.1
+72
View File
@@ -0,0 +1,72 @@
# Contributing
Everyone is welcome to contribute to WXT!
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.
## Conventional Commits
This project uses [Conventional Commits](https://www.conventionalcommits.org/en) to automate versioning. If you're a new contributor, don't worry about this. When you open a PR, a maintainer will change the PR's title so it's in the style of conventional commits, but that's all.
Maintainers, commits to the `main` branch (either directly or via PRs) must be valid conventional commits.
## Setup
WXT uses `pnpm`, so make sure you have it installed.
```sh
corepack enable
```
Then, simply run the install command:
```sh
pnpm i
```
## Development
Here are some helpful commands:
```sh
# Build WXT package
pnpm build
```
```sh
# Build WXT package, then build demo extension
cd demo
pnpm build
```
```sh
# Build WXT package, then start the demo extension in dev mode
cd demo
pnpm dev
```
```sh
# Run unit and E2E tests
pnpm test
```
```sh
# Start the docs website locally
pnpm docs:dev
```
## Testing
WXT has unit and E2E tests. When making a change or adding a feature, make sure to update the tests or add new ones.
To run tests for a specific file, add the filename at the end of the test command:
```sh
pnpm test manifest-contents
```
Unit and E2E tests are ran together via [Vitest workspaces](https://vitest.dev/guide/#workspaces-support).
If you want to manually test a change, you can modify the demo project for your test, but please don't leave those changes committed once you open a PR.
+29
View File
@@ -0,0 +1,29 @@
{
"prompt_for_name": {
"message": "What's your name?",
"description": "Ask for the user's name"
},
"hello": {
"message": "Hello, $USER$",
"description": "Greet the user",
"placeholders": {
"user": {
"content": "$1",
"example": "Cira"
}
}
},
"bye": {
"message": "Goodbye, $USER$. Come back to $OUR_SITE$ soon!",
"description": "Say goodbye to the user",
"placeholders": {
"our_site": {
"content": "Example.com"
},
"user": {
"content": "$1",
"example": "Cira"
}
}
}
}
+7
View File
@@ -12,4 +12,11 @@ export default defineBackground(() => {
browser.runtime.getURL('/');
browser.runtime.getURL('/background.js');
browser.runtime.getURL('/icon/128.png');
// @ts-expect-error: should only accept known message names
browser.i18n.getMessage('test');
browser.i18n.getMessage('prompt_for_name');
browser.i18n.getMessage('hello', 'Aaron');
browser.i18n.getMessage('bye', ['Aaron']);
browser.i18n.getMessage('@@extension_id');
});
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
+1 -1
View File
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
+1 -1
View File
@@ -1,4 +1,4 @@
import 'url:https://stats.aklinker1.io/umami.js';
import 'url:https://code.jquery.com/jquery-3.7.1.slim.min.js';
console.log(browser.runtime.id);
logId();
+1 -1
View File
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
+1 -1
View File
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
+1 -1
View File
@@ -1,3 +1,3 @@
{
"extends": ["../tsconfig.base.json", "./src/.wxt/tsconfig.json"]
"extends": ["../tsconfig.base.json", "./.wxt/tsconfig.json"]
}
+1 -7
View File
@@ -6,12 +6,6 @@ export default defineConfig({
chrome: '123',
},
manifest: {
icons: {
'16': 'icon/16.png',
'32': 'icon/32.png',
'48': 'icon/48.png',
'96': 'icon/96.png',
'128': 'icon/128.png',
},
default_locale: 'en',
},
});
+28 -30
View File
@@ -1,7 +1,10 @@
import { resolve } from 'node:path';
import { Project, ts, Type, Node, JSDocableNode } from 'ts-morph';
import Ora from 'ora';
import { readFileSync, writeFileSync } from 'node:fs';
import { format } from 'prettier';
import consola from 'consola';
let hasGenerated = false;
const externalTypesPath = resolve('src/core/types/external.ts');
const configTemplatePath = resolve('docs/config.tpl.md');
@@ -28,8 +31,10 @@ const CUSTOM_TYPES = {
};
export function generateConfigDocs() {
const generateDocs = () => {
const spinner = Ora('Generating /config.md').start();
writeFileSync(configPath, '');
const generateDocs = async () => {
consola.info('Generating /config.md');
try {
const project = new Project({
tsConfigFilePath: resolve('tsconfig.json'),
@@ -39,18 +44,10 @@ export function generateConfigDocs() {
const externalTypesFile = project.addSourceFileAtPath(externalTypesPath);
project.resolveSourceFileDependencies();
const typeChecker = project.getProgram().getTypeChecker();
const inlineConfigInterface =
externalTypesFile.getInterfaceOrThrow('InlineConfig');
const getDocsFor = (
path: string[],
node: Node<ts.Node>,
depth = 0,
): string[] => {
if (depth > 3) throw Error('Recursion to deep for ' + path.join('.'));
const getDocsFor = (path: string[], node: Node<ts.Node>): string[] => {
const pathStr = path.join('.');
let type: Type<ts.Type>;
@@ -73,11 +70,7 @@ export function generateConfigDocs() {
const childPath = [...path, property.getName()];
if (LEAF_PATHS.includes(childPath.join('.'))) return [];
return getDocsFor(
childPath,
property.getDeclarations()[0],
depth + 1,
);
return getDocsFor(childPath, property.getDeclarations()[0]);
})
);
}
@@ -115,33 +108,38 @@ export function generateConfigDocs() {
};
const lines = getDocsFor([], inlineConfigInterface);
const text =
const text = await format(
PREFACE +
'\n\n' +
readFileSync(configTemplatePath, 'utf-8').replace(
'{{ DOCS }}',
lines.join('\n'),
);
'\n\n' +
readFileSync(configTemplatePath, 'utf-8').replace(
'{{ DOCS }}',
lines.join('\n'),
),
{ parser: 'markdown' },
);
writeFileSync(configPath, text);
spinner.succeed('Generated /config.md');
consola.success('Generated /config.md');
} catch (err) {
spinner.fail('Failed to generate /config.md');
console.error(err.message);
consola.fail('Failed to generate /config.md');
consola.error(err.message);
}
};
return {
name: 'docs:generate-config-docs',
buildStart() {
generateDocs();
async config() {
if (!hasGenerated) {
hasGenerated = true;
await generateDocs();
}
},
configureServer(server: any) {
server.watcher.add(externalTypesPath);
},
handleHotUpdate(ctx: { file: string }) {
async handleHotUpdate(ctx: { file: string }) {
if ([externalTypesPath, configTemplatePath].includes(ctx.file)) {
generateDocs();
await generateDocs();
}
},
};
+36 -17
View File
@@ -1,31 +1,46 @@
/* Colors */
:root {
--wxt-c-green: #53bc4a;
--wxt-c-green-light: #67d45e;
--wxt-c-green-lighter: #67d45e;
--wxt-c-green-dark: #4fa048;
--wxt-c-green-darker: #447e3f;
--wxt-c-green-1: #67d45e;
--wxt-c-green-2: #4fa048;
--wxt-c-green-3: #447e3f;
}
/* https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css */
:root {
--vp-c-brand: var(--wxt-c-green);
--vp-c-brand-light: var(--wxt-c-green-light);
--vp-c-brand-lighter: var(--wxt-c-green-lighter);
--vp-c-brand-dark: var(--wxt-c-green-dark);
--vp-c-brand-darker: var(--wxt-c-green-darker);
--vp-c-brand-1: var(--wxt-c-green-1);
--vp-c-brand-2: var(--wxt-c-green-2);
--vp-c-brand-3: var(--wxt-c-green-3);
--vp-button-brand-bg: var(--wxt-c-green);
--vp-button-brand-hover-bg: var(--wxt-c-green-2);
--vp-button-brand-active-bg: var(--wxt-c-green-3);
--vp-code-link-color: var(--wxt-c-green);
/* --vp-c-text-1: var(--wxt-c-green-1); */
--vp-button-brand-text: var(--vp-c-black);
--vp-button-brand-hover-text: var(--vp-c-black);
--vp-button-brand-active-text: var(--vp-c-black);
--vp-custom-block-tip-border: var(--wxt-c-green-dark);
--vp-custom-block-tip-text: var(--wxt-c-green-dark);
--vp-custom-block-tip-border: var(--wxt-c-green);
--vp-custom-block-tip-text: var(--wxt-c-green);
--vp-code-block-bg: #222422;
/* --vp-code-block-bg: #222422;
--vp-code-copy-code-bg: #313431;
--vp-code-copy-code-hover-bg: #3c403c;
--vp-code-copy-code-hover-bg: #3c403c; */
--vp-custom-block-tip-bg: var(--vp-code-block-bg);
--vp-custom-block-info-bg: var(--vp-code-block-bg);
--vp-code-color: #476582;
}
.vp-doc a {
color: var(--wxt-c-green);
}
.dark {
@@ -38,15 +53,19 @@
--vp-c-bg-alt: #171817;
--vp-c-mute: #313136;
--vp-c-mute-light: #3a3a3c;
--vp-c-mute-lighter: #505053;
--vp-c-mute-dark: #2c2c30;
--vp-c-mute-darker: #252529;
--vp-c-default: #313136;
--vp-c-default-1: #3a3a3c;
--vp-c-default-2: #505053;
--vp-c-default-3: #2c2c30;
--vp-c-default-soft: #252529;
--vp-code-block-bg: #191a19;
--vp-code-copy-code-bg: #212321;
--vp-code-copy-code-hover-bg: #292d29;
--vp-custom-block-info-bg: #191a19;
--vp-code-color: #c9def1;
}
.vp-doc .no-vertical-dividers th,
-200
View File
@@ -1,200 +0,0 @@
<!--
DO NOT EDIT
Generated by `wxt/docs/.vitepress/plugins/generate-config-docs.ts`
To make changes to the config reference, update the JSDoc in `src/core/types/external.ts`.
-->
# Config Reference
Discover all the options you can use in your `wxt.config.ts` file.
## root
- **Type**: `string`
- **Default**: `process.cwd()`
Your project's root directory containing the `package.json` used to fill out the
`manifest.json`.
## srcDir
- **Type**: `string`
- **Default**: `config.root`
Directory containing all source code. Set to `"src"` to move all source code to a `src/`
directory.
## publicDir
- **Type**: `string`
- **Default**: `"${config.root}/public"`
Directory containing files that will be copied to the output directory as-is.
## entrypointsDir
- **Type**: `string`
- **Default**: `"${config.srcDir}/entrypoints"`
## configFile
- **Type**: `string | false`
- **Default**: `"wxt.config.ts"`
Path to `"wxt.config.ts"` file or false to disable config file discovery.
## storeIds.chrome
- **Type**: `string`
- **Default**: `undefined`
## storeIds.firefox
- **Type**: `string`
- **Default**: `undefined`
## storeIds.edge
- **Type**: `string`
- **Default**: `undefined`
## mode
- **Type**: `string`
- **Default**: `undefined`
Explicitly set a mode to run in. This will override the default mode for each command, and can
be overridden by the command line `--mode` option.
## browser
- **Type**: `"chrome" | "firefox" | "safari" | "edge" | "opera"`
- **Default**: `"chrome"`
Explicitly set a browser to build for. This will override the default browser for each command,
and can be overridden by the command line `--browser` option.
## manifestVersion
- **Type**: `2 | 3`
- **Default**: `undefined`
Explicitly set a manifest version to target. This will override the default manifest version
for each command, and can be overridden by the command line `--mv2` or `--mv3` option.
## manifest
- **Type**: `Manifest | Promise<Manifest> | () => Manifest | () => Promise<Manifest>`
- **Default**: `undefined`
Customize the `manifest.json` output. Can be an object, promise, or function that returns an
object or promise.
## runner.openConsole
- **Type**: `boolean`
- **Default**: `undefined`
## runner.openDevtools
- **Type**: `boolean`
- **Default**: `undefined`
## runner.binaries.chrome
- **Type**: `string`
- **Default**: `undefined`
## runner.binaries.edge
- **Type**: `string`
- **Default**: `undefined`
## runner.binaries.opera
- **Type**: `string`
- **Default**: `undefined`
## runner.binaries.firefox
- **Type**: `string`
- **Default**: `undefined`
## runner.firefoxProfile
- **Type**: `string`
- **Default**: `undefined`
## runner.chromiumProfile
- **Type**: `string`
- **Default**: `undefined`
## runner.firefoxArgs
- **Type**: `string[]`
- **Default**: `undefined`
## runner.chromiumArgs
- **Type**: `string[]`
- **Default**: `undefined`
## runner.startUrls
- **Type**: `string[]`
- **Default**: `undefined`
## zip.artifactTemplate
- **Type**: `string`
- **Default**: `"{name}-{version}-{browser}.zip"`
Configure the filename output when zipping files.
Available template variables:
- `{name}` - The project's name converted to kebab-case
- `{version}` - The version_name or version from the manifest
- `{browser}` - The target browser from the `--browser` CLI flag
- `{manifestVersion}` - Either "2" or "3"
## zip.sourcesTemplate
- **Type**: `string`
- **Default**: `"{name}-{version}-sources.zip"`
Configure the filename output when zipping files.
Available template variables:
- `{name}` - The project's name converted to kebab-case
- `{version}` - The version_name or version from the manifest
- `{browser}` - The target browser from the `--browser` CLI flag
- `{manifestVersion}` - Either "2" or "3"
## zip.name
- **Type**: `string`
- **Default**: `undefined`
Override the artifactTemplate's `{name}` template variable. Defaults to the `package.json`'s
name, or if that doesn't exist, the current working directories name.
## zip.sourcesRoot
- **Type**: `string`
- **Default**: `config.root`
Root directory to ZIP when generating the sources ZIP.
## zip.ignoredSources
- **Type**: `string[]`
- **Default**: `undefined`
[Minimatch](https://www.npmjs.com/package/minimatch) patterns of files to exclude when
creating a ZIP of all your source code for Firfox. Patterns are relative to your
`config.zip.sourcesRoot`.
Hidden files, node_modules, and tests are ignored by default.
+1 -1
View File
@@ -16,7 +16,7 @@
Plain old HTML file.
```html
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
+1 -1
View File
@@ -16,7 +16,7 @@
Plain old HTML file.
```html
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
+1 -1
View File
@@ -16,7 +16,7 @@
Plain old HTML file.
```html
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
+1 -1
View File
@@ -16,7 +16,7 @@
Plain old HTML file.
```html
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
+1 -1
View File
@@ -14,7 +14,7 @@
## Definition
```html
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
+1 -1
View File
@@ -14,7 +14,7 @@
## Definition
```html
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
+1 -1
View File
@@ -22,7 +22,7 @@ Firefox does not support sandboxed pages.
Plain old HTML file.
```html
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
+1 -1
View File
@@ -22,7 +22,7 @@ Firefox does not support sidepanel pages.
Plain old HTML file.
```html
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
+1 -1
View File
@@ -32,7 +32,7 @@ console.log(url); // "chrome-extension://<id>/<name>.html"
Plain old HTML file.
```html
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
Binary file not shown.

Before

Width:  |  Height:  |  Size: 487 KiB

After

Width:  |  Height:  |  Size: 472 KiB

+1 -1
View File
@@ -28,7 +28,7 @@ describe('Auto Imports', () => {
| \\"/background.js\\"
| \\"/content-scripts/overlay.js\\"
| \\"/popup.html\\"
export interface ProjectRuntime extends Runtime.Static {
export interface WxtRuntime extends Runtime.Static {
getURL(path: PublicPath): string;
}
}
+40
View File
@@ -266,4 +266,44 @@ describe('Manifest Content', () => {
js: ['content-scripts/one.js'],
});
});
it('should add to any content scripts declared in wxt.config.ts', async () => {
const project = new TestProject();
project.addFile(
'entrypoints/one.content/index.ts',
`export default defineContentScript({
matches: ["*://google.com/*"],
main: () => {},
})`,
);
project.addFile(
'entrypoints/two.content/style.css',
`body {
background-color: red;
}`,
);
project.setConfigFileConfig({
manifest: {
content_scripts: [
{
css: ['content-scripts/two.css'],
matches: ['*://*.google.com/*'],
},
],
},
});
await project.build();
const manifest = await project.getOutputManifest();
expect(manifest.content_scripts).toContainEqual({
css: ['content-scripts/two.css'],
matches: ['*://*.google.com/*'],
});
expect(manifest.content_scripts).toContainEqual({
matches: ['*://google.com/*'],
js: ['content-scripts/one.js'],
});
});
});
+2 -2
View File
@@ -3,7 +3,7 @@ import { TestProject } from '../utils';
describe('Remote Code', () => {
it('should download "url:*" modules and include them in the final bundle', async () => {
const url = 'https://stats.aklinker1.io/umami.js';
const url = 'https://code.jquery.com/jquery-3.7.1.slim.min.js';
const project = new TestProject();
project.addFile('entrypoints/popup.ts', `import "url:${url}"`);
@@ -12,7 +12,7 @@ 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
'umami.disabled',
'jQuery v3.7.1',
);
expect(output).not.toContain(url);
expect(
+341
View File
@@ -0,0 +1,341 @@
import { describe, it, expect } from 'vitest';
import { TestProject } from '../utils';
describe('TypeScript Project', () => {
it('should generate defined constants correctly', async () => {
const project = new TestProject();
await project.build();
const output = await project.serializeFile('.wxt/types/globals.d.ts');
expect(output).toMatchInlineSnapshot(`
".wxt/types/globals.d.ts
----------------------------------------
// Generated by wxt
export {}
declare global {
const __MANIFEST_VERSION__: 2 | 3;
const __BROWSER__: string;
const __IS_CHROME__: boolean;
const __IS_FIREFOX__: boolean;
const __IS_SAFARI__: boolean;
const __IS_EDGE__: boolean;
const __IS_OPERA__: boolean;
const __COMMAND__: \\"build\\" | \\"serve\\";
}
"
`);
});
it('should define auto-import globals', async () => {
const project = new TestProject();
await project.build();
const output = await project.serializeFile('.wxt/types/imports.d.ts');
expect(output).toMatchInlineSnapshot(`
".wxt/types/imports.d.ts
----------------------------------------
// Generated by wxt
export {}
declare global {
const browser: typeof import('wxt/browser')['browser']
const defineBackground: typeof import('wxt/client')['defineBackground']
const defineConfig: typeof import('wxt')['defineConfig']
const defineContentScript: typeof import('wxt/client')['defineContentScript']
const mountContentScriptUi: typeof import('wxt/client')['mountContentScriptUi']
}
"
`);
});
it('should augment the types for browser.runtime.getURL', async () => {
const project = new TestProject();
project.addFile('entrypoints/popup.html');
project.addFile('entrypoints/options.html');
project.addFile('entrypoints/sandbox.html');
await project.build();
const output = await project.serializeFile('.wxt/types/paths.d.ts');
expect(output).toMatchInlineSnapshot(`
".wxt/types/paths.d.ts
----------------------------------------
// Generated by wxt
import \\"wxt/browser\\";
declare module \\"wxt/browser\\" {
type PublicPath =
| \\"/options.html\\"
| \\"/popup.html\\"
| \\"/sandbox.html\\"
export interface WxtRuntime extends Runtime.Static {
getURL(path: PublicPath): string;
}
}
"
`);
});
it('should augment the types for browser.i18n.getMessage', async () => {
const project = new TestProject();
project.addFile(
'public/_locales/en/messages.json',
JSON.stringify({
prompt_for_name: {
message: "What's your name?",
description: "Ask for the user's name",
},
hello: {
message: 'Hello, $USER$',
description: 'Greet the user',
placeholders: {
user: {
content: '$1',
example: 'Cira',
},
},
},
bye: {
message: 'Goodbye, $USER$. Come back to $OUR_SITE$ soon!',
description: 'Say goodbye to the user',
placeholders: {
our_site: {
content: 'Example.com',
},
user: {
content: '$1',
example: 'Cira',
},
},
},
}),
);
project.setConfigFileConfig({
manifest: {
default_locale: 'en',
},
});
await project.build();
const output = await project.serializeFile('.wxt/types/i18n.d.ts');
expect(output).toMatchInlineSnapshot(`
".wxt/types/i18n.d.ts
----------------------------------------
// Generated by wxt
import \\"wxt/browser\\";
declare module \\"wxt/browser\\" {
/**
* See https://developer.chrome.com/docs/extensions/reference/i18n/#method-getMessage
*/
interface GetMessageOptions {
/**
* See https://developer.chrome.com/docs/extensions/reference/i18n/#method-getMessage
*/
escapeLt?: boolean
}
export interface WxtI18n extends I18n.Static {
/**
* The extension or app ID; you might use this string to construct URLs for resources inside the extension. Even unlocalized extensions can use this message.
Note: You can't use this message in a manifest file.
*
* \\"<browser.runtime.id>\\"
*/
getMessage(
messageName: \\"@@extension_id\\",
substitutions?: string | string[],
options?: GetMessageOptions,
): string;
/**
*
*
* \\"<browser.i18n.getUiLocale()>\\"
*/
getMessage(
messageName: \\"@@ui_locale\\",
substitutions?: string | string[],
options?: GetMessageOptions,
): string;
/**
* The text direction for the current locale, either \\"ltr\\" for left-to-right languages such as English or \\"rtl\\" for right-to-left languages such as Japanese.
*
* \\"<ltr|rtl>\\"
*/
getMessage(
messageName: \\"@@bidi_dir\\",
substitutions?: string | string[],
options?: GetMessageOptions,
): string;
/**
* If the @@bidi_dir is \\"ltr\\", then this is \\"rtl\\"; otherwise, it's \\"ltr\\".
*
* \\"<rtl|ltr>\\"
*/
getMessage(
messageName: \\"@@bidi_reversed_dir\\",
substitutions?: string | string[],
options?: GetMessageOptions,
): string;
/**
* If the @@bidi_dir is \\"ltr\\", then this is \\"left\\"; otherwise, it's \\"right\\".
*
* \\"<left|right>\\"
*/
getMessage(
messageName: \\"@@bidi_start_edge\\",
substitutions?: string | string[],
options?: GetMessageOptions,
): string;
/**
* If the @@bidi_dir is \\"ltr\\", then this is \\"right\\"; otherwise, it's \\"left\\".
*
* \\"<right|left>\\"
*/
getMessage(
messageName: \\"@@bidi_end_edge\\",
substitutions?: string | string[],
options?: GetMessageOptions,
): string;
/**
* Ask for the user's name
*
* \\"What's your name?\\"
*/
getMessage(
messageName: \\"prompt_for_name\\",
substitutions?: string | string[],
options?: GetMessageOptions,
): string;
/**
* Greet the user
*
* \\"Hello, $USER$\\"
*/
getMessage(
messageName: \\"hello\\",
substitutions?: string | string[],
options?: GetMessageOptions,
): string;
/**
* Say goodbye to the user
*
* \\"Goodbye, $USER$. Come back to $OUR_SITE$ soon!\\"
*/
getMessage(
messageName: \\"bye\\",
substitutions?: string | string[],
options?: GetMessageOptions,
): string;
}
}
"
`);
});
it('should reference all the required types in a single declaration file', async () => {
const project = new TestProject();
await project.build();
const output = await project.serializeFile('.wxt/wxt.d.ts');
expect(output).toMatchInlineSnapshot(`
".wxt/wxt.d.ts
----------------------------------------
// Generated by wxt
/// <reference types=\\"vite/client\\" />
/// <reference types=\\"./types/imports.d.ts\\" />
/// <reference types=\\"./types/paths.d.ts\\" />
/// <reference types=\\"./types/i18n.d.ts\\" />
/// <reference types=\\"./types/globals.d.ts\\" />
"
`);
});
it('should generate a TSConfig file for the project', async () => {
const project = new TestProject();
await project.build();
const output = await project.serializeFile('.wxt/tsconfig.json');
expect(output).toMatchInlineSnapshot(`
".wxt/tsconfig.json
----------------------------------------
{
\\"compilerOptions\\": {
\\"target\\": \\"ESNext\\",
\\"module\\": \\"ESNext\\",
\\"moduleResolution\\": \\"Bundler\\",
\\"noEmit\\": true,
\\"esModuleInterop\\": true,
\\"forceConsistentCasingInFileNames\\": true,
\\"resolveJsonModule\\": true,
\\"strict\\": true,
\\"lib\\": [\\"DOM\\", \\"WebWorker\\"],
\\"skipLibCheck\\": true,
\\"paths\\": {
\\"@@\\": [\\"..\\"],
\\"@@/*\\": [\\"../*\\"],
\\"~~\\": [\\"..\\"],
\\"~~/*\\": [\\"../*\\"],
\\"@\\": [\\"..\\"],
\\"@/*\\": [\\"../*\\"],
\\"~\\": [\\"..\\"],
\\"~/*\\": [\\"../*\\"]
}
},
\\"include\\": [
\\"../**/*\\",
\\"./wxt.d.ts\\"
],
\\"exclude\\": [\\"../.output\\"]
}"
`);
});
it('should correct path aliases for a custom srcDir', async () => {
const project = new TestProject();
project.setConfigFileConfig({
srcDir: 'src',
});
await project.build();
const output = await project.serializeFile('.wxt/tsconfig.json');
expect(output).toMatchInlineSnapshot(`
".wxt/tsconfig.json
----------------------------------------
{
\\"compilerOptions\\": {
\\"target\\": \\"ESNext\\",
\\"module\\": \\"ESNext\\",
\\"moduleResolution\\": \\"Bundler\\",
\\"noEmit\\": true,
\\"esModuleInterop\\": true,
\\"forceConsistentCasingInFileNames\\": true,
\\"resolveJsonModule\\": true,
\\"strict\\": true,
\\"lib\\": [\\"DOM\\", \\"WebWorker\\"],
\\"skipLibCheck\\": true,
\\"paths\\": {
\\"@@\\": [\\"..\\"],
\\"@@/*\\": [\\"../*\\"],
\\"~~\\": [\\"..\\"],
\\"~~/*\\": [\\"../*\\"],
\\"@\\": [\\"../src\\"],
\\"@/*\\": [\\"../src/*\\"],
\\"~\\": [\\"../src\\"],
\\"~/*\\": [\\"../src/*\\"]
}
},
\\"include\\": [
\\"../**/*\\",
\\"./wxt.d.ts\\"
],
\\"exclude\\": [\\"../.output\\"]
}"
`);
});
});
+2 -2
View File
@@ -10,8 +10,8 @@ export class TestProject {
config: UserConfig | undefined;
readonly root: string;
constructor(root = 'e2e/project') {
// We can't put each test's project inside e2e/project directly, otherwise the wxt.config.ts
constructor(root = 'e2e/dist') {
// We can't put each test's project inside e2e/dist directly, otherwise the wxt.config.ts
// file is cached and cannot be different between each test. Instead, we add a random ID to the
// end to make each test's path unique.
const id = Math.random().toString(32).substring(3);
+16 -15
View File
@@ -1,7 +1,7 @@
{
"name": "wxt",
"type": "module",
"version": "0.3.2",
"version": "0.4.1",
"description": "Next gen framework for developing web extensions",
"engines": {
"node": ">=18.16.0",
@@ -60,7 +60,8 @@
"prepublish": "pnpm -s build",
"docs:dev": "vitepress dev docs",
"docs:build": "vitepress build docs",
"docs:preview": "vitepress preview docs"
"docs:preview": "vitepress preview docs",
"sync-releases": "pnpx changelogen@latest gh release all"
},
"dependencies": {
"@types/webextension-polyfill": "^0.10.1",
@@ -77,14 +78,13 @@
"giget": "^1.1.2",
"jiti": "^1.19.1",
"json5": "^2.2.3",
"linkedom": "^0.14.26",
"linkedom": "^0.15.1",
"minimatch": "^9.0.3",
"picocolors": "^1.0.0",
"prompts": "^2.4.2",
"unimport": "^3.1.0",
"vite": "^4.4.7",
"vite-tsconfig-paths": "^4.2.0",
"web-ext": "^7.6.2",
"web-ext-run": "^0.1.0",
"webextension-polyfill": "^0.10.0",
"zip-dir": "^2.0.0"
},
@@ -93,21 +93,22 @@
"@types/fs-extra": "^11.0.1",
"@types/lodash.merge": "^4.6.7",
"@types/node": "^20.4.5",
"@types/prettier": "^3.0.0",
"@types/prompts": "^2.4.4",
"@vitest/coverage-v8": "^0.32.4",
"@vitest/coverage-v8": "^0.34.1",
"execa": "^7.2.0",
"lint-staged": "^14.0.0",
"lodash.merge": "^4.6.2",
"npm-run-all": "^4.1.5",
"ora": "^6.3.1",
"prettier": "^2.8.8",
"pretty-quick": "^3.1.3",
"ora": "^7.0.1",
"prettier": "^3.0.1",
"simple-git-hooks": "^2.9.0",
"ts-morph": "^19.0.0",
"tsup": "^7.1.0",
"tsx": "^3.12.7",
"typescript": "^5.1.6",
"vitepress": "1.0.0-beta.5",
"vitest": "^0.32.4",
"vitepress": "1.0.0-rc.10",
"vitest": "^0.34.1",
"vitest-mock-extended": "^1.1.4",
"webextension-polyfill": "^0.10.0"
},
@@ -116,16 +117,16 @@
},
"packageManager": "pnpm@8.6.3",
"simple-git-hooks": {
"pre-commit": "pnpm pretty-quick --staged"
"pre-commit": "pnpm lint-staged"
},
"lint-staged": {
"*": "prettier --write"
},
"pnpm": {
"peerDependencyRules": {
"ignoreMissing": [
"@algolia/client-search",
"search-insights"
],
"allowAny": [
"node-fetch"
]
}
}
+402 -1875
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -1,4 +1,4 @@
declare module 'web-ext' {
declare module 'web-ext-run' {
export interface WebExtRunInstance {
reloadAllExtensions(): Promise<void>;
exit(): Promise<void>;
@@ -12,7 +12,7 @@ declare module 'web-ext' {
export default webExt;
}
declare module 'web-ext/util/logger' {
declare module 'web-ext-run/util/logger' {
// https://github.com/mozilla/web-ext/blob/e37e60a2738478f512f1255c537133321f301771/src/util/logger.js#L43
export interface IConsoleStream {
stopCapturing(): void;
+2
View File
@@ -10,6 +10,7 @@ export const build = defineCommand<
browser?: wxt.TargetBrowser;
mv3?: boolean;
mv2?: boolean;
debug?: boolean;
},
]
>(async (root, flags) => {
@@ -20,6 +21,7 @@ export const build = defineCommand<
browser: flags.browser,
manifestVersion: flags.mv3 ? 3 : flags.mv2 ? 2 : undefined,
configFile: flags.config,
debug: flags.debug,
};
await wxt.build(cliConfig);
+11
View File
@@ -0,0 +1,11 @@
import { defineCommand } from '../utils/defineCommand';
import * as wxt from '../..';
export const clean = defineCommand<
[
root: string | undefined,
flags: {
debug?: boolean;
},
]
>(wxt.clean);
+2
View File
@@ -10,6 +10,7 @@ export const dev = defineCommand<
browser?: wxt.TargetBrowser;
mv3?: boolean;
mv2?: boolean;
debug?: boolean;
},
]
>(async (root, flags) => {
@@ -20,6 +21,7 @@ export const dev = defineCommand<
browser: flags.browser,
manifestVersion: flags.mv3 ? 3 : flags.mv2 ? 2 : undefined,
configFile: flags.config,
debug: flags.debug,
};
const server = await wxt.createServer(cliConfig);
+1
View File
@@ -4,3 +4,4 @@ export * from './init';
export * from './prepare';
export * from './publish';
export * from './zip';
export * from './clean';
+5 -2
View File
@@ -9,7 +9,10 @@ import pc from 'picocolors';
import { Formatter } from 'picocolors/types';
export const init = defineCommand<
[directory: string | undefined, options: { template?: string; pm?: string }]
[
directory: string | undefined,
options: { template?: string; pm?: string; debug?: boolean },
]
>(
async (userDirectory, flags) => {
consola.info('Initalizing new project');
@@ -69,7 +72,7 @@ export const init = defineCommand<
console.log();
consola.log('Next steps:');
let step = 0;
if (cdPath !== '.') consola.log(` ${++step}.`, pc.cyan(`cd ${cdPath}`));
if (cdPath !== '') consola.log(` ${++step}.`, pc.cyan(`cd ${cdPath}`));
consola.log(` ${++step}.`, pc.cyan(`${input.packageManager} install`));
console.log();
},
+2
View File
@@ -9,12 +9,14 @@ export const prepare = defineCommand<
root: string | undefined,
flags: {
config?: string;
debug?: boolean;
},
]
>(async (root, flags) => {
const cliConfig: wxt.InlineConfig = {
root,
configFile: flags.config,
debug: flags.debug,
};
const config = await getInternalConfig(cliConfig, 'build');
+4 -1
View File
@@ -2,7 +2,10 @@ import { consola } from 'consola';
import { defineCommand } from '../utils/defineCommand';
export const publish = defineCommand(
async (root: any, { config: configFile }: any) => {
async (
root: any,
{ config: configFile, debug }: { config?: string; debug?: string },
) => {
consola.warn('wxt publish: Not implemented');
},
);
+2
View File
@@ -13,6 +13,7 @@ export const zip = defineCommand<
browser?: wxt.TargetBrowser;
mv3?: boolean;
mv2?: boolean;
debug?: boolean;
},
]
>(async (root, flags) => {
@@ -23,6 +24,7 @@ export const zip = defineCommand<
browser: flags.browser,
manifestVersion: flags.mv3 ? 3 : flags.mv2 ? 2 : undefined,
configFile: flags.config,
debug: flags.debug,
};
const config = await getInternalConfig(cliConfig, 'build');
+9 -1
View File
@@ -6,6 +6,8 @@ const cli = cac('wxt');
cli.help();
cli.version(version);
cli.option('--debug', 'enable debug mode');
// DEV
cli
.command('[root]', 'start dev server')
@@ -38,10 +40,16 @@ cli
// PREPARE
cli
.command('prepare [root]', 'prepare')
.command('prepare [root]', 'prepare typescript project')
.option('-c, --config <file>', 'use specified config file')
.action(commands.prepare);
// CLEAN
cli
.command('clean [root]', 'clean generated files and caches')
.alias('cleanup')
.action(commands.clean);
// PUBLISH
cli.command('publish [root]', 'publish to stores').action(commands.publish);
+8 -1
View File
@@ -1,4 +1,4 @@
import { consola } from 'consola';
import { LogLevels, consola } from 'consola';
import { printHeader } from '../../core/log/printHeader';
import { formatDuration } from '../../core/utils/formatDuration';
@@ -9,6 +9,13 @@ export function defineCommand<TArgs extends any[]>(
},
) {
return async (...args: TArgs) => {
// 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;
}
const startTime = Date.now();
try {
printHeader();
+8 -3
View File
@@ -1,10 +1,15 @@
import originalBrowser, { Browser, Runtime } from 'webextension-polyfill';
import originalBrowser, { Browser, Runtime, I18n } from 'webextension-polyfill';
export interface AugmentedBrowser extends Browser {
runtime: ProjectRuntime;
runtime: WxtRuntime;
i18n: WxtI18n;
}
export interface ProjectRuntime extends Runtime.Static {
export interface WxtRuntime extends Runtime.Static {
// Overriden per-project
}
export interface WxtI18n extends I18n.Static {
// Overriden per-project
}
+73 -10
View File
@@ -7,6 +7,8 @@ import { getUnimportOptions } from '../utils/auto-imports';
import { getGlobals } from '../utils/globals';
import { getPublicFiles } from '../utils/public';
import { normalizePath } from '../utils/paths';
import path from 'node:path';
import { Message, parseI18nMessages } from '../utils/i18n';
/**
* Generate and write all the files inside the `InternalConfig.typesDir` directory.
@@ -20,6 +22,7 @@ export async function generateTypesDir(
const references: string[] = [];
references.push(await writeImportsDeclarationFile(config));
references.push(await writePathsDeclarationFile(entrypoints, config));
references.push(await writeI18nDeclarationFile(config));
references.push(await writeGlobalsDeclarationFile(config));
const mainReference = await writeMainDeclarationFile(references, config);
@@ -70,7 +73,7 @@ import "wxt/browser";
declare module "wxt/browser" {
type PublicPath =
{{ union }}
export interface ProjectRuntime extends Runtime.Static {
export interface WxtRuntime extends Runtime.Static {
getURL(path: PublicPath): string;
}
}
@@ -84,6 +87,65 @@ declare module "wxt/browser" {
return filePath;
}
async function writeI18nDeclarationFile(
config: InternalConfig,
): Promise<string> {
const filePath = resolve(config.typesDir, 'i18n.d.ts');
const defaultLocale = config.manifest.default_locale;
const template = `// Generated by wxt
import "wxt/browser";
declare module "wxt/browser" {
/**
* See https://developer.chrome.com/docs/extensions/reference/i18n/#method-getMessage
*/
interface GetMessageOptions {
/**
* See https://developer.chrome.com/docs/extensions/reference/i18n/#method-getMessage
*/
escapeLt?: boolean
}
export interface WxtI18n extends I18n.Static {
{{ overrides }}
}
}
`;
let messages: Message[];
if (defaultLocale) {
const defaultLocalePath = path.resolve(
config.publicDir,
'_locales',
defaultLocale,
'messages.json',
);
const content = JSON.parse(await fs.readFile(defaultLocalePath, 'utf-8'));
messages = parseI18nMessages(content);
} else {
messages = parseI18nMessages({});
}
const overrides = messages.map((message) => {
return ` /**
* ${message.description ?? 'No message description.'}
*
* "${message.message}"
*/
getMessage(
messageName: "${message.name}",
substitutions?: string | string[],
options?: GetMessageOptions,
): string;`;
});
await fs.writeFile(
filePath,
template.replace('{{ overrides }}', overrides.join('\n')),
);
return filePath;
}
async function writeGlobalsDeclarationFile(
config: InternalConfig,
): Promise<string> {
@@ -128,6 +190,8 @@ async function writeTsConfigFile(
config: InternalConfig,
) {
const dir = config.wxtDir;
const rootPath = normalizePath(relative(dir, config.root));
const srcPath = normalizePath(relative(dir, config.srcDir));
await fs.writeFile(
resolve(dir, 'tsconfig.json'),
`{
@@ -142,16 +206,15 @@ async function writeTsConfigFile(
"strict": true,
"lib": ["DOM", "WebWorker"],
"skipLibCheck": true,
"baseUrl": "${normalizePath(relative(dir, config.root))}",
"paths": {
"@@": ["."],
"@@/*": ["./*"],
"~~": ["."],
"~~/*": ["./*"],
"@": ["${normalizePath(relative(config.root, config.srcDir))}"],
"@/*": ["${normalizePath(relative(config.root, config.srcDir))}/*"],
"~": ["${normalizePath(relative(config.root, config.srcDir))}"],
"~/*": ["${normalizePath(relative(config.root, config.srcDir))}/*"]
"@@": ["${rootPath}"],
"@@/*": ["${rootPath}/*"],
"~~": ["${rootPath}"],
"~~/*": ["${rootPath}/*"],
"@": ["${srcPath}"],
"@/*": ["${srcPath}/*"],
"~": ["${srcPath}"],
"~/*": ["${srcPath}/*"]
}
},
"include": [
+41
View File
@@ -0,0 +1,41 @@
import path from 'node:path';
import glob from 'fast-glob';
import fs from 'fs-extra';
import { consola } from 'consola';
import pc from 'picocolors';
/**
* Remove generated/temp files from the directory.
*
* @param root The directory to look for generated/temp files in. Defaults to `process.cwd()`. Can be relative to `process.cwd()` or absolute.
*/
export async function clean(root = process.cwd()) {
consola.info('Cleaning Project');
const tempDirs = [
'node_modules/.vite',
'node_modules/.cache',
'**/.wxt',
'.output/*',
];
consola.debug('Looking for:', tempDirs.map(pc.cyan).join(', '));
const directories = await glob(tempDirs, {
cwd: path.resolve(root),
absolute: true,
onlyDirectories: true,
deep: 2,
});
if (directories.length === 0) {
consola.debug('No generated files found.');
return;
}
consola.debug(
'Found:',
directories.map((dir) => pc.cyan(path.relative(root, dir))).join(', '),
);
for (const directory of directories) {
await fs.rm(directory, { force: true, recursive: true });
consola.debug('Deleted ' + pc.cyan(path.relative(root, directory)));
}
}
+3 -3
View File
@@ -1,4 +1,4 @@
import type { WebExtRunInstance } from 'web-ext';
import type { WebExtRunInstance } from 'web-ext-run';
import { ExtensionRunner } from './ExtensionRunner';
/**
@@ -15,7 +15,7 @@ export function createWebExtRunner(): ExtensionRunner {
}
// Use the plugin's logger instead of web-ext's built-in one.
const webExtLogger = await import('web-ext/util/logger');
const webExtLogger = await import('web-ext-run/util/logger');
webExtLogger.consoleStream.write = ({ level, msg, name }) => {
if (level >= ERROR_LOG_LEVEL) config.logger.error(name, msg);
if (level >= WARN_LOG_LEVEL) config.logger.warn(msg);
@@ -55,7 +55,7 @@ export function createWebExtRunner(): ExtensionRunner {
config.logger.debug('web-ext config:', finalConfig);
config.logger.debug('web-ext options:', options);
const webExt = await import('web-ext');
const webExt = await import('web-ext-run');
runner = await webExt.default.cmd.run(finalConfig, options);
},
+10 -1
View File
@@ -2,6 +2,7 @@ import * as vite from 'vite';
import { Manifest, Scripting } from 'webextension-polyfill';
import { UnimportOptions } from 'unimport';
import { EntrypointGroup } from '.';
import { LogLevel } from 'consola';
export interface InlineConfig {
/**
@@ -29,11 +30,19 @@ export interface InlineConfig {
*/
entrypointsDir?: string;
/**
* > Only available when using the JS API. Not available in `wxt.config.ts` files
*
* Path to `"wxt.config.ts"` file or false to disable config file discovery.
*
* @default "wxt.config.ts"
*/
configFile?: string | false;
/**
* Set to `true` to show debug logs. Overriden by the command line `--debug` option.
*
* @default false
*/
debug?: boolean;
/**
* ID of the extension for each store. Used for publishing.
*/
@@ -218,6 +227,7 @@ export interface Logger {
error(...args: any[]): void;
fatal(...args: any[]): void;
success(...args: any[]): void;
level: LogLevel;
}
export interface BaseEntrypoint {
@@ -370,7 +380,6 @@ export type UserManifest = Partial<
| 'background'
| 'browser_action'
| 'chrome_url_overrides'
| 'content_scripts'
| 'devtools_page'
| 'manifest_version'
| 'options_page'
+1
View File
@@ -20,6 +20,7 @@ export interface InternalConfig {
entrypointsDir: string;
outBaseDir: string;
outDir: string;
debug: boolean;
storeIds: {
chrome?: string;
firefox?: string;
+5 -2
View File
@@ -9,7 +9,7 @@ import {
} from '../types';
import path, { resolve } from 'node:path';
import * as vite from 'vite';
import { consola } from 'consola';
import { LogLevels, consola } from 'consola';
import * as plugins from '../vite-plugins';
import { createFsCache } from './createFsCache';
import { getGlobals } from './globals';
@@ -33,6 +33,8 @@ export async function getInternalConfig(
const outBaseDir = path.resolve(root, '.output');
const outDir = path.resolve(outBaseDir, `${browser}-mv${manifestVersion}`);
const logger = config.logger ?? consola;
const debug = !!config.debug;
if (debug) logger.level = LogLevels.debug;
const baseConfig: InternalConfigNoUserDirs = {
root,
@@ -43,6 +45,7 @@ export async function getInternalConfig(
manifestVersion,
mode,
command,
debug,
logger,
vite: config.vite ?? {},
imports: config.imports ?? {},
@@ -81,7 +84,7 @@ export async function getInternalConfig(
userConfig.entrypointsDir ?? 'entrypoints',
);
const publicDir = resolve(root, userConfig.publicDir ?? 'public');
const wxtDir = resolve(srcDir, '.wxt');
const wxtDir = resolve(root, '.wxt');
const typesDir = resolve(wxtDir, 'types');
// Merge manifest sources
+52
View File
@@ -0,0 +1,52 @@
export interface Message {
name: string;
message: string;
description?: string;
}
const predefinedMessages = {
'@@extension_id': {
message: '<browser.runtime.id>',
description:
"The extension or app ID; you might use this string to construct URLs for resources inside the extension. Even unlocalized extensions can use this message.\nNote: You can't use this message in a manifest file.",
},
'@@ui_locale': {
message: '<browser.i18n.getUiLocale()>',
description: '',
},
'@@bidi_dir': {
message: '<ltr|rtl>',
description:
'The text direction for the current locale, either "ltr" for left-to-right languages such as English or "rtl" for right-to-left languages such as Japanese.',
},
'@@bidi_reversed_dir': {
message: '<rtl|ltr>',
description:
'If the @@bidi_dir is "ltr", then this is "rtl"; otherwise, it\'s "ltr".',
},
'@@bidi_start_edge': {
message: '<left|right>',
description:
'If the @@bidi_dir is "ltr", then this is "left"; otherwise, it\'s "right".',
},
'@@bidi_end_edge': {
message: '<right|left>',
description:
'If the @@bidi_dir is "ltr", then this is "right"; otherwise, it\'s "left".',
},
};
/**
* Get a list of all messages and their metadata from JSON file contents.
*
* @param messagesJson The contents of a `_locales/en/messages.json` file.
*/
export function parseI18nMessages(messagesJson: object): Message[] {
return Object.entries({
...predefinedMessages,
...messagesJson,
}).map<Message>(([name, details]) => ({
name,
...details,
}));
}
+5 -1
View File
@@ -302,7 +302,7 @@ function addEntrypoints(
return map;
}, new Map<string, ContentScriptEntrypoint[]>());
manifest.content_scripts = Array.from(hashToEntrypointsMap.entries()).map(
const newContentScripts = Array.from(hashToEntrypointsMap.entries()).map(
([, scripts]) => ({
...mapWxtOptionsToContentScript(scripts[0].options),
// TOOD: Sorting css and js arrays here so we get consistent test results... but we
@@ -315,6 +315,10 @@ function addEntrypoints(
.sort(),
}),
);
if (newContentScripts.length >= 0) {
manifest.content_scripts ??= [];
manifest.content_scripts.push(...newContentScripts);
}
}
}
}
+3 -1
View File
@@ -33,7 +33,9 @@ export function multipageMove(
(entry) => !!normalizePath(entry.inputPath).endsWith(oldBundlePath),
);
if (entrypoint == null) {
config.logger.debug('No entrypoint found for', oldBundlePath);
config.logger.debug(
`No entrypoint found for ${oldBundlePath}, leaving in chunks directory`,
);
continue;
}
+17 -7
View File
@@ -1,10 +1,20 @@
import { InternalConfig } from '../types';
import paths from 'vite-tsconfig-paths';
import * as vite from 'vite';
export function tsconfigPaths(config: InternalConfig) {
const fn: typeof paths =
typeof paths === 'function' ? paths : (paths as any).default;
return fn({
root: config.root,
});
export function tsconfigPaths(config: InternalConfig): vite.Plugin {
return {
name: 'wxt:aliases',
async config() {
return {
resolve: {
alias: {
'@@': config.root,
'~~': config.root,
'@': config.srcDir,
'~': config.srcDir,
},
},
};
},
};
}
+1
View File
@@ -15,6 +15,7 @@ import {
setupServer,
} from './core/server';
export * from './core/clean';
export { version } from '../package.json';
export * from './core/types/external';
export * from './core/utils/defineConfig';
+2
View File
@@ -159,6 +159,7 @@ export const fakeRollupOutputChunk = fakeObjectCreator<Rollup.OutputChunk>(
importedAssets: new Set(),
importedCss: new Set(),
},
preliminaryFileName: faker.string.alphanumeric(),
}),
);
@@ -212,6 +213,7 @@ export const fakeInternalConfig = fakeObjectCreator<InternalConfig>(() => ({
runnerConfig: {
config: {},
},
debug: faker.datatype.boolean(),
srcDir: fakeDir(),
storeIds: {},
typesDir: fakeDir(),
+1 -1
View File
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
+1 -1
View File
@@ -23,6 +23,6 @@
"@types/react-dom": "^18.2.6",
"@vitejs/plugin-react": "^4.0.3",
"typescript": "^5.1.6",
"wxt": "^0.3.0"
"wxt": "^0.4.0"
}
}
-9
View File
@@ -3,15 +3,6 @@ import react from '@vitejs/plugin-react';
// See https://wxt.dev/config.html
export default defineConfig({
manifest: {
icons: {
'16': 'icon/16.png',
'32': 'icon/32.png',
'48': 'icon/48.png',
'96': 'icon/96.png',
'128': 'icon/128.png',
},
},
vite: {
plugins: [react()],
},
+1 -1
View File
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
+1 -1
View File
@@ -20,6 +20,6 @@
"devDependencies": {
"typescript": "^5.1.6",
"vite-plugin-solid": "^2.7.0",
"wxt": "^0.3.0"
"wxt": "^0.4.0"
}
}
-9
View File
@@ -3,15 +3,6 @@ import Solid from 'vite-plugin-solid';
// See https://wxt.dev/config.html
export default defineConfig({
manifest: {
icons: {
'16': 'icon/16.png',
'32': 'icon/32.png',
'48': 'icon/48.png',
'96': 'icon/96.png',
'128': 'icon/128.png',
},
},
vite: {
build: {
target: 'esnext',
+1 -1
View File
@@ -20,6 +20,6 @@
"svelte-check": "^3.4.6",
"tslib": "^2.6.0",
"typescript": "^5.1.6",
"wxt": "^0.3.0"
"wxt": "^0.4.0"
}
}
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
+1 -1
View File
@@ -1,5 +1,5 @@
{
"extends": "./src/.wxt/tsconfig.json",
"extends": "./.wxt/tsconfig.json",
"compilerOptions": {
"useDefineForClassFields": true
}
-9
View File
@@ -4,15 +4,6 @@ import { svelte, vitePreprocess } from '@sveltejs/vite-plugin-svelte';
// See https://wxt.dev/config.html
export default defineConfig({
srcDir: 'src',
manifest: {
icons: {
'16': 'icon/16.png',
'32': 'icon/32.png',
'48': 'icon/48.png',
'96': 'icon/96.png',
'128': 'icon/128.png',
},
},
vite: {
plugins: [
svelte({
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
+1 -1
View File
@@ -16,6 +16,6 @@
},
"devDependencies": {
"typescript": "^5.1.6",
"wxt": "^0.3.0"
"wxt": "^0.4.0"
}
}
+1 -11
View File
@@ -1,14 +1,4 @@
import { defineConfig } from 'wxt';
// See https://wxt.dev/config.html
export default defineConfig({
manifest: {
icons: {
'16': 'icon/16.png',
'32': 'icon/32.png',
'48': 'icon/48.png',
'96': 'icon/96.png',
'128': 'icon/128.png',
},
},
});
export default defineConfig({});
+2 -2
View File
@@ -1,5 +1,5 @@
<script lang="ts" setup>
import HelloWorld from '../../components/HelloWorld.vue';
import HelloWorld from '@/components/HelloWorld.vue';
</script>
<template>
@@ -8,7 +8,7 @@ import HelloWorld from '../../components/HelloWorld.vue';
<img src="/wxt.svg" class="logo" alt="WXT logo" />
</a>
<a href="https://vuejs.org/" target="_blank">
<img src="../../assets/vue.svg" class="logo vue" alt="Vue logo" />
<img src="@/assets/vue.svg" class="logo vue" alt="Vue logo" />
</a>
</div>
<HelloWorld msg="WXT + Vue" />
+1 -1
View File
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
+1 -1
View File
@@ -21,6 +21,6 @@
"@vitejs/plugin-vue": "^4.2.3",
"typescript": "^5.1.6",
"vue-tsc": "^1.8.4",
"wxt": "^0.3.0"
"wxt": "^0.4.0"
}
}
-9
View File
@@ -3,15 +3,6 @@ import vue from '@vitejs/plugin-vue';
// See https://wxt.dev/config.html
export default defineConfig({
manifest: {
icons: {
'16': 'icon/16.png',
'32': 'icon/32.png',
'48': 'icon/48.png',
'96': 'icon/96.png',
'128': 'icon/128.png',
},
},
vite: {
plugins: [vue()],
},
+1 -1
View File
@@ -1,4 +1,4 @@
{
"extends": "./tsconfig.base.json",
"exclude": ["dist", "demo", "e2e/project", "templates"]
"exclude": ["dist", "demo", "e2e/dist", "templates"]
}
+2 -2
View File
@@ -16,7 +16,7 @@ const testSeed = (): Plugin => ({
});
// Clear e2e test projects
await fs.rm('e2e/project', { recursive: true, force: true });
await fs.rm('e2e/dist', { recursive: true, force: true });
export default defineWorkspace([
{
@@ -33,7 +33,7 @@ export default defineWorkspace([
name: 'e2e',
dir: 'e2e',
singleThread: true,
testTimeout: 20e3,
testTimeout: 60e3,
},
plugins: [testSeed()],
},