Add the build and web-ext files.

This commit is contained in:
Bauke 2023-04-14 11:48:52 +02:00
parent 30c042f991
commit d03e46a481
Signed by: Bauke
GPG Key ID: C1C0F29952BCF558
2 changed files with 186 additions and 0 deletions

111
source/build.ts Normal file
View File

@ -0,0 +1,111 @@
// Import native Node libraries.
import path from "node:path";
import process from "node:process";
import fsp from "node:fs/promises";
// Import Esbuild and associated plugins.
import esbuild from "esbuild";
import copyPlugin from "esbuild-copy-static-files";
import {sassPlugin} from "esbuild-sass-plugin";
// Import PostCSS and associated plugins.
import cssnano from "cssnano";
import postcss from "postcss";
// Import local functions.
import {createManifest} from "./manifest.js";
import {createWebExtConfig} from "./web-ext.js";
/**
* Create an absolute path from a given relative one, using the directory
* this file is located in as the base.
*
* @param relative The relative path to make absolute.
* @returns The absolute path.
*/
function toAbsolutePath(relative: string): string {
return new URL(relative, import.meta.url).pathname;
}
// Create variables based on the environment.
const browser = process.env.BROWSER ?? "firefox";
const dev = process.env.NODE_ENV === "development";
const test = process.env.TEST === "true";
const watch = process.env.WATCH === "true";
// Create absolute paths to various directories.
const buildDir = toAbsolutePath("build");
const outDir = path.join(buildDir, browser);
const sourceDir = toAbsolutePath("source");
// Ensure that the output directory exists.
await fsp.mkdir(outDir, {recursive: true});
// Write the WebExtension manifest file.
await fsp.writeFile(
path.join(outDir, "manifest.json"),
JSON.stringify(createManifest(browser)),
);
// Write the web-ext configuration file.
await fsp.writeFile(
path.join(buildDir, `web-ext-${browser}.json`),
JSON.stringify(createWebExtConfig(browser, buildDir, dev, outDir)),
);
const cssProcessor = postcss([cssnano()]);
const options: esbuild.BuildOptions = {
bundle: true,
// Define variables to be replaced in the code. Note that these are replaced
// "as is" and so we have to stringify them as JSON, otherwise a string won't
// have its quotes for example.
define: {
$browser: JSON.stringify(browser),
$dev: JSON.stringify(dev),
$test: JSON.stringify(test),
},
entryPoints: [
path.join(sourceDir, "background/setup.ts"),
path.join(sourceDir, "options/setup.tsx"),
],
format: "esm",
logLevel: "info",
minify: !dev,
outdir: outDir,
plugins: [
// Copy all files from `source/assets/` to the output directory.
copyPlugin({src: path.join(sourceDir, "assets/"), dest: outDir}),
// Compile SCSS to CSS.
sassPlugin({
type: "style",
async transform(source) {
// In development, don't do any extra processing.
if (dev) {
return source;
}
// But in production, run the CSS through PostCSS.
const {css} = await cssProcessor.process(source, {from: undefined});
return css;
},
}),
],
// Link sourcemaps in development but omit them in production.
sourcemap: dev ? "linked" : false,
// Currently code splitting can't be used because we use ES modules and
// Firefox doesn't run the background script with `type="module"`.
// Once Firefox properly supports Manifest V3 this should be possible though.
splitting: false,
// Target ES2022, and the first Chromium and Firefox releases from 2022.
target: ["es2022", "chrome97", "firefox102"],
treeShaking: true,
};
if (watch) {
const context = await esbuild.context(options);
await context.watch();
} else {
await esbuild.build(options);
}

75
source/web-ext.ts Normal file
View File

@ -0,0 +1,75 @@
import path from "node:path";
/**
* Barebones type definition for web-ext configuration.
*
* Since web-ext doesn't export any types this is done by ourselves. The keys
* mostly follow a camelCased version of the CLI options
* (ie. --start-url becomes startUrl).
*/
type WebExtConfig = {
artifactsDir: string;
sourceDir: string;
verbose?: boolean;
build: {
filename: string;
overwriteDest: boolean;
};
run: {
browserConsole: boolean;
firefoxProfile: string;
keepProfileChanges: boolean;
profileCreateIfMissing: boolean;
startUrl: string[];
target: string[];
};
};
/**
* Create the web-ext configuration.
*
* @param browser The browser target ("firefox" or "chromium").
* @param buildDir The path to the build directory.
* @param dev Is this for development or production.
* @param outDir The path to the output directory.
* @returns The configuration for web-ext.
*/
export function createWebExtConfig(
browser: string,
buildDir: string,
dev: boolean,
outDir: string,
): WebExtConfig {
const config: WebExtConfig = {
artifactsDir: path.join(buildDir, "artifacts"),
sourceDir: outDir,
build: {
filename: `{name}-{version}-${browser}.zip`,
overwriteDest: true,
},
run: {
browserConsole: dev,
firefoxProfile: path.join(buildDir, "firefox-profile/"),
keepProfileChanges: true,
profileCreateIfMissing: true,
startUrl: [],
target: [],
},
};
if (browser === "firefox") {
config.run.startUrl.push("about:debugging#/runtime/this-firefox");
config.run.target.push("firefox-desktop");
} else if (browser === "chromium") {
config.run.startUrl.push("chrome://extensions/");
config.run.target.push("chromium");
} else {
throw new Error(`Unknown target browser: ${browser}`);
}
return config;
}