Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 36cfcd0acb | |||
| f746d46247 | |||
| a2de6cbe44 | |||
| e632a2964a | |||
| f736a14651 | |||
| a8b0d40959 | |||
| 4c5504d139 | |||
| fb86deb388 | |||
| 3a8e6135ac | |||
| a38de0c03f | |||
| ea97410fb4 | |||
| e36549ddce | |||
| 10851ae01c | |||
| d553ef6b29 | |||
| 15bf0da82e | |||
| fc246ffaac | |||
| 9785eff21e | |||
| 52fbd2c99e | |||
| 648ae4fb8d | |||
| bbeeabc9ea | |||
| 35cf6e7bc0 | |||
| 78822acdac | |||
| aea123890f | |||
| c369f4a955 | |||
| 16d8240406 | |||
| 24cd01dd31 | |||
| fb22beadb8 | |||
| fa85177648 | |||
| ed07a49dd2 | |||
| 09c9de0a60 | |||
| 523296b29a | |||
| ef67ef47aa | |||
| cb5eb68d62 | |||
| 2e9ab75e2b | |||
| 0c2d795800 | |||
| 97aa173f7e |
@@ -59,10 +59,10 @@ Or see the [installation guide](https://wxt.dev/guide/installation.html) to get
|
||||
- 🦾 Auto-imports
|
||||
- 🤖 Automated publishing
|
||||
- 🎨 Frontend framework agnostic: works with Vue, React, Svelte, etc
|
||||
- 📦 Modular architecture with [WXT modules](https://wxt.dev/guide/go-further/reusable-modules.html#overview)
|
||||
- 🖍️ Quickly bootstrap a new project
|
||||
- 📏 Bundle analysis
|
||||
- ⬇️ Download and bundle remote URL imports
|
||||
- 📦 Modular architecture with [modules](https://wxt.dev/guide/go-further/reusable-modules.html#overview)
|
||||
|
||||
## Contributors
|
||||
|
||||
|
||||
@@ -35,6 +35,9 @@ const chromeExtensionIds = [
|
||||
'bcpgdpedphodjcjlminjbdeejccjbimp', // 汇率转换-中文版本
|
||||
'loeilaonggnalkaiiaepbegccilkmjjp', // Currency Converter Plus
|
||||
'npcnninnjghigjfiecefheeibomjpkak', // Respond Easy
|
||||
'cfkdcideecefncbglkhneoflfnmhoicc', // mindful - stay focused on your goals
|
||||
'lnhejcpclabmbgpiiomjbhalblnnbffg', // 1Proompt
|
||||
'fonflmjnjbkigocpoommgmhljdpljain', // NiceTab - https://github.com/web-dahuyou/NiceTab
|
||||
];
|
||||
|
||||
const { data, err, isLoading } = useListExtensionDetails(chromeExtensionIds);
|
||||
|
||||
@@ -53,9 +53,9 @@ declare module 'wxt/sandbox' {
|
||||
}
|
||||
|
||||
export default defineAppConfig({
|
||||
bugReportingDisabled: process.env.VITE_BUG_REPORTING_DISABLED === 'true',
|
||||
apiKey: process.env.VITE_API_KEY,
|
||||
bugReportingDisabled: import.meta.env.VITE_BUG_REPORTING_DISABLED === 'true',
|
||||
apiKey: import.meta.env.VITE_API_KEY,
|
||||
});
|
||||
```
|
||||
|
||||
> You don't have to do this, you can use `process.env.VITE_*` anywhere in your runtime code, but putting them here consolidates them to one place and defines what variables are expected.
|
||||
> You don't have to do this, you can use `import.meta.env.VITE_*` anywhere in your runtime code, but putting them here consolidates them to one place and defines what variables are expected.
|
||||
|
||||
@@ -25,12 +25,12 @@ There are two ways to add a module to your project:
|
||||
});
|
||||
```
|
||||
|
||||
2. **NPM package**: By convention, any package on NPM that starts with `@wxt-dev/module-*` or `wxt-module-*` can be installed and included in your project:
|
||||
2. **NPM package**: Find WXT modules on NPM and include them in your project:
|
||||
```ts
|
||||
// wxt.config.ts
|
||||
export default defineConfig({
|
||||
// Add the module to your project
|
||||
modules: ['wxt-module-example'],
|
||||
modules: ['@wxt-dev/auto-icons'],
|
||||
});
|
||||
```
|
||||
|
||||
@@ -99,9 +99,9 @@ export default defineConfig({
|
||||
|
||||
### Actually Doing Something
|
||||
|
||||
The first argument of the setup function, `wxt`, provides full access to the current build's context. You can access the resolved configuration via `wxt.config`, or setup hooks to manipulate the build at different steps of the build process.
|
||||
The first argument of the setup function, `wxt`, provides full access to the current build's context. You can access the resolved configuration via `wxt.config`, or setup hooks to manipulate the build at different steps of the build process with `wxt.hooks`.
|
||||
|
||||
Here's an example that shows you how to update the `outDir` based on the build mode. It does a good job showing how to access config, set up a hook, and do something when the hook is called.
|
||||
Here's an example that updates the `outDir` based on the build mode. It's a very simple example of how to access config and setup a hook.
|
||||
|
||||
```ts
|
||||
export default defineWxtModule((wxt) => {
|
||||
|
||||
@@ -53,6 +53,11 @@ features:
|
||||
details: Works with any front-end framework with a Vite plugin.
|
||||
link: /guide/key-concepts/frontend-frameworks
|
||||
linkText: Add a framework
|
||||
- icon: 📦
|
||||
title: Modular Architecture
|
||||
details: Reuse build-time and runtime-code across multiple extensions.
|
||||
link: /guide/go-further/reusable-modules
|
||||
linkText: Read docs
|
||||
- icon: 🖍️
|
||||
title: Bootstrap a New Project
|
||||
details: Get started quickly with several awesome project templates.
|
||||
|
||||
+7
-8
@@ -2,10 +2,9 @@
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"engines": {
|
||||
"node": ">=18.20.3",
|
||||
"pnpm": "^8.6.3"
|
||||
"node": ">=18.20.3"
|
||||
},
|
||||
"packageManager": "pnpm@8.15.9",
|
||||
"packageManager": "pnpm@9.6.0",
|
||||
"scripts": {
|
||||
"check": "check && pnpm -r --sequential run check",
|
||||
"test": "pnpm -r --sequential run test run",
|
||||
@@ -21,7 +20,7 @@
|
||||
"@aklinker1/buildc": "^1.0.11",
|
||||
"@aklinker1/check": "^1.3.1",
|
||||
"@types/fs-extra": "^11.0.4",
|
||||
"@vitest/coverage-v8": "^2.0.0",
|
||||
"@vitest/coverage-v8": "^2.0.4",
|
||||
"changelogen": "^0.5.5",
|
||||
"consola": "^3.2.3",
|
||||
"dependency-graph": "^1.0.0",
|
||||
@@ -37,12 +36,12 @@
|
||||
"typedoc": "^0.25.4",
|
||||
"typedoc-plugin-markdown": "4.0.0-next.23",
|
||||
"typedoc-vitepress-theme": "1.0.0-next.3",
|
||||
"typescript": "^5.5.3",
|
||||
"typescript": "^5.5.4",
|
||||
"vitepress": "^1.3.1",
|
||||
"vitest-mock-extended": "^1.3.2",
|
||||
"vue": "^3.4.33",
|
||||
"vitest-mock-extended": "^2.0.0",
|
||||
"vue": "^3.4.34",
|
||||
"wxt": "workspace:*",
|
||||
"yaml": "^2.4.5"
|
||||
"yaml": "^2.5.0"
|
||||
},
|
||||
"simple-git-hooks": {
|
||||
"pre-commit": "pnpm lint-staged"
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# Changelog
|
||||
|
||||
## v1.0.2
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/auto-icons-v1.0.1...auto-icons-v1.0.2)
|
||||
|
||||
### 📖 Documentation
|
||||
|
||||
- **auto-icons:** Fix configuration example typo ([#905](https://github.com/wxt-dev/wxt/pull/905))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- Add more metadata for npm ([#885](https://github.com/wxt-dev/wxt/pull/885))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Uncenter ([@uncenter](http://github.com/uncenter))
|
||||
- Florian Metz ([@Timeraa](http://github.com/Timeraa))
|
||||
|
||||
## v1.0.1
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/auto-icons-v1.0.0...auto-icons-v1.0.1)
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- **auto-icons:** Path option ([#880](https://github.com/wxt-dev/wxt/pull/880))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- **deps:** Upgrade all dependencies ([#869](https://github.com/wxt-dev/wxt/pull/869))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Florian Metz ([@Timeraa](http://github.com/Timeraa))
|
||||
@@ -32,7 +32,7 @@ The module can be configured via the `autoIcons` config:
|
||||
|
||||
```ts
|
||||
export default defineConfig({
|
||||
module: ['@wxt-dev/auto-icons'],
|
||||
modules: ['@wxt-dev/auto-icons'],
|
||||
autoIcons: {
|
||||
// ...
|
||||
},
|
||||
|
||||
@@ -1,6 +1,30 @@
|
||||
{
|
||||
"name": "@wxt-dev/auto-icons",
|
||||
"version": "1.0.0",
|
||||
"description": "WXT module for automatically generating extension icons in different sizes",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/wxt-dev/wxt.git",
|
||||
"directory": "packages/auto-icons"
|
||||
},
|
||||
"homepage": "https://github.com/wxt-dev/wxt/blob/main/packages/auto-icons/README.md",
|
||||
"keywords": [
|
||||
"wxt",
|
||||
"module",
|
||||
"icons",
|
||||
"manifest"
|
||||
],
|
||||
"author": {
|
||||
"name": "Florian Metz",
|
||||
"email": "me@timeraa.dev"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Aaron Klinker",
|
||||
"email": "aaronklinker1+wxt@gmail.com"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"version": "1.0.2",
|
||||
"type": "module",
|
||||
"module": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -15,7 +39,7 @@
|
||||
],
|
||||
"scripts": {
|
||||
"build": "buildc -- unbuild",
|
||||
"check": "buildc --deps-only -- check"
|
||||
"check": "pnpm build && check"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"wxt": ">=0.19.0"
|
||||
@@ -23,7 +47,7 @@
|
||||
"devDependencies": {
|
||||
"@aklinker1/check": "^1.3.1",
|
||||
"publint": "^0.2.9",
|
||||
"typescript": "^5.5.3",
|
||||
"typescript": "^5.5.4",
|
||||
"unbuild": "^2.0.0",
|
||||
"wxt": "workspace:*"
|
||||
},
|
||||
|
||||
@@ -9,20 +9,24 @@ export default defineWxtModule<AutoIconsOptions>({
|
||||
name: '@wxt-dev/auto-icons',
|
||||
configKey: 'autoIcons',
|
||||
async setup(wxt, options) {
|
||||
const parsedOptions = defu(options, {
|
||||
enabled: true,
|
||||
baseIconsPath: resolve(wxt.config.srcDir, 'assets/icon.png'),
|
||||
grayscaleOnDevelopment: true,
|
||||
sizes: [128, 48, 32, 16],
|
||||
});
|
||||
const parsedOptions = defu<Required<AutoIconsOptions>, AutoIconsOptions[]>(
|
||||
options,
|
||||
{
|
||||
enabled: true,
|
||||
baseIconPath: resolve(wxt.config.srcDir, 'assets/icon.png'),
|
||||
grayscaleOnDevelopment: true,
|
||||
sizes: [128, 48, 32, 16],
|
||||
},
|
||||
);
|
||||
|
||||
const resolvedPath = resolve(wxt.config.srcDir, parsedOptions.baseIconPath);
|
||||
|
||||
if (!parsedOptions.enabled)
|
||||
return wxt.logger.warn(`\`[auto-icons]\` ${this.name} disabled`);
|
||||
|
||||
if (!(await exists(parsedOptions.baseIconsPath))) {
|
||||
const relativePath = relative(process.cwd(), parsedOptions.baseIconsPath);
|
||||
if (!(await exists(resolvedPath))) {
|
||||
return wxt.logger.warn(
|
||||
`\`[auto-icons]\` Skipping icon generation, no base icon found at ${relativePath}`,
|
||||
`\`[auto-icons]\` Skipping icon generation, no base icon found at ${relative(process.cwd(), resolvedPath)}`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -38,7 +42,7 @@ export default defineWxtModule<AutoIconsOptions>({
|
||||
});
|
||||
|
||||
wxt.hooks.hook('build:done', async (wxt, output) => {
|
||||
const image = sharp(parsedOptions.baseIconsPath).png();
|
||||
const image = sharp(resolvedPath).png();
|
||||
|
||||
if (
|
||||
wxt.config.mode === 'development' &&
|
||||
@@ -80,6 +84,8 @@ export interface AutoIconsOptions {
|
||||
enabled?: boolean;
|
||||
/**
|
||||
* Path to the image to use.
|
||||
*
|
||||
* Path is relative to the project's src directory.
|
||||
* @default "<srcDir>/assets/icon.png"
|
||||
*/
|
||||
baseIconPath?: string;
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
# Changelog
|
||||
|
||||
## v1.1.1
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/module-react-v1.1.0...module-react-v1.1.1)
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- **deps:** Bump all non-major dependencies ([#834](https://github.com/wxt-dev/wxt/pull/834))
|
||||
- **deps:** Upgrade all dependencies ([#869](https://github.com/wxt-dev/wxt/pull/869))
|
||||
- Add more metadata for npm ([#885](https://github.com/wxt-dev/wxt/pull/885))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Florian Metz ([@Timeraa](http://github.com/Timeraa))
|
||||
|
||||
## v1.1.0
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/module-react-v1.0.0...module-react-v1.1.0)
|
||||
|
||||
@@ -9,7 +9,6 @@ export default defineWxtModule<ReactModuleOptions>({
|
||||
const { vite } = options ?? {};
|
||||
|
||||
addViteConfig(wxt, () => ({
|
||||
// @ts-expect-error: Vite version conflicts
|
||||
plugins: [react(vite)],
|
||||
}));
|
||||
|
||||
|
||||
@@ -1,6 +1,23 @@
|
||||
{
|
||||
"name": "@wxt-dev/module-react",
|
||||
"version": "1.1.0",
|
||||
"description": "WXT module to enable React support",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/wxt-dev/wxt.git",
|
||||
"directory": "packages/module-react"
|
||||
},
|
||||
"homepage": "https://github.com/wxt-dev/wxt/blob/main/packages/module-react/README.md",
|
||||
"keywords": [
|
||||
"wxt",
|
||||
"module",
|
||||
"react"
|
||||
],
|
||||
"author": {
|
||||
"name": "Aaron Klinker",
|
||||
"email": "aaronklinker1+wxt@gmail.com"
|
||||
},
|
||||
"license": "MIT",
|
||||
"version": "1.1.1",
|
||||
"type": "module",
|
||||
"main": "./dist/index.cjs",
|
||||
"module": "./dist/index.mjs",
|
||||
@@ -22,7 +39,7 @@
|
||||
],
|
||||
"scripts": {
|
||||
"dev": "wxt",
|
||||
"check": "buildc --deps-only -- check",
|
||||
"check": "pnpm build && check",
|
||||
"build": "buildc -- unbuild",
|
||||
"prepare": "buildc --deps-only -- wxt prepare"
|
||||
},
|
||||
@@ -39,7 +56,7 @@
|
||||
"publint": "^0.2.9",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"typescript": "^5.5.3",
|
||||
"typescript": "^5.5.4",
|
||||
"unbuild": "^2.0.0",
|
||||
"wxt": "workspace:*"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
# Changelog
|
||||
|
||||
## v1.1.2
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/module-solid-v1.1.1...module-solid-v1.1.2)
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- **deps:** Bump all non-major dependencies ([#834](https://github.com/wxt-dev/wxt/pull/834))
|
||||
- **deps:** Upgrade all dependencies ([#869](https://github.com/wxt-dev/wxt/pull/869))
|
||||
- Add more metadata for npm ([#885](https://github.com/wxt-dev/wxt/pull/885))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Florian Metz ([@Timeraa](http://github.com/Timeraa))
|
||||
|
||||
## v1.1.1
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/module-solid-v1.1.0...module-solid-v1.1.1)
|
||||
|
||||
@@ -9,7 +9,6 @@ export default defineWxtModule<SolidModuleOptions>({
|
||||
const { vite } = options ?? {};
|
||||
|
||||
addViteConfig(wxt, () => ({
|
||||
// @ts-expect-error: Vite version mismatch
|
||||
plugins: [solid(vite)],
|
||||
build: {
|
||||
target: 'esnext',
|
||||
|
||||
@@ -1,6 +1,23 @@
|
||||
{
|
||||
"name": "@wxt-dev/module-solid",
|
||||
"version": "1.1.1",
|
||||
"description": "WXT module to enable SolidJS support",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/wxt-dev/wxt.git",
|
||||
"directory": "packages/module-solid"
|
||||
},
|
||||
"homepage": "https://github.com/wxt-dev/wxt/blob/main/packages/module-solid/README.md",
|
||||
"keywords": [
|
||||
"wxt",
|
||||
"module",
|
||||
"solidjs"
|
||||
],
|
||||
"author": {
|
||||
"name": "Aaron Klinker",
|
||||
"email": "aaronklinker1+wxt@gmail.com"
|
||||
},
|
||||
"license": "MIT",
|
||||
"version": "1.1.2",
|
||||
"type": "module",
|
||||
"main": "./dist/index.cjs",
|
||||
"module": "./dist/index.mjs",
|
||||
@@ -22,7 +39,7 @@
|
||||
],
|
||||
"scripts": {
|
||||
"dev": "wxt",
|
||||
"check": "buildc --deps-only -- check",
|
||||
"check": "pnpm build && check",
|
||||
"build": "buildc -- unbuild",
|
||||
"prepare": "buildc --deps-only -- wxt prepare"
|
||||
},
|
||||
@@ -35,8 +52,8 @@
|
||||
"devDependencies": {
|
||||
"@aklinker1/check": "^1.3.1",
|
||||
"publint": "^0.2.9",
|
||||
"solid-js": "^1.8.18",
|
||||
"typescript": "^5.5.3",
|
||||
"solid-js": "^1.8.19",
|
||||
"typescript": "^5.5.4",
|
||||
"unbuild": "^2.0.0",
|
||||
"wxt": "workspace:*"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,31 @@
|
||||
# Changelog
|
||||
|
||||
## v1.0.1
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/module-svelte-v1.0.0...module-svelte-v1.0.1)
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Upgrade wxt peer to >= 0.18.6 ([7edf1c8](https://github.com/wxt-dev/wxt/commit/7edf1c8))
|
||||
|
||||
### 📖 Documentation
|
||||
|
||||
- Fix link to unimport ([#826](https://github.com/wxt-dev/wxt/pull/826))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- Add changelog ([21e8ca0](https://github.com/wxt-dev/wxt/commit/21e8ca0))
|
||||
- Extract build cache script to NPM package ([#737](https://github.com/wxt-dev/wxt/pull/737))
|
||||
- **deps:** Upgrade non-major deps ([#778](https://github.com/wxt-dev/wxt/pull/778))
|
||||
- **deps:** Bump all non-major dependencies ([#834](https://github.com/wxt-dev/wxt/pull/834))
|
||||
- **deps:** Upgrade all dependencies ([#869](https://github.com/wxt-dev/wxt/pull/869))
|
||||
- Add more metadata for npm ([#885](https://github.com/wxt-dev/wxt/pull/885))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Florian Metz ([@Timeraa](http://github.com/Timeraa))
|
||||
- Eetann ([@eetann](http://github.com/eetann))
|
||||
|
||||
## v1.0.0
|
||||
|
||||
Initial release 🎉
|
||||
Initial release 🎉
|
||||
@@ -1,6 +1,23 @@
|
||||
{
|
||||
"name": "@wxt-dev/module-svelte",
|
||||
"version": "1.0.0",
|
||||
"description": "WXT module to enable Svelte support",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/wxt-dev/wxt.git",
|
||||
"directory": "packages/module-svelte"
|
||||
},
|
||||
"homepage": "https://github.com/wxt-dev/wxt/blob/main/packages/module-svelte/README.md",
|
||||
"keywords": [
|
||||
"wxt",
|
||||
"module",
|
||||
"svelte"
|
||||
],
|
||||
"author": {
|
||||
"name": "Aaron Klinker",
|
||||
"email": "aaronklinker1+wxt@gmail.com"
|
||||
},
|
||||
"license": "MIT",
|
||||
"version": "1.0.1",
|
||||
"type": "module",
|
||||
"main": "./dist/index.cjs",
|
||||
"module": "./dist/index.mjs",
|
||||
@@ -22,7 +39,7 @@
|
||||
],
|
||||
"scripts": {
|
||||
"build": "buildc -- unbuild",
|
||||
"check": "buildc --deps-only -- check"
|
||||
"check": "pnpm build && check"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"wxt": ">=0.18.6"
|
||||
@@ -33,7 +50,7 @@
|
||||
"devDependencies": {
|
||||
"@aklinker1/check": "^1.3.1",
|
||||
"publint": "^0.2.9",
|
||||
"typescript": "^5.5.3",
|
||||
"typescript": "^5.5.4",
|
||||
"unbuild": "^2.0.0",
|
||||
"wxt": "workspace:*"
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ export default defineWxtModule<SvelteModuleOptions>({
|
||||
|
||||
addViteConfig(wxt, () => ({
|
||||
plugins: [
|
||||
// @ts-expect-error: Vite version mismatch
|
||||
svelte({
|
||||
// Using a svelte.config.js file causes a segmentation fault when importing the file
|
||||
configFile: false,
|
||||
|
||||
@@ -1,5 +1,26 @@
|
||||
# Changelog
|
||||
|
||||
## v1.0.1
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/module-vue-v1.0.0...module-vue-v1.0.1)
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Upgrade wxt peer to >= 0.18.6 ([7edf1c8](https://github.com/wxt-dev/wxt/commit/7edf1c8))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- Add changelog ([21e8ca0](https://github.com/wxt-dev/wxt/commit/21e8ca0))
|
||||
- Extract build cache script to NPM package ([#737](https://github.com/wxt-dev/wxt/pull/737))
|
||||
- **deps:** Upgrade non-major deps ([#778](https://github.com/wxt-dev/wxt/pull/778))
|
||||
- **deps:** Bump all non-major dependencies ([#834](https://github.com/wxt-dev/wxt/pull/834))
|
||||
- **deps:** Upgrade all dependencies ([#869](https://github.com/wxt-dev/wxt/pull/869))
|
||||
- Add more metadata for npm ([#885](https://github.com/wxt-dev/wxt/pull/885))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Florian Metz ([@Timeraa](http://github.com/Timeraa))
|
||||
|
||||
## v1.0.0
|
||||
|
||||
Initial release 🎉
|
||||
Initial release 🎉
|
||||
@@ -1,6 +1,23 @@
|
||||
{
|
||||
"name": "@wxt-dev/module-vue",
|
||||
"version": "1.0.0",
|
||||
"description": "WXT module to enable Vue support",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/wxt-dev/wxt.git",
|
||||
"directory": "packages/module-vue"
|
||||
},
|
||||
"homepage": "https://github.com/wxt-dev/wxt/blob/main/packages/module-vue/README.md",
|
||||
"keywords": [
|
||||
"wxt",
|
||||
"module",
|
||||
"vue"
|
||||
],
|
||||
"author": {
|
||||
"name": "Aaron Klinker",
|
||||
"email": "aaronklinker1+wxt@gmail.com"
|
||||
},
|
||||
"license": "MIT",
|
||||
"version": "1.0.1",
|
||||
"type": "module",
|
||||
"main": "./dist/index.cjs",
|
||||
"module": "./dist/index.mjs",
|
||||
@@ -22,18 +39,18 @@
|
||||
],
|
||||
"scripts": {
|
||||
"build": "buildc -- unbuild",
|
||||
"check": "buildc --deps-only -- check"
|
||||
"check": "pnpm build && check"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"wxt": ">=0.18.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vitejs/plugin-vue": "^5.0.5"
|
||||
"@vitejs/plugin-vue": "^5.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@aklinker1/check": "^1.3.1",
|
||||
"publint": "^0.2.9",
|
||||
"typescript": "^5.5.3",
|
||||
"typescript": "^5.5.4",
|
||||
"unbuild": "^2.0.0",
|
||||
"wxt": "workspace:*"
|
||||
}
|
||||
|
||||
@@ -21,13 +21,13 @@
|
||||
"react-dom": "^18.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/chrome": "^0.0.268",
|
||||
"@types/chrome": "^0.0.269",
|
||||
"@types/react": "^18.3.3",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@wxt-dev/auto-icons": "workspace:*",
|
||||
"sass": "^1.77.8",
|
||||
"typescript": "^5.5.3",
|
||||
"vitest": "^2.0.3",
|
||||
"typescript": "^5.5.4",
|
||||
"vitest": "^2.0.4",
|
||||
"vitest-plugin-random-seed": "^1.1.0",
|
||||
"wxt": "workspace:*"
|
||||
},
|
||||
|
||||
@@ -6,8 +6,5 @@ export default defineProject({
|
||||
mockReset: true,
|
||||
restoreMocks: true,
|
||||
},
|
||||
plugins: [
|
||||
// @ts-expect-error: Vite version mismatch
|
||||
WxtVitest(),
|
||||
],
|
||||
plugins: [WxtVitest()],
|
||||
});
|
||||
|
||||
@@ -1,5 +1,78 @@
|
||||
# Changelog
|
||||
|
||||
## v0.19.4
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.19.3...wxt-v0.19.4)
|
||||
|
||||
### 🚀 Enhancements
|
||||
|
||||
- Add `injectScript` helper ([#900](https://github.com/wxt-dev/wxt/pull/900))
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Do not clear `.wxt/tsconfig.json` in `findEntrypoints` if it exists ([#898](https://github.com/wxt-dev/wxt/pull/898))
|
||||
- **types:** `PublicPath` type resolution with `extensionApi: "chrome"` ([#901](https://github.com/wxt-dev/wxt/pull/901))
|
||||
- Fix `createIframeUi` `page` option types ([3a8e613](https://github.com/wxt-dev/wxt/commit/3a8e613))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Hikiko4ern ([@hikiko4ern](http://github.com/hikiko4ern))
|
||||
|
||||
## v0.19.3
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.19.2...wxt-v0.19.3)
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Add `consola` to `wxt` dependencies ([#892](https://github.com/wxt-dev/wxt/pull/892))
|
||||
- **content-script-context:** Fix initialization logic for Firefox ([#895](https://github.com/wxt-dev/wxt/pull/895))
|
||||
|
||||
### 📖 Documentation
|
||||
|
||||
- Improve `prepare:types` hook JSDoc ([#886](https://github.com/wxt-dev/wxt/pull/886))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Hikiko4ern ([@hikiko4ern](http://github.com/hikiko4ern))
|
||||
- Himanshu Patil ([@mehimanshupatil](https://github.com/mehimanshupatil))
|
||||
|
||||
## v0.19.2
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.19.1...wxt-v0.19.2)
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Remove unused top-level functions and variables when loading entrypoints with the `vite-node` loader ([#875](https://github.com/wxt-dev/wxt/pull/875))
|
||||
- Don't default to dev mode for production builds when using `vite-node` loader ([#877](https://github.com/wxt-dev/wxt/pull/877))
|
||||
|
||||
### 📖 Documentation
|
||||
|
||||
- Update README and homepage features with WXT modules ([ed07a49](https://github.com/wxt-dev/wxt/commit/ed07a49))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- **deps:** Upgrade all dependencies ([#869](https://github.com/wxt-dev/wxt/pull/869))
|
||||
|
||||
## v0.19.1
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.19.0...wxt-v0.19.1)
|
||||
|
||||
### 🚀 Enhancements
|
||||
|
||||
- Auto Icons Module ([#851](https://github.com/wxt-dev/wxt/pull/851))
|
||||
|
||||
### 🔥 Performance
|
||||
|
||||
- Tree-shake unrelated code inside `vite-node` entrypoint loader ([#867](https://github.com/wxt-dev/wxt/pull/867))
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Define web globals when importing entrypoints ([#865](https://github.com/wxt-dev/wxt/pull/865))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Florian Metz ([@Timeraa](http://github.com/Timeraa))
|
||||
|
||||
## v0.19.0
|
||||
|
||||
[⚠️ breaking changes](https://wxt.dev/guide/upgrade-guide/wxt) • [compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.18.15...wxt-v0.19.0)
|
||||
|
||||
@@ -59,6 +59,7 @@ Or see the [installation guide](https://wxt.dev/guide/installation.html) to get
|
||||
- 🦾 Auto-imports
|
||||
- 🤖 Automated publishing
|
||||
- 🎨 Frontend framework agnostic: works with Vue, React, Svelte, etc
|
||||
- 📦 Modular architecture with [WXT modules](https://wxt.dev/guide/go-further/reusable-modules.html#overview)
|
||||
- 🖍️ Quickly bootstrap a new project
|
||||
- 📏 Bundle analysis
|
||||
- ⬇️ Download and bundle remote URL imports
|
||||
|
||||
@@ -19,6 +19,7 @@ exports[`Auto Imports > eslintrc > "enabled: 8" should output a JSON config file
|
||||
"defineUnlistedScript": true,
|
||||
"defineWxtPlugin": true,
|
||||
"fakeBrowser": true,
|
||||
"injectScript": true,
|
||||
"storage": true,
|
||||
"useAppConfig": true
|
||||
}
|
||||
@@ -44,6 +45,7 @@ const globals = {
|
||||
"defineUnlistedScript": true,
|
||||
"defineWxtPlugin": true,
|
||||
"fakeBrowser": true,
|
||||
"injectScript": true,
|
||||
"storage": true,
|
||||
"useAppConfig": true
|
||||
}
|
||||
@@ -77,6 +79,7 @@ exports[`Auto Imports > eslintrc > "enabled: true" should output a JSON config f
|
||||
"defineUnlistedScript": true,
|
||||
"defineWxtPlugin": true,
|
||||
"fakeBrowser": true,
|
||||
"injectScript": true,
|
||||
"storage": true,
|
||||
"useAppConfig": true
|
||||
}
|
||||
@@ -103,6 +106,7 @@ exports[`Auto Imports > eslintrc > should allow customizing the output 1`] = `
|
||||
"defineUnlistedScript": "readonly",
|
||||
"defineWxtPlugin": "readonly",
|
||||
"fakeBrowser": "readonly",
|
||||
"injectScript": "readonly",
|
||||
"storage": "readonly",
|
||||
"useAppConfig": "readonly"
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ describe('Auto Imports', () => {
|
||||
const defineUnlistedScript: typeof import('wxt/sandbox')['defineUnlistedScript']
|
||||
const defineWxtPlugin: typeof import('wxt/sandbox')['defineWxtPlugin']
|
||||
const fakeBrowser: typeof import('wxt/testing')['fakeBrowser']
|
||||
const injectScript: typeof import('wxt/client')['injectScript']
|
||||
const storage: typeof import('wxt/storage')['storage']
|
||||
const useAppConfig: typeof import('wxt/client')['useAppConfig']
|
||||
}
|
||||
|
||||
@@ -280,7 +280,7 @@ describe('Output Directory Structure', () => {
|
||||
var _a, _b;
|
||||
import { l as logHello, i as initPlugins } from "./chunks/_virtual_wxt-plugins-OjKtWpmY.js";
|
||||
function defineBackground(arg) {
|
||||
if (typeof arg === "function") return { main: arg };
|
||||
if (arg == null || typeof arg === "function") return { main: arg };
|
||||
return arg;
|
||||
}
|
||||
const definition = defineBackground({
|
||||
@@ -366,7 +366,7 @@ describe('Output Directory Structure', () => {
|
||||
"use strict";
|
||||
var _a, _b;
|
||||
function defineBackground(arg) {
|
||||
if (typeof arg === "function") return { main: arg };
|
||||
if (arg == null || typeof arg === "function") return { main: arg };
|
||||
return arg;
|
||||
}
|
||||
function logHello(name) {
|
||||
|
||||
@@ -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://code.jquery.com/jquery-3.7.1.slim.min.js';
|
||||
const url = 'https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js';
|
||||
const project = new TestProject();
|
||||
project.addFile(
|
||||
'entrypoints/popup.ts',
|
||||
@@ -16,7 +16,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
|
||||
'jQuery v3.7.1',
|
||||
'lodash.com',
|
||||
);
|
||||
expect(output).not.toContain(url);
|
||||
expect(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "wxt",
|
||||
"type": "module",
|
||||
"version": "0.19.0",
|
||||
"version": "0.19.4",
|
||||
"description": "Next gen framework for developing web extensions",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -72,7 +72,7 @@
|
||||
"scripts": {
|
||||
"wxt": "tsx src/cli/index.ts",
|
||||
"build": "buildc -- unbuild",
|
||||
"check": "buildc --deps-only -- run-s -c check:*",
|
||||
"check": "pnpm build && run-s -c check:*",
|
||||
"check:default": "check",
|
||||
"check:tsc-virtual": "tsc --noEmit -p src/virtual",
|
||||
"test": "buildc --deps-only -- vitest",
|
||||
@@ -91,6 +91,7 @@
|
||||
"cac": "^6.7.14",
|
||||
"chokidar": "^3.6.0",
|
||||
"ci-info": "^4.0.0",
|
||||
"consola": "^3.2.3",
|
||||
"defu": "^6.1.4",
|
||||
"dequal": "^2.0.3",
|
||||
"esbuild": "^0.23.0",
|
||||
@@ -116,20 +117,20 @@
|
||||
"picocolors": "^1.0.1",
|
||||
"prompts": "^2.4.2",
|
||||
"publish-browser-extension": "^2.1.3",
|
||||
"unimport": "^3.9.0",
|
||||
"vite": "^5.3.4",
|
||||
"vite-node": "^2.0.0",
|
||||
"unimport": "^3.9.1",
|
||||
"vite": "^5.3.5",
|
||||
"vite-node": "^2.0.4",
|
||||
"web-ext-run": "^0.2.1",
|
||||
"webextension-polyfill": "^0.12.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@aklinker1/check": "^1.3.1",
|
||||
"@faker-js/faker": "^8.4.1",
|
||||
"@types/chrome": "^0.0.268",
|
||||
"@types/chrome": "^0.0.269",
|
||||
"@types/fs-extra": "^11.0.4",
|
||||
"@types/lodash.merge": "^4.6.9",
|
||||
"@types/natural-compare": "^1.4.3",
|
||||
"@types/node": "^20.14.11",
|
||||
"@types/node": "^20.14.12",
|
||||
"@types/normalize-path": "^3.0.2",
|
||||
"@types/prompts": "^2.4.9",
|
||||
"execa": "^9.3.0",
|
||||
@@ -139,9 +140,9 @@
|
||||
"p-map": "^7.0.2",
|
||||
"publint": "^0.2.9",
|
||||
"tsx": "4.15.7",
|
||||
"typescript": "^5.5.3",
|
||||
"typescript": "^5.5.4",
|
||||
"unbuild": "^2.0.0",
|
||||
"vitest": "^2.0.3",
|
||||
"vitest": "^2.0.4",
|
||||
"vitest-plugin-random-seed": "^1.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/// <reference types="chrome" />
|
||||
import type { WxtRuntime, WxtI18n } from './index';
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL
|
||||
*
|
||||
@@ -7,13 +9,6 @@
|
||||
* @module wxt/browser/chrome
|
||||
*/
|
||||
|
||||
export interface WxtRuntime {
|
||||
// Overriden per-project
|
||||
}
|
||||
export interface WxtI18n {
|
||||
// Overriden per-project
|
||||
}
|
||||
|
||||
export type Chrome = typeof chrome;
|
||||
export type WxtBrowser = Omit<Chrome, 'runtime' | 'i18n'> & {
|
||||
runtime: WxtRuntime & Omit<Chrome['runtime'], 'getURL'>;
|
||||
|
||||
@@ -4,18 +4,18 @@
|
||||
* @module wxt/browser
|
||||
*/
|
||||
|
||||
import originalBrowser, { Browser, Runtime, I18n } from 'webextension-polyfill';
|
||||
import originalBrowser, { Browser } from 'webextension-polyfill';
|
||||
|
||||
export interface AugmentedBrowser extends Browser {
|
||||
runtime: WxtRuntime;
|
||||
i18n: WxtI18n;
|
||||
}
|
||||
export type AugmentedBrowser = Omit<Browser, 'runtime' | 'i18n'> & {
|
||||
runtime: WxtRuntime & Omit<Browser['runtime'], 'getURL'>;
|
||||
i18n: WxtI18n & Omit<Browser['i18n'], 'getMessage'>;
|
||||
};
|
||||
|
||||
export interface WxtRuntime extends Runtime.Static {
|
||||
export interface WxtRuntime {
|
||||
// Overriden per-project
|
||||
}
|
||||
|
||||
export interface WxtI18n extends I18n.Static {
|
||||
export interface WxtI18n {
|
||||
// Overriden per-project
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/** @vitest-environment happy-dom */
|
||||
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { ContentScriptContext } from '..';
|
||||
import { fakeBrowser } from '@webext-core/fake-browser';
|
||||
import { sleep } from '../../../core/utils/time';
|
||||
|
||||
describe('Content Script Context', () => {
|
||||
beforeEach(() => {
|
||||
vi.useRealTimers();
|
||||
fakeBrowser.runtime.id = 'anything';
|
||||
});
|
||||
|
||||
it("should recognize when the content script has lost it's connection to the extension API", () => {
|
||||
const ctx = new ContentScriptContext('test');
|
||||
const onInvalidated = vi.fn();
|
||||
|
||||
ctx.onInvalidated(onInvalidated);
|
||||
// @ts-expect-error
|
||||
delete fakeBrowser.runtime.id;
|
||||
const isValid = ctx.isValid;
|
||||
|
||||
expect(onInvalidated).toBeCalled();
|
||||
expect(isValid).toBe(false);
|
||||
});
|
||||
|
||||
it('should invalidate the current content script when a new context is created', async () => {
|
||||
const name = 'test';
|
||||
const onInvalidated = vi.fn();
|
||||
const ctx = new ContentScriptContext(name);
|
||||
ctx.onInvalidated(onInvalidated);
|
||||
|
||||
// Wait for events to run before next tick next tick
|
||||
await sleep(0);
|
||||
|
||||
// Create a new context after first is initialized, and wait for it to initialize
|
||||
new ContentScriptContext(name);
|
||||
await sleep(0);
|
||||
|
||||
expect(onInvalidated).toBeCalled();
|
||||
expect(ctx.isValid).toBe(false);
|
||||
});
|
||||
|
||||
it('should not invalidate the current content script when a new context is created with a different name', async () => {
|
||||
const onInvalidated = vi.fn();
|
||||
const ctx = new ContentScriptContext('test1');
|
||||
ctx.onInvalidated(onInvalidated);
|
||||
|
||||
// Wait for events to run before next tick next tick
|
||||
await sleep(0);
|
||||
|
||||
// Create a new context after first is initialized, and wait for it to initialize
|
||||
new ContentScriptContext('test2');
|
||||
await sleep(0);
|
||||
|
||||
expect(onInvalidated).not.toBeCalled();
|
||||
expect(ctx.isValid).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -46,13 +46,13 @@ export class ContentScriptContext implements AbortController {
|
||||
public readonly options?: Omit<ContentScriptDefinition, 'main'>,
|
||||
) {
|
||||
this.#abortController = new AbortController();
|
||||
|
||||
if (this.#isTopFrame) {
|
||||
this.#listenForNewerScripts({ ignoreFirstEvent: true });
|
||||
this.#stopOldScripts();
|
||||
}
|
||||
this.setTimeout(() => {
|
||||
// Run on next tick so the listener it adds isn't triggered by stopOldScript
|
||||
} else {
|
||||
this.#listenForNewerScripts();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
get signal() {
|
||||
@@ -224,12 +224,18 @@ export class ContentScriptContext implements AbortController {
|
||||
);
|
||||
}
|
||||
|
||||
#listenForNewerScripts() {
|
||||
#listenForNewerScripts(options?: { ignoreFirstEvent?: boolean }) {
|
||||
let isFirst = true;
|
||||
|
||||
const cb = (event: MessageEvent) => {
|
||||
if (
|
||||
event.data?.type === ContentScriptContext.SCRIPT_STARTED_MESSAGE_TYPE &&
|
||||
event.data?.contentScriptName === this.contentScriptName
|
||||
) {
|
||||
const wasFirst = isFirst;
|
||||
isFirst = false;
|
||||
if (wasFirst && options?.ignoreFirstEvent) return;
|
||||
|
||||
this.notifyInvalidated();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -62,6 +62,7 @@ export function createIframeUi<TMounted>(
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.setAttribute('data-wxt-iframe', '');
|
||||
const iframe = document.createElement('iframe');
|
||||
// @ts-expect-error: getURL is defined per-project, but not inside the package
|
||||
iframe.src = browser.runtime.getURL(options.page);
|
||||
wrapper.appendChild(iframe);
|
||||
|
||||
@@ -258,6 +259,7 @@ function mountUi(
|
||||
* Load the CSS for the current entrypoint.
|
||||
*/
|
||||
async function loadCss(): Promise<string> {
|
||||
// @ts-expect-error: getURL is defined per-project, but not inside the package
|
||||
const url = browser.runtime.getURL(
|
||||
`/content-scripts/${import.meta.env.ENTRYPOINT}.css`,
|
||||
);
|
||||
|
||||
@@ -83,7 +83,8 @@ export type IframeContentScriptUiOptions<TMounted> =
|
||||
* The path to the HTML page that will be shown in the iframe. This string is passed into
|
||||
* `browser.runtime.getURL`.
|
||||
*/
|
||||
page: PublicPath;
|
||||
// @ts-expect-error: HtmlPublicPath is generated per-project
|
||||
page: import('wxt/browser').HtmlPublicPath;
|
||||
/**
|
||||
* Callback executed when mounting the UI. Use this function to customize the iframe or wrapper
|
||||
* element's appearance. It is called every time `ui.mount()` is called.
|
||||
|
||||
@@ -5,3 +5,4 @@
|
||||
*/
|
||||
export * from './content-scripts';
|
||||
export * from './app-config';
|
||||
export * from './inject-script';
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import { browser } from 'wxt/browser';
|
||||
|
||||
export type ScriptPublicPath = Extract<
|
||||
// @ts-expect-error: PublicPath is generated per-project
|
||||
import('wxt/browser').PublicPath,
|
||||
`${string}.js`
|
||||
>;
|
||||
|
||||
/**
|
||||
* This function can only be called inside content scripts.
|
||||
*
|
||||
* Inject an unlisted script into the page. Scripts are added to the `<head>`
|
||||
* element or `document.documentElement` if there is no head.
|
||||
*
|
||||
* Make sure to add the injected script to your manifest's
|
||||
* `web_accessible_resources`.
|
||||
*/
|
||||
export async function injectScript(
|
||||
path: ScriptPublicPath,
|
||||
options?: InjectScriptOptions,
|
||||
): Promise<void> {
|
||||
// @ts-expect-error: getURL is defined per-project, but not inside the package
|
||||
const url = browser.runtime.getURL(path);
|
||||
const script = document.createElement('script');
|
||||
|
||||
if (browser.runtime.getManifest().manifest_version === 2) {
|
||||
// MV2 requires using an inline script
|
||||
script.innerHTML = await fetch(url).then((res) => res.text());
|
||||
} else {
|
||||
// MV3 requires using src
|
||||
script.src = url;
|
||||
}
|
||||
|
||||
if (!options?.keepInDom) {
|
||||
script.onload = () => script.remove();
|
||||
}
|
||||
|
||||
(document.head ?? document.documentElement).append(script);
|
||||
}
|
||||
|
||||
export interface InjectScriptOptions {
|
||||
/**
|
||||
* By default, the injected script is removed from the DOM after being
|
||||
* injected. To disable this behavior, set this flag to true.
|
||||
*/
|
||||
keepInDom?: boolean;
|
||||
}
|
||||
@@ -230,10 +230,7 @@ export async function createViteBuilder(
|
||||
baseConfig.optimizeDeps.noDiscovery = true;
|
||||
baseConfig.optimizeDeps.include = [];
|
||||
const envConfig: vite.InlineConfig = {
|
||||
plugins: [
|
||||
wxtPlugins.extensionApiMock(wxtConfig),
|
||||
wxtPlugins.removeEntrypointMainFunction(wxtConfig, path),
|
||||
],
|
||||
plugins: [wxtPlugins.removeEntrypointMainFunction(wxtConfig, path)],
|
||||
};
|
||||
const config = vite.mergeConfig(baseConfig, envConfig);
|
||||
const server = await vite.createServer(config);
|
||||
|
||||
@@ -14,8 +14,17 @@ export function removeEntrypointMainFunction(
|
||||
const absPath = normalizePath(resolve(config.root, path));
|
||||
return {
|
||||
name: 'wxt:remove-entrypoint-main-function',
|
||||
transform(code, id) {
|
||||
if (id === absPath) return removeMainFunctionCode(code);
|
||||
transform: {
|
||||
order: 'pre',
|
||||
handler(code, id) {
|
||||
if (id === absPath) {
|
||||
const newCode = removeMainFunctionCode(code);
|
||||
config.logger.debug('vite-node transformed entrypoint', path);
|
||||
config.logger.debug(`Original:\n---\n${code}\n---`);
|
||||
config.logger.debug(`Transformed:\n---\n${newCode.code}\n---`);
|
||||
return newCode;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Generated
+22
-15
@@ -1,34 +1,41 @@
|
||||
lockfileVersion: '6.0'
|
||||
lockfileVersion: '9.0'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
dependencies:
|
||||
mime-types:
|
||||
specifier: 2.1.35
|
||||
version: 2.1.35
|
||||
importers:
|
||||
|
||||
devDependencies:
|
||||
flatten:
|
||||
specifier: 1.0.3
|
||||
version: 1.0.3
|
||||
.:
|
||||
dependencies:
|
||||
mime-types:
|
||||
specifier: 2.1.35
|
||||
version: 2.1.35
|
||||
devDependencies:
|
||||
flatten:
|
||||
specifier: 1.0.3
|
||||
version: 1.0.3
|
||||
|
||||
packages:
|
||||
|
||||
/flatten@1.0.3:
|
||||
flatten@1.0.3:
|
||||
resolution: {integrity: sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg==}
|
||||
deprecated: flatten is deprecated in favor of utility frameworks such as lodash.
|
||||
dev: true
|
||||
|
||||
/mime-db@1.52.0:
|
||||
mime-db@1.52.0:
|
||||
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
|
||||
engines: {node: '>= 0.6'}
|
||||
dev: false
|
||||
|
||||
/mime-types@2.1.35:
|
||||
mime-types@2.1.35:
|
||||
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
snapshots:
|
||||
|
||||
flatten@1.0.3: {}
|
||||
|
||||
mime-db@1.52.0: {}
|
||||
|
||||
mime-types@2.1.35:
|
||||
dependencies:
|
||||
mime-db: 1.52.0
|
||||
dev: false
|
||||
|
||||
@@ -6,23 +6,28 @@ describe('Transform Utils', () => {
|
||||
it.each(['defineBackground', 'defineUnlistedScript'])(
|
||||
'should remove the first arrow function argument for %s',
|
||||
(def) => {
|
||||
const input = `export default ${def}(() => {
|
||||
const input = `
|
||||
export default ${def}(() => {
|
||||
console.log();
|
||||
})`;
|
||||
const expected = `export default ${def}(() => {})`;
|
||||
})
|
||||
`;
|
||||
const expected = `export default ${def}();`;
|
||||
|
||||
const actual = removeMainFunctionCode(input).code;
|
||||
|
||||
expect(actual).toEqual(expected);
|
||||
},
|
||||
);
|
||||
|
||||
it.each(['defineBackground', 'defineUnlistedScript'])(
|
||||
'should remove the first function argument for %s',
|
||||
(def) => {
|
||||
const input = `export default ${def}(function () {
|
||||
const input = `
|
||||
export default ${def}(function () {
|
||||
console.log();
|
||||
})`;
|
||||
const expected = `export default ${def}(function () {})`;
|
||||
})
|
||||
`;
|
||||
const expected = `export default ${def}();`;
|
||||
|
||||
const actual = removeMainFunctionCode(input).code;
|
||||
|
||||
@@ -35,10 +40,12 @@ describe('Transform Utils', () => {
|
||||
'defineContentScript',
|
||||
'defineUnlistedScript',
|
||||
])('should remove the main field from %s', (def) => {
|
||||
const input = `export default ${def}({
|
||||
asdf: "asdf",
|
||||
main: () => {},
|
||||
})`;
|
||||
const input = `
|
||||
export default ${def}({
|
||||
asdf: "asdf",
|
||||
main: () => {},
|
||||
})
|
||||
`;
|
||||
const expected = `export default ${def}({
|
||||
asdf: "asdf"
|
||||
})`;
|
||||
@@ -47,5 +54,88 @@ describe('Transform Utils', () => {
|
||||
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should remove unused imports', () => {
|
||||
const input = `
|
||||
import { defineBackground } from "wxt/sandbox"
|
||||
import { test1 } from "somewhere1"
|
||||
import test2 from "somewhere2"
|
||||
|
||||
export default defineBackground(() => {})
|
||||
`;
|
||||
const expected = `import { defineBackground } from "wxt/sandbox"
|
||||
|
||||
export default defineBackground();`;
|
||||
|
||||
const actual = removeMainFunctionCode(input).code;
|
||||
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should remove explict side-effect imports', () => {
|
||||
const input = `
|
||||
import { defineBackground } from "wxt/sandbox"
|
||||
import "my-polyfill"
|
||||
import "./style.css"
|
||||
|
||||
export default defineBackground(() => {})
|
||||
`;
|
||||
const expected = `import { defineBackground } from "wxt/sandbox"
|
||||
|
||||
export default defineBackground();`;
|
||||
|
||||
const actual = removeMainFunctionCode(input).code;
|
||||
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
|
||||
it("should remove any functions delcared outside the main function that aren't used", () => {
|
||||
const input = `
|
||||
function getMatches() {
|
||||
return ["*://*/*"]
|
||||
}
|
||||
function unused1() {}
|
||||
function unused2() {
|
||||
unused1();
|
||||
}
|
||||
|
||||
export default defineContentScript({
|
||||
matches: getMatches(),
|
||||
main: () => {},
|
||||
})
|
||||
`;
|
||||
const expected = `function getMatches() {
|
||||
return ["*://*/*"]
|
||||
}
|
||||
|
||||
export default defineContentScript({
|
||||
matches: getMatches()
|
||||
})`;
|
||||
|
||||
const actual = removeMainFunctionCode(input).code;
|
||||
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
|
||||
it("should remove any variables delcared outside the main function that aren't used", () => {
|
||||
const input = `
|
||||
const unused1 = "a", matches = ["*://*/*"];
|
||||
let unused2 = unused1 + "b";
|
||||
|
||||
export default defineContentScript({
|
||||
matches,
|
||||
main: () => {}
|
||||
})
|
||||
`;
|
||||
const expected = `const matches = ["*://*/*"];
|
||||
|
||||
export default defineContentScript({
|
||||
matches
|
||||
})`;
|
||||
|
||||
const actual = removeMainFunctionCode(input).code;
|
||||
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -28,6 +28,7 @@ import { VIRTUAL_NOOP_BACKGROUND_MODULE_ID } from '../../utils/constants';
|
||||
import { CSS_EXTENSIONS_PATTERN } from '../../utils/paths';
|
||||
import pc from 'picocolors';
|
||||
import { wxt } from '../../wxt';
|
||||
import { createExtensionEnvironment } from '../environments';
|
||||
|
||||
/**
|
||||
* Return entrypoints and their configuration by looking through the project's files.
|
||||
@@ -35,7 +36,17 @@ import { wxt } from '../../wxt';
|
||||
export async function findEntrypoints(): Promise<Entrypoint[]> {
|
||||
// Make sure required TSConfig file exists to load dependencies
|
||||
await fs.mkdir(wxt.config.wxtDir, { recursive: true });
|
||||
await fs.writeJson(resolve(wxt.config.wxtDir, 'tsconfig.json'), {});
|
||||
try {
|
||||
await fs.writeJson(
|
||||
resolve(wxt.config.wxtDir, 'tsconfig.json'),
|
||||
{},
|
||||
{ flag: 'wx' },
|
||||
);
|
||||
} catch (err) {
|
||||
if (!(err instanceof Error) || !('code' in err) || err.code !== 'EEXIST') {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
const relativePaths = await glob(Object.keys(PATH_GLOB_TO_TYPE_MAP), {
|
||||
cwd: wxt.config.entrypointsDir,
|
||||
@@ -72,47 +83,50 @@ export async function findEntrypoints(): Promise<Entrypoint[]> {
|
||||
|
||||
// Import entrypoints to get their config
|
||||
let hasBackground = false;
|
||||
const entrypoints: Entrypoint[] = await Promise.all(
|
||||
entrypointInfos.map(async (info): Promise<Entrypoint> => {
|
||||
const { type } = info;
|
||||
switch (type) {
|
||||
case 'popup':
|
||||
return await getPopupEntrypoint(info);
|
||||
case 'sidepanel':
|
||||
return await getSidepanelEntrypoint(info);
|
||||
case 'options':
|
||||
return await getOptionsEntrypoint(info);
|
||||
case 'background':
|
||||
hasBackground = true;
|
||||
return await getBackgroundEntrypoint(info);
|
||||
case 'content-script':
|
||||
return await getContentScriptEntrypoint(info);
|
||||
case 'unlisted-page':
|
||||
return await getUnlistedPageEntrypoint(info);
|
||||
case 'unlisted-script':
|
||||
return await getUnlistedScriptEntrypoint(info);
|
||||
case 'content-script-style':
|
||||
return {
|
||||
...info,
|
||||
type,
|
||||
outputDir: resolve(wxt.config.outDir, CONTENT_SCRIPT_OUT_DIR),
|
||||
options: {
|
||||
include: undefined,
|
||||
exclude: undefined,
|
||||
},
|
||||
};
|
||||
default:
|
||||
return {
|
||||
...info,
|
||||
type,
|
||||
outputDir: wxt.config.outDir,
|
||||
options: {
|
||||
include: undefined,
|
||||
exclude: undefined,
|
||||
},
|
||||
};
|
||||
}
|
||||
}),
|
||||
const env = createExtensionEnvironment();
|
||||
const entrypoints: Entrypoint[] = await env.run(() =>
|
||||
Promise.all(
|
||||
entrypointInfos.map(async (info): Promise<Entrypoint> => {
|
||||
const { type } = info;
|
||||
switch (type) {
|
||||
case 'popup':
|
||||
return await getPopupEntrypoint(info);
|
||||
case 'sidepanel':
|
||||
return await getSidepanelEntrypoint(info);
|
||||
case 'options':
|
||||
return await getOptionsEntrypoint(info);
|
||||
case 'background':
|
||||
hasBackground = true;
|
||||
return await getBackgroundEntrypoint(info);
|
||||
case 'content-script':
|
||||
return await getContentScriptEntrypoint(info);
|
||||
case 'unlisted-page':
|
||||
return await getUnlistedPageEntrypoint(info);
|
||||
case 'unlisted-script':
|
||||
return await getUnlistedScriptEntrypoint(info);
|
||||
case 'content-script-style':
|
||||
return {
|
||||
...info,
|
||||
type,
|
||||
outputDir: resolve(wxt.config.outDir, CONTENT_SCRIPT_OUT_DIR),
|
||||
options: {
|
||||
include: undefined,
|
||||
exclude: undefined,
|
||||
},
|
||||
};
|
||||
default:
|
||||
return {
|
||||
...info,
|
||||
type,
|
||||
outputDir: wxt.config.outDir,
|
||||
options: {
|
||||
include: undefined,
|
||||
exclude: undefined,
|
||||
},
|
||||
};
|
||||
}
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
if (wxt.config.command === 'serve' && !hasBackground) {
|
||||
|
||||
@@ -94,9 +94,9 @@ async function getPathsDeclarationEntry(
|
||||
.join('\n');
|
||||
|
||||
const template = `// Generated by wxt
|
||||
import "${wxt.config.browserModule}";
|
||||
import "wxt/browser";
|
||||
|
||||
declare module "${wxt.config.browserModule}" {
|
||||
declare module "wxt/browser" {
|
||||
export type PublicPath =
|
||||
{{ union }}
|
||||
type HtmlPublicPath = Extract<PublicPath, \`\${string}.html\`>
|
||||
@@ -117,9 +117,9 @@ declare module "${wxt.config.browserModule}" {
|
||||
async function getI18nDeclarationEntry(): Promise<WxtDirFileEntry> {
|
||||
const defaultLocale = wxt.config.manifest.default_locale;
|
||||
const template = `// Generated by wxt
|
||||
import "${wxt.config.browserModule}";
|
||||
import "wxt/browser";
|
||||
|
||||
declare module "${wxt.config.browserModule}" {
|
||||
declare module "wxt/browser" {
|
||||
/**
|
||||
* See https://developer.chrome.com/docs/extensions/reference/i18n/#method-getMessage
|
||||
*/
|
||||
|
||||
@@ -183,8 +183,6 @@ export async function resolveConfig(
|
||||
userConfigMetadata: userConfigMetadata ?? {},
|
||||
alias,
|
||||
extensionApi,
|
||||
browserModule:
|
||||
extensionApi === 'chrome' ? 'wxt/browser/chrome' : 'wxt/browser',
|
||||
entrypointLoader: mergedConfig.entrypointLoader ?? 'vite-node',
|
||||
experimental: defu(mergedConfig.experimental, {}),
|
||||
dev: {
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import { parseHTML } from 'linkedom';
|
||||
import { createEnvironment, Environment, EnvGlobals } from './environment';
|
||||
|
||||
export function createBrowserEnvironment(): Environment {
|
||||
return createEnvironment(getBrowserEnvironmentGlobals);
|
||||
}
|
||||
|
||||
export function getBrowserEnvironmentGlobals(): EnvGlobals {
|
||||
const { window, document, global } = parseHTML(`
|
||||
<html>
|
||||
<head></head>
|
||||
<body></body>
|
||||
</html>
|
||||
`);
|
||||
return {
|
||||
...global,
|
||||
window,
|
||||
document,
|
||||
self: global,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
export interface Environment {
|
||||
setup: () => () => void;
|
||||
run: <T>(fn: () => Promise<T>) => Promise<T>;
|
||||
}
|
||||
|
||||
export function createEnvironment(getGlobals: () => EnvGlobals): Environment {
|
||||
const setup = () => {
|
||||
const envGlobals = getGlobals();
|
||||
const ogGlobals = getOgGlobals(envGlobals);
|
||||
applyGlobals(envGlobals);
|
||||
|
||||
return () => {
|
||||
applyGlobals(ogGlobals);
|
||||
};
|
||||
};
|
||||
const run = async (fn: () => any) => {
|
||||
const teardown = setup();
|
||||
try {
|
||||
return await fn();
|
||||
} finally {
|
||||
teardown();
|
||||
}
|
||||
};
|
||||
return {
|
||||
setup,
|
||||
run,
|
||||
};
|
||||
}
|
||||
|
||||
export type EnvGlobals = Record<string, any>;
|
||||
|
||||
export function getOgGlobals(envGlobals: EnvGlobals): EnvGlobals {
|
||||
return Object.keys(envGlobals).reduce<typeof envGlobals>((acc, key) => {
|
||||
// @ts-expect-error: Untyped key on globalThis
|
||||
acc[key] = globalThis[key];
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
|
||||
export function applyGlobals(globals: EnvGlobals): void {
|
||||
Object.entries(globals).forEach(([key, envValue]) => {
|
||||
try {
|
||||
// @ts-expect-error: Untyped key on globalThis
|
||||
globalThis[key] = envValue;
|
||||
} catch (err) {
|
||||
// ignore any globals that can't be set
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { fakeBrowser } from '@webext-core/fake-browser';
|
||||
import { getBrowserEnvironmentGlobals } from './browser-environment';
|
||||
import { createEnvironment, Environment } from './environment';
|
||||
|
||||
export function createExtensionEnvironment(): Environment {
|
||||
return createEnvironment(getExtensionEnvironmentGlobals);
|
||||
}
|
||||
|
||||
export function getExtensionEnvironmentGlobals() {
|
||||
return {
|
||||
...getBrowserEnvironmentGlobals(),
|
||||
chrome: fakeBrowser,
|
||||
browser: fakeBrowser,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './browser-environment';
|
||||
export * from './extension-environment';
|
||||
@@ -297,7 +297,6 @@ export const fakeResolvedConfig = fakeObjectCreator<ResolvedConfig>(() => {
|
||||
userConfigMetadata: {},
|
||||
alias: {},
|
||||
extensionApi: 'webextension-polyfill',
|
||||
browserModule: 'wxt/browser',
|
||||
entrypointLoader: 'vite-node',
|
||||
experimental: {},
|
||||
dev: {
|
||||
|
||||
@@ -2,8 +2,10 @@ import { ProxifiedModule, parseModule } from 'magicast';
|
||||
|
||||
/**
|
||||
* Removes any code used at runtime related to an entrypoint's main function.
|
||||
* - Removes or clears out `main` function from returned object
|
||||
* - TODO: Removes unused imports after main function has been removed to prevent importing runtime modules
|
||||
* 1. Removes or clears out `main` function from returned object
|
||||
* 2. Removes any unused functions/variables outside the definition that aren't being called/used
|
||||
* 3. Removes unused imports
|
||||
* 3. Removes value-less, side-effect only imports (like `import "./styles.css"` or `import "webextension-polyfill"`)
|
||||
*/
|
||||
export function removeMainFunctionCode(code: string): {
|
||||
code: string;
|
||||
@@ -11,16 +13,26 @@ export function removeMainFunctionCode(code: string): {
|
||||
} {
|
||||
const mod = parseModule(code);
|
||||
emptyMainFunction(mod);
|
||||
let removedCount = 0;
|
||||
let depth = 0;
|
||||
const maxDepth = 10;
|
||||
do {
|
||||
removedCount = 0;
|
||||
removedCount += removeUnusedTopLevelVariables(mod);
|
||||
removedCount += removeUnusedTopLevelFunctions(mod);
|
||||
removedCount += removeUnusedImports(mod);
|
||||
} while (removedCount > 0 && depth++ <= maxDepth);
|
||||
removeSideEffectImports(mod);
|
||||
return mod.generate();
|
||||
}
|
||||
|
||||
function emptyMainFunction(mod: ProxifiedModule) {
|
||||
function emptyMainFunction(mod: ProxifiedModule): void {
|
||||
if (mod.exports?.default?.$type === 'function-call') {
|
||||
if (mod.exports.default.$ast?.arguments?.[0]?.body) {
|
||||
// Remove body from function
|
||||
// ex: "fn(() => { ... })" to "fn(() => {})"
|
||||
// ex: "fn(function () { ... })" to "fn(function () {})"
|
||||
mod.exports.default.$ast.arguments[0].body.body = [];
|
||||
// ex: "fn(() => { ... })" to "fn()"
|
||||
// ex: "fn(function () { ... })" to "fn()"
|
||||
delete mod.exports.default.$ast.arguments[0];
|
||||
} else if (mod.exports.default.$ast?.arguments?.[0]?.properties) {
|
||||
// Remove main field from object
|
||||
// ex: "fn({ ..., main: () => {} })" to "fn({ ... })"
|
||||
@@ -31,3 +43,131 @@ function emptyMainFunction(mod: ProxifiedModule) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function removeUnusedTopLevelVariables(mod: ProxifiedModule): number {
|
||||
const simpleAst = getSimpleAstJson(mod.$ast);
|
||||
const usedMap = findUsedIdentifiers(simpleAst);
|
||||
|
||||
let deletedCount = 0;
|
||||
const ast = mod.$ast as any;
|
||||
for (let i = ast.body.length - 1; i >= 0; i--) {
|
||||
if (ast.body[i].type === 'VariableDeclaration') {
|
||||
for (let j = ast.body[i].declarations.length - 1; j >= 0; j--) {
|
||||
if (!usedMap.get(ast.body[i].declarations[j].id.name)) {
|
||||
ast.body[i].declarations.splice(j, 1);
|
||||
deletedCount++;
|
||||
}
|
||||
}
|
||||
if (ast.body[i].declarations.length === 0) {
|
||||
ast.body.splice(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return deletedCount;
|
||||
}
|
||||
|
||||
function removeUnusedTopLevelFunctions(mod: ProxifiedModule): number {
|
||||
const simpleAst = getSimpleAstJson(mod.$ast);
|
||||
const usedMap = findUsedIdentifiers(simpleAst);
|
||||
|
||||
let deletedCount = 0;
|
||||
const ast = mod.$ast as any;
|
||||
for (let i = ast.body.length - 1; i >= 0; i--) {
|
||||
if (
|
||||
ast.body[i].type === 'FunctionDeclaration' &&
|
||||
!usedMap.get(ast.body[i].id.name)
|
||||
) {
|
||||
ast.body.splice(i, 1);
|
||||
deletedCount++;
|
||||
}
|
||||
}
|
||||
return deletedCount;
|
||||
}
|
||||
|
||||
function removeUnusedImports(mod: ProxifiedModule): number {
|
||||
const simpleAst = getSimpleAstJson(mod.$ast);
|
||||
const usedMap = findUsedIdentifiers(simpleAst);
|
||||
const importSymbols = Object.keys(mod.imports);
|
||||
|
||||
let deletedCount = 0;
|
||||
importSymbols.forEach((name) => {
|
||||
if (usedMap.get(name)) return;
|
||||
|
||||
delete mod.imports[name];
|
||||
deletedCount++;
|
||||
});
|
||||
return deletedCount;
|
||||
}
|
||||
|
||||
// TODO: Do a more complex declaration analysis where shadowed variables are detected and ignored.
|
||||
// Right now, this code assumes there are no shadowed variables.
|
||||
function findUsedIdentifiers(simpleAst: any) {
|
||||
const usedMap = new Map<string, boolean>();
|
||||
const queue: any[] = [simpleAst];
|
||||
for (const item of queue) {
|
||||
if (!item) {
|
||||
} else if (Array.isArray(item)) {
|
||||
queue.push(...item);
|
||||
} else if (item.type === 'ImportDeclaration') {
|
||||
// Don't look inside imports, identifiers are only used for declaration
|
||||
continue;
|
||||
} else if (item.type === 'Identifier') {
|
||||
usedMap.set(item.name, true);
|
||||
} else if (typeof item === 'object') {
|
||||
const filterFns: Record<string, (entry: [string, any]) => boolean> = {
|
||||
// Ignore the function declaration's name
|
||||
FunctionDeclaration: ([key]) => key !== 'id',
|
||||
// Ignore object property names
|
||||
ObjectProperty: ([key]) => key !== 'key',
|
||||
// Ignore variable declaration's name
|
||||
VariableDeclarator: ([key]) => key !== 'id',
|
||||
};
|
||||
queue.push(
|
||||
Object.entries(item)
|
||||
.filter(filterFns[item.type] ?? (() => true))
|
||||
.map(([_, value]) => value),
|
||||
);
|
||||
}
|
||||
}
|
||||
return usedMap;
|
||||
}
|
||||
|
||||
function deleteImportAst(
|
||||
mod: ProxifiedModule,
|
||||
shouldDelete: (node: any) => boolean,
|
||||
): void {
|
||||
const importIndexesToDelete: number[] = [];
|
||||
(mod.$ast as any).body.forEach((node: any, index: number) => {
|
||||
if (node.type === 'ImportDeclaration' && shouldDelete(node)) {
|
||||
importIndexesToDelete.push(index);
|
||||
}
|
||||
});
|
||||
importIndexesToDelete.reverse().forEach((i) => {
|
||||
delete (mod.$ast as any).body[i];
|
||||
});
|
||||
}
|
||||
|
||||
function removeSideEffectImports(mod: ProxifiedModule): void {
|
||||
deleteImportAst(mod, (node) => node.specifiers.length === 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Util to get the AST as a simple JSON object, stripping out large objects and file locations to keep it readible
|
||||
*/
|
||||
function getSimpleAstJson(ast: any): any {
|
||||
if (!ast) {
|
||||
return ast;
|
||||
} else if (Array.isArray(ast)) {
|
||||
return ast.map(getSimpleAstJson);
|
||||
} else if (typeof ast === 'object') {
|
||||
return Object.fromEntries(
|
||||
Object.entries(ast)
|
||||
.filter(
|
||||
([key, value]) => key !== 'loc' && key !== 'start' && key !== 'end',
|
||||
)
|
||||
.map(([key, value]) => [key, getSimpleAstJson(value)]),
|
||||
);
|
||||
} else {
|
||||
return ast;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,10 @@ export async function registerWxt(
|
||||
inlineConfig: InlineConfig = {},
|
||||
getServer?: (config: ResolvedConfig) => Promise<WxtDevServer>,
|
||||
): Promise<void> {
|
||||
// Default NODE_ENV environment variable before other packages, like vite, do it
|
||||
// See https://github.com/wxt-dev/wxt/issues/873#issuecomment-2254555523
|
||||
process.env.NODE_ENV ??= command === 'serve' ? 'development' : 'production';
|
||||
|
||||
const hooks = createHooks<WxtHooks>();
|
||||
const config = await resolveConfig(inlineConfig, command);
|
||||
const server = await getServer?.(config);
|
||||
|
||||
@@ -7,6 +7,6 @@ export function defineBackground(
|
||||
export function defineBackground(
|
||||
arg: (() => void) | BackgroundDefinition,
|
||||
): BackgroundDefinition {
|
||||
if (typeof arg === 'function') return { main: arg };
|
||||
if (arg == null || typeof arg === 'function') return { main: arg };
|
||||
return arg;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,6 @@ export function defineUnlistedScript(
|
||||
export function defineUnlistedScript(
|
||||
arg: (() => void) | UnlistedScriptDefinition,
|
||||
): UnlistedScriptDefinition {
|
||||
if (typeof arg === 'function') return { main: arg };
|
||||
if (arg == null || typeof arg === 'function') return { main: arg };
|
||||
return arg;
|
||||
}
|
||||
|
||||
@@ -1046,9 +1046,14 @@ export interface WxtHooks {
|
||||
* // variable called "example" in the TS project.
|
||||
* entries.push({
|
||||
* path: "types/example.d.ts",
|
||||
* textContent: "declare const a: string;",
|
||||
* text: "declare const a: string;",
|
||||
* tsReference: true,
|
||||
* });
|
||||
* // use module to add Triple-Slash Directive in .wxt/wxt.d.ts
|
||||
* // eg: /// <reference types="@types/example" />
|
||||
* entries.push({
|
||||
* module: '@types/example'
|
||||
* });
|
||||
* })
|
||||
*/
|
||||
'prepare:types': (wxt: Wxt, entries: WxtDirEntry[]) => HookResult;
|
||||
@@ -1210,7 +1215,6 @@ export interface ResolvedConfig {
|
||||
*/
|
||||
alias: Record<string, string>;
|
||||
extensionApi: 'webextension-polyfill' | 'chrome';
|
||||
browserModule: 'wxt/browser' | 'wxt/browser/chrome';
|
||||
entrypointLoader: 'vite-node' | 'jiti';
|
||||
experimental: {};
|
||||
dev: {
|
||||
@@ -1409,6 +1413,10 @@ export type WxtDirEntry = WxtDirTypeReferenceEntry | WxtDirFileEntry;
|
||||
* Represents type reference to a node module to be added to `.wxt/wxt.d.ts` file
|
||||
*/
|
||||
export interface WxtDirTypeReferenceEntry {
|
||||
/**
|
||||
* Specifies the module name that will be used in the `/// <reference types="..." />` directive.
|
||||
* This value will be added to the `.wxt/wxt.d.ts` file to include type definitions from the specified module.
|
||||
*/
|
||||
module: string;
|
||||
}
|
||||
|
||||
|
||||
Generated
+5239
-4207
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "wxt-starter",
|
||||
"name": "wxt-react-starter",
|
||||
"description": "manifest.json description",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
@@ -22,7 +22,7 @@
|
||||
"@types/react": "^18.3.3",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@wxt-dev/module-react": "^1.1.0",
|
||||
"typescript": "^5.5.3",
|
||||
"wxt": "^0.18.15"
|
||||
"typescript": "^5.5.4",
|
||||
"wxt": "^0.19.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "wxt-starter",
|
||||
"name": "wxt-solid-starter",
|
||||
"description": "manifest.json description",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
@@ -15,11 +15,11 @@
|
||||
"postinstall": "wxt prepare"
|
||||
},
|
||||
"dependencies": {
|
||||
"solid-js": "^1.8.18"
|
||||
"solid-js": "^1.8.19"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@wxt-dev/module-solid": "^1.1.1",
|
||||
"typescript": "^5.5.3",
|
||||
"wxt": "^0.18.15"
|
||||
"typescript": "^5.5.4",
|
||||
"wxt": "^0.19.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "wxt-starter",
|
||||
"name": "wxt-svelte-starter",
|
||||
"description": "manifest.json description",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
@@ -19,7 +19,7 @@
|
||||
"svelte": "^4.2.18",
|
||||
"svelte-check": "^3.8.4",
|
||||
"tslib": "^2.6.3",
|
||||
"typescript": "^5.5.3",
|
||||
"wxt": "^0.18.15"
|
||||
"typescript": "^5.5.4",
|
||||
"wxt": "^0.19.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"postinstall": "wxt prepare"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.5.3",
|
||||
"wxt": "^0.18.15"
|
||||
"typescript": "^5.5.4",
|
||||
"wxt": "^0.19.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "wxt-starter",
|
||||
"name": "wxt-vue-starter",
|
||||
"description": "manifest.json description",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
@@ -15,12 +15,12 @@
|
||||
"postinstall": "wxt prepare"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue": "^3.4.33"
|
||||
"vue": "^3.4.34"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@wxt-dev/module-vue": "^1.0.0",
|
||||
"typescript": "^5.5.3",
|
||||
"vue-tsc": "^2.0.26",
|
||||
"wxt": "^0.18.15"
|
||||
"typescript": "^5.5.4",
|
||||
"vue-tsc": "^2.0.29",
|
||||
"wxt": "^0.19.1"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user