Compare commits

...

29 Commits

Author SHA1 Message Date
GitHub Actions 1c3009a48f chore(release): @wxt-dev/i18n v0.2.0
vhs / vhs (push) Waiting to run
2024-10-04 23:12:34 +00:00
Aaron 6c6087249f fix!: Remove invalid options argument (#1048) 2024-10-04 18:07:57 -05:00
Aaron 539d482f71 chore: Remove TS compilerOptions.noUnusedLocals because Oxlint already does it (#1047) 2024-10-04 16:48:35 -05:00
Aaron cab97bca1e perf: Downgrade esbuild so a single version is shared between sub-dependencies (#1045) 2024-10-04 16:48:25 -05:00
Florian Metz 6020083b89 perf: Replace execa with nano-spawn for smaller package size (#1042) 2024-10-04 16:38:06 -05:00
GitHub Actions 947b24f1b0 chore(release): @wxt-dev/i18n v0.1.1
vhs / vhs (push) Waiting to run
2024-10-04 18:24:18 +00:00
windmillcode0 2c5ba64b61 fix: Friendly error messages for null and undefined values inside message files (#1041)
Co-authored-by: windmillcode0 <michaelodumosu57@gmail.com>
2024-10-04 13:19:35 -05:00
Aaron faa4fcb718 chore: Upgrade all non-major dependencies (#1040) 2024-10-03 18:47:16 -05:00
dependabot[bot] 8e9b67fea2 chore(deps): bump execa from 9.3.1 to 9.4.0 (#1031)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-03 18:24:43 -05:00
dependabot[bot] 659bdd46a0 chore(deps): bump linkedom from 0.18.4 to 0.18.5 (#1034)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-03 13:25:47 -05:00
dependabot[bot] edcc411d26 chore(deps-dev): bump changelogen from 0.5.5 to 0.5.7 (#1019)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-03 13:25:11 -05:00
dependabot[bot] e022423bad chore(deps): bump @vitejs/plugin-vue from 5.1.1 to 5.1.4 (#1020)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-03 13:13:24 -05:00
dependabot[bot] 84e1fd44eb chore(deps): bump esbuild from 0.23.0 to 0.24.0 (#1018)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-03 13:13:00 -05:00
dependabot[bot] b68d1ff828 chore(deps): bump magicast from 0.3.4 to 0.3.5 (#1017)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-03 13:11:46 -05:00
dependabot[bot] c31a5c30ed chore(deps): bump stefanzweifel/git-auto-commit-action from 4 to 5 (#1022)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-03 13:10:26 -05:00
Aaron 5b408c2bc2 chore: Update dependabot configuration 2024-10-03 13:09:01 -05:00
mezannic ca29419db6 chore: remove email from changelog (#1027) 2024-10-03 13:04:33 -05:00
Aaron ab26bdc7c1 fix: Use directory name when zip.name and package.json#name are not provided (#1028) 2024-10-03 12:26:36 -05:00
GitHub Actions d270250633 chore(release): wxt v0.19.11
vhs / vhs (push) Waiting to run
2024-10-02 13:59:29 +00:00
Florian Metz d75f64df79 feat(zip): wxt zip --sources and auto sources for opera (#1014)
Co-authored-by: Timeraa <Timeraa@users.noreply.github.com>
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2024-10-02 08:55:08 -05:00
Gurvir Singh 5faa5d7537 fix: #1005 fixed, by updating type-definations to getItem method. (#1007)
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2024-10-02 08:20:32 -05:00
mezannic 177223c625 fix: Reverse env files priority (#1016)
Co-authored-by: Mathieu Ezannic <mathieu.ezannic@plebicom.com>
2024-10-01 16:00:52 -05:00
deyu a64ff22917 docs: Add "Discord Message Translator" extension to homepage (#1011) 2024-09-29 21:57:23 -05:00
Gourav Goyal 0bf08329b0 docs: Add "ChatGPT Writer" to homepage (#1006) 2024-09-27 20:50:21 -05:00
Guilherme Oenning e3f00d2797 docs: Add "Dofollow Links for SEO" to homepage (#1001)
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2024-09-27 08:03:06 -05:00
Andy Zhou 09de72895e docs: Add "social-media-copilot" to homepage (#1000) 2024-09-27 08:02:23 -05:00
Aaron c0aa12089e chore: Move some files around (#996) 2024-09-25 20:54:40 -05:00
Aaron 0248f58785 chore: Add Aaron back to changelog contributions 2024-09-25 20:11:02 -05:00
Florian Metz 247cd66f74 feat(zip): hooks (#993)
Co-authored-by: Timeraa <Timeraa@users.noreply.github.com>
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2024-09-25 20:08:54 -05:00
59 changed files with 1896 additions and 1383 deletions
+3 -1
View File
@@ -6,7 +6,9 @@
version: 2
updates:
- package-ecosystem: npm
directory: '/' # Location of package manifests
directories:
- /
- packages/*
schedule:
interval: 'monthly'
- package-ecosystem: 'github-actions'
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
- uses: charmbracelet/vhs-action@v2.1.0
with:
path: 'docs/tapes/init-demo.tape'
- uses: stefanzweifel/git-auto-commit-action@v4
- uses: stefanzweifel/git-auto-commit-action@v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
@@ -40,6 +40,10 @@ const chromeExtensionIds = [
'fonflmjnjbkigocpoommgmhljdpljain', // NiceTab - https://github.com/web-dahuyou/NiceTab
'fcffekbnfcfdemeekijbbmgmkognnmkd', // Draftly for LinkedIn
'nkndldfehcidpejfkokbeghpnlbppdmo', // YouTube Summarized - Summarize any YouTube video
'dbichmdlbjdeplpkhcejgkakobjbjalc', // 社媒助手 - https://github.com/iszhouhua/social-media-copilot
'opepfpjeogkbgeigkbepobceinnfmjdd', // Dofollow Links for SEO
'pdnenlnelpdomajfejgapbdpmjkfpjkp', // ChatGPT Writer: Use AI on Any Site (GPT-4o, Claude, Gemini, and More)
'jobnhifpphkgoelnhnopgkdhbdkiadmj', // discord message translator
];
const { data, err, isLoading } = useListExtensionDetails(chromeExtensionIds);
+4 -3
View File
@@ -1,6 +1,6 @@
import { resolve, join } from 'node:path';
import { resolve } from 'node:path';
import consola from 'consola';
import { execaCommand } from 'execa';
import spawn from 'nano-spawn';
const cliDir = resolve('packages/wxt/src/cli/commands');
const cliDirGlob = resolve(cliDir, '**');
@@ -37,7 +37,8 @@ export default {
};
async function getHelp(command: string): Promise<string> {
const res = await execaCommand(command + ' --help', {
const args = command.split(' ');
const res = await spawn(args[0], [...args.slice(1), '--help'], {
cwd: 'packages/wxt',
});
return res.stdout;
Binary file not shown.

Before

Width:  |  Height:  |  Size: 137 KiB

After

Width:  |  Height:  |  Size: 136 KiB

+11 -16
View File
@@ -4,7 +4,7 @@
"engines": {
"node": ">=18.20.3"
},
"packageManager": "pnpm@9.6.0",
"packageManager": "pnpm@9.12.0",
"scripts": {
"check": "check && pnpm -r --sequential run check",
"test": "pnpm -r --sequential run test run",
@@ -17,18 +17,18 @@
"docs:preview": "pnpm -s docs:gen && vitepress preview docs"
},
"devDependencies": {
"@aklinker1/buildc": "^1.1.1",
"@aklinker1/buildc": "^1.1.4",
"@aklinker1/check": "^1.4.5",
"@types/fs-extra": "^11.0.4",
"@vitest/coverage-v8": "^2.0.4",
"changelogen": "^0.5.5",
"@vitest/coverage-v8": "^2.1.2",
"changelogen": "^0.5.7",
"consola": "^3.2.3",
"dependency-graph": "^1.0.0",
"execa": "^9.3.1",
"fast-glob": "^3.3.2",
"fs-extra": "^11.2.0",
"hasha": "^6.0.0",
"lint-staged": "^15.2.7",
"lint-staged": "^15.2.10",
"nano-spawn": "^0.1.0",
"npm-run-all": "^4.1.5",
"prettier": "^3.3.3",
"simple-git-hooks": "^2.11.1",
@@ -36,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.4",
"vitepress": "^1.3.1",
"vitest-mock-extended": "^2.0.0",
"vue": "^3.4.34",
"typescript": "^5.6.2",
"vitepress": "^1.3.4",
"vitest-mock-extended": "^2.0.2",
"vue": "^3.5.11",
"wxt": "workspace:*",
"yaml": "^2.5.0"
"yaml": "^2.5.1"
},
"simple-git-hooks": {
"pre-commit": "pnpm lint-staged"
@@ -56,10 +56,5 @@
"search-insights"
]
}
},
"changelog": {
"excludeAuthors": [
"aaronklinker1@gmail.com"
]
}
}
+3 -3
View File
@@ -46,9 +46,9 @@
},
"devDependencies": {
"@aklinker1/check": "^1.4.5",
"oxlint": "^0.9.1",
"publint": "^0.2.9",
"typescript": "^5.5.4",
"oxlint": "^0.9.9",
"publint": "^0.2.11",
"typescript": "^5.6.2",
"unbuild": "^2.0.0",
"wxt": "workspace:*"
},
+35
View File
@@ -0,0 +1,35 @@
# Changelog
## v0.2.0
[⚠️ breaking changes](https://wxt.dev/guide/upgrade-guide/wxt) &bull; [compare changes](https://github.com/wxt-dev/wxt/compare/i18n-v0.1.1...i18n-v0.2.0)
### 🩹 Fixes
- ⚠️ Remove invalid options argument ([#1048](https://github.com/wxt-dev/wxt/pull/1048))
#### ⚠️ Breaking Changes
- ⚠️ Remove invalid options argument ([#1048](https://github.com/wxt-dev/wxt/pull/1048))
### ❤️ Contributors
- Aaron ([@aklinker1](http://github.com/aklinker1))
## v0.1.1
[compare changes](https://github.com/wxt-dev/wxt/compare/i18n-v0.1.0...i18n-v0.1.1)
### 🩹 Fixes
- Friendly error messages for `null` and `undefined` values inside message files ([#1041](https://github.com/wxt-dev/wxt/pull/1041))
### 🏡 Chore
- Add `oxlint` for linting ([#947](https://github.com/wxt-dev/wxt/pull/947))
- Upgrade all non-major dependencies ([#1040](https://github.com/wxt-dev/wxt/pull/1040))
### ❤️ Contributors
- Windmillcode0 <shieldmousetower734@gmail.com>
- Aaron ([@aklinker1](http://github.com/aklinker1))
+6 -6
View File
@@ -1,7 +1,7 @@
{
"name": "@wxt-dev/i18n",
"description": "Type-safe wrapper around browser.i18n.getMessage with additional features",
"version": "0.1.0",
"version": "0.2.0",
"type": "module",
"repository": {
"type": "git",
@@ -40,12 +40,12 @@
"devDependencies": {
"@aklinker1/check": "^1.4.5",
"@types/chrome": "^0.0.268",
"@types/node": "^20.14.2",
"oxlint": "^0.9.1",
"publint": "^0.2.8",
"typescript": "^5.4.5",
"@types/node": "^20.16.10",
"oxlint": "^0.9.9",
"publint": "^0.2.11",
"typescript": "^5.6.2",
"unbuild": "^2.0.0",
"vitest": "^1.6.0",
"vitest": "^2.0.0",
"vitest-plugin-random-seed": "^1.1.0",
"wxt": "workspace:*"
},
+13
View File
@@ -161,4 +161,17 @@ describe('Built Tools', () => {
);
expect(mockWriteFile).toBeCalledWith('output.d.ts', expectedDts, 'utf8');
});
it('should throw an error if messages file contains null or undefined', async () => {
const invalidFileContent = stringifyYAML({
simple: 'example',
invalidField: null,
});
mockReadFile.mockResolvedValue(invalidFileContent);
await expect(parseMessagesFile('invalid.yml')).rejects.toThrowError(
'Messages file should not contain `null` (found at "invalidField")',
);
});
});
+3 -19
View File
@@ -1,6 +1,5 @@
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { createI18n } from '../index';
import { GetMessageOptions } from '../types';
const getMessageMock = vi.fn();
@@ -28,7 +27,7 @@ describe('createI18n', () => {
expect(actual).toBe(expectedValue);
expect(getMessageMock).toBeCalledTimes(1);
expect(getMessageMock).toBeCalledWith(expectedKey, undefined);
expect(getMessageMock).toBeCalledWith(expectedKey);
});
it.each([
@@ -55,28 +54,13 @@ describe('createI18n', () => {
expect(actual).toBe(expected);
expect(getMessageMock).toBeCalledTimes(1);
expect(getMessageMock).toBeCalledWith(key, [String(count)], undefined);
expect(getMessageMock).toBeCalledWith(key, [String(count)]);
},
);
it('should allow overriding the plural substitutions', () => {
const i18n = createI18n();
i18n.t('key', 3, ['custom']);
expect(getMessageMock).toBeCalledWith('key', ['custom'], undefined);
});
it('should pass options into browser.i18n.getMessage', () => {
const i18n = createI18n();
const options: GetMessageOptions = {
escapeLt: true,
};
i18n.t('key', options);
i18n.t('key', [''], options);
i18n.t('key', 1, options);
i18n.t('key', 1, [''], options);
getMessageMock.mock.calls.forEach((call) => {
expect(call.pop()).toEqual(options);
});
expect(getMessageMock).toBeCalledWith('key', ['custom']);
});
});
+1 -12
View File
@@ -22,13 +22,9 @@ describe('I18n Types', () => {
describe('t', () => {
it('should allow passing any combination of arguments', () => {
i18n.t('any');
i18n.t('any', { escapeLt: true });
i18n.t('any', ['one']);
i18n.t('any', ['one'], { escapeLt: true });
i18n.t('any', ['one', 'two']);
i18n.t('any', ['one', 'two'], { escapeLt: true });
i18n.t('any', n, ['one', 'two']);
i18n.t('any', n, ['one', 'two'], { escapeLt: true });
});
});
});
@@ -46,7 +42,6 @@ describe('I18n Types', () => {
describe('t', () => {
it('should only allow passing valid combinations of arguments', () => {
i18n.t('simple');
i18n.t('simple', { escapeLt: true });
// @ts-expect-error
i18n.t('simple', []);
// @ts-expect-error
@@ -55,7 +50,6 @@ describe('I18n Types', () => {
i18n.t('simple', n);
i18n.t('simpleSub1', ['one']);
i18n.t('simpleSub1', ['one'], { escapeLt: true });
// @ts-expect-error
i18n.t('simpleSub1');
// @ts-expect-error
@@ -66,7 +60,6 @@ describe('I18n Types', () => {
i18n.t('simpleSub1', n);
i18n.t('simpleSub2', ['one', 'two']);
i18n.t('simpleSub2', ['one', 'two'], { escapeLt: true });
// @ts-expect-error
i18n.t('simpleSub2');
// @ts-expect-error
@@ -77,7 +70,6 @@ describe('I18n Types', () => {
i18n.t('simpleSub2', n);
i18n.t('plural', n);
i18n.t('plural', n, { escapeLt: true });
// @ts-expect-error
i18n.t('plural');
// @ts-expect-error
@@ -88,10 +80,8 @@ describe('I18n Types', () => {
i18n.t('plural', n, ['sub']);
i18n.t('pluralSub1', n);
i18n.t('pluralSub1', n, { escapeLt: true });
i18n.t('pluralSub1', n, undefined, { escapeLt: true });
i18n.t('pluralSub1', n, undefined);
i18n.t('pluralSub1', n, ['one']);
i18n.t('pluralSub1', n, ['one'], { escapeLt: true });
// @ts-expect-error
i18n.t('pluralSub1');
// @ts-expect-error
@@ -102,7 +92,6 @@ describe('I18n Types', () => {
i18n.t('pluralSub1', n, ['one', 'two']);
i18n.t('pluralSub2', n, ['one', 'two']);
i18n.t('pluralSub2', n, ['one', 'two'], { escapeLt: true });
// @ts-expect-error
i18n.t('pluralSub2');
// @ts-expect-error
+5
View File
@@ -166,6 +166,11 @@ function _parseMessagesObject(
];
}
case 'object':
if ([null, undefined].includes(object)) {
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),
+2 -15
View File
@@ -6,7 +6,6 @@ import {
DefaultI18nStructure,
I18n,
Substitution,
GetMessageOptions,
} from './types';
export function createI18n<
@@ -16,7 +15,6 @@ export function createI18n<
// Resolve args
let sub: Substitution[] | undefined;
let count: number | undefined;
let options: GetMessageOptions | undefined;
args.forEach((arg, i) => {
if (arg == null) {
// ignore nullish args
@@ -24,8 +22,6 @@ export function createI18n<
count = arg;
} else if (Array.isArray(arg)) {
sub = arg;
} else if (typeof arg === 'object') {
options = arg;
} else {
throw Error(
`Unknown argument at index ${i}. Must be a number for pluralization, substitution array, or options object.`,
@@ -43,18 +39,9 @@ export function createI18n<
if (sub?.length) {
// Convert all substitutions to strings
const stringSubs = sub?.map((sub) => String(sub));
message = chrome.i18n.getMessage(
key.replaceAll('.', '_'),
stringSubs,
// @ts-ignore - @types/chrome doesn't type the options object, but it's there
options,
);
message = chrome.i18n.getMessage(key.replaceAll('.', '_'), stringSubs);
} else {
message = chrome.i18n.getMessage(
key.replaceAll('.', '_'),
// @ts-ignore - @types/chrome doesn't type the options object, but it's there
options,
);
message = chrome.i18n.getMessage(key.replaceAll('.', '_'));
}
if (!message) {
console.warn(`[i18n] Message not found: "${key}"`);
-14
View File
@@ -29,7 +29,6 @@ export type TFunction<T extends I18nStructure> = {
<K extends keyof T>(
// prettier-ignore
key: K & { [P in keyof T]: T[P] extends { plural: false; substitutions: 0 } ? P : never; }[keyof T],
options?: GetMessageOptions,
): string;
// Non-plural with substitutions
@@ -39,7 +38,6 @@ export type TFunction<T extends I18nStructure> = {
substitutions: T[K] extends I18nFeatures
? SubstitutionTuple<T[K]['substitutions']>
: never,
options?: GetMessageOptions,
): string;
// Plural with 1 substitution
@@ -48,7 +46,6 @@ export type TFunction<T extends I18nStructure> = {
key: K & { [P in keyof T]: T[P] extends { plural: true; substitutions: 1 } ? P : never; }[keyof T],
n: number,
substitutions?: SubstitutionTuple<1>,
options?: GetMessageOptions,
): string;
// Plural without substitutions
@@ -56,7 +53,6 @@ export type TFunction<T extends I18nStructure> = {
// prettier-ignore
key: K & { [P in keyof T]: T[P] extends { plural: true; substitutions: 0 | 1 } ? P : never; }[keyof T],
n: number,
options?: GetMessageOptions,
): string;
// Plural with substitutions
@@ -67,7 +63,6 @@ export type TFunction<T extends I18nStructure> = {
substitutions: T[K] extends I18nFeatures
? SubstitutionTuple<T[K]['substitutions']>
: never,
options?: GetMessageOptions,
): string;
};
@@ -77,13 +72,4 @@ export interface I18n<T extends DefaultI18nStructure> {
export type Substitution = string | number;
export interface GetMessageOptions {
/**
* Escape `<` in translation to `&lt;`. This applies only to the message itself, not to the placeholders. Developers might want to use this if the translation is used in an HTML context. Closure Templates used with Closure Compiler generate this automatically.
*
* See https://developer.chrome.com/docs/extensions/reference/api/i18n#type-getMessage-options
*/
escapeLt?: boolean;
}
type SubstitutionCount = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
+4 -4
View File
@@ -47,16 +47,16 @@
"wxt": ">=0.18.6"
},
"dependencies": {
"@vitejs/plugin-react": "^4.3.1"
"@vitejs/plugin-react": "^4.3.2"
},
"devDependencies": {
"@aklinker1/check": "^1.4.5",
"@types/react": "^18.3.3",
"@types/react": "^18.3.11",
"@types/react-dom": "^18.3.0",
"publint": "^0.2.9",
"publint": "^0.2.11",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"typescript": "^5.5.4",
"typescript": "^5.6.2",
"unbuild": "^2.0.0",
"wxt": "workspace:*"
}
+3 -3
View File
@@ -51,9 +51,9 @@
},
"devDependencies": {
"@aklinker1/check": "^1.4.5",
"publint": "^0.2.9",
"solid-js": "^1.8.19",
"typescript": "^5.5.4",
"publint": "^0.2.11",
"solid-js": "^1.9.1",
"typescript": "^5.6.2",
"unbuild": "^2.0.0",
"wxt": "workspace:*"
}
+3 -3
View File
@@ -45,12 +45,12 @@
"wxt": ">=0.18.6"
},
"dependencies": {
"@sveltejs/vite-plugin-svelte": "^3.1.1"
"@sveltejs/vite-plugin-svelte": "^3.1.2"
},
"devDependencies": {
"@aklinker1/check": "^1.4.5",
"publint": "^0.2.9",
"typescript": "^5.5.4",
"publint": "^0.2.11",
"typescript": "^5.6.2",
"unbuild": "^2.0.0",
"wxt": "workspace:*"
}
+3 -3
View File
@@ -45,12 +45,12 @@
"wxt": ">=0.18.6"
},
"dependencies": {
"@vitejs/plugin-vue": "^5.1.1"
"@vitejs/plugin-vue": "^5.1.4"
},
"devDependencies": {
"@aklinker1/check": "^1.4.5",
"publint": "^0.2.9",
"typescript": "^5.5.4",
"publint": "^0.2.11",
"typescript": "^5.6.2",
"unbuild": "^2.0.0",
"wxt": "workspace:*"
}
+4 -4
View File
@@ -23,12 +23,12 @@
},
"devDependencies": {
"@types/chrome": "^0.0.269",
"@types/react": "^18.3.3",
"@types/react": "^18.3.11",
"@types/react-dom": "^18.3.0",
"@wxt-dev/auto-icons": "workspace:*",
"sass": "^1.77.8",
"typescript": "^5.5.4",
"vitest": "^2.0.4",
"sass": "^1.79.4",
"typescript": "^5.6.2",
"vitest": "^2.1.2",
"vitest-plugin-random-seed": "^1.1.0",
"wxt": "workspace:*"
},
+25
View File
@@ -1,5 +1,30 @@
# Changelog
## v0.19.11
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.19.10...wxt-v0.19.11)
### 🚀 Enhancements
- **zip:** Hooks ([#993](https://github.com/wxt-dev/wxt/pull/993))
- **zip:** `wxt zip --sources` and auto sources for opera ([#1014](https://github.com/wxt-dev/wxt/pull/1014))
### 🩹 Fixes
- Reverse env files priority ([#1016](https://github.com/wxt-dev/wxt/pull/1016))
- #1005 fixed, by updating type-definations to getItem method. ([#1007](https://github.com/wxt-dev/wxt/pull/1007), [#1005](https://github.com/wxt-dev/wxt/issues/1005))
### 🏡 Chore
- Move some files around ([#996](https://github.com/wxt-dev/wxt/pull/996))
### ❤️ Contributors
- Florian Metz ([@Timeraa](http://github.com/Timeraa))
- Gurvir Singh ([@baraich](http://github.com/baraich))
- Mezannic ([@mezannic](http://github.com/mezannic))
- Aaron ([@aklinker1](http://github.com/aklinker1))
## v0.19.10
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.19.9...wxt-v0.19.10)
+6 -4
View File
@@ -1,6 +1,6 @@
import { describe, it, expect } from 'vitest';
import { TestProject } from '../utils';
import { execaCommand } from 'execa';
import spawn from 'nano-spawn';
describe('Auto Imports', () => {
describe('imports: { ... }', () => {
@@ -180,7 +180,7 @@ describe('Auto Imports', () => {
await project.prepare({
imports: { eslintrc: { enabled: version } },
});
return await execaCommand('pnpm eslint entrypoints/background.js', {
return await spawn('pnpm', ['eslint', 'entrypoints/background.js'], {
cwd: project.root,
});
}
@@ -205,7 +205,8 @@ describe('Auto Imports', () => {
);
await expect(runEslint(project, 9)).rejects.toMatchObject({
message: expect.stringContaining(
exitCode: 1,
stdout: expect.stringContaining(
"'defineBackground' is not defined",
),
});
@@ -253,7 +254,8 @@ describe('Auto Imports', () => {
);
await expect(runEslint(project, 8)).rejects.toMatchObject({
message: expect.stringContaining(
exitCode: 1,
stdout: expect.stringContaining(
"'defineBackground' is not defined",
),
});
+57
View File
@@ -14,6 +14,12 @@ const hooks: WxtHooks = {
'entrypoints:grouped': vi.fn(),
'vite:build:extendConfig': vi.fn(),
'vite:devServer:extendConfig': vi.fn(),
'zip:start': vi.fn(),
'zip:extension:start': vi.fn(),
'zip:extension:done': vi.fn(),
'zip:sources:start': vi.fn(),
'zip:sources:done': vi.fn(),
'zip:done': vi.fn(),
};
function expectHooksToBeCalled(
@@ -53,6 +59,12 @@ describe('Hooks', () => {
'entrypoints:resolved': true,
'vite:build:extendConfig': false,
'vite:devServer:extendConfig': false,
'zip:start': false,
'zip:extension:start': false,
'zip:extension:done': false,
'zip:sources:start': false,
'zip:sources:done': false,
'zip:done': false,
});
});
@@ -74,6 +86,12 @@ describe('Hooks', () => {
'entrypoints:resolved': true,
'vite:build:extendConfig': 1,
'vite:devServer:extendConfig': false,
'zip:start': false,
'zip:extension:start': false,
'zip:extension:done': false,
'zip:sources:start': false,
'zip:sources:done': false,
'zip:done': false,
});
});
@@ -95,6 +113,39 @@ describe('Hooks', () => {
'entrypoints:resolved': true,
'vite:build:extendConfig': 1,
'vite:devServer:extendConfig': false,
'zip:start': true,
'zip:extension:start': true,
'zip:extension:done': true,
'zip:sources:start': false,
'zip:sources:done': false,
'zip:done': true,
});
});
it('zip -b firefox should call hooks', async () => {
const project = new TestProject();
project.addFile('entrypoints/popup.html', '<html></html>');
await project.zip({ hooks, browser: 'firefox' });
expectHooksToBeCalled({
ready: true,
'prepare:types': true,
'prepare:publicPaths': true,
'build:before': true,
'build:done': true,
'build:publicAssets': true,
'build:manifestGenerated': true,
'entrypoints:grouped': true,
'entrypoints:resolved': true,
'vite:build:extendConfig': 1,
'vite:devServer:extendConfig': false,
'zip:start': true,
'zip:extension:start': true,
'zip:extension:done': true,
'zip:sources:start': true,
'zip:sources:done': true,
'zip:done': true,
});
});
@@ -122,6 +173,12 @@ describe('Hooks', () => {
'entrypoints:resolved': true,
'vite:build:extendConfig': 2,
'vite:devServer:extendConfig': 1,
'zip:start': false,
'zip:extension:start': false,
'zip:extension:done': false,
'zip:sources:start': false,
'zip:sources:done': false,
'zip:done': false,
});
});
});
+19 -11
View File
@@ -1,6 +1,6 @@
import { describe, it, expect } from 'vitest';
import { TestProject, WXT_PACKAGE_DIR } from '../utils';
import { execaCommand } from 'execa';
import spawn from 'nano-spawn';
import glob from 'fast-glob';
import { mkdir, writeJson } from 'fs-extra';
@@ -8,11 +8,15 @@ describe('Init command', () => {
it('should download and create a template', async () => {
const project = new TestProject();
await execaCommand(`pnpm -s wxt init ${project.root} -t vue --pm npm`, {
env: { ...process.env, CI: 'true' },
stdio: 'ignore',
cwd: WXT_PACKAGE_DIR,
});
await spawn(
'pnpm',
['-s', 'wxt', 'init', project.root, '-t', 'vue', '--pm', 'npm'],
{
env: { CI: 'true' },
stdio: 'ignore',
cwd: WXT_PACKAGE_DIR,
},
);
const files = await glob('**/*', {
cwd: project.root,
onlyFiles: true,
@@ -51,11 +55,15 @@ describe('Init command', () => {
await writeJson(project.resolvePath('package.json'), {});
await expect(() =>
execaCommand(`pnpm -s wxt init ${project.root} -t vue --pm npm`, {
env: { ...process.env, CI: 'true' },
stdio: 'ignore',
cwd: WXT_PACKAGE_DIR,
}),
spawn(
'pnpm',
['-s', 'wxt', 'init', project.root, '-t', 'vue', '--pm', 'npm'],
{
env: { CI: 'true' },
stdio: 'ignore',
cwd: WXT_PACKAGE_DIR,
},
),
).rejects.toThrowError('Command failed with exit code 1:');
});
});
@@ -0,0 +1,40 @@
import { test, expect } from 'vitest';
import spawn from 'nano-spawn';
import {
NpmListDependency,
NpmListProject,
} from '../../src/core/package-managers/npm';
// Tests to ensure the total size of the WXT module is as small as possible
// https://pkg-size.dev/wxt
test('Only one version of esbuild should be installed (each version is ~20mb of node_modules)', async () => {
const { stdout } = await spawn('pnpm', [
'why',
'esbuild',
'--prod',
'--json',
]);
const projects: NpmListProject[] = JSON.parse(stdout);
const esbuildVersions = new Set<string>();
iterateDependencies(projects, (name, meta) => {
if (name === 'esbuild') esbuildVersions.add(meta.version);
});
expect([...esbuildVersions]).toHaveLength(1);
});
function iterateDependencies(
projects: NpmListProject[],
cb: (name: string, meta: NpmListDependency) => void,
) {
const recurse = (dependencies: Record<string, NpmListDependency>) => {
Object.entries(dependencies).forEach(([name, meta]) => {
cb(name, meta);
if (meta.dependencies) recurse(meta.dependencies);
});
};
projects.forEach((project) => {
if (project.dependencies) recurse(project.dependencies);
});
}
+76 -5
View File
@@ -1,7 +1,7 @@
import { describe, expect, it } from 'vitest';
import { TestProject } from '../utils';
import extract from 'extract-zip';
import { execaCommand } from 'execa';
import spawn from 'nano-spawn';
import { readFile, writeFile } from 'fs-extra';
process.env.WXT_PNPM_IGNORE_WORKSPACE = 'true';
@@ -41,13 +41,15 @@ describe('Zipping', () => {
// Build zipped extension
await expect(
execaCommand('pnpm i --ignore-workspace --frozen-lockfile false', {
spawn('pnpm', ['i', '--ignore-workspace', '--frozen-lockfile', 'false'], {
cwd: unzipDir,
}),
).resolves.toMatchObject({ exitCode: 0 });
).resolves.not.toHaveProperty('exitCode');
await expect(
execaCommand('pnpm wxt build -b firefox', { cwd: unzipDir }),
).resolves.toMatchObject({ exitCode: 0 });
spawn('pnpm', ['wxt', 'build', '-b', 'firefox'], {
cwd: unzipDir,
}),
).resolves.not.toHaveProperty('exitCode');
await expect(project.fileExists(unzipDir, '.output')).resolves.toBe(true);
expect(
@@ -178,4 +180,73 @@ describe('Zipping', () => {
true,
);
});
it.each(['firefox', 'opera'])(
'should create sources zip for "%s" browser when sourcesZip is undefined',
async (browser) => {
const project = new TestProject({
name: 'test',
version: '1.0.0',
});
project.addFile(
'entrypoints/background.ts',
'export default defineBackground(() => {});',
);
const sourcesZip = project.resolvePath('.output/test-1.0.0-sources.zip');
await project.zip({
browser,
});
expect(await project.fileExists(sourcesZip)).toBe(true);
},
);
it.each(['firefox', 'chrome'])(
'should create sources zip for "%s" when sourcesZip is true',
async (browser) => {
const project = new TestProject({
name: 'test',
version: '1.0.0',
});
project.addFile(
'entrypoints/background.ts',
'export default defineBackground(() => {});',
);
const sourcesZip = project.resolvePath('.output/test-1.0.0-sources.zip');
await project.zip({
browser,
zip: {
zipSources: true,
},
});
expect(await project.fileExists(sourcesZip)).toBe(true);
},
);
it.each(['firefox', 'chrome'])(
'should not create sources zip for "%s" when sourcesZip is false',
async (browser) => {
const project = new TestProject({
name: 'test',
version: '1.0.0',
});
project.addFile(
'entrypoints/background.ts',
'export default defineBackground(() => {});',
);
const sourcesZip = project.resolvePath('.output/test-1.0.0-sources.zip');
await project.zip({
browser,
zip: {
zipSources: false,
},
});
expect(await project.fileExists(sourcesZip)).toBe(false);
},
);
});
+2 -2
View File
@@ -1,7 +1,7 @@
import { dirname, relative, resolve } from 'path';
import fs, { mkdir } from 'fs-extra';
import glob from 'fast-glob';
import { execaCommand } from 'execa';
import spawn from 'nano-spawn';
import {
InlineConfig,
UserConfig,
@@ -119,7 +119,7 @@ export class TestProject {
await fs.writeFile(filePath, content ?? '', 'utf-8');
}
await execaCommand('pnpm --ignore-workspace i --ignore-scripts', {
await spawn('pnpm', ['--ignore-workspace', 'i', '--ignore-scripts'], {
cwd: this.root,
});
await mkdir(resolve(this.root, 'public'), { recursive: true }).catch(
+19 -19
View File
@@ -1,7 +1,7 @@
{
"name": "wxt",
"type": "module",
"version": "0.19.10",
"version": "0.19.11",
"description": "Next gen framework for developing web extensions",
"repository": {
"type": "git",
@@ -88,7 +88,7 @@
"@webext-core/isolated-element": "^1.1.2",
"@webext-core/match-patterns": "^1.0.3",
"async-mutex": "^0.5.0",
"c12": "^1.11.1",
"c12": "^1.11.2",
"cac": "^6.7.14",
"chokidar": "^3.6.0",
"ci-info": "^4.0.0",
@@ -96,10 +96,9 @@
"defu": "^6.1.4",
"dequal": "^2.0.3",
"dotenv": "^16.4.5",
"esbuild": "^0.23.0",
"execa": "^9.3.1",
"esbuild": "^0.21.5",
"fast-glob": "^3.3.2",
"filesize": "^10.1.4",
"filesize": "^10.1.6",
"fs-extra": "^11.2.0",
"get-port": "^7.1.0",
"giget": "^1.2.3",
@@ -108,23 +107,24 @@
"jiti": "^1.21.6",
"json5": "^2.2.3",
"jszip": "^3.10.1",
"linkedom": "^0.18.4",
"magicast": "^0.3.4",
"linkedom": "^0.18.5",
"magicast": "^0.3.5",
"minimatch": "^10.0.1",
"nano-spawn": "^0.1.0",
"natural-compare": "^1.4.0",
"normalize-path": "^3.0.0",
"nypm": "^0.3.9",
"ohash": "^1.1.3",
"nypm": "^0.3.12",
"ohash": "^1.1.4",
"open": "^10.1.0",
"ora": "^8.1.0",
"perfect-debounce": "^1.0.0",
"picocolors": "^1.0.1",
"picocolors": "^1.1.0",
"prompts": "^2.4.2",
"publish-browser-extension": "^2.1.3",
"publish-browser-extension": "^2.2.2",
"scule": "^1.3.0",
"unimport": "^3.11.1",
"vite": "^5.3.5",
"vite-node": "^2.0.4",
"unimport": "^3.13.1",
"vite": "^5.4.8",
"vite-node": "^2.1.2",
"web-ext-run": "^0.2.1",
"webextension-polyfill": "^0.12.0"
},
@@ -134,19 +134,19 @@
"@types/fs-extra": "^11.0.4",
"@types/lodash.merge": "^4.6.9",
"@types/natural-compare": "^1.4.3",
"@types/node": "^20.14.12",
"@types/node": "^20.16.10",
"@types/normalize-path": "^3.0.2",
"@types/prompts": "^2.4.9",
"extract-zip": "^2.0.1",
"happy-dom": "^14.12.3",
"lodash.merge": "^4.6.2",
"oxlint": "^0.9.1",
"oxlint": "^0.9.9",
"p-map": "^7.0.2",
"publint": "^0.2.9",
"publint": "^0.2.11",
"tsx": "4.15.7",
"typescript": "^5.5.4",
"typescript": "^5.6.2",
"unbuild": "^2.0.0",
"vitest": "^2.0.4",
"vitest": "^2.1.2",
"vitest-plugin-random-seed": "^1.1.0"
},
"peerDependenciesMeta": {
@@ -903,5 +903,24 @@ describe('Storage Utils', () => {
// @ts-expect-error
await storage.getItem('loca:test').catch(() => {});
});
it('should return a nullable type when getItem is called without a fallback', async () => {
const res = await storage.getItem<string>('local:test');
expectTypeOf(res).toBeNullable();
});
it('should return a non-null type when getItem is called with a fallback', async () => {
const res = await storage.getItem('local:test', {
fallback: 'test',
});
expectTypeOf(res).not.toBeNullable();
});
it('should return a non-null type when getItem is called with a fallback and the first type parameter is passed', async () => {
const res = await storage.getItem<string>('local:test', {
fallback: 'test',
});
expectTypeOf(res).not.toBeNullable();
});
});
});
+10 -6
View File
@@ -11,13 +11,17 @@ export type AugmentedBrowser = Omit<Browser, 'runtime' | 'i18n'> & {
i18n: WxtI18n & Omit<Browser['i18n'], 'getMessage'>;
};
export interface WxtRuntime {
// Overriden per-project
}
/**
* This interface is empty because it is generated per-project when running `wxt prepare`. See:
* - `.wxt/types/paths.d.ts`
*/
export interface WxtRuntime {}
export interface WxtI18n {
// Overriden per-project
}
/**
* This interface is empty because it is generated per-project when running `wxt prepare`. See:
* - `.wxt/types/i18n.d.ts`
*/
export interface WxtI18n {}
export const browser: AugmentedBrowser = originalBrowser;
+43 -1
View File
@@ -237,7 +237,9 @@ describe('CLI', () => {
mockArgv('zip');
await importCli();
expect(zipMock).toBeCalledWith({});
expect(zipMock).toBeCalledWith({
zip: {},
});
});
it('should respect passing a custom root', async () => {
@@ -246,6 +248,7 @@ describe('CLI', () => {
expect(zipMock).toBeCalledWith({
root: 'path/to/root',
zip: {},
});
});
@@ -255,6 +258,7 @@ describe('CLI', () => {
expect(zipMock).toBeCalledWith({
configFile: './path/to/config.ts',
zip: {},
});
});
@@ -264,6 +268,7 @@ describe('CLI', () => {
expect(zipMock).toBeCalledWith({
mode: 'development',
zip: {},
});
});
@@ -273,6 +278,7 @@ describe('CLI', () => {
expect(zipMock).toBeCalledWith({
browser: 'firefox',
zip: {},
});
});
@@ -282,6 +288,7 @@ describe('CLI', () => {
expect(zipMock).toBeCalledWith({
manifestVersion: 2,
zip: {},
});
});
@@ -291,6 +298,7 @@ describe('CLI', () => {
expect(zipMock).toBeCalledWith({
manifestVersion: 3,
zip: {},
});
});
@@ -300,6 +308,40 @@ describe('CLI', () => {
expect(zipMock).toBeCalledWith({
debug: true,
zip: {},
});
});
it('should pass undefined for zipSources when --sources is not passed', async () => {
mockArgv('zip');
await importCli();
expect(zipMock).toBeCalledWith({
zip: {
zipSources: undefined,
},
});
});
it('should pass true for zipSources when --sources is passed', async () => {
mockArgv('zip', '--sources');
await importCli();
expect(zipMock).toBeCalledWith({
zip: {
zipSources: true,
},
});
});
it('should pass false for zipSources when --sources=false is passed', async () => {
mockArgv('zip', '--sources=false');
await importCli();
expect(zipMock).toBeCalledWith({
zip: {
zipSources: false,
},
});
});
});
+2 -2
View File
@@ -5,6 +5,7 @@ import { printHeader } from '../core/utils/log';
import { formatDuration } from '../core/utils/time';
import { ValidationError } from '../core/utils/validation';
import { registerWxt } from '../core/wxt';
import spawn from 'nano-spawn';
/**
* Wrap an action handler to add a timer, error handling, and maybe enable debug mode.
@@ -87,8 +88,7 @@ export function createAliasedCommand(
const args = process.argv.slice(
process.argv.indexOf(aliasedCommand.name) + 1,
);
const { execa } = await import('execa');
await execa(bin, args, {
await spawn(bin, args, {
stdio: 'inherit',
});
} catch {
+4
View File
@@ -95,6 +95,7 @@ cli
.option('-b, --browser <browser>', 'specify a browser')
.option('--mv3', 'target manifest v3')
.option('--mv2', 'target manifest v2')
.option('--sources', 'always create sources zip')
.action(
wrapAction(async (root, flags) => {
await zip({
@@ -104,6 +105,9 @@ cli
manifestVersion: flags.mv3 ? 3 : flags.mv2 ? 2 : undefined,
configFile: flags.config,
debug: flags.debug,
zip: {
zipSources: flags.sources,
},
});
}),
);
@@ -1,23 +1,18 @@
import { Entrypoint, WxtDirEntry, WxtDirFileEntry } from '../../../types';
import { Entrypoint, WxtDirEntry, WxtDirFileEntry } from '../types';
import fs from 'fs-extra';
import { dirname, relative, resolve } from 'node:path';
import {
getEntrypointBundlePath,
isHtmlEntrypoint,
} from '../../utils/entrypoints';
import { getEntrypointGlobals, getGlobals } from '../../utils/globals';
import { normalizePath } from '../../utils/paths';
import { getEntrypointBundlePath, isHtmlEntrypoint } from './utils/entrypoints';
import { getEntrypointGlobals, getGlobals } from './utils/globals';
import { normalizePath } from './utils/paths';
import path from 'node:path';
import { Message, parseI18nMessages } from '../../utils/i18n';
import { writeFileIfDifferent, getPublicFiles } from '../../utils/fs';
import { wxt } from '../../wxt';
import { Message, parseI18nMessages } from './utils/i18n';
import { writeFileIfDifferent, getPublicFiles } from './utils/fs';
import { wxt } from './wxt';
/**
* Generate and write all the files inside the `InternalConfig.typesDir` directory.
*/
export async function generateTypesDir(
entrypoints: Entrypoint[],
): Promise<void> {
export async function generateWxtDir(entrypoints: Entrypoint[]): Promise<void> {
await fs.ensureDir(wxt.config.typesDir);
const entries: WxtDirEntry[] = [
@@ -1,7 +1,7 @@
import { beforeAll, describe, expect, it } from 'vitest';
import path from 'node:path';
import { npm } from '../npm';
import { execaCommand } from 'execa';
import spawn from 'nano-spawn';
import { exists } from 'fs-extra';
describe('NPM Package Management Utils', () => {
@@ -9,7 +9,7 @@ describe('NPM Package Management Utils', () => {
const cwd = path.resolve(__dirname, 'fixtures/simple-npm-project');
beforeAll(async () => {
// NPM needs the modules installed for 'npm ls' to work
await execaCommand('npm i', { cwd });
await spawn('npm', ['i'], { cwd });
}, 60e3);
it('should list direct dependencies', async () => {
@@ -1,7 +1,7 @@
import { beforeAll, describe, expect, it } from 'vitest';
import path from 'node:path';
import { pnpm } from '../pnpm';
import { execaCommand } from 'execa';
import spawn from 'nano-spawn';
process.env.WXT_PNPM_IGNORE_WORKSPACE = 'true';
@@ -10,7 +10,7 @@ describe('PNPM Package Management Utils', () => {
const cwd = path.resolve(__dirname, 'fixtures/simple-pnpm-project');
beforeAll(async () => {
// PNPM needs the modules installed, or 'pnpm ls' will return a blank list.
await execaCommand('pnpm i --ignore-workspace', { cwd });
await spawn('pnpm', ['i', '--ignore-workspace'], { cwd });
});
it('should list direct dependencies', async () => {
@@ -1,5 +1,6 @@
import { dedupeDependencies, npm } from './npm';
import { WxtPackageManagerImpl } from './types';
import spawn from 'nano-spawn';
export const bun: WxtPackageManagerImpl = {
overridesKey: 'overrides', // But also supports "resolutions"
@@ -11,8 +12,7 @@ export const bun: WxtPackageManagerImpl = {
if (options?.all) {
args.push('--all');
}
const { execa } = await import('execa');
const res = await execa('bun', args, { cwd: options?.cwd });
const res = await spawn('bun', args, { cwd: options?.cwd });
return dedupeDependencies(
res.stdout
.split('\n')
@@ -2,13 +2,13 @@ import { Dependency } from '../../types';
import { WxtPackageManagerImpl } from './types';
import path from 'node:path';
import { ensureDir } from 'fs-extra';
import spawn from 'nano-spawn';
export const npm: WxtPackageManagerImpl = {
overridesKey: 'overrides',
async downloadDependency(id, downloadDir) {
await ensureDir(downloadDir);
const { execa } = await import('execa');
const res = await execa('npm', ['pack', id, '--json'], {
const res = await spawn('npm', ['pack', id, '--json'], {
cwd: downloadDir,
});
const packed: PackedDependency[] = JSON.parse(res.stdout);
@@ -19,8 +19,7 @@ export const npm: WxtPackageManagerImpl = {
if (options?.all) {
args.push('--depth', 'Infinity');
}
const { execa } = await import('execa');
const res = await execa('npm', args, { cwd: options?.cwd });
const res = await spawn('npm', args, { cwd: options?.cwd });
const project: NpmListProject = JSON.parse(res.stdout);
return flattenNpmListOutput([project]);
@@ -1,5 +1,6 @@
import { NpmListProject, flattenNpmListOutput, npm } from './npm';
import { WxtPackageManagerImpl } from './types';
import spawn from 'nano-spawn';
export const pnpm: WxtPackageManagerImpl = {
overridesKey: 'resolutions', // "pnpm.overrides" has a higher priority, but I don't want to deal with nesting
@@ -19,8 +20,7 @@ export const pnpm: WxtPackageManagerImpl = {
) {
args.push('--ignore-workspace');
}
const { execa } = await import('execa');
const res = await execa('pnpm', args, { cwd: options?.cwd });
const res = await spawn('pnpm', args, { cwd: options?.cwd });
const projects: NpmListProject[] = JSON.parse(res.stdout);
return flattenNpmListOutput(projects);
@@ -1,6 +1,7 @@
import { Dependency } from '../../types';
import { WxtPackageManagerImpl } from './types';
import { dedupeDependencies, npm } from './npm';
import spawn from 'nano-spawn';
export const yarn: WxtPackageManagerImpl = {
overridesKey: 'resolutions',
@@ -12,8 +13,7 @@ export const yarn: WxtPackageManagerImpl = {
if (options?.all) {
args.push('--depth', 'Infinity');
}
const { execa } = await import('execa');
const res = await execa('yarn', args, { cwd: options?.cwd });
const res = await spawn('yarn', args, { cwd: options?.cwd });
const tree = res.stdout
.split('\n')
.map<JsonLine>((line) => JSON.parse(line))
+3 -2
View File
@@ -1,5 +1,6 @@
import { InlineConfig } from '../types';
import { findEntrypoints, generateTypesDir } from './utils/building';
import { findEntrypoints } from './utils/building';
import { generateWxtDir } from './generate-wxt-dir';
import { registerWxt, wxt } from './wxt';
export async function prepare(config: InlineConfig) {
@@ -7,5 +8,5 @@ export async function prepare(config: InlineConfig) {
wxt.logger.info('Generating types...');
const entrypoints = await findEntrypoints();
await generateTypesDir(entrypoints);
await generateWxtDir(entrypoints);
}
@@ -14,19 +14,19 @@ import {
WxtModuleWithMetadata,
ResolvedEslintrc,
Eslintrc,
} from '../../../types';
} from '../types';
import path from 'node:path';
import { createFsCache } from '../../utils/cache';
import { createFsCache } from './utils/cache';
import consola, { LogLevels } from 'consola';
import defu from 'defu';
import { NullablyRequired } from '../types';
import { NullablyRequired } from './utils/types';
import fs from 'fs-extra';
import { normalizePath } from '../paths';
import { normalizePath } from './utils/paths';
import glob from 'fast-glob';
import { builtinModules } from '../../../builtin-modules';
import { getEslintVersion } from '../eslint';
import { safeStringToNumber } from '../number';
import { loadEnv } from '../env';
import { builtinModules } from '../builtin-modules';
import { getEslintVersion } from './utils/eslint';
import { safeStringToNumber } from './utils/number';
import { loadEnv } from './utils/env';
/**
* Given an inline config, discover the config file if necessary, merge the results, resolve any
@@ -179,7 +179,7 @@ export async function resolveConfig(
srcDir,
typesDir,
wxtDir,
zip: resolveZipConfig(root, outBaseDir, mergedConfig),
zip: resolveZipConfig(root, browser, outBaseDir, mergedConfig),
transformManifest: mergedConfig.transformManifest,
analysis: resolveAnalysisConfig(root, mergedConfig),
userConfigMetadata: userConfigMetadata ?? {},
@@ -258,6 +258,7 @@ async function mergeInlineConfig(
function resolveZipConfig(
root: string,
browser: string,
outBaseDir: string,
mergedConfig: InlineConfig,
): NullablyRequired<ResolvedConfig['zip']> {
@@ -270,6 +271,8 @@ function resolveZipConfig(
includeSources: [],
compressionLevel: 9,
...mergedConfig.zip,
zipSources:
mergedConfig.zip?.zipSources ?? ['firefox', 'opera'].includes(browser),
exclude: mergedConfig.zip?.exclude ?? [],
excludeSources: [
'**/node_modules',
@@ -1,8 +1,6 @@
export * from './build-entrypoints';
export * from './detect-dev-changes';
export * from './find-entrypoints';
export * from './generate-wxt-dir';
export * from './resolve-config';
export * from './group-entrypoints';
export * from './import-entrypoint';
export * from './internal-build';
@@ -1,6 +1,6 @@
import type { Manifest } from 'wxt/browser';
import { BuildOutput, Entrypoint, EntrypointGroup } from '../../../types';
import { generateTypesDir } from './generate-wxt-dir';
import { generateWxtDir } from '../../generate-wxt-dir';
import { buildEntrypoints } from './build-entrypoints';
import { generateManifest, writeManifest } from '../../utils/manifest';
import { wxt } from '../../wxt';
@@ -37,7 +37,7 @@ export async function rebuild(
const spinner = ora(`Preparing...`).start();
// Update types directory with new files and types
await generateTypesDir(allEntrypoints).catch((err) => {
await generateWxtDir(allEntrypoints).catch((err) => {
wxt.logger.warn('Failed to update .wxt directory:', err);
// Throw the error if doing a regular build, don't for dev mode.
if (wxt.config.command === 'build') throw err;
+1 -1
View File
@@ -5,6 +5,6 @@ import { config } from 'dotenv';
*/
export function loadEnv(mode: string) {
return config({
path: [`.env`, `.env.local`, `.env.${mode}`, `.env.${mode}.local`],
path: [`.env.${mode}.local`, `.env.${mode}`, `.env.local`, `.env`],
});
}
@@ -293,6 +293,7 @@ export const fakeResolvedConfig = fakeObjectCreator<ResolvedConfig>(() => {
downloadedPackagesDir: fakeDir(),
downloadPackages: [],
compressionLevel: 9,
zipSources: false,
},
transformManifest: () => {},
userConfigMetadata: {},
+1 -1
View File
@@ -7,7 +7,7 @@ import {
WxtHooks,
WxtModule,
} from '../types';
import { resolveConfig } from './utils/building';
import { resolveConfig } from './resolve-config';
import { createHooks } from 'hookable';
import { createWxtPackageManager } from './package-managers';
import { createViteBuilder } from './builders/vite';
+12 -5
View File
@@ -20,6 +20,7 @@ import { normalizePath } from './utils/paths';
export async function zip(config?: InlineConfig): Promise<string[]> {
await registerWxt('build', config);
const output = await internalBuild();
await wxt.hooks.callHook('zip:start', wxt);
const start = Date.now();
wxt.logger.info('Zipping extension...');
@@ -27,7 +28,9 @@ export async function zip(config?: InlineConfig): Promise<string[]> {
const projectName =
wxt.config.zip.name ??
safeFilename((await getPackageJson())?.name || path.dirname(process.cwd()));
safeFilename(
(await getPackageJson())?.name || path.basename(process.cwd()),
);
const applyTemplate = (template: string): string =>
template
.replaceAll('{{name}}', projectName)
@@ -42,17 +45,17 @@ export async function zip(config?: InlineConfig): Promise<string[]> {
await fs.ensureDir(wxt.config.outBaseDir);
// ZIP output directory
await wxt.hooks.callHook('zip:extension:start', wxt);
const outZipFilename = applyTemplate(wxt.config.zip.artifactTemplate);
const outZipPath = path.resolve(wxt.config.outBaseDir, outZipFilename);
await zipDir(wxt.config.outDir, outZipPath, {
exclude: wxt.config.zip.exclude,
});
zipFiles.push(outZipPath);
await wxt.hooks.callHook('zip:extension:done', wxt, outZipPath);
// ZIP sources for Firefox
if (wxt.config.browser === 'firefox') {
if (wxt.config.zip.zipSources) {
await wxt.hooks.callHook('zip:sources:start', wxt);
const { overrides, files: downloadedPackages } =
await downloadPrivatePackages();
const sourcesZipFilename = applyTemplate(wxt.config.zip.sourcesTemplate);
@@ -71,6 +74,7 @@ export async function zip(config?: InlineConfig): Promise<string[]> {
additionalFiles: downloadedPackages,
});
zipFiles.push(sourcesZipPath);
await wxt.hooks.callHook('zip:sources:done', wxt, sourcesZipPath);
}
await printFileList(
@@ -80,8 +84,11 @@ export async function zip(config?: InlineConfig): Promise<string[]> {
zipFiles,
);
await wxt.hooks.callHook('zip:done', wxt, zipFiles);
return zipFiles;
}
async function zipDir(
directory: string,
outputPath: string,
+10 -1
View File
@@ -461,7 +461,16 @@ export interface WxtStorage {
* @example
* await storage.getItem<number>("local:installDate");
*/
getItem<T>(key: StorageItemKey, opts?: GetItemOptions<T>): Promise<T | null>;
getItem<TValue>(
key: StorageItemKey,
opts: GetItemOptions<TValue> & { fallback: TValue },
): Promise<TValue>;
getItem<TValue>(
key: StorageItemKey,
opts?: GetItemOptions<TValue>,
): Promise<TValue | null>;
/**
* Get multiple items from storage. The return order is guaranteed to be the same as the order
* requested.
+52
View File
@@ -130,6 +130,16 @@ export interface InlineConfig {
* @default "{{name}}-{{version}}-{{browser}}.zip"
*/
artifactTemplate?: string;
/**
* When zipping the extension, also zip sources.
*
* - `undefined`: zip sources if the target browser is "firefox" or "opera"
* - `true`: always zip sources
* - `false`: never zip sources
*
* @default undefined
*/
zipSources?: boolean;
/**
* Configure the filename output when zipping files.
*
@@ -1164,6 +1174,44 @@ export interface WxtHooks {
* @param entrypoints The list of files that will be copied into the output directory
*/
'build:publicAssets': (wxt: Wxt, files: ResolvedPublicFile[]) => HookResult;
/**
* Called before the zip process starts.
* @param wxt The configured WXT object
*/
'zip:start': (wxt: Wxt) => HookResult;
/**
* Called before zipping the extension files.
* @param wxt The configured WXT object
*/
'zip:extension:start': (wxt: Wxt) => HookResult;
/**
* Called after zipping the extension files.
* @param wxt The configured WXT object
* @param zipPath The path to the created extension zip file
*/
'zip:extension:done': (wxt: Wxt, zipPath: string) => HookResult;
/**
* Called before zipping the source files (for Firefox).
* @param wxt The configured WXT object
*/
'zip:sources:start': (wxt: Wxt) => HookResult;
/**
* Called after zipping the source files (for Firefox).
* @param wxt The configured WXT object
* @param zipPath The path to the created sources zip file
*/
'zip:sources:done': (wxt: Wxt, zipPath: string) => HookResult;
/**
* Called after the entire zip process is complete.
* @param wxt The configured WXT object
* @param zipFiles An array of paths to all created zip files
*/
'zip:done': (wxt: Wxt, zipFiles: string[]) => HookResult;
}
export interface Wxt {
@@ -1247,6 +1295,10 @@ export interface ResolvedConfig {
downloadPackages: string[];
compressionLevel: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
exclude: string[];
/**
* If true, when zipping the extension, also zip the sources.
*/
zipSources: boolean;
};
/**
* @deprecated Use `build:manifestGenerated` hook instead.
+1317 -1146
View File
File diff suppressed because it is too large Load Diff
+5 -5
View File
@@ -5,7 +5,7 @@ import {
generateMarkDown,
parseChangelogMarkdown,
} from 'changelogen';
import { execa } from 'execa';
import spawn from 'nano-spawn';
import { getPkgTag, grabPackageDetails, listCommitsInDir } from './git';
import { consola } from 'consola';
import fs from 'fs-extra';
@@ -36,7 +36,7 @@ if (currentVersion.startsWith('0.')) {
bumpType = 'patch';
}
}
await execa('pnpm', ['version', bumpType], {
await spawn('pnpm', ['version', bumpType], {
cwd: pkgDir,
});
const updatedPkgJson = await fs.readJson(pkgJsonPath);
@@ -82,11 +82,11 @@ await fs.writeFile(changelogPath, newChangelog, 'utf8');
consola.success('Updated changelog');
// Commit changes
await execa('git', ['add', pkgJsonPath, changelogPath]);
await execa('git', [
await spawn('git', ['add', pkgJsonPath, changelogPath]);
await spawn('git', [
'commit',
'-m',
`chore(release): ${pkgName} v${newVersion}`,
]);
await execa('git', ['tag', newTag]);
await spawn('git', ['tag', newTag]);
consola.success('Committed version and changelog');
+8 -1
View File
@@ -1,4 +1,11 @@
// https://github.com/antfu-collective/taze?tab=readme-ov-file#config-file
export default {
exclude: ['typedoc', 'typedoc-plugin-markdown', 'typedoc-vitepress-theme'],
exclude: [
// Very touchy, don't change:
'typedoc',
'typedoc-plugin-markdown',
'typedoc-vitepress-theme',
// Manually manage version so a single version is used:
'esbuild',
],
};
+4 -4
View File
@@ -19,10 +19,10 @@
"react-dom": "^18.3.1"
},
"devDependencies": {
"@types/react": "^18.3.3",
"@types/react": "^18.3.11",
"@types/react-dom": "^18.3.0",
"@wxt-dev/module-react": "^1.1.0",
"typescript": "^5.5.4",
"wxt": "^0.19.1"
"@wxt-dev/module-react": "^1.1.1",
"typescript": "^5.6.2",
"wxt": "^0.19.11"
}
}
+4 -4
View File
@@ -15,11 +15,11 @@
"postinstall": "wxt prepare"
},
"dependencies": {
"solid-js": "^1.8.19"
"solid-js": "^1.9.1"
},
"devDependencies": {
"@wxt-dev/module-solid": "^1.1.1",
"typescript": "^5.5.4",
"wxt": "^0.19.1"
"@wxt-dev/module-solid": "^1.1.2",
"typescript": "^5.6.2",
"wxt": "^0.19.11"
}
}
+6 -6
View File
@@ -16,11 +16,11 @@
},
"devDependencies": {
"@tsconfig/svelte": "^5.0.4",
"@wxt-dev/module-svelte": "^1.0.0",
"svelte": "^4.2.18",
"svelte-check": "^3.8.4",
"tslib": "^2.6.3",
"typescript": "^5.5.4",
"wxt": "^0.19.1"
"@wxt-dev/module-svelte": "^1.0.1",
"svelte": "^4.2.19",
"svelte-check": "^3.8.6",
"tslib": "^2.7.0",
"typescript": "^5.6.2",
"wxt": "^0.19.11"
}
}
+2 -2
View File
@@ -15,7 +15,7 @@
"postinstall": "wxt prepare"
},
"devDependencies": {
"typescript": "^5.5.4",
"wxt": "^0.19.1"
"typescript": "^5.6.2",
"wxt": "^0.19.11"
}
}
+5 -5
View File
@@ -15,12 +15,12 @@
"postinstall": "wxt prepare"
},
"dependencies": {
"vue": "^3.4.34"
"vue": "^3.5.11"
},
"devDependencies": {
"@wxt-dev/module-vue": "^1.0.0",
"typescript": "^5.5.4",
"vue-tsc": "^2.0.29",
"wxt": "^0.19.1"
"@wxt-dev/module-vue": "^1.0.1",
"typescript": "^5.6.2",
"vue-tsc": "^2.1.6",
"wxt": "^0.19.11"
}
}
-3
View File
@@ -11,9 +11,6 @@
"strict": true,
"lib": ["DOM", "WebWorker", "ESNext"],
/* Linting */
"noUnusedLocals": true,
/* Completeness */
"skipLibCheck": true
}