Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 91ef7f2ab5 | |||
| 0bf7279c8f | |||
| 62525d33c6 | |||
| 88ff40e301 | |||
| 1a72a0cdc6 | |||
| 2b07b4bc12 | |||
| 06c09e7c87 | |||
| 30b96ac87c | |||
| 2e9b5cffe8 | |||
| 3e1641a6ec |
@@ -59,6 +59,8 @@ const chromeExtensionIds = [
|
||||
'npgghjedpchajflknnbngajkjkdhncdo', // aesthetic Notion, styled
|
||||
'hmdcmlfkchdmnmnmheododdhjedfccka', // Eye Dropper
|
||||
'eihpmapodnppeemkhkbhikmggfojdkjd', // Cursorful - Screen Recorder with Auto Zoom
|
||||
'hjjkgbibknbahijglkffklflidncplkn', // Show IP – Live View of Website IPs for Developers
|
||||
'ilbikcehnpkmldojkcmlldkoelofnbde', // Strong Password Generator
|
||||
];
|
||||
|
||||
const { data, err, isLoading } = useListExtensionDetails(chromeExtensionIds);
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
--wxt-c-green-1: #0b8a00;
|
||||
--wxt-c-green-2: #096600;
|
||||
--wxt-c-green-3: #096600;
|
||||
--wxt-c-green-soft: rgba(#0b8a00 / 0.14);
|
||||
--wxt-c-green-soft: rgba(11, 138, 0, 0.14);
|
||||
}
|
||||
|
||||
.dark {
|
||||
--wxt-c-green-1: #67d45e;
|
||||
--wxt-c-green-2: #329929;
|
||||
--wxt-c-green-3: #21651b;
|
||||
--wxt-c-green-soft: rgba(#67d45e / 0.14);
|
||||
--wxt-c-green-soft: rgba(103, 212, 94, 0.14);
|
||||
}
|
||||
|
||||
/* https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css */
|
||||
|
||||
@@ -156,6 +156,11 @@ Alternatively, you can use [`@wxt-dev/auto-icons`](https://www.npmjs.com/package
|
||||
|
||||
> [Chrome docs](https://developer.chrome.com/docs/extensions/reference/permissions/)
|
||||
|
||||
Most of the time, you need to manually add permissions to your manifest. Only in a few specific situations are permissions added automatically:
|
||||
|
||||
- During development: the `tabs` and `scripting` permissions will be added to enable hot reloading.
|
||||
- When a `sidepanel` entrypoint is present: The `sidepanel` permission is added.
|
||||
|
||||
```ts
|
||||
export default defineConfig({
|
||||
manifest: {
|
||||
|
||||
@@ -306,9 +306,12 @@ Follow the [Devtools Example](https://github.com/wxt-dev/examples/tree/main/exam
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Options Title</title>
|
||||
|
||||
<!-- Customize the manifest options -->
|
||||
<meta name="manifest.open_in_tab" content="true|false" />
|
||||
<meta name="manifest.chrome_style" content="true|false" />
|
||||
<meta name="manifest.browser_style" content="true|false" />
|
||||
|
||||
<!-- Set include/exclude if the page should be removed from some builds -->
|
||||
<meta name="manifest.include" content="['chrome', ...]" />
|
||||
<meta name="manifest.exclude" content="['chrome', ...]" />
|
||||
@@ -336,7 +339,11 @@ Follow the [Devtools Example](https://github.com/wxt-dev/examples/tree/main/exam
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
|
||||
<!-- Set the `action.default_title` in the manifest -->
|
||||
<title>Default Popup Title</title>
|
||||
|
||||
<!-- Customize the manifest options -->
|
||||
<meta
|
||||
name="manifest.default_icon"
|
||||
content="{
|
||||
@@ -347,6 +354,7 @@ Follow the [Devtools Example](https://github.com/wxt-dev/examples/tree/main/exam
|
||||
/>
|
||||
<meta name="manifest.type" content="page_action|browser_action" />
|
||||
<meta name="manifest.browser_style" content="true|false" />
|
||||
|
||||
<!-- Set include/exclude if the page should be removed from some builds -->
|
||||
<meta name="manifest.include" content="['chrome', ...]" />
|
||||
<meta name="manifest.exclude" content="['chrome', ...]" />
|
||||
@@ -381,6 +389,7 @@ Firefox does not support sandboxed pages.
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Title</title>
|
||||
|
||||
<!-- Set include/exclude if the page should be removed from some builds -->
|
||||
<meta name="manifest.include" content="['chrome', ...]" />
|
||||
<meta name="manifest.exclude" content="['chrome', ...]" />
|
||||
@@ -413,6 +422,8 @@ In Chrome, side panels use the `side_panel` API, while Firefox uses the `sidebar
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Default Side Panel Title</title>
|
||||
|
||||
<!-- Customize the manifest options -->
|
||||
<meta
|
||||
name="manifest.default_icon"
|
||||
content="{
|
||||
@@ -423,6 +434,7 @@ In Chrome, side panels use the `side_panel` API, while Firefox uses the `sidebar
|
||||
/>
|
||||
<meta name="manifest.open_at_install" content="true|false" />
|
||||
<meta name="manifest.browser_style" content="true|false" />
|
||||
|
||||
<!-- Set include/exclude if the page should be removed from some builds -->
|
||||
<meta name="manifest.include" content="['chrome', ...]" />
|
||||
<meta name="manifest.exclude" content="['chrome', ...]" />
|
||||
@@ -472,6 +484,7 @@ body {
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Title</title>
|
||||
|
||||
<!-- Set include/exclude if the page should be removed from some builds -->
|
||||
<meta name="manifest.include" content="['chrome', ...]" />
|
||||
<meta name="manifest.exclude" content="['chrome', ...]" />
|
||||
|
||||
@@ -167,6 +167,31 @@ This file could then be loaded at runtime:
|
||||
const res = await fetch(browser.runtime.getURL('/some-text.txt'));
|
||||
```
|
||||
|
||||
#### Add custom entrypoints
|
||||
|
||||
Once the existing files under the `entrypoints/` directory have been discovered, the `entrypoints:found` hook can be used to add custom entrypoints.
|
||||
|
||||
:::info
|
||||
The `entrypoints:found` hook is triggered before validation is carried out on the list of entrypoints. Thus, any custom entrypoints will still be checked for duplicate names and logged during debugging.
|
||||
:::
|
||||
|
||||
```ts
|
||||
import { defineWxtModule } from 'wxt/modules';
|
||||
|
||||
export default defineWxtModule({
|
||||
setup(wxt) {
|
||||
wxt.hook('entrypoints:found', (_, entrypointInfos) => {
|
||||
// Add your new entrypoint
|
||||
entrypointInfos.push({
|
||||
name: 'my-custom-script',
|
||||
inputPath: 'path/to/custom-script.js',
|
||||
type: 'content-script',
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
#### Generate runtime module
|
||||
|
||||
Create a file in `.wxt`, add an alias to import it, and add auto-imports for exported variables.
|
||||
|
||||
@@ -28,7 +28,7 @@ See https://wxt.dev/guide/essentials/config/browser-startup.html#persist-data
|
||||
|
||||
## My component library doesn't work in content scripts!
|
||||
|
||||
Component libraries place their CSS in the document's `<head>` by default. When using `createShadowRoot`, your UI is isolated from the document's styles because it's inside a ShadowRoot.
|
||||
Component libraries place their CSS in the document's `<head>` by default. When using `createShadowRootUi`, your UI is isolated from the document's styles because it's inside a ShadowRoot.
|
||||
|
||||
To fix this, you need to tell your component library to insert it's CSS inside the shadow root. Here's the docs for a couple of popular libraries:
|
||||
|
||||
@@ -38,7 +38,7 @@ To fix this, you need to tell your component library to insert it's CSS inside t
|
||||
|
||||
> If your library isn't listed above, try searching it's docs/issues for "shadow root", "shadow dom", or "css container".
|
||||
|
||||
`createShadowRoot` provides it's own `<head>` element inside the shadow root, so that were you should tell the library to add the CSS. Here's an example with Ant Design:
|
||||
`createShadowRootUi` provides it's own `<head>` element inside the shadow root, so that were you should tell the library to add the CSS. Here's an example with Ant Design:
|
||||
|
||||
```tsx
|
||||
import { StyleProvider } from '@ant-design/cssinjs'; // [!code ++]
|
||||
|
||||
@@ -1,5 +1,31 @@
|
||||
# Changelog
|
||||
|
||||
## v0.19.23
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.19.22...wxt-v0.19.23)
|
||||
|
||||
### 🚀 Enhancements
|
||||
|
||||
- **hooks:** Move `entrypoints:resolved` before debug logs and add `entrypoints:found` ([#1292](https://github.com/wxt-dev/wxt/pull/1292))
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Allow runtime registered content scripts to not have `matches` ([#1306](https://github.com/wxt-dev/wxt/pull/1306))
|
||||
- Properly close readline instance on close ([#1278](https://github.com/wxt-dev/wxt/pull/1278))
|
||||
|
||||
### 📖 Documentation
|
||||
|
||||
- Sync READMEs ([27298b7](https://github.com/wxt-dev/wxt/commit/27298b7))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- Simplify keyboard shortcuts ([#1284](https://github.com/wxt-dev/wxt/pull/1284))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Aaron ([@aklinker1](http://github.com/aklinker1))
|
||||
- Abhigyan Trips <abhigyantrips@gmail.com>
|
||||
|
||||
## v0.19.22
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.19.21...wxt-v0.19.22)
|
||||
|
||||
@@ -11,6 +11,7 @@ const hooks: WxtHooks = {
|
||||
'build:done': vi.fn(),
|
||||
'build:manifestGenerated': vi.fn(),
|
||||
'build:publicAssets': vi.fn(),
|
||||
'entrypoints:found': vi.fn(),
|
||||
'entrypoints:resolved': vi.fn(),
|
||||
'entrypoints:grouped': vi.fn(),
|
||||
'vite:build:extendConfig': vi.fn(),
|
||||
@@ -60,6 +61,7 @@ describe('Hooks', () => {
|
||||
'build:done': false,
|
||||
'build:publicAssets': false,
|
||||
'build:manifestGenerated': false,
|
||||
'entrypoints:found': true,
|
||||
'entrypoints:grouped': false,
|
||||
'entrypoints:resolved': true,
|
||||
'vite:build:extendConfig': false,
|
||||
@@ -91,6 +93,7 @@ describe('Hooks', () => {
|
||||
'build:done': true,
|
||||
'build:publicAssets': true,
|
||||
'build:manifestGenerated': true,
|
||||
'entrypoints:found': true,
|
||||
'entrypoints:grouped': true,
|
||||
'entrypoints:resolved': true,
|
||||
'vite:build:extendConfig': 1,
|
||||
@@ -122,6 +125,7 @@ describe('Hooks', () => {
|
||||
'build:done': true,
|
||||
'build:publicAssets': true,
|
||||
'build:manifestGenerated': true,
|
||||
'entrypoints:found': true,
|
||||
'entrypoints:grouped': true,
|
||||
'entrypoints:resolved': true,
|
||||
'vite:build:extendConfig': 1,
|
||||
@@ -153,6 +157,7 @@ describe('Hooks', () => {
|
||||
'build:done': true,
|
||||
'build:publicAssets': true,
|
||||
'build:manifestGenerated': true,
|
||||
'entrypoints:found': 2,
|
||||
'entrypoints:grouped': true,
|
||||
'entrypoints:resolved': 2,
|
||||
'vite:build:extendConfig': 1,
|
||||
@@ -191,6 +196,7 @@ describe('Hooks', () => {
|
||||
'build:done': true,
|
||||
'build:publicAssets': true,
|
||||
'build:manifestGenerated': true,
|
||||
'entrypoints:found': true,
|
||||
'entrypoints:grouped': true,
|
||||
'entrypoints:resolved': true,
|
||||
'vite:build:extendConfig': 2,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "wxt",
|
||||
"type": "module",
|
||||
"version": "0.19.22",
|
||||
"version": "0.19.23",
|
||||
"description": "Next gen framework for developing web extensions",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -372,6 +372,9 @@ export async function createViteBuilder(
|
||||
},
|
||||
},
|
||||
watcher: viteServer.watcher,
|
||||
on(event, cb) {
|
||||
viteServer.httpServer?.on(event, cb);
|
||||
},
|
||||
};
|
||||
|
||||
return server;
|
||||
|
||||
@@ -171,6 +171,8 @@ async function createServerInternal(): Promise<WxtDevServer> {
|
||||
await runner.openBrowser();
|
||||
};
|
||||
|
||||
builderServer.on?.('close', () => keyboardShortcuts.stop());
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
|
||||
@@ -72,9 +72,10 @@ describe('Validation Utils', () => {
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
|
||||
it("should return an error when content scripts don't have a matches", () => {
|
||||
it('should return an error when "registration: manifest" content scripts don\'t have matches', () => {
|
||||
const entrypoint = fakeContentScriptEntrypoint({
|
||||
options: {
|
||||
registration: 'manifest',
|
||||
// @ts-expect-error
|
||||
matches: null,
|
||||
},
|
||||
@@ -83,7 +84,8 @@ describe('Validation Utils', () => {
|
||||
errors: [
|
||||
{
|
||||
type: 'error',
|
||||
message: '`matches` is required',
|
||||
message:
|
||||
'`matches` is required for manifest registered content scripts',
|
||||
value: null,
|
||||
entrypoint,
|
||||
},
|
||||
@@ -96,5 +98,24 @@ describe('Validation Utils', () => {
|
||||
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should allow "registration: runtime" content scripts to not have matches', () => {
|
||||
const entrypoint = fakeContentScriptEntrypoint({
|
||||
options: {
|
||||
registration: 'runtime',
|
||||
// @ts-expect-error
|
||||
matches: null,
|
||||
},
|
||||
});
|
||||
const expected = {
|
||||
errors: [],
|
||||
errorCount: 0,
|
||||
warningCount: 0,
|
||||
};
|
||||
|
||||
const actual = validateEntrypoints([entrypoint]);
|
||||
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
BackgroundEntrypoint,
|
||||
ContentScriptEntrypoint,
|
||||
Entrypoint,
|
||||
EntrypointInfo,
|
||||
GenericEntrypoint,
|
||||
OptionsEntrypoint,
|
||||
PopupEntrypoint,
|
||||
@@ -67,6 +68,8 @@ export async function findEntrypoints(): Promise<Entrypoint[]> {
|
||||
return results;
|
||||
}, []);
|
||||
|
||||
await wxt.hooks.callHook('entrypoints:found', wxt, entrypointInfos);
|
||||
|
||||
// Validation
|
||||
preventNoEntrypoints(entrypointInfos);
|
||||
preventDuplicateEntrypointNames(entrypointInfos);
|
||||
@@ -137,6 +140,8 @@ export async function findEntrypoints(): Promise<Entrypoint[]> {
|
||||
skipped: isEntrypointSkipped(entry),
|
||||
}));
|
||||
|
||||
await wxt.hooks.callHook('entrypoints:resolved', wxt, entrypoints);
|
||||
|
||||
wxt.logger.debug('All entrypoints:', entrypoints);
|
||||
const skippedEntrypointNames = entrypoints
|
||||
.filter((item) => item.skipped)
|
||||
@@ -151,17 +156,10 @@ export async function findEntrypoints(): Promise<Entrypoint[]> {
|
||||
].join('\n'),
|
||||
);
|
||||
}
|
||||
await wxt.hooks.callHook('entrypoints:resolved', wxt, entrypoints);
|
||||
|
||||
return entrypoints;
|
||||
}
|
||||
|
||||
interface EntrypointInfo {
|
||||
name: string;
|
||||
inputPath: string;
|
||||
type: Entrypoint['type'];
|
||||
}
|
||||
|
||||
/** Returns a map of input paths to the file's options. */
|
||||
async function importEntrypoints(infos: EntrypointInfo[]) {
|
||||
const resMap: Record<string, Record<string, any> | undefined> = {};
|
||||
|
||||
@@ -30,10 +30,13 @@ function validateContentScriptEntrypoint(
|
||||
definition: ContentScriptEntrypoint,
|
||||
): ValidationResult[] {
|
||||
const errors = validateBaseEntrypoint(definition);
|
||||
if (definition.options.matches == null) {
|
||||
if (
|
||||
definition.options.registration !== 'runtime' &&
|
||||
definition.options.matches == null
|
||||
) {
|
||||
errors.push({
|
||||
type: 'error',
|
||||
message: '`matches` is required',
|
||||
message: '`matches` is required for manifest registered content scripts',
|
||||
value: definition.options.matches,
|
||||
entrypoint: definition,
|
||||
});
|
||||
|
||||
@@ -789,6 +789,13 @@ export type Entrypoint =
|
||||
| OptionsEntrypoint
|
||||
| SidepanelEntrypoint;
|
||||
|
||||
export interface EntrypointInfo {
|
||||
name: string;
|
||||
/** Absolute path to the entrypoint file. */
|
||||
inputPath: string;
|
||||
type: Entrypoint['type'];
|
||||
}
|
||||
|
||||
export type EntrypointGroup = Entrypoint | Entrypoint[];
|
||||
|
||||
export type OnContentScriptStopped = (cb: () => void) => void;
|
||||
@@ -1091,6 +1098,7 @@ export interface WxtBuilderServer {
|
||||
* Chokidar file watcher instance.
|
||||
*/
|
||||
watcher: FSWatcher;
|
||||
on?(event: string, callback: () => void): void;
|
||||
}
|
||||
|
||||
export interface ServerInfo {
|
||||
@@ -1182,6 +1190,12 @@ export interface WxtHooks {
|
||||
wxt: Wxt,
|
||||
manifest: Manifest.WebExtensionManifest,
|
||||
) => HookResult;
|
||||
/**
|
||||
* Called once the names and paths of all entrypoints have been resolved.
|
||||
* @param wxt The configured WXT object
|
||||
* @param infos List of entrypoints found in the project's `entrypoints` directory
|
||||
*/
|
||||
'entrypoints:found': (wxt: Wxt, infos: EntrypointInfo[]) => HookResult;
|
||||
/**
|
||||
* Called once all entrypoints have been loaded from the `entrypointsDir`.
|
||||
* Use `wxt.builder.importEntrypoint` to load entrypoint options from the
|
||||
|
||||
Reference in New Issue
Block a user