Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 38345481df | |||
| da92449e0f | |||
| 23b3980645 | |||
| 81b4b629c9 | |||
| 4f7e9cb050 | |||
| b226d9b947 | |||
| aabba41e86 | |||
| f19e6908b0 | |||
| 5f651cc3fe | |||
| 8a6acbaaf2 | |||
| 13ab8e4d01 | |||
| bd039dcbab | |||
| 9cd4e8342b | |||
| c9633cefec |
@@ -1,5 +1,40 @@
|
||||
# Changelog
|
||||
|
||||
## v0.17.7
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.17.6...v0.17.7)
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- **zip:** List `.wxt/local_modules` overrides relative to the `package.json` they're added to ([#526](https://github.com/wxt-dev/wxt/pull/526))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- Bump templates to v0.17 ([#524](https://github.com/wxt-dev/wxt/pull/524))
|
||||
- Increase test timeout for windows NPM tests ([#525](https://github.com/wxt-dev/wxt/pull/525))
|
||||
|
||||
## v0.17.6
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.17.5...v0.17.6)
|
||||
|
||||
### 🚀 Enhancements
|
||||
|
||||
- Add warnings when important directories are missing ([#516](https://github.com/wxt-dev/wxt/pull/516))
|
||||
- Automatically remove top-level MV2-only or MV3-only keys ([#518](https://github.com/wxt-dev/wxt/pull/518))
|
||||
- Automatically generate `browser_action` based on `action` for MV2 ([#519](https://github.com/wxt-dev/wxt/pull/519))
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- **zip:** List all private packages correctly in a PNPM workspace ([#520](https://github.com/wxt-dev/wxt/pull/520))
|
||||
|
||||
### 📖 Documentation
|
||||
|
||||
- Mentions moving folders into `srcDir` ([9cd4e83](https://github.com/wxt-dev/wxt/commit/9cd4e83))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- **deps-dev:** Bump @types/react from 18.2.34 to 18.2.61 ([#510](https://github.com/wxt-dev/wxt/pull/510))
|
||||
|
||||
## v0.17.5
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.17.4...v0.17.5)
|
||||
|
||||
@@ -130,6 +130,72 @@ See the official localization examples for more details:
|
||||
|
||||
<ExampleList tag="i18n" />
|
||||
|
||||
## Per-Manifest Version Config
|
||||
|
||||
WXT applies several transformations to your manifest to simplify managing both MV2 and MV3 keys in your `wxt.config.ts` file:
|
||||
|
||||
1. Top level MV2-only or MV3-only keys are stripped from the final manifest when targeting the other manifest version
|
||||
2. Some keys, are automatically converted between versions when possible:
|
||||
- Define `web_accessible_resources` in it's MV3 style and it will be converted to the MV2 style automatically
|
||||
- `action` will automatically be converted to `browser_action` for MV3. To use `page_action` instead, add both `action` and `page_action` entries to your manifest
|
||||
|
||||
For example, a `wxt.config.ts` file that looks like this:
|
||||
|
||||
```ts
|
||||
import { defineConfig } from 'wxt';
|
||||
|
||||
export default defineConfig({
|
||||
mainfest: {
|
||||
action: {
|
||||
default_title: 'Some Title',
|
||||
},
|
||||
web_accessible_resources: [
|
||||
{
|
||||
matches: ['*://*.google.com/*'],
|
||||
resources: ['icon/*.png'],
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Will be output differently for each manifest version:
|
||||
|
||||
:::code-group
|
||||
|
||||
```json [MV2]
|
||||
{
|
||||
"manifest_version": 2,
|
||||
// ...
|
||||
"browser_action": {
|
||||
"default_title": "Some Title"
|
||||
},
|
||||
"web_accessible_resources": ["icon/*.png"]
|
||||
}
|
||||
```
|
||||
|
||||
```json [MV3]
|
||||
{
|
||||
"manifest_version": 3,
|
||||
// ...
|
||||
"action": {
|
||||
"default_title": "Some Title"
|
||||
},
|
||||
"web_accessible_resources": [
|
||||
{
|
||||
"matches": ["*://*.google.com/*"],
|
||||
"resources": ["icon/*.png"]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
:::tip
|
||||
If this isn't enough control for your use-case, remember you can use a function for the `manifest` key and generate it however you'd like, or you can use the `build:manifestGenerated` hook to apply additional transformations.
|
||||
:::
|
||||
|
||||
## Per-Browser Configuration
|
||||
|
||||
The `manifest` field can be a function. If you are building and extension for multiple browsers, and need to modify the manifest per browser, using a function instead of an object is very useful.
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "wxt",
|
||||
"type": "module",
|
||||
"version": "0.17.5",
|
||||
"version": "0.17.7",
|
||||
"description": "Next gen framework for developing web extensions",
|
||||
"engines": {
|
||||
"node": ">=18",
|
||||
|
||||
Generated
+20
-12
@@ -34,7 +34,7 @@ importers:
|
||||
version: 6.7.14
|
||||
chokidar:
|
||||
specifier: ^3.5.3
|
||||
version: 3.5.3
|
||||
version: 3.6.0
|
||||
consola:
|
||||
specifier: ^3.2.3
|
||||
version: 3.2.3
|
||||
@@ -79,7 +79,7 @@ importers:
|
||||
version: 3.10.1
|
||||
linkedom:
|
||||
specifier: ^0.16.1
|
||||
version: 0.16.1
|
||||
version: 0.16.8
|
||||
minimatch:
|
||||
specifier: ^9.0.3
|
||||
version: 9.0.3
|
||||
@@ -1155,7 +1155,7 @@ packages:
|
||||
/@types/react-dom@18.2.14:
|
||||
resolution: {integrity: sha512-V835xgdSVmyQmI1KLV2BEIUgqEuinxp9O4G6g3FqO/SqLac049E53aysv0oEFD2kHfejeKU+ZqL2bcFWj9gLAQ==}
|
||||
dependencies:
|
||||
'@types/react': 18.2.34
|
||||
'@types/react': 18.2.61
|
||||
dev: true
|
||||
|
||||
/@types/react@18.2.34:
|
||||
@@ -1166,6 +1166,14 @@ packages:
|
||||
csstype: 3.1.2
|
||||
dev: true
|
||||
|
||||
/@types/react@18.2.61:
|
||||
resolution: {integrity: sha512-NURTN0qNnJa7O/k4XUkEW2yfygA+NxS0V5h1+kp9jPwhzZy95q3ADoGMP0+JypMhrZBTTgjKAUlTctde1zzeQA==}
|
||||
dependencies:
|
||||
'@types/prop-types': 15.7.9
|
||||
'@types/scheduler': 0.16.5
|
||||
csstype: 3.1.3
|
||||
dev: true
|
||||
|
||||
/@types/scheduler@0.16.5:
|
||||
resolution: {integrity: sha512-s/FPdYRmZR8SjLWGMCuax7r3qCWQw9QKHzXVukAuuIJkXkDRwp+Pu5LMIVFi0Fxbav35WURicYr8u1QsoybnQw==}
|
||||
dev: true
|
||||
@@ -1374,7 +1382,7 @@ packages:
|
||||
dependencies:
|
||||
'@vue/runtime-core': 3.3.10
|
||||
'@vue/shared': 3.3.10
|
||||
csstype: 3.1.2
|
||||
csstype: 3.1.3
|
||||
dev: true
|
||||
|
||||
/@vue/runtime-dom@3.4.3:
|
||||
@@ -1760,7 +1768,7 @@ packages:
|
||||
/c12@1.5.1:
|
||||
resolution: {integrity: sha512-BWZRJgDEveT8uI+cliCwvYSSSSvb4xKoiiu5S0jaDbKBopQLQF7E+bq9xKk1pTcG+mUa3yXuFO7bD9d8Lr9Xxg==}
|
||||
dependencies:
|
||||
chokidar: 3.5.3
|
||||
chokidar: 3.6.0
|
||||
defu: 6.1.4
|
||||
dotenv: 16.3.1
|
||||
giget: 1.1.3
|
||||
@@ -1846,8 +1854,8 @@ packages:
|
||||
dependencies:
|
||||
get-func-name: 2.0.2
|
||||
|
||||
/chokidar@3.5.3:
|
||||
resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
|
||||
/chokidar@3.6.0:
|
||||
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
|
||||
engines: {node: '>= 8.10.0'}
|
||||
dependencies:
|
||||
anymatch: 3.1.3
|
||||
@@ -3394,8 +3402,8 @@ packages:
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
dev: false
|
||||
|
||||
/linkedom@0.16.1:
|
||||
resolution: {integrity: sha512-kbK4txFSjGstS8aHkYo3sRSD7viQbE1TAlYRqiqU13oihzzQFp23D1OwW3VdAQJuzqzBB+1qo9Qvp0xOeoVKig==}
|
||||
/linkedom@0.16.8:
|
||||
resolution: {integrity: sha512-+HtHVHBb3yZKlP9pgcJdi1AIG9tsAuo+Qtlz+79cCTsxgQwDzajsZjYvpp+DEckCK/zoGVhzkADniYZQ57KcFQ==}
|
||||
dependencies:
|
||||
css-select: 5.1.0
|
||||
cssom: 0.5.0
|
||||
@@ -4479,7 +4487,7 @@ packages:
|
||||
engines: {node: '>=14.0.0'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
chokidar: 3.5.3
|
||||
chokidar: 3.6.0
|
||||
immutable: 4.3.4
|
||||
source-map-js: 1.0.2
|
||||
|
||||
@@ -4989,7 +4997,7 @@ packages:
|
||||
dependencies:
|
||||
bundle-require: 4.0.1(esbuild@0.19.8)
|
||||
cac: 6.7.14
|
||||
chokidar: 3.5.3
|
||||
chokidar: 3.6.0
|
||||
debug: 4.3.4
|
||||
esbuild: 0.19.8
|
||||
execa: 5.1.1
|
||||
@@ -5148,7 +5156,7 @@ packages:
|
||||
resolution: {integrity: sha512-9ZdRwbh/4gcm1JTOkp9lAkIDrtOyOxgHmY7cjuwI8L/2RTikMcVG25GsZwNAgRuap3iDw2jeq7eoqtAsz5rW3A==}
|
||||
dependencies:
|
||||
acorn: 8.11.2
|
||||
chokidar: 3.5.3
|
||||
chokidar: 3.6.0
|
||||
webpack-sources: 3.2.3
|
||||
webpack-virtual-modules: 0.5.0
|
||||
dev: false
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ export type {
|
||||
Identity,
|
||||
Idle,
|
||||
Management,
|
||||
Manifest,
|
||||
Manifest, // TODO: Export custom manifest types that are valid for both Chrome and Firefox.
|
||||
ContextMenus,
|
||||
Menus,
|
||||
NetworkStatus,
|
||||
|
||||
@@ -6,41 +6,45 @@ import { exists } from 'fs-extra';
|
||||
|
||||
const cwd = path.resolve(__dirname, 'fixtures/npm-project');
|
||||
|
||||
describe('NPM Package Management Utils', () => {
|
||||
beforeAll(async () => {
|
||||
// NPM needs the modules installed for 'npm ls' to work
|
||||
await execaCommand('npm i', { cwd });
|
||||
});
|
||||
|
||||
describe('listDependencies', () => {
|
||||
it('should list direct dependencies', async () => {
|
||||
const actual = await npm.listDependencies({ cwd });
|
||||
expect(actual).toEqual([
|
||||
{ name: 'flatten', version: '1.0.3' },
|
||||
{ name: 'mime-types', version: '2.1.35' },
|
||||
]);
|
||||
describe(
|
||||
'NPM Package Management Utils',
|
||||
() => {
|
||||
beforeAll(async () => {
|
||||
// NPM needs the modules installed for 'npm ls' to work
|
||||
await execaCommand('npm i', { cwd });
|
||||
});
|
||||
|
||||
it('should list all dependencies', async () => {
|
||||
const actual = await npm.listDependencies({ cwd, all: true });
|
||||
expect(actual).toEqual([
|
||||
{ name: 'flatten', version: '1.0.3' },
|
||||
{ name: 'mime-types', version: '2.1.35' },
|
||||
{ name: 'mime-db', version: '1.52.0' },
|
||||
]);
|
||||
describe('listDependencies', () => {
|
||||
it('should list direct dependencies', async () => {
|
||||
const actual = await npm.listDependencies({ cwd });
|
||||
expect(actual).toEqual([
|
||||
{ name: 'flatten', version: '1.0.3' },
|
||||
{ name: 'mime-types', version: '2.1.35' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('should list all dependencies', async () => {
|
||||
const actual = await npm.listDependencies({ cwd, all: true });
|
||||
expect(actual).toEqual([
|
||||
{ name: 'flatten', version: '1.0.3' },
|
||||
{ name: 'mime-types', version: '2.1.35' },
|
||||
{ name: 'mime-db', version: '1.52.0' },
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('downloadDependency', () => {
|
||||
it('should download the dependency as a tarball', async () => {
|
||||
const downloadDir = path.resolve(cwd, 'dist');
|
||||
const id = 'mime-db@1.52.0';
|
||||
const expected = path.resolve(downloadDir, 'mime-db-1.52.0.tgz');
|
||||
describe('downloadDependency', () => {
|
||||
it('should download the dependency as a tarball', async () => {
|
||||
const downloadDir = path.resolve(cwd, 'dist');
|
||||
const id = 'mime-db@1.52.0';
|
||||
const expected = path.resolve(downloadDir, 'mime-db-1.52.0.tgz');
|
||||
|
||||
const actual = await npm.downloadDependency(id, downloadDir);
|
||||
const actual = await npm.downloadDependency(id, downloadDir);
|
||||
|
||||
expect(actual).toEqual(expected);
|
||||
expect(await exists(actual)).toBe(true);
|
||||
expect(actual).toEqual(expected);
|
||||
expect(await exists(actual)).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
{ timeout: 20e3 },
|
||||
);
|
||||
|
||||
@@ -7,7 +7,7 @@ export const pnpm: WxtPackageManagerImpl = {
|
||||
return npm.downloadDependency(...args);
|
||||
},
|
||||
async listDependencies(options) {
|
||||
const args = ['ls', '--json'];
|
||||
const args = ['ls', '-r', '--json'];
|
||||
if (options?.all) {
|
||||
args.push('--depth', 'Infinity');
|
||||
}
|
||||
|
||||
@@ -111,6 +111,7 @@ describe('Manifest Utils', () => {
|
||||
setFakeWxt({
|
||||
config: {
|
||||
outDir,
|
||||
manifestVersion: 3,
|
||||
manifest: {
|
||||
action: {
|
||||
default_icon: 'icon-16.png',
|
||||
@@ -119,13 +120,83 @@ describe('Manifest Utils', () => {
|
||||
},
|
||||
},
|
||||
});
|
||||
const expected: Partial<Manifest.WebExtensionManifest> = {
|
||||
action: wxt.config.manifest.action,
|
||||
};
|
||||
|
||||
const { manifest: actual } = await generateManifest([], buildOutput);
|
||||
|
||||
expect(actual).toMatchObject(expected);
|
||||
expect(actual.action).toEqual(wxt.config.manifest.action);
|
||||
expect(actual.browser_action).toBeUndefined();
|
||||
expect(actual.page_action).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should generate `browser_action` for MV2 when only `action` is defined', async () => {
|
||||
const buildOutput = fakeBuildOutput();
|
||||
setFakeWxt({
|
||||
config: {
|
||||
outDir,
|
||||
manifestVersion: 2,
|
||||
manifest: {
|
||||
action: {
|
||||
default_title: 'Action',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const { manifest: actual } = await generateManifest([], buildOutput);
|
||||
|
||||
expect(actual.action).toBeUndefined();
|
||||
expect(actual.browser_action).toEqual(wxt.config.manifest.action);
|
||||
expect(actual.page_action).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should keep the `page_action` for MV2 when both `action` and `page_action` are defined', async () => {
|
||||
const buildOutput = fakeBuildOutput();
|
||||
setFakeWxt({
|
||||
config: {
|
||||
outDir,
|
||||
manifestVersion: 2,
|
||||
manifest: {
|
||||
action: {
|
||||
default_title: 'Action',
|
||||
},
|
||||
page_action: {
|
||||
default_title: 'Page Action',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const { manifest: actual } = await generateManifest([], buildOutput);
|
||||
|
||||
expect(actual.action).toBeUndefined();
|
||||
expect(actual.browser_action).toBeUndefined();
|
||||
expect(actual.page_action).toEqual(wxt.config.manifest.page_action);
|
||||
});
|
||||
|
||||
it('should keep the custom `browser_action` for MV2 when both `action` and `browser_action` are defined', async () => {
|
||||
const buildOutput = fakeBuildOutput();
|
||||
setFakeWxt({
|
||||
config: {
|
||||
outDir,
|
||||
manifestVersion: 2,
|
||||
manifest: {
|
||||
action: {
|
||||
default_title: 'Action',
|
||||
},
|
||||
browser_action: {
|
||||
default_title: 'Browser Action',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const { manifest: actual } = await generateManifest([], buildOutput);
|
||||
|
||||
expect(actual.action).toBeUndefined();
|
||||
expect(actual.browser_action).toEqual(
|
||||
wxt.config.manifest.browser_action,
|
||||
);
|
||||
expect(actual.page_action).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1306,6 +1377,76 @@ describe('Manifest Utils', () => {
|
||||
expect(actual.commands).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Stripping keys', () => {
|
||||
const mv2Manifest = {
|
||||
page_action: {},
|
||||
browser_action: {},
|
||||
automation: {},
|
||||
content_capabilities: {},
|
||||
converted_from_user_script: {},
|
||||
current_locale: {},
|
||||
differential_fingerprint: {},
|
||||
event_rules: {},
|
||||
file_browser_handlers: {},
|
||||
file_system_provider_capabilities: {},
|
||||
input_components: {},
|
||||
nacl_modules: {},
|
||||
natively_connectable: {},
|
||||
offline_enabled: {},
|
||||
platforms: {},
|
||||
replacement_web_app: {},
|
||||
system_indicator: {},
|
||||
user_scripts: {},
|
||||
};
|
||||
const mv3Manifest = {
|
||||
action: {},
|
||||
export: {},
|
||||
optional_host_permissions: {},
|
||||
side_panel: {},
|
||||
};
|
||||
const hostPermissionsManifest = {
|
||||
host_permissions: {},
|
||||
};
|
||||
const manifest: any = {
|
||||
...mv2Manifest,
|
||||
...mv3Manifest,
|
||||
...hostPermissionsManifest,
|
||||
};
|
||||
|
||||
it.each([
|
||||
['firefox', 2, mv2Manifest],
|
||||
['chrome', 2, { ...mv2Manifest, ...hostPermissionsManifest }],
|
||||
['safari', 2, { ...mv2Manifest, ...hostPermissionsManifest }],
|
||||
['edge', 2, { ...mv2Manifest, ...hostPermissionsManifest }],
|
||||
['firefox', 3, { ...mv3Manifest, ...hostPermissionsManifest }],
|
||||
['chrome', 3, { ...mv3Manifest, ...hostPermissionsManifest }],
|
||||
['safari', 3, { ...mv3Manifest, ...hostPermissionsManifest }],
|
||||
['edge', 3, { ...mv3Manifest, ...hostPermissionsManifest }],
|
||||
] as const)(
|
||||
"%s MV%s should only include that version's keys",
|
||||
async (browser, manifestVersion, expected) => {
|
||||
setFakeWxt({
|
||||
config: {
|
||||
browser,
|
||||
manifest,
|
||||
manifestVersion,
|
||||
command: 'build',
|
||||
},
|
||||
});
|
||||
const output = fakeBuildOutput();
|
||||
|
||||
const { manifest: actual } = await generateManifest([], output);
|
||||
|
||||
expect(actual).toEqual({
|
||||
name: expect.any(String),
|
||||
version: expect.any(String),
|
||||
manifest_version: manifestVersion,
|
||||
...expected,
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('stripPathFromMatchPattern', () => {
|
||||
|
||||
@@ -18,6 +18,8 @@ import { createViteBuilder } from '~/core/builders/vite';
|
||||
import defu from 'defu';
|
||||
import { NullablyRequired } from '../types';
|
||||
import { isModuleInstalled } from '../package';
|
||||
import fs from 'fs-extra';
|
||||
import { normalizePath } from '../paths';
|
||||
|
||||
/**
|
||||
* Given an inline config, discover the config file if necessary, merge the results, resolve any
|
||||
@@ -77,10 +79,16 @@ export async function resolveConfig(
|
||||
srcDir,
|
||||
mergedConfig.entrypointsDir ?? 'entrypoints',
|
||||
);
|
||||
if (await isDirMissing(entrypointsDir)) {
|
||||
logMissingDir(logger, 'Entrypoints', entrypointsDir);
|
||||
}
|
||||
const filterEntrypoints = !!mergedConfig.filterEntrypoints?.length
|
||||
? new Set(mergedConfig.filterEntrypoints)
|
||||
: undefined;
|
||||
const publicDir = path.resolve(srcDir, mergedConfig.publicDir ?? 'public');
|
||||
if (await isDirMissing(publicDir)) {
|
||||
logMissingDir(logger, 'Public', publicDir);
|
||||
}
|
||||
const typesDir = path.resolve(wxtDir, 'types');
|
||||
const outBaseDir = path.resolve(root, mergedConfig.outDir ?? '.output');
|
||||
const outDir = path.resolve(outBaseDir, `${browser}-mv${manifestVersion}`);
|
||||
@@ -339,3 +347,15 @@ async function resolveWxtModuleDir() {
|
||||
// require.resolve returns the wxt/dist/index file, not the package's root directory, which we want to return
|
||||
return path.resolve(requireResolve('wxt'), '../..');
|
||||
}
|
||||
|
||||
async function isDirMissing(dir: string) {
|
||||
return !(await fs.exists(dir));
|
||||
}
|
||||
|
||||
function logMissingDir(logger: Logger, name: string, expected: string) {
|
||||
logger.warn(
|
||||
`${name} directory not found: ./${normalizePath(
|
||||
path.relative(process.cwd(), expected),
|
||||
)}`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -114,13 +114,17 @@ export async function generateManifest(
|
||||
wxt.config.transformManifest(manifest);
|
||||
await wxt.hooks.callHook('build:manifestGenerated', wxt, manifest);
|
||||
|
||||
if (wxt.config.manifestVersion === 2)
|
||||
if (wxt.config.manifestVersion === 2) {
|
||||
convertWebAccessibleResourcesToMv2(manifest);
|
||||
convertActionToMv2(manifest);
|
||||
}
|
||||
|
||||
if (wxt.config.manifestVersion === 3) {
|
||||
validateMv3WebAccessbileResources(manifest);
|
||||
}
|
||||
|
||||
stripKeys(manifest);
|
||||
|
||||
if (manifest.name == null)
|
||||
throw Error(
|
||||
"Manifest 'name' is missing. Either:\n1. Set the name in your <rootDir>/package.json\n2. Set a name via the manifest option in your wxt.config.ts",
|
||||
@@ -613,6 +617,17 @@ export function convertWebAccessibleResourcesToMv2(
|
||||
);
|
||||
}
|
||||
|
||||
function convertActionToMv2(manifest: Manifest.WebExtensionManifest): void {
|
||||
if (
|
||||
manifest.action == null ||
|
||||
manifest.browser_action != null ||
|
||||
manifest.page_action != null
|
||||
)
|
||||
return;
|
||||
|
||||
manifest.browser_action = manifest.action;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure all resources are in MV3 format. If not, add a wanring
|
||||
*/
|
||||
@@ -632,3 +647,50 @@ export function validateMv3WebAccessbileResources(
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove keys from the manifest based on the build target.
|
||||
*/
|
||||
function stripKeys(manifest: Manifest.WebExtensionManifest): void {
|
||||
let keysToRemove: string[] = [];
|
||||
if (wxt.config.manifestVersion === 2) {
|
||||
keysToRemove.push(...mv3OnlyKeys);
|
||||
if (wxt.config.browser === 'firefox')
|
||||
keysToRemove.push(...firefoxMv3OnlyKeys);
|
||||
} else {
|
||||
keysToRemove.push(...mv2OnlyKeys);
|
||||
}
|
||||
|
||||
keysToRemove.forEach((key) => {
|
||||
delete manifest[key as keyof Manifest.WebExtensionManifest];
|
||||
});
|
||||
}
|
||||
|
||||
const mv2OnlyKeys = [
|
||||
'page_action',
|
||||
'browser_action',
|
||||
'automation',
|
||||
'content_capabilities',
|
||||
'converted_from_user_script',
|
||||
'current_locale',
|
||||
'differential_fingerprint',
|
||||
'event_rules',
|
||||
'file_browser_handlers',
|
||||
'file_system_provider_capabilities',
|
||||
'input_components',
|
||||
'nacl_modules',
|
||||
'natively_connectable',
|
||||
'offline_enabled',
|
||||
'platforms',
|
||||
'replacement_web_app',
|
||||
'system_indicator',
|
||||
'user_scripts',
|
||||
];
|
||||
|
||||
const mv3OnlyKeys = [
|
||||
'action',
|
||||
'export',
|
||||
'optional_host_permissions',
|
||||
'side_panel',
|
||||
];
|
||||
const firefoxMv3OnlyKeys = ['host_permissions'];
|
||||
|
||||
@@ -314,6 +314,7 @@ export const fakeWxt = fakeObjectCreator<Wxt>(() => ({
|
||||
export function setFakeWxt(overrides?: DeepPartial<Wxt>) {
|
||||
const wxt = fakeWxt(overrides);
|
||||
setWxtForTesting(wxt);
|
||||
return wxt;
|
||||
}
|
||||
|
||||
export const fakeBuildOutput = fakeObjectCreator<BuildOutput>(() => ({
|
||||
|
||||
+14
-11
@@ -62,9 +62,9 @@ export async function zip(config?: InlineConfig): Promise<string[]> {
|
||||
await zipDir(wxt.config.zip.sourcesRoot, sourcesZipPath, {
|
||||
include: wxt.config.zip.includeSources,
|
||||
exclude: wxt.config.zip.excludeSources,
|
||||
transform(file, content) {
|
||||
if (file.endsWith('package.json')) {
|
||||
return addOverridesToPackageJson(content, overrides);
|
||||
transform(absolutePath, zipPath, content) {
|
||||
if (zipPath.endsWith('package.json')) {
|
||||
return addOverridesToPackageJson(absolutePath, content, overrides);
|
||||
}
|
||||
},
|
||||
additionalFiles: downloadedPackages,
|
||||
@@ -88,7 +88,8 @@ async function zipDir(
|
||||
include?: string[];
|
||||
exclude?: string[];
|
||||
transform?: (
|
||||
file: string,
|
||||
absolutePath: string,
|
||||
zipPath: string,
|
||||
content: string,
|
||||
) => Promise<string | undefined | void> | string | undefined | void;
|
||||
additionalWork?: (archive: JSZip) => Promise<void> | void;
|
||||
@@ -125,7 +126,7 @@ async function zipDir(
|
||||
const content = await fs.readFile(absolutePath, 'utf-8');
|
||||
archive.file(
|
||||
file,
|
||||
(await options?.transform?.(file, content)) || content,
|
||||
(await options?.transform?.(absolutePath, file, content)) || content,
|
||||
);
|
||||
} else {
|
||||
const content = await fs.readFile(absolutePath);
|
||||
@@ -159,8 +160,7 @@ async function downloadPrivatePackages() {
|
||||
wxt.config.zip.downloadedPackagesDir,
|
||||
);
|
||||
files.push(tgzPath);
|
||||
overrides[id] =
|
||||
'file://./' + normalizePath(path.relative(wxt.config.root, tgzPath));
|
||||
overrides[id] = tgzPath;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,18 +168,21 @@ async function downloadPrivatePackages() {
|
||||
}
|
||||
|
||||
function addOverridesToPackageJson(
|
||||
absolutePackageJsonPath: string,
|
||||
content: string,
|
||||
overrides: Record<string, string>,
|
||||
): string {
|
||||
if (Object.keys(overrides).length === 0) return content;
|
||||
|
||||
const packageJsonDir = path.dirname(absolutePackageJsonPath);
|
||||
const oldPackage = JSON.parse(content);
|
||||
const newPackage = {
|
||||
...oldPackage,
|
||||
[wxt.pm.overridesKey]: {
|
||||
...oldPackage[wxt.pm.overridesKey],
|
||||
...overrides,
|
||||
},
|
||||
[wxt.pm.overridesKey]: { ...oldPackage[wxt.pm.overridesKey] },
|
||||
};
|
||||
Object.entries(overrides).forEach(([key, absolutePath]) => {
|
||||
newPackage[wxt.pm.overridesKey][key] =
|
||||
'file://./' + normalizePath(path.relative(packageJsonDir, absolutePath));
|
||||
});
|
||||
return JSON.stringify(newPackage, null, 2);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,9 @@ export interface InlineConfig {
|
||||
* Directory containing all source code. Set to `"src"` to move all source code to a `src/`
|
||||
* directory.
|
||||
*
|
||||
* After changing, don't forget to move the `public/` and `entrypoints/` directories into the new
|
||||
* source dir.
|
||||
*
|
||||
* @default config.root
|
||||
*/
|
||||
srcDir?: string;
|
||||
|
||||
@@ -23,6 +23,6 @@
|
||||
"@types/react-dom": "^18.2.18",
|
||||
"@vitejs/plugin-react": "^4.2.1",
|
||||
"typescript": "^5.3.3",
|
||||
"wxt": "^0.16.0"
|
||||
"wxt": "^0.17.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,6 @@
|
||||
"devDependencies": {
|
||||
"typescript": "^5.3.3",
|
||||
"vite-plugin-solid": "^2.8.0",
|
||||
"wxt": "^0.16.0"
|
||||
"wxt": "^0.17.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,6 @@
|
||||
"svelte-check": "^3.6.2",
|
||||
"tslib": "^2.6.2",
|
||||
"typescript": "^5.3.3",
|
||||
"wxt": "^0.16.0"
|
||||
"wxt": "^0.17.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,6 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.3.3",
|
||||
"wxt": "^0.16.0"
|
||||
"wxt": "^0.17.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,6 @@
|
||||
"@vitejs/plugin-vue": "^5.0.1",
|
||||
"typescript": "^5.3.3",
|
||||
"vue-tsc": "^1.8.27",
|
||||
"wxt": "^0.16.0"
|
||||
"wxt": "^0.17.0"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user