Files
wehub-resource-sync e30e75b5d4
Changesets / Create Version PR (push) Has been cancelled
Deploy Shadcn Registry / Deploy Production (push) Has been cancelled
Template Metrics / LOC + Bundle Size (push) Has been cancelled
Code Quality / Oxlint + Oxfmt (push) Has been cancelled
Code Quality / Template Sync (push) Has been cancelled
Code Quality / Build Changed Packages (push) Has been cancelled
Code Quality / Test Changed Packages (push) Has been cancelled
Deploy Expo Example / Deploy Production (push) Has been cancelled
Deploy Ink Example / Deploy Production (push) Has been cancelled
Python Tests / pytest (assistant-stream, 3.10) (push) Has been cancelled
Python Tests / pytest (assistant-stream, 3.12) (push) Has been cancelled
Python Tests / pytest (assistant-ui-sync-server-api, 3.10) (push) Has been cancelled
Python Tests / pytest (assistant-ui-sync-server-api, 3.12) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:40:13 +08:00

108 lines
3.1 KiB
TypeScript

import { build, context, type BuildOptions } from "esbuild";
import { promises as fs, watch as fsWatch } from "node:fs";
import path from "node:path";
import postcss from "postcss";
import tailwindcss from "@tailwindcss/postcss";
const isWatch = process.argv.includes("--watch");
const rootDir = process.cwd();
const distDir = path.join(rootDir, "dist");
const cssEntry = path.join(rootDir, "app.css");
const buildCss = async () => {
const input = await fs.readFile(cssEntry, "utf-8");
const result = await postcss([tailwindcss]).process(input, {
from: cssEntry,
to: path.join(distDir, "sidepanel.css"),
});
await fs.writeFile(path.join(distDir, "sidepanel.css"), result.css);
if (result.map) {
await fs.writeFile(
path.join(distDir, "sidepanel.css.map"),
result.map.toString(),
);
}
};
const commonOptions: BuildOptions = {
bundle: true,
format: "iife",
target: "chrome100",
minify: !isWatch,
sourcemap: true,
resolveExtensions: [".tsx", ".ts", ".jsx", ".js"],
define: {
"process.env.NODE_ENV": JSON.stringify(
isWatch ? "development" : "production",
),
},
};
const backgroundOptions: BuildOptions = {
...commonOptions,
entryPoints: [path.join(rootDir, "background.ts")],
outfile: path.join(distDir, "background.js"),
};
const sidepanelOptions: BuildOptions = {
...commonOptions,
entryPoints: [path.join(rootDir, "sidepanel.tsx")],
outfile: path.join(distDir, "sidepanel.js"),
jsx: "automatic",
};
const buildExtension = async () => {
await fs.rm(distDir, { recursive: true, force: true });
await fs.mkdir(distDir, { recursive: true });
const staticDir = path.join(rootDir, "static");
const staticFiles = await fs.readdir(staticDir);
await Promise.all([
fs.copyFile(
path.join(rootDir, "manifest.json"),
path.join(distDir, "manifest.json"),
),
fs.copyFile(
path.join(rootDir, "sidepanel.html"),
path.join(distDir, "sidepanel.html"),
),
...staticFiles.map((file) =>
fs.copyFile(path.join(staticDir, file), path.join(distDir, file)),
),
]);
if (isWatch) {
const [backgroundCtx, sidepanelCtx] = await Promise.all([
context(backgroundOptions),
context(sidepanelOptions),
buildCss(),
]);
await Promise.all([backgroundCtx.watch(), sidepanelCtx.watch()]);
// Re-run buildCss whenever app.css changes. fs.watch dedupes via debounce
// since editors may fire multiple events per save.
let cssTimer: NodeJS.Timeout | null = null;
fsWatch(cssEntry, () => {
if (cssTimer) clearTimeout(cssTimer);
cssTimer = setTimeout(() => {
cssTimer = null;
buildCss().catch((err) => console.error("CSS rebuild failed:", err));
}, 50);
});
console.log("Watching background.ts, sidepanel.tsx, and app.css...");
} else {
await Promise.all([
build(backgroundOptions),
build(sidepanelOptions),
buildCss(),
]);
console.log("Built background.js, sidepanel.js, sidepanel.css");
}
console.log(
"Build complete. Load dist/ as unpacked extension in chrome://extensions",
);
};
await buildExtension();