build.mjs
Rama master · réplica de lectura del repositorio original.
// Build both browser targets with esbuild. No framework, no CSS pipeline:
// the extension has three pages and they load plain stylesheets.
import * as esbuild from "esbuild";
import { readFile, writeFile, mkdir, cp, rm } from "node:fs/promises";
import { existsSync } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
const root = path.dirname(fileURLToPath(import.meta.url));
const src = path.join(root, "src");
const watch = process.argv.includes("--watch");
const dist = process.argv.includes("--dist");
const outRoot = path.join(root, dist ? "dist" : "build");
const TARGETS = [
{ name: "chrome", manifest: "manifest.chrome.json" },
{ name: "firefox", manifest: "manifest.firefox.json" }
];
const ENTRIES = {
background: "background/index.js",
options: "options/index.js",
popup: "popup/index.js",
viewer: "viewer/index.js"
};
const PAGES = [
{ entry: "options", html: "options/index.html", out: "options.html", css: "options/styles.css" },
{ entry: "popup", html: "popup/index.html", out: "popup.html", css: "popup/styles.css" },
{ entry: "viewer", html: "viewer/index.html", out: "viewer.html", css: "viewer/styles.css" }
];
async function buildTarget({ name, manifest }) {
const outdir = path.join(outRoot, name);
await rm(outdir, { recursive: true, force: true });
await mkdir(outdir, { recursive: true });
const entryPoints = Object.fromEntries(
Object.entries(ENTRIES)
.filter(([, rel]) => existsSync(path.join(src, rel)))
.map(([out, rel]) => [out, path.join(src, rel)])
);
const options = {
entryPoints,
outdir,
bundle: true,
format: "esm",
target: ["chrome111", "firefox115"],
sourcemap: dist ? false : "inline",
minify: dist,
logLevel: "warning",
// Firefox MV3 background scripts are not modules in all versions; splitting
// would emit bare imports the loader cannot resolve there.
splitting: false
};
const ctx = watch ? await esbuild.context(options) : null;
if (ctx) await ctx.watch();
else await esbuild.build(options);
await writeFile(
path.join(outdir, "manifest.json"),
await readFile(path.join(src, manifest), "utf8")
);
const common = path.join(src, "ui", "common.css");
if (existsSync(common)) await cp(common, path.join(outdir, "common.css"));
for (const page of PAGES) {
const htmlPath = path.join(src, page.html);
if (!existsSync(htmlPath)) continue;
await writeFile(path.join(outdir, page.out), await readFile(htmlPath, "utf8"));
const cssPath = path.join(src, page.css);
if (existsSync(cssPath)) {
await cp(cssPath, path.join(outdir, `${page.entry}.css`));
}
}
if (existsSync(path.join(src, "icons"))) {
await cp(path.join(src, "icons"), path.join(outdir, "icons"), { recursive: true });
}
return outdir;
}
for (const target of TARGETS) {
const out = await buildTarget(target);
console.log(`${target.name}: ${path.relative(root, out)}`);
}
if (watch) console.log("watching…");