hyperhive/frontend/packages/dashboard/build.mjs
iris 3c6c2ed272 ci: add .mjs to check-comment-blocks.sh + check-issue-refs.sh's scope
mara: "add mjs to the lint and fix it in this pr". Both lints scope their
git ls-files scan to a fixed extension list that never included .mjs, so
all three frontend build.mjs files (swarm-ui, dashboard, agent) were
completely invisible to both -- not merely under the limits, outside the
scan entirely.

check-comment-blocks.sh: added '*.mjs' to the ls-files glob and to the
mode_of regex (same slash-comment treatment .js/.ts/.tsx already get --
.mjs is the same comment syntax, argus's exact proposed fix). check-issue-refs.sh:
added '*.mjs' to its glob list, no regex change needed.

Fixing the scope immediately surfaced real, pre-existing violations in
the other two build.mjs files (swarm-ui's own is already handled by this
PR's earlier commits):
- dashboard/build.mjs: 49-line comment block (trimmed to 15 -- redundant
  per-file output-layout table cut, the code below already names every
  output path) plus three bare tracker tags (#448 x2, #453) in the
  stream-worker comment, reworded to prose
- agent/build.mjs: two bare tracker tags (hyperhive#3685 x2), reworded

No logic changes anywhere -- comment-only edits plus the two lint
scripts. Closes #4300 and (independently filed, consolidated into that
one) #4299.
2026-09-12 13:04:01 +02:00

134 lines
5 KiB
JavaScript

// esbuild build for @hive/dashboard: one JS+CSS bundle per page (H0M3 at
// `/`, dashboard/flow/logs/core/builds/credentials at their own
// `.html`), each named after its own entry point below — see the
// `entryPoints`/`for` lists for the exact map, not repeated here to
// avoid this comment drifting out of sync with the real build steps.
//
// Each JS entry bundles `./common.js` (DOM helpers, Panel singleton,
// NOTIF, path linkification) independently — esbuild inlines the shared
// module into each bundle rather than emitting a shared chunk (no
// `splitting: true`). The Rust binary mounts `dist/` as a
// `tower_http::ServeDir` fallback (`append_index_html_on_directories`
// serves index.html at /); the dashboard SPA lives at /dashboard.html
// (a plain file, not a /dashboard/ prefix) so it never shadows the
// exact-match /dashboard/stream + /dashboard/history SSE routes
// registered before the ServeDir fallback.
import { build } from "esbuild";
import { mkdirSync, copyFileSync, rmSync } from "node:fs";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
const here = dirname(fileURLToPath(import.meta.url));
const src = (p) => resolve(here, "src", p);
const dist = (p) => resolve(here, "dist", p);
const staticDir = (p) => resolve(here, "dist", "static", p);
rmSync(dist(""), { recursive: true, force: true });
mkdirSync(staticDir(""), { recursive: true });
// Bundle the JS entries. ES-module output, browser target, no minify
// (line-aligned source aids debugging; minification belongs in a later
// follow-up once asset sizes warrant it). esbuild writes each entry
// to `static/<name>.js` based on the entryPoint basename.
await build({
entryPoints: [
src("tabs.js"),
src("flow.js"),
src("logs.js"),
src("home.js"),
src("stats.js"),
src("core.js"),
src("builds.js"),
src("credentials.js"),
],
outdir: staticDir(""),
bundle: true,
format: "esm",
platform: "browser",
target: ["es2022"],
sourcemap: true,
logLevel: "info",
// `@hive/shared/modal.js` and `hive-btn.js` import their shadow-DOM
// component CSS (hive-dialog.css, hive-toast.css, hive-btn.css) as raw
// text via a plain `import css from './foo.css'` — the `text` loader turns
// that into a string constant at bundle time instead of erroring on an
// unrecognised extension. None of these JS entries import a `.css`
// file any other way, so this doesn't collide with the separate
// page-stylesheet bundling below (`loader: { '.css': 'css' }`), which
// runs as its own esbuild invocation over different entry points.
loader: { ".css": "text" },
// `@hive/shared/jobq-graph.js` resolves to a real `.jsx` file
// (`JobqGraph.jsx`), pulled in transitively by `builds.js` — esbuild
// already picks the `jsx` loader for `.jsx` by extension, this just
// sets the transform mode to match swarm-ui's (which also authors
// this file). No other entry here uses JSX today; this doesn't turn
// any plain `.js` file into one, `.js` still parses as plain JS.
jsx: "automatic",
jsxImportSource: "preact",
});
// Stream-worker entry. Lives in a separate bundle: SharedWorker
// scripts run in a different global (`self` is the worker scope, no
// `window`) so they can't be inlined into tabs.js / flow.js. Output is
// at `static/stream-worker.js`; common.js's `openStream` references
// `/static/stream-worker.js` as the SharedWorker URL. `format: 'iife'`
// matches the classic-script load (`new SharedWorker(url, name)` with
// no `{ type: 'module' }`); Firefox's module SharedWorker support is
// patchy, so keeping the worker as a classic script + IIFE bundle is
// the compatible default. argus's own review nit here: if a future
// contributor adds an `import` to this bundle, the IIFE format will
// surface it as a build error rather than silently shipping broken code.
await build({
entryPoints: [src("stream-worker.js")],
outdir: staticDir(""),
bundle: true,
format: "iife",
platform: "browser",
target: ["es2022"],
sourcemap: true,
logLevel: "info",
});
// Bundle CSS — one entry per page. esbuild resolves @import including
// the package re-exports from @hive/shared. Each page loads colors.css
// (the standalone base16 palette — the theme swap contract, its own file
// so a swap replaces only it) + theme.css (the semantic derivation
// layer) + common.css (shared typography, badges, buttons, inbox, side
// panel) plus its own page-specific bundle.
for (const entry of [
"colors.css",
"theme.css",
"common.css",
"dashboard.css",
"flow.css",
"logs.css",
"home.css",
"stats.css",
"core.css",
"builds.css",
"credentials.css",
]) {
await build({
entryPoints: [src(entry)],
outfile: staticDir(entry),
bundle: true,
loader: { ".css": "css" },
logLevel: "info",
});
}
for (const html of [
"index.html",
"dashboard.html",
"flow.html",
"logs.html",
"stats.html",
"core.html",
"builds.html",
"credentials.html",
]) {
copyFileSync(src(html), dist(html));
}
console.log("dashboard build ok →", dist(""));