do the manifest rewriting stuff smart hooly fuck
This commit is contained in:
parent
d750550c8d
commit
bd778cbd1c
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
node_modules
|
89
entrypoints.ts
Normal file
89
entrypoints.ts
Normal file
|
@ -0,0 +1,89 @@
|
|||
/** The kind of an entrypoint in an extension manifest. */
|
||||
enum ManifestEntrypointKind {
|
||||
/** Javascript run as part of a content script */
|
||||
CONTENT_SCRIPT_JS,
|
||||
/** CSS applied as part of a content script */
|
||||
CONTENT_SCRIPT_CSS,
|
||||
/** Javascript run in the background page of an MV2 extension */
|
||||
BACKGROUND_SCRIPT,
|
||||
/** Javascript run the service worker of an MV3 extension */
|
||||
BACKGROUND_SERVICE_WORKER,
|
||||
/** Image file loaded as the extension's icon at a particular size */
|
||||
ICON,
|
||||
/** Path listed in the `web_accessible_resources` of an MV2 extension */
|
||||
WEB_ACCESSIBLE_RESOURCE_V2,
|
||||
/** Path listed in the `web_accessible_resources` of an MV3 extension */
|
||||
WEB_ACCESSIBLE_RESOURCE_V3,
|
||||
}
|
||||
|
||||
/**
|
||||
* A handle to a single entrypoint from a manifest, which allows for rewriting
|
||||
* the path of the asset in the manifest.
|
||||
*/
|
||||
interface ManifestEntrypoint {
|
||||
type: ManifestEntrypointKind;
|
||||
/** The full path to the entrypoint file. */
|
||||
path: string;
|
||||
/**
|
||||
* Replaces this entry path with the given new path. This is an in-place
|
||||
* operation and directly affects the original manifest object.
|
||||
*/
|
||||
replacePath: (path: string) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all script entrypoints from a manifest, returning them as
|
||||
* {@link ManifestEntrypoint} objects which allow for rewriting the path of each
|
||||
* individual entrypoint in place.
|
||||
* @param manifest Parsed `manifest.json` data.
|
||||
*/
|
||||
export const getScriptEntrypoints = (manifest: chrome.runtime.Manifest): ManifestEntrypoint[] => [
|
||||
...(manifest.content_scripts ?? []).flatMap(script => (script.js ?? []).map((path, i) => ({
|
||||
type: ManifestEntrypointKind.CONTENT_SCRIPT_JS,
|
||||
path,
|
||||
replacePath: newPath => script.js!.splice(i, 1, newPath),
|
||||
}))),
|
||||
...(manifest.manifest_version === 2
|
||||
? (manifest.background?.scripts || []).map((path, i) => ({
|
||||
type: ManifestEntrypointKind.BACKGROUND_SCRIPT,
|
||||
path,
|
||||
replacePath: newPath => manifest.background!.scripts!.splice(i, 1, newPath),
|
||||
}))
|
||||
: (manifest.background?.service_worker ? [{
|
||||
type: ManifestEntrypointKind.BACKGROUND_SERVICE_WORKER,
|
||||
path: manifest.background.service_worker,
|
||||
replacePath: newPath => manifest.background!.service_worker = newPath,
|
||||
}] : [])
|
||||
),
|
||||
];
|
||||
|
||||
/**
|
||||
* Gets all asset entrypoints from a manifest, returning them as
|
||||
* {@link ManifestEntrypoint} objects which allow for rewriting the path of each
|
||||
* individual entrypoint in place.
|
||||
* @param manifest Parsed `manifest.json` data.
|
||||
*/
|
||||
export const getAssetEntrypoints = (manifest: chrome.runtime.Manifest): ManifestEntrypoint[] => [
|
||||
...(manifest.content_scripts ?? []).flatMap(script => (script.css ?? []).map((path, i) => ({
|
||||
type: ManifestEntrypointKind.CONTENT_SCRIPT_CSS,
|
||||
path,
|
||||
replacePath: newPath => script.css!.splice(i, 1, newPath),
|
||||
}))),
|
||||
...Object.entries(manifest.icons || {}).map(([iconSize, path]) => ({
|
||||
type: ManifestEntrypointKind.ICON,
|
||||
path,
|
||||
replacePath: newPath => manifest.icons![iconSize] = newPath,
|
||||
})),
|
||||
...(manifest.manifest_version === 2
|
||||
? (manifest.web_accessible_resources ?? []).map((path, i) => ({
|
||||
type: ManifestEntrypointKind.WEB_ACCESSIBLE_RESOURCE_V2,
|
||||
path,
|
||||
replacePath: newPath => manifest.web_accessible_resources![i] = newPath,
|
||||
}))
|
||||
: (manifest.web_accessible_resources ?? []).flatMap(entry => entry.resources.map((path, i) => ({
|
||||
type: ManifestEntrypointKind.WEB_ACCESSIBLE_RESOURCE_V3,
|
||||
path,
|
||||
replacePath: newPath => entry.resources.splice(i, 1, newPath),
|
||||
})))
|
||||
)
|
||||
];
|
114
index.mjs
114
index.mjs
|
@ -2,6 +2,7 @@
|
|||
|
||||
import {readFileSync} from 'node:fs';
|
||||
import {resolve, basename, extname, dirname, relative, join} from 'node:path';
|
||||
import { getAssetEntrypoints, getScriptEntrypoints } from './entrypoints';
|
||||
|
||||
export function buildConfig ({
|
||||
manifest: manifestPathRelative,
|
||||
|
@ -47,81 +48,31 @@ export function buildConfig ({
|
|||
return join(base, uniqueFileNameSegment(entryPath, ext));
|
||||
}
|
||||
|
||||
/** Scans a manifest for entrypoints */
|
||||
function getEntryPointsFromManifest (manifestContent) {
|
||||
const scriptEntrypointAbsolutePaths = [];
|
||||
const styleEntrypointAbsolutePathss = [];
|
||||
const otherAssetAbsolutePaths = [];
|
||||
// Gather all JS entry points specified in the manifest
|
||||
(manifestContent.content_scripts || []).forEach(({css, js}) => {
|
||||
css && css.forEach((filename, i) => {
|
||||
const id = resolve(manifestDirname, filename);
|
||||
styleEntrypointAbsolutePathss.push(id);
|
||||
css.splice(i, 1, getOutputFilename(id, 'css'));
|
||||
});
|
||||
js && js.forEach((filename, i) => {
|
||||
const id = resolve(manifestDirname, filename);
|
||||
scriptEntrypointAbsolutePaths.push(id);
|
||||
js.splice(i, 1, getOutputFilename(id, 'js'));
|
||||
});
|
||||
});
|
||||
manifestContent.background?.scripts && manifestContent.background.scripts.forEach((filename, i) => {
|
||||
const id = resolve(manifestDirname, filename);
|
||||
scriptEntrypointAbsolutePaths.push(id);
|
||||
manifestContent.background.scripts.splice(i, 1, getOutputFilename(id));
|
||||
});
|
||||
if (manifestContent.background?.service_worker) {
|
||||
const id = resolve(manifestDirname, manifestContent.background.service_worker);
|
||||
scriptEntrypointAbsolutePaths.push(id);
|
||||
manifestContent.background.service_worker = getOutputFilename(id);
|
||||
}
|
||||
manifestContent.icons && Object.entries(manifestContent.icons).forEach(([size, filename]) => {
|
||||
const id = resolve(manifestDirname, filename);
|
||||
// console.log('icon:', size, filename, getOutputFilename(id));
|
||||
otherAssetAbsolutePaths.push(id);
|
||||
manifestContent.icons[size] = getOutputFilename(id);
|
||||
});
|
||||
(manifestContent.web_accessible_resources || []).forEach((entry, i) => {
|
||||
if (typeof entry === 'string') {
|
||||
// mv2 - single top-level array of items
|
||||
const id = resolve(manifestDirname, entry);
|
||||
otherAssetAbsolutePaths.push(id);
|
||||
manifestContent.web_accessible_resources.splice(i, 1, getOutputFilename(id));
|
||||
} else {
|
||||
// mv3 - array of objects with `resources` keys
|
||||
const {resources} = entry;
|
||||
resources && resources.forEach((filename, j) => {
|
||||
const id = resolve(manifestDirname, filename);
|
||||
otherAssetAbsolutePaths.push(id);
|
||||
resources.splice(j, 1, getOutputFilename(id));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
scripts: scriptEntrypointAbsolutePaths,
|
||||
assets: [
|
||||
...styleEntrypointAbsolutePathss,
|
||||
...otherAssetAbsolutePaths,
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
const {scripts, assets} = getEntryPointsFromManifest(manifestContent);
|
||||
const scripts = getScriptEntrypoints(manifestContent);
|
||||
const assets = getAssetEntrypoints(manifestContent);
|
||||
|
||||
return [
|
||||
...scripts.map(entrypointPath => ({
|
||||
input: relative(process.cwd(), entrypointPath),
|
||||
output: {
|
||||
file: join(outDir, getOutputFilename(entrypointPath, 'js')),
|
||||
format: 'iife',
|
||||
sourcemap,
|
||||
},
|
||||
plugins: scriptPlugins,
|
||||
})),
|
||||
// Process each script entrypoint independently
|
||||
...scripts.map(({path, replacePath}) => {
|
||||
// Figure out where this bundle will live in the output
|
||||
const outPath = getOutputFilename(path, 'js');
|
||||
|
||||
// A special step that processes the manifest and copies over non-JS
|
||||
// assets in the meantime
|
||||
// Rewrite the manifest with that path
|
||||
replacePath(outPath);
|
||||
|
||||
// Build the bundle
|
||||
return {
|
||||
input: relative(process.cwd(), path),
|
||||
output: {
|
||||
file: join(outDir, outPath),
|
||||
format: 'iife',
|
||||
sourcemap,
|
||||
},
|
||||
plugins: scriptPlugins,
|
||||
};
|
||||
}),
|
||||
|
||||
// Special step that processes the manifest and injects other assets
|
||||
{
|
||||
input: manifestPathRelative,
|
||||
output: {
|
||||
|
@ -131,11 +82,20 @@ export function buildConfig ({
|
|||
{
|
||||
// emit other assets
|
||||
buildStart () {
|
||||
assets.forEach(absolutePath => this.emitFile({
|
||||
type: 'asset',
|
||||
fileName: getOutputFilename(absolutePath),
|
||||
source: readFileSync(absolutePath),
|
||||
}));
|
||||
assets.forEach(({path, replacePath}) => {
|
||||
// Figure out where the asset will live in output
|
||||
const outPath = getOutputFilename(path);
|
||||
|
||||
// Rewrite the manifest with that path
|
||||
replacePath(outPath);
|
||||
|
||||
// Emit the asset as part of the build step
|
||||
this.emitFile({
|
||||
type: 'asset',
|
||||
fileName: getOutputFilename(absolutePath),
|
||||
source: readFileSync(absolutePath),
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
// hacks to make sure the manifest is emitted as bare JSON
|
||||
|
|
46
package-lock.json
generated
Normal file
46
package-lock.json
generated
Normal file
|
@ -0,0 +1,46 @@
|
|||
{
|
||||
"name": "rollup-create-webext-config",
|
||||
"version": "0.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "rollup-create-webext-config",
|
||||
"version": "0.0.0",
|
||||
"devDependencies": {
|
||||
"@types/chrome": "^0.0.242"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/chrome": {
|
||||
"version": "0.0.242",
|
||||
"resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.242.tgz",
|
||||
"integrity": "sha512-SeMXBSfcAGX9ezTz7Pro7n/AiNdIH3cetkdbM+Kfg3zD24jmbnm0IAEIxzx8ccqrnJenLCfD7fR+4WIYAbeQHw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/filesystem": "*",
|
||||
"@types/har-format": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/filesystem": {
|
||||
"version": "0.0.32",
|
||||
"resolved": "https://registry.npmjs.org/@types/filesystem/-/filesystem-0.0.32.tgz",
|
||||
"integrity": "sha512-Yuf4jR5YYMR2DVgwuCiP11s0xuVRyPKmz8vo6HBY3CGdeMj8af93CFZX+T82+VD1+UqHOxTq31lO7MI7lepBtQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/filewriter": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/filewriter": {
|
||||
"version": "0.0.29",
|
||||
"resolved": "https://registry.npmjs.org/@types/filewriter/-/filewriter-0.0.29.tgz",
|
||||
"integrity": "sha512-BsPXH/irW0ht0Ji6iw/jJaK8Lj3FJemon2gvEqHKpCdDCeemHa+rI3WBGq5z7cDMZgoLjY40oninGxqk+8NzNQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/har-format": {
|
||||
"version": "1.2.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/har-format/-/har-format-1.2.11.tgz",
|
||||
"integrity": "sha512-T232/TneofqK30AD1LRrrf8KnjLvzrjWDp7eWST5KoiSzrBfRsLrWDPk4STQPW4NZG6v2MltnduBVmakbZOBIQ==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,8 @@
|
|||
{
|
||||
"name": "rollup-create-webext-config",
|
||||
"version": "0.0.0",
|
||||
"main": "index.mjs"
|
||||
"main": "index.mjs",
|
||||
"devDependencies": {
|
||||
"@types/chrome": "^0.0.242"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue