feat: Automatically generate browser_action based on action for MV2 (#519)
This commit is contained in:
@@ -137,6 +137,7 @@ WXT applies several transformations to your manifest to simplify managing both M
|
||||
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:
|
||||
|
||||
@@ -146,10 +147,7 @@ import { defineConfig } from 'wxt';
|
||||
export default defineConfig({
|
||||
mainfest: {
|
||||
action: {
|
||||
default_title: 'Some MV3 Title',
|
||||
},
|
||||
browser_action: {
|
||||
default_title: 'Some MV2 Title',
|
||||
default_title: 'Some Title',
|
||||
},
|
||||
web_accessible_resources: [
|
||||
{
|
||||
@@ -170,7 +168,7 @@ Will be output differently for each manifest version:
|
||||
"manifest_version": 2,
|
||||
// ...
|
||||
"browser_action": {
|
||||
"default_title": "Some MV2 Title"
|
||||
"default_title": "Some Title"
|
||||
},
|
||||
"web_accessible_resources": ["icon/*.png"]
|
||||
}
|
||||
@@ -181,7 +179,7 @@ Will be output differently for each manifest version:
|
||||
"manifest_version": 3,
|
||||
// ...
|
||||
"action": {
|
||||
"default_title": "Some MV3 Title"
|
||||
"default_title": "Some Title"
|
||||
},
|
||||
"web_accessible_resources": [
|
||||
{
|
||||
|
||||
@@ -120,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();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -110,19 +110,21 @@ export async function generateManifest(
|
||||
if (wxt.config.command === 'serve') addDevModeCsp(manifest);
|
||||
if (wxt.config.command === 'serve') addDevModePermissions(manifest);
|
||||
|
||||
stripKeys(manifest);
|
||||
|
||||
// TODO: Remove in v1
|
||||
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",
|
||||
@@ -615,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
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user