Compare commits

...

11 Commits

Author SHA1 Message Date
github-actions[bot] f2d3061e97 chore(release): wxt v0.20.3
📼 VHS / Create VHS (push) Waiting to run
2025-04-19 17:17:39 +00:00
Aaron 760c34e416 feat: Automatically place document-level CSS outside shadow root (#1594) 2025-04-19 12:12:04 -05:00
Bang·_· 48398b315c docs: Added "[Blens - Time Tracker and AI Insight]" to the homepage (#1587) 2025-04-18 21:53:19 -05:00
techlism 45d0d9d7f1 docs: Fix entrypoints.md examples (#1586) 2025-04-18 21:11:04 -05:00
Aaron b0f4ac8221 fix: Fix double hashing of inline script keys
Additionally, update the vite plugin name to better align with purpose
2025-04-18 20:50:02 -05:00
github-actions[bot] 719192b1aa chore(release): wxt v0.20.2
📼 VHS / Create VHS (push) Waiting to run
2025-04-19 00:40:32 +00:00
Yunsup Sim 7eb32bdac8 fix: Fix hashing issue with inline scripts (#1591) 2025-04-18 19:35:18 -05:00
nostro 862756fd5b chore: update docs to point to webExt instead of runner; update config in demo (#1582) 2025-04-16 09:42:55 -05:00
nostro 5ba16e72e0 docs: add radiofrance extension to usingWXT (#1581) 2025-04-16 09:42:20 -05:00
Aaron e43ae0504d docs: Add filenames to startup examples 2025-04-16 08:09:46 -05:00
Aaron acb6cd180c docs: Fix typo in changelog 2025-04-14 17:24:10 -05:00
12 changed files with 177 additions and 17 deletions
@@ -70,6 +70,8 @@ const chromeExtensionIds = [
'hafcajcllbjnoolpfngclfmmgpikdhlm', // Monochromate
'bmoggiinmnodjphdjnmpcnlleamkfedj', // AliasVault - Open-Source Password & (Email) Alias Manager
'hlnhhamckimoaiekbglafiebkfimhapb', // SnapThePrice: AI-Powered Real-time Lowest Price Finder
'gdjampjdgjmbifnhldgcnccdjkcoicmg', // radiofrance - news & broadcasts (French), music (international)
'jlnhphlghikichhgbnkepenehbmloenb', // Blens - Time Tracker and AI Insight
];
const { data, err, isLoading } = useListExtensionDetails(chromeExtensionIds);
@@ -14,7 +14,7 @@ You can configure browser startup in 3 places:
1. `<rootDir>/web-ext.config.ts`: Ignored from version control, this file lets you configure your own options for a specific project without affecting other developers
```ts
```ts [web-ext.config.ts]
import { defineWebExtConfig } from 'wxt';
export default defineWebExtConfig({
@@ -22,7 +22,7 @@ You can configure browser startup in 3 places:
});
```
2. `<rootDir>/wxt.config.ts`: Via the [`runner` config](/api/reference/wxt/interfaces/InlineConfig#runner), included in version control
2. `<rootDir>/wxt.config.ts`: Via the [`webExt` config](/api/reference/wxt/interfaces/InlineConfig#webext), included in version control
3. `$HOME/web-ext.config.ts`: Provide default values for all WXT projects on your computer
## Recipes
@@ -31,7 +31,7 @@ You can configure browser startup in 3 places:
To set or customize the browser opened during development:
```ts
```ts [web-ext.config.ts]
export default defineWebExtConfig({
binaries: {
chrome: '/path/to/chrome-beta', // Use Chrome Beta instead of regular Chrome
@@ -81,7 +81,7 @@ You can use any directory you'd like for `--user-data-dir`, the examples above c
If you prefer to load the extension into your browser manually, you can disable the auto-open behavior:
```ts
```ts [web-ext.config.ts]
export default defineWebExtConfig({
disabled: true,
});
+2 -2
View File
@@ -211,12 +211,12 @@ When defining your background entrypoint, keep in mind that WXT will import this
<!-- prettier-ignore -->
```ts
browser.action.onClick.addListener(() => { // [!code --]
browser.action.onClicked.addListener(() => { // [!code --]
// ... // [!code --]
}); // [!code --]
export default defineBackground(() => {
browser.action.onClick.addListener(() => { // [!code ++]
browser.action.onClicked.addListener(() => { // [!code ++]
// ... // [!code ++]
}); // [!code ++]
});
+1 -1
View File
@@ -20,7 +20,7 @@ export default defineConfig({
analysis: {
open: true,
},
runner: {
webExt: {
startUrls: ['https://duckduckgo.com'],
},
example: {
+34 -1
View File
@@ -1,5 +1,38 @@
# Changelog
## v0.20.3
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.20.2...wxt-v0.20.3)
### 🚀 Enhancements
- Automatically place document-level CSS outside shadow root ([#1594](https://github.com/wxt-dev/wxt/pull/1594))
### 🩹 Fixes
- Fix double hashing of inline script keys ([b0f4ac8](https://github.com/wxt-dev/wxt/commit/b0f4ac8))
### ❤️ Contributors
- Aaron ([@aklinker1](https://github.com/aklinker1))
## v0.20.2
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.20.1...wxt-v0.20.2)
### 🩹 Fixes
- Fix hashing issue with inline scripts ([#1591](https://github.com/wxt-dev/wxt/pull/1591))
### 📖 Documentation
- Fix typo in changelog ([acb6cd1](https://github.com/wxt-dev/wxt/commit/acb6cd1))
### ❤️ Contributors
- Yunsup Sim ([@SimYunSup](https://github.com/SimYunSup))
- Aaron ([@aklinker1](https://github.com/aklinker1))
## v0.20.1
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.20.0...wxt-v0.20.1)
@@ -7,7 +40,7 @@
### 🚀 Enhancements
- Enable wxt usage inside of devcontainers ([#1406](https://github.com/wxt-dev/wxt/pull/1406))
- Type-safe `import.meta.env.BROWSER` with new `targetBrowers` config ([#1574](https://github.com/wxt-dev/wxt/pull/1574))
- Type-safe `import.meta.env.BROWSER` with new `targetBrowsers` config ([#1574](https://github.com/wxt-dev/wxt/pull/1574))
### 🩹 Fixes
+5 -1
View File
@@ -1,7 +1,7 @@
{
"name": "wxt",
"type": "module",
"version": "0.20.1",
"version": "0.20.3",
"description": "⚡ Next-gen Web Extension Framework",
"license": "MIT",
"scripts": {
@@ -167,6 +167,10 @@
"types": "./dist/utils/match-patterns.d.ts",
"default": "./dist/utils/match-patterns.mjs"
},
"./utils/split-shadow-root-css": {
"types": "./dist/utils/split-shadow-root-css.d.ts",
"default": "./dist/utils/split-shadow-root-css.mjs"
},
"./utils/storage": {
"types": "./dist/utils/storage.d.ts",
"default": "./dist/utils/storage.mjs"
@@ -85,13 +85,13 @@ export function devHtmlPrerender(
inlineScripts.forEach((script) => {
// Save the text content for later
const textContent = script.textContent ?? '';
const textHash = hash(textContent);
inlineScriptContents[textHash] = textContent;
const key = hash(textContent);
inlineScriptContents[key] = textContent;
// Replace unsafe inline script
const virtualScript = document.createElement('script');
virtualScript.type = 'module';
virtualScript.src = `${server.origin}/@id/${virtualInlineScript}?${textHash}`;
virtualScript.src = `${server.origin}/@id/${virtualInlineScript}?${key}`;
script.replaceWith(virtualScript);
});
@@ -111,7 +111,7 @@ export function devHtmlPrerender(
},
},
{
name: 'wxt:virtualize-react-refresh',
name: 'wxt:virtualize-inline-scripts',
apply: 'serve',
resolveId(id) {
// Resolve inline scripts
@@ -127,9 +127,9 @@ export function devHtmlPrerender(
load(id) {
// Resolve virtualized inline scripts
if (id.startsWith(resolvedVirtualInlineScript)) {
// id="virtual:wxt-inline-script?<hash>"
const hash = Number(id.substring(id.indexOf('?') + 1));
return inlineScriptContents[hash];
// id="virtual:wxt-inline-script?<key>"
const key = id.substring(id.indexOf('?') + 1);
return inlineScriptContents[key];
}
// Ignore chunks during HTML file pre-rendering
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -5,6 +5,7 @@ import type { ContentScriptUi, ContentScriptUiOptions } from './types';
import { createIsolatedElement } from '@webext-core/isolated-element';
import { applyPosition, createMountFunctions, mountUi } from './shared';
import { logger } from '../internal/logger';
import { splitShadowRootCss } from '../split-shadow-root-css';
/**
* Create a content script UI inside a [`ShadowRoot`](https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot).
@@ -17,6 +18,7 @@ export async function createShadowRootUi<TMounted>(
ctx: ContentScriptContext,
options: ShadowRootContentScriptUiOptions<TMounted>,
): Promise<ShadowRootContentScriptUi<TMounted>> {
const instanceId = crypto.randomUUID();
const css: string[] = [];
if (!options.inheritStyles) {
@@ -31,6 +33,9 @@ export async function createShadowRootUi<TMounted>(
css.push(entryCss.replaceAll(':root', ':host'));
}
// Some rules must be applied outside the shadow root, so split the CSS apart
const { shadowCss, documentCss } = splitShadowRootCss(css.join('\n').trim());
const {
isolatedElement: uiContainer,
parentElement: shadowHost,
@@ -38,7 +43,7 @@ export async function createShadowRootUi<TMounted>(
} = await createIsolatedElement({
name: options.name,
css: {
textContent: css.join('\n').trim(),
textContent: shadowCss,
},
mode: options.mode ?? 'open',
isolateEvents: options.isolateEvents,
@@ -51,6 +56,20 @@ export async function createShadowRootUi<TMounted>(
// Add shadow root element to DOM
mountUi(shadowHost, options);
applyPosition(shadowHost, shadow.querySelector('html'), options);
// Add document CSS
if (
documentCss &&
!document.querySelector(
`style[wxt-shadow-root-document-styles="${instanceId}"]`,
)
) {
const style = document.createElement('style');
style.textContent = documentCss;
style.setAttribute('wxt-shadow-root-document-styles', instanceId);
(document.head ?? document.body).append(style);
}
// Mount UI inside shadow root
mounted = options.onMount(uiContainer, shadow, shadowHost);
};
@@ -58,11 +77,20 @@ export async function createShadowRootUi<TMounted>(
const remove = () => {
// Cleanup mounted state
options.onRemove?.(mounted);
// Detach shadow root from DOM
shadowHost.remove();
// Remove document CSS
const documentStyle = document.querySelector(
`style[wxt-shadow-root-document-styles="${instanceId}"]`,
);
documentStyle?.remove();
// Remove children from uiContainer
while (uiContainer.lastChild)
uiContainer.removeChild(uiContainer.lastChild);
// Clear mounted value
mounted = undefined;
};
@@ -0,0 +1,25 @@
/**
* Given a CSS string that will be loaded into a shadow root, split it into two parts:
* - `documentCss`: CSS that needs to be applied to the document (like `@property`)
* - `shadowCss`: CSS that needs to be applied to the shadow root
* @param css
*/
export function splitShadowRootCss(css: string): {
documentCss: string;
shadowCss: string;
} {
let shadowCss = css;
let documentCss = '';
const rulesRegex = /(\s*@property[\s\S]*?{[\s\S]*?})/gm;
let match;
while ((match = rulesRegex.exec(css)) !== null) {
documentCss += match[1];
shadowCss = shadowCss.replace(match[1], '');
}
return {
documentCss: documentCss.trim(),
shadowCss: shadowCss.trim(),
};
}
+1
View File
@@ -14,6 +14,7 @@
"src/utils/define-unlisted-script.ts",
"src/utils/define-wxt-plugin.ts",
"src/utils/match-patterns.ts",
"src/utils/split-shadow-root-css.ts",
"src/utils/storage.ts",
"src/testing/index.ts",
"src/modules.ts"