Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Web Extension manifest V3 #7050

Merged
merged 43 commits into from Apr 11, 2022
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
1871c28
initial work
101arrowz Oct 10, 2021
663bce3
Fix MV3
101arrowz Oct 11, 2021
967ad13
Merge branch 'v2' into v2
101arrowz Oct 12, 2021
d06a776
Merge branch 'v2' into v2
101arrowz Oct 13, 2021
cd58baa
Merge branch 'v2' into v2
101arrowz Oct 14, 2021
bf15cd3
Merge branch 'v2' into v2
101arrowz Oct 21, 2021
8c40207
working on hmr
101arrowz Oct 21, 2021
2f03e50
Merge branch 'v2' into v2
101arrowz Oct 21, 2021
5434a10
Merge branch 'v2' into v2
101arrowz Oct 25, 2021
9b5698b
Improved error messages
101arrowz Oct 25, 2021
a71db1d
fix sourceType for script background service workers
101arrowz Oct 25, 2021
fa12c2f
new tests
101arrowz Oct 25, 2021
93927b4
Merge branch 'v2' into v2
101arrowz Oct 26, 2021
d638758
Merge branch 'v2' into v2
101arrowz Oct 26, 2021
e2dc5c1
Fix lint
101arrowz Oct 26, 2021
da0a335
Merge branch 'v2' into v2
101arrowz Oct 28, 2021
6847f22
Merge branch 'v2' into v2
101arrowz Oct 29, 2021
6ec72ba
Merge branch 'v2' into v2
101arrowz Nov 13, 2021
0cb5cd7
Merge branch 'v2' into v2
101arrowz Nov 19, 2021
754f308
Merge branch 'v2' into v2
101arrowz Dec 8, 2021
b71d986
Merge branch 'v2' into v2
101arrowz Feb 10, 2022
9d4f6df
revamp
101arrowz Mar 19, 2022
8145bb7
merge
101arrowz Mar 19, 2022
d4e2227
patch versions
101arrowz Mar 19, 2022
69e355e
bugfixes
101arrowz Mar 22, 2022
49f08de
fix tests
101arrowz Mar 22, 2022
c651b44
fix lint
101arrowz Mar 22, 2022
c8522ed
Merge branch 'v2' into v2
101arrowz Mar 22, 2022
e8b4279
automatic web_accessible_resources installation, fixed url imports
101arrowz Mar 22, 2022
a9b7766
Merge branch 'v2' of https://github.com/101arrowz/parcel into v2
101arrowz Mar 22, 2022
206e863
bugfixes
101arrowz Mar 22, 2022
8040212
more bugfixes
101arrowz Mar 24, 2022
22567b0
Merge branch 'v2' into v2
101arrowz Mar 24, 2022
1b1c326
fix lint
101arrowz Mar 24, 2022
f109735
fix asset invalidation
101arrowz Mar 24, 2022
01c23d2
fix versions
101arrowz Mar 24, 2022
4bb01ec
Merge branch 'v2' into v2
101arrowz Mar 28, 2022
7ed00e4
Merge branch 'v2' into v2
101arrowz Mar 30, 2022
b40cf67
minor patches
101arrowz Apr 4, 2022
8afd736
review fixes
101arrowz Apr 5, 2022
cf429a2
improvements
101arrowz Apr 6, 2022
fa91a63
Merge branch 'v2' into v2
devongovett Apr 11, 2022
669f618
Fix dependencies
devongovett Apr 11, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/configs/webextension/index.json
Expand Up @@ -2,6 +2,7 @@
"extends": "@parcel/config-default",
"transformers": {
"manifest.json": ["@parcel/transformer-webextension"],
"mv3-bg-sw:*": ["...", "@parcel/transformer-webextension"],
"raw:*": ["@parcel/transformer-raw"]
},
"packagers": {
Expand Down
152 changes: 106 additions & 46 deletions packages/transformers/webextension/src/WebExtensionTransformer.js
@@ -1,8 +1,9 @@
// @flow
import type {MutableAsset} from '@parcel/types';
import type {MutableAsset, TransformerResult, ResolveFn} from '@parcel/types';

import {Transformer} from '@parcel/plugin';
import path from 'path';
import fs from 'fs';
import jsm from 'json-source-map';
import parseCSP from 'content-security-policy-parser';
import {validateSchema} from '@parcel/utils';
Expand All @@ -19,7 +20,10 @@ const DEP_LOCS = [
['browser_action', 'default_popup'],
['page_action', 'default_icon'],
['page_action', 'default_popup'],
['action', 'default_icon'],
['action', 'default_popup'],
['background', 'scripts'],
['background', 'page'],
['chrome_url_overrides'],
['devtools_page'],
['options_ui', 'page'],
Expand All @@ -31,16 +35,23 @@ const DEP_LOCS = [
['user_scripts', 'api_script'],
];

const AUTORELOAD_BG = fs.readFileSync(
path.join(__dirname, 'runtime', 'autoreload-bg.js'),
'utf8',
);

async function collectDependencies(
asset: MutableAsset,
program: any,
ptrs: {[key: string]: any, ...},
hot: boolean,
resolve: ResolveFn,
) {
// isEntry used whenever strictly necessary to preserve filename
// also for globs because it's wasteful to write out every file name
const fs = asset.fs;
const filePath = asset.filePath;
const isMV2 = program.manifest_version == 2;
if (program.default_locale) {
const locales = path.join(path.dirname(filePath), '_locales');
let err = !(await fs.exists(locales))
Expand Down Expand Up @@ -152,12 +163,13 @@ async function collectDependencies(
});
}
}
if (program.browser_action?.theme_icons) {
for (let i = 0; i < program.browser_action.theme_icons.length; ++i) {
const themeIcon = program.browser_action.theme_icons[i];
const browserActionName = isMV2 ? 'browser_action' : 'action';
if (program[browserActionName]?.theme_icons) {
for (let i = 0; i < program[browserActionName].theme_icons.length; ++i) {
const themeIcon = program[browserActionName].theme_icons[i];
for (const k of ['light', 'dark']) {
const loc = getJSONSourceLocation(
ptrs[`/browser_action/theme_icons/${i}/${k}`],
ptrs[`/${browserActionName}/theme_icons/${i}/${k}`],
'value',
);
themeIcon[k] = asset.addURLDependency(themeIcon[k], {
Expand All @@ -174,12 +186,10 @@ async function collectDependencies(
let war = [];
for (let i = 0; i < program.web_accessible_resources.length; ++i) {
// TODO: this doesn't support Parcel resolution
const files = program.web_accessible_resources[i];
const globFiles = (
await glob(
path.join(
path.dirname(filePath),
program.web_accessible_resources[i],
),
path.join(path.dirname(filePath), isMV2 ? files : files.resources),
fs,
{},
)
Expand All @@ -188,11 +198,20 @@ async function collectDependencies(
needsStableName: true,
loc: {
filePath,
...getJSONSourceLocation(ptrs[`/web_accessible_resources/${i}`]),
...getJSONSourceLocation(
ptrs[
`/web_accessible_resources/${i}${isMV2 ? '' : '/resources'}`
],
),
},
}),
);
war = war.concat(globFiles);
if (isMV2) {
war = war.concat(globFiles);
} else {
files.resources = globFiles;
war.push(files);
}
}
program.web_accessible_resources = war;
}
Expand Down Expand Up @@ -227,18 +246,53 @@ async function collectDependencies(
}
}
}
if (needRuntimeBG) {
if (!program.background) {
program.background = {};
if (isMV2) {
if (hot) {
// To enable HMR, we must override the CSP to allow 'unsafe-eval'
program.content_security_policy = cspPatchHMR(
program.content_security_policy,
);

if (needRuntimeBG) {
if (!program.background) {
program.background = {};
}
if (!program.background.scripts) {
program.background.scripts = [];
}
program.background.scripts.push(
asset.addURLDependency('./runtime/autoreload-bg.js', {
resolveFrom: __filename,
}),
);
}
}
if (!program.background.scripts) {
program.background.scripts = [];
} else {
if (program.background?.service_worker) {
program.background.service_worker = asset.addURLDependency(
program.background.service_worker,
{
needsStableName: true,
// Extra pipeline needed to accept URL specifier
pipeline: needRuntimeBG ? 'mv3-bg-sw' : '',
env: {
context: 'service-worker',
sourceType: 'module',
},
},
);
} else if (needRuntimeBG) {
if (!program.background) {
program.background = {};
}
program.background.service_worker = asset.addURLDependency(
'./runtime/autoreload-bg.js',
{
resolveFrom: __filename,
env: {context: 'service-worker'},
},
);
}
program.background.scripts.push(
asset.addURLDependency('./runtime/autoreload-bg.js', {
resolveFrom: __filename,
}),
);
}
}

Expand All @@ -265,32 +319,38 @@ function cspPatchHMR(policy: ?string) {
}

export default (new Transformer({
async transform({asset, options}) {
async transform({asset, options, resolve}) {
const code = await asset.getCode();
const parsed = jsm.parse(code);
const data: any = parsed.data;
validateSchema.diagnostic(
WebExtensionSchema,
{
data: data,
source: code,
filePath: asset.filePath,
},
'@parcel/transformer-webextension',
'Invalid Web Extension manifest',
);
await collectDependencies(
asset,
data,
parsed.pointers,
Boolean(options.hmrOptions),
);
if (options.hmrOptions) {
// To enable HMR, we must override the CSP to allow 'unsafe-eval'
data.content_security_policy = cspPatchHMR(data.content_security_policy);
if (asset.pipeline == 'mv3-bg-sw') {
101arrowz marked this conversation as resolved.
Show resolved Hide resolved
asset.setCode(`
(function() {
${AUTORELOAD_BG}
})();
${code}
`);
return [asset];
} else {
const parsed = jsm.parse(code);
const data: any = parsed.data;
validateSchema.diagnostic(
101arrowz marked this conversation as resolved.
Show resolved Hide resolved
WebExtensionSchema,
{
data: data,
source: code,
filePath: asset.filePath,
},
'@parcel/transformer-webextension',
'Invalid Web Extension manifest',
);
await collectDependencies(
asset,
data,
parsed.pointers,
Boolean(options.hmrOptions),
resolve,
);
asset.setCode(JSON.stringify(data, null, 2));
return [asset];
}
asset.meta.handled = true;
asset.setCode(JSON.stringify(data, null, 2));
return [asset];
},
}): Transformer);
@@ -1,5 +1,6 @@
/* global window */
var env = window.chrome || window.browser;
var global = typeof self == 'undefined' ? window : self;
var env = global.chrome || global.browser;
env.runtime.onMessage.addListener(function(msg) {
if (msg.__parcel_hmr_reload__) {
env.runtime.reload();
Expand Down