mirror of
https://github.com/teamchong/pxpipe.git
synced 2026-07-22 02:02:51 +02:00
feat(dashboard): rewrite dashboard in Svelte (#25)
Replace the hand-rolled dashboard with a Svelte component tree (App + Sessions / StatsTable / LatestPng / RecentRequests / StatsHeader / Cleanup / CompressionToggle / ToastTray), move the API layer into lib/, and split state into stores/. Add a dedicated dashboard build (`build:dashboard-ui` + a separate tsconfig.dashboard.json) so dashboard sources typecheck independently of the proxy core, which previously broke the root `tsc` build.
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
// Build the Svelte dashboard UI into a single JS bundle string.
|
||||
//
|
||||
// Writes `src/dashboard-bundle.ts` with an exported `DASHBOARD_JS` constant
|
||||
// containing the compiled IIFE bundle. `src/dashboard.ts` embeds this in the
|
||||
// HTML template it serves; no runtime deps on the Node host.
|
||||
//
|
||||
// CSS is compiled inline (each component injects its own <style> on mount via
|
||||
// the svelte compiler's `css: 'injected'` mode), so we ship ONE string.
|
||||
|
||||
import { build } from 'esbuild';
|
||||
import sveltePlugin from 'esbuild-svelte';
|
||||
import { sveltePreprocess } from 'svelte-preprocess';
|
||||
import { writeFile, mkdir } from 'node:fs/promises';
|
||||
import { dirname } from 'node:path';
|
||||
|
||||
const ENTRY = 'src/dashboard/main.ts';
|
||||
const OUT_FILE = 'src/dashboard-bundle.ts';
|
||||
|
||||
const result = await build({
|
||||
entryPoints: [ENTRY],
|
||||
bundle: true,
|
||||
format: 'iife',
|
||||
platform: 'browser',
|
||||
target: 'es2022',
|
||||
// Svelte 5 ships ESM; we IIFE-wrap so the bundle is a single self-contained
|
||||
// script tag in the dashboard HTML. No globals leak — the IIFE returns void.
|
||||
minify: true,
|
||||
write: false,
|
||||
sourcemap: false,
|
||||
// The dashboard runs in the operator's browser, not Workers — `console` is fine.
|
||||
// We keep the bundle small by stripping debug logs but leaving warn/error.
|
||||
drop: ['debugger'],
|
||||
plugins: [
|
||||
sveltePlugin({
|
||||
preprocess: sveltePreprocess(),
|
||||
compilerOptions: {
|
||||
// Inject CSS via JS so we ship ONE artifact, not a separate stylesheet.
|
||||
css: 'injected',
|
||||
// Legacy reactivity (`$:`, `export let`) — Svelte 5 still supports it.
|
||||
// Runes mode would require rewriting every component to `$state`/`$derived`/
|
||||
// `$props`. Worth doing eventually; not blocking this rewrite.
|
||||
runes: false,
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
const js = result.outputFiles[0].text;
|
||||
|
||||
await mkdir(dirname(OUT_FILE), { recursive: true });
|
||||
|
||||
// Embed as a backtick string. JS bundle output is safe inside backticks EXCEPT
|
||||
// for `${`, `` ` ``, and `\`. Escape all three. The compiled IIFE can contain
|
||||
// any of these inside string literals (e.g. an HTML template).
|
||||
const escaped = js
|
||||
.replace(/\\/g, '\\\\')
|
||||
.replace(/`/g, '\\`')
|
||||
.replace(/\$\{/g, '\\${');
|
||||
|
||||
const header = `// AUTO-GENERATED by scripts/build-dashboard-ui.mjs — do not edit by hand.
|
||||
// Source: src/dashboard/ (Svelte). Run \`pnpm run build:dashboard-ui\` to regenerate.
|
||||
// Size: ${js.length} chars (${(js.length / 1024).toFixed(1)} KB).
|
||||
|
||||
export const DASHBOARD_JS = \`${escaped}\`;
|
||||
`;
|
||||
|
||||
await writeFile(OUT_FILE, header);
|
||||
console.log(`✓ built ${OUT_FILE} (${(js.length / 1024).toFixed(1)} KB)`);
|
||||
Reference in New Issue
Block a user