Compare commits

..

14 Commits

Author SHA1 Message Date
github-actions[bot] 0b5424cadb chore(release): @wxt-dev/module-svelte v2.0.5
📼 VHS / Create VHS (push) Waiting to run
2026-03-19 14:06:34 +00:00
Aaron 48571f5032 fix: Update @sveltejs/vite-plugin-svelte version range to support Vite
8
2026-03-19 09:01:44 -05:00
Aaron c6c9f65040 chore: Remove any from i18n's internal types (#2201)
Co-authored-by: Patryk Kuniczak <p.kuniczak@gmail.com>
2026-03-19 09:22:15 +01:00
Harryson ace6c20164 feat: replace dotenv with native node:util parseEnv (#2181)
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2026-03-18 15:04:45 +00:00
Aditi d64b64f39e chore: replace minimatch with picomatch (#2188)
Co-authored-by: Aaron <aaronklinker1@gmail.com>
Co-authored-by: Rizky Mirzaviandy Priambodo <Xavrir@users.noreply.github.com>
2026-03-18 14:22:38 +00:00
Aaron 41a687a63e docs: Add note about adding the browser package as a dependency for
module augmentation
2026-03-17 17:40:48 -05:00
Aaron f4f6704510 docs: Document augmenting the browser type for Firefox (#2199) 2026-03-17 08:44:33 -05:00
github-actions[bot] 65fc0fadb3 chore(release): wxt v0.20.20
📼 VHS / Create VHS (push) Waiting to run
2026-03-17 13:21:45 +00:00
Aaron 64b686713b chore(deps): Add vite-node 6 support 2026-03-17 08:16:33 -05:00
Joseph Hu 9c6d3e37d4 docs: Add Extension Rank Checker to the list of extensions (#2193)
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2026-03-17 08:00:23 -05:00
FJRG2007 ツ 37abe9db39 docs: Add Dymo extension ID to UsingWxtSection.vue (#2187)
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2026-03-17 12:43:08 +00:00
Yue Yang 9ebef4a268 chore: remove useDefineForClassFields from svelte/tsconfig.json (#2190) 2026-03-17 07:37:38 -05:00
Hampus Tågerud e60f7c7e77 fix: unlisted script return values broken with Vite 8 sourcemaps (#2197) 2026-03-17 12:35:22 +00:00
aklinker1 36aadd0604 fix: Upgrade @wxt-dev/browser to latest @types/chrome version 2026-03-17 00:39:30 +00:00
25 changed files with 394 additions and 123 deletions
@@ -121,6 +121,8 @@ const chromeExtensionIds = [
'lapnciffpekdengooeolaienkeoilfeo', // All API Hub AI Relay & New API Manager - https://github.com/qixing-jk/all-api-hub
'bhgobenflkkhfcgkikejaaejenoddcmo', // Scrape Similar - Extract data from websites into spreadsheets - https://github.com/zizzfizzix/scrape-similar
'kinlknncggaihnhdcalijdmpbhbflalm', // isTrust - https://github.com/Internet-Society-Belgium/isTrust/
'ojpakgiekphppgkcdihbjpafobhnhlkp', // Dymo
'pmgehhllikbjmadpenhabejhpemplhmd', // Extension Rank Checker - Extension Ranker
];
const { data, err, isLoading } = useListExtensionDetails(chromeExtensionIds);
+22
View File
@@ -76,6 +76,28 @@ Alternatively, if you're trying to use similar APIs under different names (to su
});
```
### Augmenting the Browser Type
WXT's `browser` types are based on the `@types/chrome` package. That means some Firefox-specific APIs may not be typed, like `browser.sidebarAction`. If you want to add types for these APIs, you can augment the browser type to add them yourself:
```ts
// <srcDir>/browser-types.d.ts
import '@wxt-dev/browser';
import type { SidebarAction } from 'webextension-polyfill';
declare module '@wxt-dev/browser' {
namespace Browser {
export const sidebarAction: SidebarAction.Static;
}
}
```
> For this to work, you may need to install `@wxt-dev/browser` as a direct dependency.
>
> ```sh
> pnpm add @wxt-dev/browser
> ```
## Entrypoint Limitations
Because WXT imports your entrypoint files into a NodeJS, non-extension environment, the `chrome`/`browser` variables provided to extensions by the browser **will not be available**.
+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.1.37",
"version": "0.1.38",
"type": "module",
"main": "src/index.mjs",
"types": "src/index.d.ts",
@@ -23,7 +23,7 @@
"src"
],
"devDependencies": {
"@types/chrome": "0.1.37",
"@types/chrome": "0.1.38",
"@types/node": "^20.0.0",
"nano-spawn": "^2.0.0",
"typescript": "^5.9.3",
+11 -8
View File
@@ -4076,14 +4076,17 @@ export namespace Browser {
id: string;
/**
* Implements the WebCrypto's SubtleCrypto interface. The cryptographic operations, including key generation, are hardware-backed.
* Only non-extractable keys can be generated. The supported key types are RSASSA-PKCS1-V1_5 and RSA-OAEP (on Chrome versions 134+) with `modulusLength` up to 2048 and ECDSA with `namedCurve` P-256. Each RSASSA-PKCS1-V1_5 and ECDSA key can be used for signing data at most once, unless the extension is allowlisted through the KeyPermissions policy, in which case the key can be used indefinitely. RSA-OAEP keys are supported since Chrome version 134 and can be used by extensions allowlisted through that same policy to unwrap other keys.
*
* Only non-extractable keys can be generated. The supported key types are RSASSA-PKCS1-V1_5 with `modulusLength` up to 2048 and ECDSA with `namedCurve` P-256. Each key can be used for signing data at most once, unless the extension is allowlisted by the KeyPermissions policy, in which case the key can be used indefinitely.
*
* Keys generated on a specific `Token` cannot be used with any other Tokens, nor can they be used with `window.crypto.subtle`. Equally, `Key` objects created with `window.crypto.subtle` cannot be used with this interface.
*/
subtleCrypto: SubtleCrypto;
/**
* Implements the WebCrypto's SubtleCrypto interface. The cryptographic operations, including key generation, are software-backed.
* Protection of the keys, and thus implementation of the non-extractable property, is done in software, so the keys are less protected than hardware-backed keys.
* Only non-extractable keys can be generated. The supported key types are RSASSA-PKCS1-V1_5 and RSA-OAEP (on Chrome versions 134+) with `modulusLength` up to 2048. Each RSASSA-PKCS1-V1_5 key can be used for signing data at most once, unless the extension is allowlisted through the KeyPermissions policy, in which case the key can be used indefinitely. RSA-OAEP keys are supported since Chrome version 134 and can be used by extensions allowlisted through that same policy to unwrap other keys.
* Implements the WebCrypto's SubtleCrypto interface. The cryptographic operations, including key generation, are software-backed. Protection of the keys, and thus implementation of the non-extractable property, is done in software, so the keys are less protected than hardware-backed keys.
*
* Only non-extractable keys can be generated. The only supported key type is RSASSA-PKCS1-V1_5 with `modulusLength` up to 2048. up to 2048. Each key can be used for signing data at most once, unless the extension is allowlisted through the KeyPermissions policy, in which case the key can be used indefinitely.
*
* Keys generated on a specific `Token` cannot be used with any other Tokens, nor can they be used with `window.crypto.subtle`. Equally, `Key` objects created with `window.crypto.subtle` cannot be used with this interface.
* @since Chrome 97
*/
@@ -9692,7 +9695,7 @@ export namespace Browser {
/** Sent after onSuspend to indicate that the app won't be unloaded after all. */
export const onSuspendCanceled: events.Event<() => void>;
/** Fired when a message is sent from either an extension process (by {@link runtime.sendMessage}) or a content script (by {@link tabs.sendMessage}). */
/** Fired when a message is sent from either {@link runtime.sendMessage} or {@link tabs.sendMessage}. */
export const onMessage: events.Event<
(message: any, sender: MessageSender, sendResponse: (response?: any) => void) => void
>;
@@ -11058,7 +11061,7 @@ export namespace Browser {
sessionId?: string | undefined;
/**
* The ID of the Split View that the tab belongs to.
* @since Chrome 145
* @since Chrome 140
*/
splitViewId?: number | undefined;
/**
@@ -11134,7 +11137,7 @@ export namespace Browser {
/**
* An ID that represents the absence of a split tab.
* @since Chrome 145
* @since Chrome 140
*/
export const SPLIT_VIEW_ID_NONE: -1;
@@ -11581,7 +11584,7 @@ export namespace Browser {
export function duplicate(tabId: number, callback: (tab?: Tab) => void): void;
/**
* Sends a single message to the content script(s) in the specified tab, with an optional callback to run when a response is sent back. The {@link runtime.onMessage} event is fired in each content script running in the specified tab for the current extension.
* Sends a single message to the content script(s) in the specified tab. The {@link runtime.onMessage} event is fired in each content script running in the specified tab for the current extension.
*
* Can return its result via Promise in Manifest V3 or later since Chrome 99.
*/
+25 -7
View File
@@ -16,12 +16,25 @@ export { SUPPORTED_LOCALES } from './supported-locales';
// TYPES
//
export type SimpleMessage = string;
export type PluralMessage = Record<'n' | number, string>;
export interface ChromeMessage {
message: string;
description?: string;
placeholders?: Record<string, { content: string; example?: string }>;
}
export type Message =
| SimpleMessage
| PluralMessage
| ChromeMessage
| Message[]
| { [key: string]: Message };
export type MessagesObject = Record<string, Message>;
export interface ParsedBaseMessage {
key: string[];
substitutions: number;
@@ -95,7 +108,7 @@ const EXT_FORMATS_MAP: Record<string, MessageFormat> = {
'.toml': 'TOML',
};
const PARSERS: Record<MessageFormat, (text: string) => any> = {
const PARSERS: Record<MessageFormat, (text: string) => MessagesObject> = {
YAML: parseYAML,
JSON5: parseJSON5,
TOML: parseTOML,
@@ -117,6 +130,7 @@ export async function parseMessagesFile(
): Promise<ParsedMessage[]> {
const text = await readFile(file, 'utf8');
const ext = extname(file).toLowerCase();
return parseMessagesText(text, EXT_FORMATS_MAP[ext] ?? 'JSON5');
}
@@ -129,7 +143,7 @@ export function parseMessagesText(
}
/** Given the JS object form of a raw messages file, extract the messages. */
export function parseMessagesObject(object: any): ParsedMessage[] {
export function parseMessagesObject(object: MessagesObject): ParsedMessage[] {
return _parseMessagesObject(
[],
{
@@ -142,7 +156,7 @@ export function parseMessagesObject(object: any): ParsedMessage[] {
function _parseMessagesObject(
path: string[],
object: any,
object: Message,
depth: number,
): ParsedMessage[] {
switch (typeof object) {
@@ -163,15 +177,17 @@ function _parseMessagesObject(
];
}
case 'object':
if ([null, undefined].includes(object)) {
if (object == null) {
throw new Error(
`Messages file should not contain \`${object}\` (found at "${path.join('.')}")`,
);
}
if (Array.isArray(object))
return object.flatMap((item, i) =>
_parseMessagesObject(path.concat(String(i)), item, depth + 1),
);
if (isPluralMessage(object)) {
const message = Object.values(object).join('|');
const substitutions = getSubstitutionCount(message);
@@ -184,6 +200,7 @@ function _parseMessagesObject(
},
];
}
if (depth === 1 && isChromeMessage(object)) {
const message = applyChromeMessagePlaceholders(object);
const substitutions = getSubstitutionCount(message);
@@ -196,6 +213,7 @@ function _parseMessagesObject(
},
];
}
return Object.entries(object).flatMap(([key, value]) =>
_parseMessagesObject(path.concat(key), value, depth + 1),
);
@@ -204,13 +222,13 @@ function _parseMessagesObject(
}
}
function isPluralMessage(object: any): object is Record<number | 'n', string> {
function isPluralMessage(object: Message): object is PluralMessage {
return Object.keys(object).every(
(key) => key === 'n' || isFinite(Number(key)),
);
}
function isChromeMessage(object: any): object is ChromeMessage {
function isChromeMessage(object: Message): object is ChromeMessage {
return Object.keys(object).every((key) =>
ALLOWED_CHROME_MESSAGE_KEYS.has(key),
);
@@ -222,7 +240,7 @@ function isChromeMessage(object: any): object is ChromeMessage {
export function generateTypeText(messages: ParsedMessage[]): string {
const renderMessageEntry = (message: ParsedMessage): string => {
// Use . for deep keys at runtime and types
// Use '.' for deep keys at runtime and types
const key = message.key.join('.');
const features = [
+21
View File
@@ -1,5 +1,26 @@
# Changelog
## v2.0.5
[compare changes](https://github.com/wxt-dev/wxt/compare/module-svelte-v2.0.4...module-svelte-v2.0.5)
### 🩹 Fixes
- Update `@sveltejs/vite-plugin-svelte` version range to support Vite 8 ([48571f50](https://github.com/wxt-dev/wxt/commit/48571f50))
### 🏡 Chore
- Upgrade dev and non-major prod dependencies ([#2000](https://github.com/wxt-dev/wxt/pull/2000))
- Use `tsdown` to build packages ([#2006](https://github.com/wxt-dev/wxt/pull/2006))
- Move script-only dev dependencies to top-level `package.json` ([#2007](https://github.com/wxt-dev/wxt/pull/2007))
- Update dependencies ([#2069](https://github.com/wxt-dev/wxt/pull/2069))
- **deps:** Upgrade deps ([#2175](https://github.com/wxt-dev/wxt/pull/2175))
- Add prepack script to all packages ([032f7931](https://github.com/wxt-dev/wxt/commit/032f7931))
### ❤️ Contributors
- Aaron ([@aklinker1](https://github.com/aklinker1))
## v2.0.4
[compare changes](https://github.com/wxt-dev/wxt/compare/module-svelte-v2.0.3...module-svelte-v2.0.4)
+2 -2
View File
@@ -18,7 +18,7 @@
},
"license": "MIT",
"funding": "https://github.com/sponsors/wxt-dev",
"version": "2.0.4",
"version": "2.0.5",
"type": "module",
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
@@ -48,7 +48,7 @@
"svelte": ">=5"
},
"dependencies": {
"@sveltejs/vite-plugin-svelte": "^4.0.0 || ^5.0.0 || ^6.0.0"
"@sveltejs/vite-plugin-svelte": ">=4"
},
"devDependencies": {
"publint": "^0.3.18",
+24
View File
@@ -1,5 +1,29 @@
# Changelog
## v0.20.20
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.20.19...wxt-v0.20.20)
### 🩹 Fixes
- Unlisted script return values broken with Vite 8 sourcemaps ([#2197](https://github.com/wxt-dev/wxt/pull/2197))
### 📖 Documentation
- Add Dymo extension ID to UsingWxtSection.vue ([#2187](https://github.com/wxt-dev/wxt/pull/2187))
- Add Extension Rank Checker to the list of extensions ([#2193](https://github.com/wxt-dev/wxt/pull/2193))
### 🏡 Chore
- **deps:** Add vite-node 6 support ([64b68671](https://github.com/wxt-dev/wxt/commit/64b68671))
### ❤️ Contributors
- Aaron ([@aklinker1](https://github.com/aklinker1))
- Joseph Hu ([@KiJO94GO](https://github.com/KiJO94GO))
- FJRG2007 ツ ([@FJRG2007](https://github.com/FJRG2007))
- Hampus Tågerud ([@hampustagerud](https://github.com/hampustagerud))
## v0.20.19
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.20.18...wxt-v0.20.19)
+4 -4
View File
@@ -1,7 +1,7 @@
{
"name": "wxt",
"type": "module",
"version": "0.20.19",
"version": "0.20.20",
"description": "⚡ Next-gen Web Extension Framework",
"license": "MIT",
"scripts": {
@@ -30,7 +30,6 @@
"ci-info": "^4.4.0",
"consola": "^3.4.2",
"defu": "^6.1.4",
"dotenv": "^17.3.1",
"dotenv-expand": "^12.0.3",
"esbuild": "^0.27.1",
"filesize": "^11.0.13",
@@ -43,7 +42,6 @@
"jszip": "^3.10.1",
"linkedom": "^0.18.12",
"magicast": "^0.5.2",
"minimatch": "^10.2.4",
"nano-spawn": "^2.0.0",
"nanospinner": "^1.2.2",
"normalize-path": "^3.0.0",
@@ -52,13 +50,14 @@
"open": "^11.0.0",
"perfect-debounce": "^2.1.0",
"picocolors": "^1.1.1",
"picomatch": "^4.0.3",
"prompts": "^2.4.2",
"publish-browser-extension": "^2.3.0 || ^3.0.2 || ^4.0.4",
"scule": "^1.3.0",
"tinyglobby": "^0.2.15",
"unimport": "^3.13.1 || ^4.0.0 || ^5.0.0 || ^6.0.0",
"vite": "^5.4.19 || ^6.3.4 || ^7.0.0 || ^8.0.0-0",
"vite-node": "^3.2.4 || ^5.0.0",
"vite-node": "^3.2.4 || ^5.0.0 || ^6.0.0",
"web-ext-run": "^0.2.4"
},
"peerDependencies": {
@@ -74,6 +73,7 @@
"@types/lodash.merge": "^4.6.9",
"@types/node": "^20.17.6",
"@types/normalize-path": "^3.0.2",
"@types/picomatch": "^4.0.2",
"@types/prompts": "^2.4.9",
"eslint": "^10.0.0",
"extract-zip": "^2.0.1",
@@ -0,0 +1,119 @@
import { describe, expect, it } from 'vitest';
import { iifeFooter } from '../iifeFooter';
interface OutputChunk {
type: 'chunk';
code: string;
isEntry: boolean;
}
interface OutputAsset {
type: 'asset';
source: string;
}
type OutputBundle = Record<string, OutputChunk | OutputAsset>;
function dedent(code: string) {
const lines = code.trim().split('\n');
return lines.map((line) => line.trimStart()).join('\n');
}
function createBundle(code: string): OutputBundle {
return {
'entry.js': {
type: 'chunk',
code: dedent(code),
isEntry: true,
},
};
}
function getCode(bundle: OutputBundle): string {
const entry = bundle['entry.js'];
if (entry.type !== 'chunk') {
throw new Error('expected chunk');
}
return entry.code;
}
function runPlugin(name: string, bundle: OutputBundle) {
const plugin = iifeFooter(name);
// @ts-expect-error -- calling the hook directly
plugin.generateBundle(undefined, bundle);
}
describe('IIFE return value plugin', () => {
it('should append return value when no sourcemap comment', () => {
const bundle = createBundle(`
var foo = (function(){return 1})();
`);
runPlugin('foo', bundle);
expect(getCode(bundle)).toBe(
dedent(`
var foo = (function(){return 1})();
foo;
`),
);
});
it('should insert return value before sourcemap comment', () => {
const bundle = createBundle(`
var foo = (function(){return 1})();
//# ${'sourceMappingURL'}=foo.js.map
`);
runPlugin('foo', bundle);
expect(getCode(bundle)).toBe(
dedent(`
var foo = (function(){return 1})();
foo;
//# ${'sourceMappingURL'}=foo.js.map
`),
);
});
it('should insert return value before inline sourcemap', () => {
const bundle = createBundle(`
var foo = (function(){return 1})();
//# ${'sourceMappingURL'}=data:application/json;base64,abc123
`);
runPlugin('foo', bundle);
expect(getCode(bundle)).toBe(
dedent(`
var foo = (function(){return 1})();
foo;
//# ${'sourceMappingURL'}=data:application/json;base64,abc123
`),
);
});
it('should skip non-entry chunks', () => {
const bundle = createBundle('var x = 1;');
(bundle['entry.js'] as OutputChunk).isEntry = false;
runPlugin('x', bundle);
expect(getCode(bundle)).toBe('var x = 1;');
});
it('should skip assets', () => {
const bundle: OutputBundle = {
'style.css': {
type: 'asset',
source: 'body {}',
} satisfies OutputAsset,
};
runPlugin('style', bundle);
expect((bundle['style.css'] as OutputAsset).source).toBe('body {}');
});
});
@@ -13,7 +13,20 @@ export function iifeFooter(iifeReturnValueName: string): Plugin {
generateBundle(_, bundle) {
for (const chunk of Object.values(bundle)) {
if (chunk.type === 'chunk' && chunk.isEntry) {
chunk.code += `${iifeReturnValueName};`;
const code = chunk.code;
const marker = '\n//# sourceMappingURL=';
const returnValue = `${iifeReturnValueName};`;
const index = code.indexOf(marker);
if (index >= 0) {
chunk.code =
code.slice(0, index + 1) +
`${returnValue}\n` +
code.slice(index + 1);
} else {
chunk.code += `\n${returnValue}`;
}
}
}
},
@@ -1,46 +0,0 @@
import { describe, it, expect } from 'vitest';
import { minimatchMultiple } from '../minimatch-multiple';
describe('minimatchMultiple', () => {
it('should return false if the pattern array is undefined', () => {
const patterns = undefined;
const search = 'test.json';
expect(minimatchMultiple(search, patterns)).toBe(false);
});
it('should return false if the pattern array is empty', () => {
const patterns: string[] = [];
const search = 'test.json';
expect(minimatchMultiple(search, patterns)).toBe(false);
});
it('should return true if the pattern array contains a match', () => {
const patterns = ['test.yml', 'test.json'];
const search = 'test.json';
expect(minimatchMultiple(search, patterns)).toBe(true);
});
it('should return false if the pattern array does not contain a match', () => {
const patterns = ['test.yml', 'test.json'];
const search = 'test.txt';
expect(minimatchMultiple(search, patterns)).toBe(false);
});
it('should return false if the pattern matches a negative pattern', () => {
const patterns = ['test.*', '!test.json'];
const search = 'test.json';
expect(minimatchMultiple(search, patterns)).toBe(false);
});
it('should return false if the pattern matches a negative pattern, regardless of order', () => {
const patterns = ['!test.json', 'test.*'];
const search = 'test.json';
expect(minimatchMultiple(search, patterns)).toBe(false);
});
});
@@ -0,0 +1,71 @@
import { describe, it, expect } from 'vitest';
import { picomatchMultiple } from '../picomatch-multiple';
describe('picomatchMultiple', () => {
it('should return false if the pattern array is undefined', () => {
const patterns = undefined;
const search = 'test.json';
expect(picomatchMultiple(search, patterns)).toBe(false);
});
it('should return false if the pattern array is empty', () => {
const patterns: string[] = [];
const search = 'test.json';
expect(picomatchMultiple(search, patterns)).toBe(false);
});
it('should return true if the pattern array contains a match', () => {
const patterns = ['test.yml', 'test.json'];
const search = 'test.json';
expect(picomatchMultiple(search, patterns)).toBe(true);
});
it('should return false if the pattern array does not contain a match', () => {
const patterns = ['test.yml', 'test.json'];
const search = 'test.txt';
expect(picomatchMultiple(search, patterns)).toBe(false);
});
it('should return false if the pattern matches a negative pattern', () => {
const patterns = ['test.*', '!test.json'];
const search = 'test.json';
expect(picomatchMultiple(search, patterns)).toBe(false);
});
it('should return false if the pattern matches a negative pattern, regardless of order', () => {
const patterns = ['!test.json', 'test.*'];
const search = 'test.json';
expect(picomatchMultiple(search, patterns)).toBe(false);
});
it('should support extglob-like extension matching', () => {
const patterns = ['content.[jt]s?(x)'];
expect(picomatchMultiple('content.ts', patterns)).toBe(true);
expect(picomatchMultiple('content.jsx', patterns)).toBe(true);
expect(picomatchMultiple('content.css', patterns)).toBe(false);
});
it('should support nested paths', () => {
const patterns = ['foo/**/*.ts'];
expect(picomatchMultiple('foo/bar/baz.ts', patterns)).toBe(true);
expect(picomatchMultiple('foo/bar/baz.js', patterns)).toBe(false);
});
it('should preserve include/exclude interaction used by zip filtering', () => {
const include = ['special.txt'];
const exclude = ['**/*.txt'];
const search = 'special.txt';
const shouldInclude =
picomatchMultiple(search, include) || !picomatchMultiple(search, exclude);
expect(shouldInclude).toBe(true);
});
});
@@ -13,7 +13,7 @@ import {
UnlistedScriptEntrypoint,
} from '../../../types';
import { mkdir, readFile, writeFile } from 'node:fs/promises';
import { minimatch } from 'minimatch';
import picomatch from 'picomatch';
import { parseHTML } from 'linkedom';
import JSON5 from 'json5';
import { glob } from 'tinyglobby';
@@ -61,7 +61,7 @@ export async function findEntrypoints(): Promise<Entrypoint[]> {
const inputPath = resolve(wxt.config.entrypointsDir, relativePath);
const name = getEntrypointName(wxt.config.entrypointsDir, inputPath);
const matchingGlob = pathGlobs.find((glob) =>
minimatch(relativePath, glob),
picomatch(glob)(relativePath),
);
if (matchingGlob) {
const type = PATH_GLOB_TO_TYPE_MAP[matchingGlob];
+37 -15
View File
@@ -1,23 +1,45 @@
import { config } from 'dotenv';
import { readFileSync, existsSync } from 'node:fs';
import { parseEnv } from 'node:util';
import { expand } from 'dotenv-expand';
import type { TargetBrowser } from '../../types';
/** Load environment files based on the current mode and browser. */
export function loadEnv(mode: string, browser: TargetBrowser) {
return expand(
config({
quiet: true,
// Files on top override files below
path: [
`.env.${mode}.${browser}.local`,
`.env.${mode}.${browser}`,
`.env.${browser}.local`,
`.env.${browser}`,
`.env.${mode}.local`,
`.env.${mode}`,
`.env.local`,
`.env`,
],
const envFiles = [
// List is ordered with general files first, specific ones last, so the more
// specific files override the more general ones in the loop below.
`.env`,
`.env.local`,
`.env.${mode}`,
`.env.${mode}.local`,
`.env.${browser}`,
`.env.${browser}.local`,
`.env.${mode}.${browser}`,
`.env.${mode}.${browser}.local`,
];
const parsed = Object.fromEntries<string>(
envFiles.flatMap((filePath) => {
if (!existsSync(filePath)) return [];
try {
const content = readFileSync(filePath, 'utf-8');
const parsedEnv = parseEnv(content);
return Object.entries(parsedEnv) as [string, string][];
} catch {
return [];
}
}),
);
// Make a copy of `process.env` so that `dotenv-expand` doesn't re-assign the
// expanded values to the global `process.env`.
const processEnv = { ...process.env } as Record<string, string>;
expand({
parsed,
processEnv,
});
return parsed;
}
@@ -1,7 +1,7 @@
import { minimatch, MinimatchOptions } from 'minimatch';
import picomatch, { PicomatchOptions } from 'picomatch';
/**
* Run [`minimatch`](https://npmjs.com/package/minimatch) against multiple
* Run [`picomatch`](https://npmjs.com/package/picomatch) against multiple
* patterns.
*
* Supports negated patterns, the order does not matter. If your `search` string
@@ -9,14 +9,14 @@ import { minimatch, MinimatchOptions } from 'minimatch';
*
* @example
* ```ts
* minimatchMultiple('a.json', ['*.json', '!b.json']); // => true
* minimatchMultiple('b.json', ['*.json', '!b.json']); // => false
* picomatchMultiple('a.json', ['*.json', '!b.json']); // => true
* picomatchMultiple('b.json', ['*.json', '!b.json']); // => false
* ```;
*/
export function minimatchMultiple(
export function picomatchMultiple(
search: string,
patterns: string[] | undefined,
options?: MinimatchOptions,
options?: PicomatchOptions,
): boolean {
if (patterns == null) return false;
@@ -29,12 +29,12 @@ export function minimatchMultiple(
if (
negatePatterns.some((negatePattern) =>
minimatch(search, negatePattern, options),
picomatch(negatePattern, options)(search),
)
)
return false;
return positivePatterns.some((positivePattern) =>
minimatch(search, positivePattern, options),
picomatch(positivePattern, options)(search),
);
}
+3 -3
View File
@@ -11,7 +11,7 @@ import { registerWxt, wxt } from './wxt';
import JSZip from 'jszip';
import { glob } from 'tinyglobby';
import { normalizePath } from './utils';
import { minimatchMultiple } from './utils/minimatch-multiple';
import { picomatchMultiple } from './utils/picomatch-multiple';
/**
* Build and zip the extension for distribution.
@@ -125,8 +125,8 @@ async function zipDir(
})
).filter((relativePath) => {
return (
minimatchMultiple(relativePath, options?.include) ||
!minimatchMultiple(relativePath, options?.exclude)
picomatchMultiple(relativePath, options?.include) ||
!picomatchMultiple(relativePath, options?.exclude)
);
});
const filesToZip = [
+3 -3
View File
@@ -212,7 +212,7 @@ export interface InlineConfig {
*/
sourcesRoot?: string;
/**
* [Minimatch](https://www.npmjs.com/package/minimatch) patterns of files to
* [Picomatch](https://www.npmjs.com/package/picomatch) patterns of files to
* include when creating a ZIP of all your source code for Firefox. Patterns
* are relative to your `config.zip.sourcesRoot`.
*
@@ -226,7 +226,7 @@ export interface InlineConfig {
*/
includeSources?: string[];
/**
* [Minimatch](https://www.npmjs.com/package/minimatch) patterns of files to
* [Picomatch](https://www.npmjs.com/package/picomatch) patterns of files to
* exclude when creating a ZIP of all your source code for Firefox. Patterns
* are relative to your `config.zip.sourcesRoot`.
*
@@ -239,7 +239,7 @@ export interface InlineConfig {
*/
excludeSources?: string[];
/**
* [Minimatch](https://www.npmjs.com/package/minimatch) patterns of files to
* [Picomatch](https://www.npmjs.com/package/picomatch) patterns of files to
* exclude when zipping the extension.
*
* @example
+18 -13
View File
@@ -173,8 +173,8 @@ importers:
version: 1.2.16
devDependencies:
'@types/chrome':
specifier: 0.1.37
version: 0.1.37
specifier: 0.1.38
version: 0.1.38
'@types/node':
specifier: ^20.0.0
version: 20.19.32
@@ -297,7 +297,7 @@ importers:
packages/module-svelte:
dependencies:
'@sveltejs/vite-plugin-svelte':
specifier: ^4.0.0 || ^5.0.0 || ^6.0.0
specifier: '>=4'
version: 6.2.4(vite@7.3.1(@types/node@20.19.32)(jiti@2.6.1)(sass@1.97.3)(tsx@4.21.0)(yaml@2.8.2))
devDependencies:
publint:
@@ -456,9 +456,6 @@ importers:
defu:
specifier: ^6.1.4
version: 6.1.4
dotenv:
specifier: ^17.3.1
version: 17.3.1
dotenv-expand:
specifier: ^12.0.3
version: 12.0.3
@@ -495,9 +492,6 @@ importers:
magicast:
specifier: ^0.5.2
version: 0.5.2
minimatch:
specifier: ^10.2.4
version: 10.2.4
nano-spawn:
specifier: ^2.0.0
version: 2.0.0
@@ -522,6 +516,9 @@ importers:
picocolors:
specifier: ^1.1.1
version: 1.1.1
picomatch:
specifier: ^4.0.3
version: 4.0.3
prompts:
specifier: ^2.4.2
version: 2.4.2
@@ -541,7 +538,7 @@ importers:
specifier: ^5.4.19 || ^6.3.4 || ^7.0.0 || ^8.0.0-0
version: 7.3.1(@types/node@20.19.32)(jiti@2.6.1)(sass@1.97.3)(tsx@4.21.0)(yaml@2.8.2)
vite-node:
specifier: ^3.2.4 || ^5.0.0
specifier: ^3.2.4 || ^5.0.0 || ^6.0.0
version: 5.3.0(@types/node@20.19.32)(jiti@2.6.1)(sass@1.97.3)(tsx@4.21.0)(yaml@2.8.2)
web-ext-run:
specifier: ^0.2.4
@@ -559,6 +556,9 @@ importers:
'@types/normalize-path':
specifier: ^3.0.2
version: 3.0.2
'@types/picomatch':
specifier: ^4.0.2
version: 4.0.2
'@types/prompts':
specifier: ^2.4.9
version: 2.4.9
@@ -2129,8 +2129,8 @@ packages:
'@types/chai@5.2.3':
resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==}
'@types/chrome@0.1.37':
resolution: {integrity: sha512-IJE4ceuDO7lrEuua7Pow47zwNcI8E6qqkowRP7aFPaZ0lrjxh6y836OPqqkIZeTX64FTogbw+4RNH0+QrweCTQ==}
'@types/chrome@0.1.38':
resolution: {integrity: sha512-5aK4m9wZqoWAoB98aElESLm/5pXpqJnFWMNoiCs/XdPsXR6wNdVkJFSdQ9Wr4PnTuUrxD0SuNuDHh3EG5QeBzA==}
'@types/debug@4.1.12':
resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==}
@@ -2195,6 +2195,9 @@ packages:
'@types/normalize-path@3.0.2':
resolution: {integrity: sha512-DO++toKYPaFn0Z8hQ7Tx+3iT9t77IJo/nDiqTXilgEP+kPNIYdpS9kh3fXuc53ugqwp9pxC1PVjCpV1tQDyqMA==}
'@types/picomatch@4.0.2':
resolution: {integrity: sha512-qHHxQ+P9PysNEGbALT8f8YOSHW0KJu6l2xU8DYY0fu/EmGxXdVnuTLvFUvBgPJMSqXq29SYHveejeAha+4AYgA==}
'@types/prompts@2.4.9':
resolution: {integrity: sha512-qTxFi6Buiu8+50/+3DGIWLHM6QuWsEKugJnnP6iv2Mc4ncxE4A/OJkjuVOA+5X0X1S/nq5VJRa8Lu+nwcvbrKA==}
@@ -6237,7 +6240,7 @@ snapshots:
'@types/deep-eql': 4.0.2
assertion-error: 2.0.1
'@types/chrome@0.1.37':
'@types/chrome@0.1.38':
dependencies:
'@types/filesystem': 0.0.36
'@types/har-format': 1.2.16
@@ -6299,6 +6302,8 @@ snapshots:
'@types/normalize-path@3.0.2': {}
'@types/picomatch@4.0.2': {}
'@types/prompts@2.4.9':
dependencies:
'@types/node': 20.19.32
+1 -1
View File
@@ -23,6 +23,6 @@
"@types/react-dom": "^19.2.3",
"@wxt-dev/module-react": "^1.1.5",
"typescript": "^5.9.3",
"wxt": "^0.20.19"
"wxt": "^0.20.20"
}
}
+1 -1
View File
@@ -20,6 +20,6 @@
"devDependencies": {
"@wxt-dev/module-solid": "^1.1.4",
"typescript": "^5.9.3",
"wxt": "^0.20.19"
"wxt": "^0.20.20"
}
}
+1 -1
View File
@@ -21,6 +21,6 @@
"svelte-check": "^4.4.4",
"tslib": "^2.8.1",
"typescript": "^5.9.3",
"wxt": "^0.20.19"
"wxt": "^0.20.20"
}
}
+1 -4
View File
@@ -1,6 +1,3 @@
{
"extends": "./.wxt/tsconfig.json",
"compilerOptions": {
"useDefineForClassFields": true
}
"extends": "./.wxt/tsconfig.json"
}
+1 -1
View File
@@ -16,6 +16,6 @@
},
"devDependencies": {
"typescript": "^5.9.3",
"wxt": "^0.20.19"
"wxt": "^0.20.20"
}
}
+1 -1
View File
@@ -21,6 +21,6 @@
"@wxt-dev/module-vue": "^1.0.3",
"typescript": "^5.9.3",
"vue-tsc": "^3.2.5",
"wxt": "^0.20.19"
"wxt": "^0.20.20"
}
}