Compare commits

...

18 Commits

Author SHA1 Message Date
github-actions[bot] 7ea36a3cfc chore(release): wxt v0.20.5
📼 VHS / Create VHS (push) Cancelled after 0s
2025-04-26 13:53:46 +00:00
Aaron 3577c0b47a fix: Don't use crypto.randUUID for shadow root UIs 2025-04-26 08:48:42 -05:00
Aaron d0bef42186 fix: Standardize locale codes and warn about unsupported ones (#1617) 2025-04-26 08:03:22 -05:00
github-actions[bot] d9f10c62ad chore(release): wxt v0.20.4
📼 VHS / Create VHS (push) Cancelled after 0s
2025-04-25 03:03:08 +00:00
aklinker1 35d3c03e4b fix: Upgrade @wxt-dev/browser to latest @types/chrome version 2025-04-25 01:52:10 +00:00
Yunsup Sim fdd38a1580 fix: Fix CORS error in Firefox (#1607) 2025-04-24 19:01:30 -05:00
ТΞNSΛI 3018801f06 feat: add {{packageVersion}} as template variable (#1604) 2025-04-24 12:06:50 -05:00
Anh71me 8e96bfef06 fix: fix typescript error on defineItem fallback (#1601) 2025-04-24 07:31:48 -05:00
ТΞNSΛI 31071bd11e feat: ignore elements with a vite-ignore or wxt-ignore attribute (#1603)
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2025-04-24 00:34:49 -05:00
Yuan f5619f6be1 chore: Move the public folder outside of src for the default Svelte template (#1602) 2025-04-24 00:26:34 -05:00
Aaron adad1b5a2c chore: Fix formatting 2025-04-24 00:24:49 -05:00
Nishu a6c4e19a5d fix: adding missing "" to PublicPath and browser.runtime.getUrl (#1597) 2025-04-24 00:18:06 -05:00
Jack af6f74c344 docs: Added "[Always Light Mode]" to the homepage (#1608) 2025-04-24 00:05:37 -05:00
Aaron ce45cb8a89 docs: Add warning about --load-extension deprecation 2025-04-23 23:35:28 -05:00
aklinker1 14d4aa202d fix: Upgrade @wxt-dev/browser to latest @types/chrome version 2025-04-23 01:51:01 +00:00
Nishu 4c35798dba feat: Ignore popup/index.ts instead of erroring (#1520)
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2025-04-20 21:17:05 -05:00
Aaron 656a9b365f docs(Content Script UI): Add additional details about when onRemove is called 2025-04-20 21:15:08 -05:00
Namu 67fa3db921 docs: Fix import in unit-testing.md (#1598) 2025-04-20 20:36:06 -05:00
32 changed files with 364 additions and 56 deletions
@@ -72,6 +72,7 @@ const chromeExtensionIds = [
'hlnhhamckimoaiekbglafiebkfimhapb', // SnapThePrice: AI-Powered Real-time Lowest Price Finder
'gdjampjdgjmbifnhldgcnccdjkcoicmg', // radiofrance - news & broadcasts (French), music (international)
'jlnhphlghikichhgbnkepenehbmloenb', // Blens - Time Tracker and AI Insight
'njnammmpdodmfkodnfpammnpdcbhnlcm', // Always Light Mode - Setting website always in light mode
];
const { data, err, isLoading } = useListExtensionDetails(chromeExtensionIds);
@@ -8,6 +8,16 @@ outline: deep
During development, WXT uses [`web-ext` by Mozilla](https://www.npmjs.com/package/web-ext) to automatically open a browser window with your extension installed.
:::danger
Chrome 137 removed support for the `--load-extension` CLI flag, which WXT relied on to open the browser with an extension installed. So this feature will not work for Chrome.
You have two options:
1. Install [Chrome for Testing](https://developer.chrome.com/blog/chrome-for-testing/) (which still supports the `--load-extension` flag) and [point the `chrome` binary to it](#set-browser-binaries), or
2. [Disable this feature](#disable-opening-browser) and manually load your extension
:::
## Config Files
You can configure browser startup in 3 places:
+1 -1
View File
@@ -85,7 +85,7 @@ import { injectScript, createShadowRootUi } from '#imports';
But Vitest sees this:
```ts
import { injectScript } from 'wxt/browser';
import { injectScript } from 'wxt/utils/inject-script';
import { createShadowRootUi } from 'wxt/utils/content-script-ui/shadow-root';
```
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "@wxt-dev/browser",
"description": "Provides a cross-browser API for using extension APIs and types based on @types/chrome",
"version": "0.0.315",
"version": "0.0.317",
"type": "module",
"main": "src/index.mjs",
"types": "src/index.d.ts",
@@ -23,7 +23,7 @@
"src"
],
"devDependencies": {
"@types/chrome": "0.0.315",
"@types/chrome": "0.0.317",
"fs-extra": "catalog:",
"nano-spawn": "catalog:",
"tsx": "catalog:",
+67 -5
View File
@@ -8958,7 +8958,7 @@ export namespace Browser {
default_popup?: string | undefined;
}
// Source: https://developer.Browser.com/docs/extensions/mv3/declare_permissions/
/** Source: https://developer.Browser.com/docs/extensions/reference/permissions-list */
export type ManifestPermissions =
| "accessibilityFeatures.modify"
| "accessibilityFeatures.read"
@@ -9015,11 +9015,11 @@ export namespace Browser {
| "privacy"
| "processes"
| "proxy"
| "readingList"
| "scripting"
| "search"
| "sessions"
| "sidePanel"
| "signedInDevices"
| "storage"
| "system.cpu"
| "system.display"
@@ -9042,6 +9042,23 @@ export namespace Browser {
| "webRequestBlocking"
| "webRequestAuthProvider";
/** Source : https://developer.Browser.com/docs/extensions/reference/api/permissions */
export type ManifestOptionalPermissions = Exclude<
ManifestPermissions,
| "debugger"
| "declarativeNetRequest"
| "devtools"
| "experimental"
| "fontSettings"
| "geolocation"
| "proxy"
| "tts"
| "ttsEngine"
| "unlimitedStorage"
| "wallpaper"
| "webAuthenticationProxy"
>;
export interface SearchProvider {
name?: string | undefined;
keyword?: string | undefined;
@@ -9261,8 +9278,8 @@ export namespace Browser {
}
| undefined;
content_security_policy?: string | undefined;
optional_permissions?: string[] | undefined;
permissions?: string[] | undefined;
optional_permissions?: ManifestOptionalPermissions[] | string[] | undefined;
permissions?: ManifestPermissions[] | string[] | undefined;
web_accessible_resources?: string[] | undefined;
}
@@ -9297,7 +9314,7 @@ export namespace Browser {
sandbox?: string;
};
host_permissions?: string[] | undefined;
optional_permissions?: ManifestPermissions[] | undefined;
optional_permissions?: ManifestOptionalPermissions[] | undefined;
optional_host_permissions?: string[] | undefined;
permissions?: ManifestPermissions[] | undefined;
web_accessible_resources?: Array<{ resources: string[]; matches: string[] }> | undefined;
@@ -14845,6 +14862,18 @@ export namespace Browser {
*/
export type ExecutionWorld = "MAIN" | "USER_SCRIPT";
/** @since Chrome 135 */
export interface InjectionResult {
/** The document associated with the injection. */
documentId: string;
/** The error, if any. `error` and `result` are mutually exclusive. */
error?: string;
/** The frame associated with the injection. */
frameId: number;
/** The result of the script execution. */
result: any;
}
export interface WorldProperties {
/** Specifies the world csp. The default is the `ISOLATED` world csp. */
csp?: string;
@@ -14861,6 +14890,18 @@ export namespace Browser {
ids?: string[];
}
/** @since Chrome 135 */
export interface InjectionTarget {
/** Whether the script should inject into all frames within the tab. Defaults to false. This must not be true if `frameIds` is specified. */
allFrames?: boolean;
/** The IDs of specific documentIds to inject into. This must not be set if `frameIds` is set. */
documentIds?: string[];
/** The IDs of specific frames to inject into. */
frameIds?: number[];
/** The ID of the tab into which to inject. */
tabId: number;
}
export interface RegisteredUserScript {
/** If true, it will inject into all frames, even if the frame is not the top-most frame in the tab. Each frame is checked independently for URL requirements; it will not inject into child frames if the URL requirements are not met. Defaults to false, meaning that only the top frame is matched. */
allFrames?: boolean;
@@ -14887,6 +14928,20 @@ export namespace Browser {
worldId?: string;
}
/** @since Chrome 135 */
export interface UserScriptInjection {
/** Whether the injection should be triggered in the target as soon as possible. Note that this is not a guarantee that injection will occur prior to page load, as the page may have already loaded by the time the script reaches the target. */
injectImmediately?: boolean;
/** The list of ScriptSource objects defining sources of scripts to be injected into the target. */
js: ScriptSource[];
/** Details specifying the target into which to inject the script. */
target: InjectionTarget;
/** The JavaScript "world" to run the script in. The default is `USER_SCRIPT`. */
world?: ExecutionWorld;
/** Specifies the user script world ID to execute in. If omitted, the script will execute in the default user script world. Only valid if `world` is omitted or is `USER_SCRIPT`. Values with leading underscores (`_`) are reserved. */
worldId?: string;
}
/**
* Properties for a script source.
*/
@@ -14939,6 +14994,13 @@ export namespace Browser {
export function getWorldConfigurations(): Promise<WorldProperties[]>;
export function getWorldConfigurations(callback: (worlds: WorldProperties[]) => void): void;
/**
* Injects a script into a target context. By default, the script will be run at `document_idle`, or immediately if the page has already loaded. If the `injectImmediately` property is set, the script will inject without waiting, even if the page has not finished loading. If the script evaluates to a promise, the browser will wait for the promise to settle and return the resulting value.
* @since Chrome 135
*/
export function execute(injection: UserScriptInjection): Promise<InjectionResult[]>;
export function execute(injection: UserScriptInjection, callback: (result: InjectionResult[]) => void): void;
/**
* Registers one or more user scripts for this extension.
*
+32 -2
View File
@@ -1,10 +1,14 @@
import { describe, it, expect } from 'vitest';
import { ChromeMessage } from '../build';
import { applyChromeMessagePlaceholders, getSubstitutionCount } from '../utils';
import {
applyChromeMessagePlaceholders,
getSubstitutionCount,
standardizeLocale,
} from '../utils';
describe('Utils', () => {
describe('applyChromeMessagePlaceholders', () => {
it('should return the combined stirng', () => {
it('should return the combined string', () => {
const input = {
message: 'Hello $username$, welcome to $appName$',
placeholders: {
@@ -60,4 +64,30 @@ describe('Utils', () => {
expect(getSubstitutionCount('Hello $10')).toBe(1);
});
});
describe('standardizeLocale', () => {
it('should convert two-letter locale codes to lowercase', () => {
expect(standardizeLocale('en')).toEqual('en');
expect(standardizeLocale('EN')).toEqual('en');
});
it('should convert locale code extensions to uppercase', () => {
expect(standardizeLocale('en_US')).toEqual('en_US');
expect(standardizeLocale('en_us')).toEqual('en_US');
expect(standardizeLocale('es_419')).toEqual('es_419');
});
it('should convert dashes to underscores', () => {
expect(standardizeLocale('en_US')).toEqual('en_US');
expect(standardizeLocale('en-US')).toEqual('en_US');
});
it('should return the input string as-is for unknown formats', () => {
expect(standardizeLocale('en_USSS')).toEqual('en_USSS');
expect(standardizeLocale('en-')).toEqual('en-');
expect(standardizeLocale('------')).toEqual('------');
expect(standardizeLocale('test')).toEqual('test');
expect(standardizeLocale('hello-world')).toEqual('hello-world');
});
});
});
+2
View File
@@ -10,6 +10,8 @@ import { parseYAML, parseJSON5, parseTOML } from 'confbox';
import { dirname, extname } from 'node:path';
import { applyChromeMessagePlaceholders, getSubstitutionCount } from './utils';
export { SUPPORTED_LOCALES } from './supported-locales';
//
// TYPES
//
+18 -4
View File
@@ -16,12 +16,14 @@ import {
generateChromeMessagesText,
parseMessagesFile,
generateTypeText,
SUPPORTED_LOCALES,
} from './build';
import glob from 'fast-glob';
import { basename, extname, join, resolve } from 'node:path';
import { watch } from 'chokidar';
import { GeneratedPublicFile, WxtDirFileEntry } from 'wxt';
import { writeFile } from 'node:fs/promises';
import { standardizeLocale } from './utils';
export default defineWxtModule<I18nOptions>({
name: '@wxt-dev/i18n',
@@ -46,10 +48,22 @@ export default defineWxtModule<I18nOptions>({
cwd: localesDir,
absolute: true,
});
return files.map((file) => ({
file,
locale: basename(file).replace(extname(file), ''),
}));
const unsupportedLocales: string[] = [];
const res = files.map((file) => {
const rawLocale = basename(file).replace(extname(file), '');
const locale = standardizeLocale(rawLocale);
if (!SUPPORTED_LOCALES.has(locale)) unsupportedLocales.push(locale);
return { file, locale };
});
if (unsupportedLocales.length > 0)
wxt.logger.warn(
`Unsupported locales: [${unsupportedLocales.join(', ')}].\n\nWeb extensions only support a limited set of locales as described here: https://developer.chrome.com/docs/extensions/reference/api/i18n#locales`,
);
return res;
};
const generateOutputJsonFiles = async (): Promise<
+58
View File
@@ -0,0 +1,58 @@
/** From https://developer.chrome.com/docs/extensions/reference/api/i18n#locales */
export const SUPPORTED_LOCALES = new Set([
'ar',
'am',
'bg',
'bn',
'ca',
'cs',
'da',
'de',
'el',
'en',
'en_AU',
'en_GB',
'en_US',
'es',
'es_419',
'et',
'fa',
'fi',
'fil',
'fr',
'gu',
'he',
'hi',
'hr',
'hu',
'id',
'it',
'ja',
'kn',
'ko',
'lt',
'lv',
'ml',
'mr',
'ms',
'nl',
'no',
'pl',
'pt_BR',
'pt_PT',
'ro',
'ru',
'sk',
'sl',
'sr',
'sv',
'sw',
'ta',
'te',
'th',
'tr',
'uk',
'vi',
'zh_CN',
'zh_TW',
]);
+13
View File
@@ -21,3 +21,16 @@ export function getSubstitutionCount(message: string): number {
}
const MAX_SUBSTITUTIONS = 9;
/** Given a string, standardize it to the format `xx_YY`. */
export function standardizeLocale(locale: string): string {
if (locale.length === 2) return locale.toLowerCase();
const [is_match, prefix, suffix] =
locale.match(/^([a-z]{2})[-_]([a-z]{2,3})$/i) ?? [];
if (is_match) {
return `${prefix.toLowerCase()}_${suffix.toUpperCase()}`;
}
return locale;
}
@@ -1281,6 +1281,19 @@ describe('Storage Utils', () => {
it('should define a nullable value when options are not passed', () => {
const item = storage.defineItem<number>(`local:test`);
expectTypeOf(item).toEqualTypeOf<WxtStorageItem<number | null, {}>>();
const item2 = storage.defineItem<number>(`local:test`, {});
expectTypeOf(item2).toEqualTypeOf<WxtStorageItem<number | null, {}>>();
const item3 = storage.defineItem<number>(`local:test`, {
fallback: undefined,
});
expectTypeOf(item3).toEqualTypeOf<WxtStorageItem<number | null, {}>>();
const item4 = storage.defineItem<number>(`local:test`, {
defaultValue: undefined,
});
expectTypeOf(item4).toEqualTypeOf<WxtStorageItem<number | null, {}>>();
});
it('should define a non-null value when options are passed with a nullish default value', () => {
@@ -1288,6 +1301,11 @@ describe('Storage Utils', () => {
defaultValue: 123,
});
expectTypeOf(item).toEqualTypeOf<WxtStorageItem<number, {}>>();
const item2 = storage.defineItem(`local:test`, {
fallback: 123,
});
expectTypeOf(item2).toEqualTypeOf<WxtStorageItem<number, {}>>();
});
it('should define a nullable value when options are passed with null default value', () => {
+9 -1
View File
@@ -750,8 +750,16 @@ export interface WxtStorage {
): WxtStorageItem<TValue | null, TMetadata>;
defineItem<TValue, TMetadata extends Record<string, unknown> = {}>(
key: StorageItemKey,
options: WxtStorageItemOptions<TValue>,
options: WxtStorageItemOptions<TValue> & { fallback: TValue },
): WxtStorageItem<TValue, TMetadata>;
defineItem<TValue, TMetadata extends Record<string, unknown> = {}>(
key: StorageItemKey,
options: WxtStorageItemOptions<TValue> & { defaultValue: TValue },
): WxtStorageItem<TValue, TMetadata>;
defineItem<TValue, TMetadata extends Record<string, unknown> = {}>(
key: StorageItemKey,
options: WxtStorageItemOptions<TValue>,
): WxtStorageItem<TValue | null, TMetadata>;
}
interface WxtStorageDriver {
+38
View File
@@ -1,5 +1,43 @@
# Changelog
## v0.20.5
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.20.4...wxt-v0.20.5)
### 🩹 Fixes
- Don't use crypto.randUUID for shadow root UIs ([3577c0b](https://github.com/wxt-dev/wxt/commit/3577c0b))
### ❤️ Contributors
- Aaron ([@aklinker1](https://github.com/aklinker1))
## v0.20.4
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.20.3...wxt-v0.20.4)
### 🚀 Enhancements
- Ignore popup/index.ts instead of erroring ([#1520](https://github.com/wxt-dev/wxt/pull/1520))
- Ignore elements with a `vite-ignore` or `wxt-ignore` attribute ([#1603](https://github.com/wxt-dev/wxt/pull/1603))
- Add `{{packageVersion}}` as template variable ([#1604](https://github.com/wxt-dev/wxt/pull/1604))
### 🩹 Fixes
- Adding missing `""` to `PublicPath` and `browser.runtime.getUrl` ([#1597](https://github.com/wxt-dev/wxt/pull/1597))
- Fix CORS error in Firefox ([#1607](https://github.com/wxt-dev/wxt/pull/1607))
### 📖 Documentation
- **Content Script UI:** Add additional details about when `onRemove` is called ([656a9b3](https://github.com/wxt-dev/wxt/commit/656a9b3))
### ❤️ Contributors
- Yunsup Sim <pedogunu@gmail.com>
- ТΞNSΛI <tensai@gmx.net>
- Nishu ([@nishu-murmu](https://github.com/nishu-murmu))
- Aaron ([@aklinker1](https://github.com/aklinker1))
## v0.20.3
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.20.2...wxt-v0.20.3)
@@ -48,6 +48,7 @@ describe('TypeScript Project', () => {
declare module "wxt/browser" {
export type PublicPath =
| ""
| "/"
| "/options.html"
| "/popup.html"
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "wxt",
"type": "module",
"version": "0.20.3",
"version": "0.20.5",
"description": "⚡ Next-gen Web Extension Framework",
"license": "MIT",
"scripts": {
@@ -150,6 +150,13 @@ export function pointToDevServer(
attr: string,
) {
document.querySelectorAll(querySelector).forEach((element) => {
if (
element.hasAttribute('vite-ignore') ||
element.hasAttribute('wxt-ignore')
) {
element.removeAttribute('wxt-ignore');
return;
}
const src = element.getAttribute(attr);
if (!src || isUrl(src)) return;
+8 -6
View File
@@ -73,16 +73,18 @@ async function getPathsDeclarationEntry(
isHtmlEntrypoint(entry) ? '.html' : '.js',
),
)
.concat([''])
.concat(await getPublicFiles());
await wxt.hooks.callHook('prepare:publicPaths', wxt, paths);
const unions = paths
.map(normalizePath)
.sort()
.map((path) => ` | "/${path}"`)
.join('\n');
const unions = [
` | ""`,
` | "/"`,
...paths
.map(normalizePath)
.sort()
.map((path) => ` | "/${path}"`),
].join('\n');
const template = `// Generated by wxt
import "wxt/browser";
@@ -1503,7 +1503,7 @@ describe('Manifest Utils', () => {
expect(actual).toMatchObject({
content_security_policy:
"script-src 'self' http://localhost:3000; object-src 'self';",
permissions: ['http://localhost:3000/*', 'tabs'],
permissions: ['http://localhost/*', 'tabs'],
});
});
@@ -1535,7 +1535,7 @@ describe('Manifest Utils', () => {
sandbox:
"script-src 'self' 'unsafe-inline' 'unsafe-eval' http://localhost:3000; sandbox allow-scripts allow-forms allow-popups allow-modals; child-src 'self';",
},
host_permissions: ['http://localhost:3000/*'],
host_permissions: ['http://localhost/*'],
permissions: ['tabs', 'scripting'],
});
});
@@ -668,27 +668,46 @@ describe('findEntrypoints', () => {
expect(entrypoints[0]).toEqual(expected);
});
it('should not allow multiple entrypoints with the same name', async () => {
it('should ignore other index files in the same directory when index.html exists', async () => {
globMock.mockResolvedValueOnce([
'content/index.ts',
'popup/index.html',
'popup/index.ts',
'popup/index.css',
]);
const entrypoints = await findEntrypoints();
expect(entrypoints).toHaveLength(2);
expect(entrypoints[0]).toMatchObject({
type: 'content-script',
name: 'content',
});
expect(entrypoints[1]).toMatchObject({
type: 'popup',
name: 'popup',
});
});
it('should not allow a file entrypoint and directory entrypoint to have the same name', async () => {
globMock.mockResolvedValueOnce([
'options/index.html',
'options/index.jsx',
'popup.html',
'popup/index.html',
'popup/index.ts',
'ui.html',
'other.ts',
'other/index.ts',
]);
await expect(() => findEntrypoints()).rejects.toThrowError(
[
'Multiple entrypoints with the same name detected, only one entrypoint for each name is allowed.',
'',
'- options',
` - ${unnormalizePath('src/entrypoints/options/index.html')}`,
` - ${unnormalizePath('src/entrypoints/options/index.jsx')}`,
'- other',
` - ${unnormalizePath('src/entrypoints/other.ts')}`,
` - ${unnormalizePath('src/entrypoints/other/index.ts')}`,
'- popup',
` - ${unnormalizePath('src/entrypoints/popup.html')}`,
` - ${unnormalizePath('src/entrypoints/popup/index.html')}`,
` - ${unnormalizePath('src/entrypoints/popup/index.ts')}`,
].join('\n'),
);
});
@@ -53,20 +53,34 @@ export async function findEntrypoints(): Promise<Entrypoint[]> {
relativePaths.sort();
const pathGlobs = Object.keys(PATH_GLOB_TO_TYPE_MAP);
const entrypointInfos: EntrypointInfo[] = relativePaths.reduce<
EntrypointInfo[]
>((results, relativePath) => {
const inputPath = resolve(wxt.config.entrypointsDir, relativePath);
const name = getEntrypointName(wxt.config.entrypointsDir, inputPath);
const matchingGlob = pathGlobs.find((glob) =>
minimatch(relativePath, glob),
);
if (matchingGlob) {
const type = PATH_GLOB_TO_TYPE_MAP[matchingGlob];
results.push({ name, inputPath, type });
}
return results;
}, []);
const entrypointInfos: EntrypointInfo[] = relativePaths
.reduce<EntrypointInfo[]>((results, relativePath) => {
const inputPath = resolve(wxt.config.entrypointsDir, relativePath);
const name = getEntrypointName(wxt.config.entrypointsDir, inputPath);
const matchingGlob = pathGlobs.find((glob) =>
minimatch(relativePath, glob),
);
if (matchingGlob) {
const type = PATH_GLOB_TO_TYPE_MAP[matchingGlob];
results.push({ name, inputPath, type });
}
return results;
}, [])
.filter(({ name, inputPath }, _, entrypointInfos) => {
// Remove <name>/index.* if <name>/index.html exists
if (inputPath.endsWith('.html')) return true;
const isIndexFile = /index\..+$/.test(inputPath);
if (!isIndexFile) return true;
const hasIndexHtml = entrypointInfos.some(
(entry) =>
entry.name === name && entry.inputPath.endsWith('index.html'),
);
if (hasIndexHtml) return false;
return true;
});
await wxt.hooks.callHook('entrypoints:found', wxt, entrypointInfos);
+7 -1
View File
@@ -459,7 +459,13 @@ function discoverIcons(
}
function addDevModeCsp(manifest: Browser.runtime.Manifest): void {
const permission = `${wxt.server?.origin ?? ''}/*`;
let permissonUrl = wxt.server?.origin;
if (permissonUrl) {
const permissionUrlInstance = new URL(permissonUrl);
permissionUrlInstance.port = '';
permissonUrl = permissionUrlInstance.toString();
}
const permission = `${permissonUrl}*`;
const allowedCsp = wxt.server?.origin ?? 'http://localhost:*';
if (manifest.manifest_version === 3) {
+3 -3
View File
@@ -26,11 +26,10 @@ export async function zip(config?: InlineConfig): Promise<string[]> {
wxt.logger.info('Zipping extension...');
const zipFiles: string[] = [];
const packageJson = await getPackageJson();
const projectName =
wxt.config.zip.name ??
safeFilename(
(await getPackageJson())?.name || path.basename(process.cwd()),
);
safeFilename(packageJson?.name || path.basename(process.cwd()));
const applyTemplate = (template: string): string =>
template
.replaceAll('{{name}}', projectName)
@@ -39,6 +38,7 @@ export async function zip(config?: InlineConfig): Promise<string[]> {
'{{version}}',
output.manifest.version_name ?? output.manifest.version,
)
.replaceAll('{{packageVersion}}', packageJson?.version)
.replaceAll('{{mode}}', wxt.config.mode)
.replaceAll('{{manifestVersion}}', `mv${wxt.config.manifestVersion}`);
+2
View File
@@ -147,6 +147,7 @@ export interface InlineConfig {
*
* - <span v-pre>`{{name}}`</span> - The project's name converted to kebab-case
* - <span v-pre>`{{version}}`</span> - The version_name or version from the manifest
* - <span v-pre>`{{packageVersion}}`</span> - The version from the package.json
* - <span v-pre>`{{browser}}`</span> - The target browser from the `--browser` CLI flag
* - <span v-pre>`{{mode}}`</span> - The current mode
* - <span v-pre>`{{manifestVersion}}`</span> - Either "2" or "3"
@@ -171,6 +172,7 @@ export interface InlineConfig {
*
* - <span v-pre>`{{name}}`</span> - The project's name converted to kebab-case
* - <span v-pre>`{{version}}`</span> - The version_name or version from the manifest
* - <span v-pre>`{{packageVersion}}`</span> - The version from the package.json
* - <span v-pre>`{{browser}}`</span> - The target browser from the `--browser` CLI flag
* - <span v-pre>`{{mode}}`</span> - The current mode
* - <span v-pre>`{{manifestVersion}}`</span> - Either "2" or "3"
@@ -18,7 +18,7 @@ export async function createShadowRootUi<TMounted>(
ctx: ContentScriptContext,
options: ShadowRootContentScriptUiOptions<TMounted>,
): Promise<ShadowRootContentScriptUi<TMounted>> {
const instanceId = crypto.randomUUID();
const instanceId = Math.random().toString(36).substring(2, 15);
const css: string[] = [];
if (!options.inheritStyles) {
@@ -9,6 +9,9 @@ export type ContentScriptUiOptions<TMounted> = ContentScriptPositioningOptions &
/**
* Callback called before the UI is removed from the webpage. Use to cleanup your UI, like
* unmounting your Vue or React apps.
*
* Note that this callback is called only when `ui.remove` is called - that means it is
* not called automatically when the anchor is removed, unless you use `autoMount`.
*/
onRemove?: (mounted: TMounted | undefined) => void;
};
+5 -5
View File
@@ -464,8 +464,8 @@ importers:
version: 1.2.15
devDependencies:
'@types/chrome':
specifier: 0.0.315
version: 0.0.315
specifier: 0.0.317
version: 0.0.317
fs-extra:
specifier: 'catalog:'
version: 11.3.0
@@ -2188,8 +2188,8 @@ packages:
'@types/chrome@0.0.313':
resolution: {integrity: sha512-9R5T7gTaYZhkxlu+Ho4wk9FL+y/werWQY2yjGWSqCuiTsqS7nL/BE5UMTP6rU7J+oIG2FRKqrEycHhJATeltVA==}
'@types/chrome@0.0.315':
resolution: {integrity: sha512-Oy1dYWkr6BCmgwBtOngLByCHstQ3whltZg7/7lubgIZEYvKobDneqplgc6LKERNRBwckFviV4UU5AZZNUFrJ4A==}
'@types/chrome@0.0.317':
resolution: {integrity: sha512-ibKycbXX8ZZToFshjgWg98BTvFUSvQht8m53Xc+87ye3Z6ZoHJubLjoiDsil8rtW+noWE+Z0+7y0nwLxArU+CQ==}
'@types/conventional-commits-parser@5.0.1':
resolution: {integrity: sha512-7uz5EHdzz2TqoMfV7ee61Egf5y6NkcO4FB/1iCCQnbeiI1F3xzv3vK5dBCXUCLQgGYS+mUeigK1iKQzvED+QnQ==}
@@ -6441,7 +6441,7 @@ snapshots:
'@types/filesystem': 0.0.36
'@types/har-format': 1.2.15
'@types/chrome@0.0.315':
'@types/chrome@0.0.317':
dependencies:
'@types/filesystem': 0.0.36
'@types/har-format': 1.2.15

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Before

Width:  |  Height:  |  Size: 559 B

After

Width:  |  Height:  |  Size: 559 B

Before

Width:  |  Height:  |  Size: 916 B

After

Width:  |  Height:  |  Size: 916 B

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB