Variables grouped into per-node cards with kind squares, module facts, toggle true/false and value + .bool, Injector type chips, Loop frame line; long values fold until Show all; .axis/.bool/tags as kit chips. Trace stays numbered run order. Show node blinks the module or field on the canvas. Grouped right-click menus with a kind header. Loop trace rows, node warning labels and links.
470 lines
29 KiB
JavaScript
470 lines
29 KiB
JavaScript
#!/usr/bin/env node
|
||
import { gzipSync } from "node:zlib";
|
||
import { readFileSync, readdirSync, statSync, writeFileSync, mkdirSync } from "node:fs";
|
||
import { dirname, join } from "node:path";
|
||
import { fileURLToPath } from "node:url";
|
||
|
||
const JS_DIR = fileURLToPath(new URL("../js", import.meta.url));
|
||
|
||
// `--json <path>` writes a machine-readable manifest alongside the human
|
||
// console report. Used by .github/workflows/bundle-size-pr.yml to compute
|
||
// the delta between base and head.
|
||
const args = process.argv.slice(2);
|
||
const jsonIdx = args.indexOf("--json");
|
||
const jsonPath = jsonIdx >= 0 ? args[jsonIdx + 1] : null;
|
||
|
||
// Budgets (gzipped bytes) — tune only with explicit review
|
||
// 2026-05-10: total bumped 250 → 256 KB to fit Phase B duplicate/fork
|
||
// system (per-kind save-to-library fork handlers + supporting helpers
|
||
// + flash/shake CSS). Cycle was explicitly scoped + approved.
|
||
// 2026-05-12: total bumped 256 → 300 KB to fit Batch 2 bundle drag/drop
|
||
// overhaul + headroom for follow-up batches without per-task contortion.
|
||
// Cycle was explicitly scoped + approved.
|
||
// 2026-05-20: total bumped 300 → 312 KB to fit RichTextInput atomic-chip
|
||
// editor reused inside the canvas combine TemplateSection (lazy chunk
|
||
// ~9 KB gzipped). The textarea-with-pills pattern was replaced with the
|
||
// SPA's chip editor so canvas + SPA share one $var/@ref editing surface.
|
||
// Explicitly approved feature request.
|
||
const ENTRY_LIMIT = 30 * 1024; // 30 KB
|
||
// 316 KB — bumped from 312 KB during the nested-bundle drag redesign.
|
||
// The container-scoped resolver (drop-zone.ts), pure applier (drop.ts),
|
||
// floating indicator SFC (BundleDropBar.vue), zoom-aware offsetTop
|
||
// walker, and moving-range filter for bundle drags added ~1 KB net.
|
||
// Bump approved alongside the feature land.
|
||
// 321 KB — bumped from 316 KB for the bundle edit modal
|
||
// (BundleInstanceModal + IdentitySection + RuntimeSection). Modal is
|
||
// lazy-loaded so the entry chunk is unaffected; total grows ~5 KB
|
||
// gzipped for the once-per-bundle edit surface (display name + frame
|
||
// color + master Lock/Hide cascades + Save/Reset-to-library footer).
|
||
// Mirrors the per-kind module modal shell users already know.
|
||
// 323 KB — bumped from 321 KB to fit the HSV color popover inside
|
||
// the bundle modal (shared HsvPicker.vue + hsv.ts moved to
|
||
// `src/components/shared/` so SPA's ColorPicker / TweaksPanel and
|
||
// the canvas bundle modal both drive one picker). Adds ~2 KB
|
||
// gzipped in the lazy modal chunk; entry stays untouched.
|
||
// 324 KB — bumped from 323 KB for the bundle-modal polish round:
|
||
// SPA link in footer, popover Teleport + viewport-aware positioning,
|
||
// always-on "clear color" affordance, stableStringify-based bundle
|
||
// fingerprint that folds meta + instance overrides into the MOD
|
||
// signal, and child-uid preservation on reset-to-library so the
|
||
// outer bundle's MOD evaluates against its existing snapshot rather
|
||
// than flipping to "modified" via spurious uid churn. ~0.5 KB net.
|
||
// 325 KB — bumped from 324 KB for the bundle detach + master toggle
|
||
// rework + true-duplicate-with-local-edits. Adds `setBundleInternal`
|
||
// / `setBundleLock` helpers that delegate to inner-bundle masters
|
||
// (skipping inner-owned rows + recursing into them) and the smart
|
||
// OFF cascade, plus the per-instance deep-clone duplicate that
|
||
// rewrites bundle_origin + parent_uid through a uid map. Net
|
||
// growth ~0.2 KB gzip.
|
||
// 327 KB — bumped from 325 KB for the rule matrix redesign. Replaces
|
||
// the 4-state click-cycle + cog-anchored CellFactorPopover with a
|
||
// click-driven CellRulePopover (4 labeled state buttons + numeric
|
||
// factor input) plus a new collapsible MatrixLegend. Net growth
|
||
// ~1.2 KB gzip across the lazy ContextWidget chunk; entry untouched.
|
||
// 328 KB — bumped from 327 KB for the rule matrix polish pass: popover
|
||
// now Teleports to body (escapes the cell's hover / clipping context),
|
||
// adds a reset-to-library button + native-styled stepper input (mirror
|
||
// of OptionRow's spinner), and the watcher narrows so factor typing
|
||
// no longer select-all-clobbers each keystroke. ~0.4 KB net gzip in
|
||
// the lazy ContextWidget chunk; entry stays put.
|
||
// 330 KB — bumped from 328 KB for the null-wildcard-option feature
|
||
// (2026-05-24). Adds `is_null` option flag + "+ Add null" button on
|
||
// the wildcard editor, pi-ban chip rendering across canvas OptionRow
|
||
// + ExceptionsSection + TestRunner + WildcardEditor, "Include null"
|
||
// checkbox on the nested-ref sub-cat picker, new is_empty /
|
||
// is_not_empty derivation operators + flipped "is empty" tick UI,
|
||
// and engine-side validation + nested-ref filter keyword support.
|
||
// ~0.7 KB net gzip across the lazy ContextWidget chunk; entry stays
|
||
// put. See docs/superpowers/specs/2026-05-24-null-wildcard-option-design.md.
|
||
// 340 KB — bumped from 330 KB during the polish-cleanup cycle.
|
||
// Absorbs the count-aware cross-node downstream scanner + per-instance
|
||
// wildcard uuid collection (graph.ts), library-fallback RichTextPreview
|
||
// wired into the preview-resolver cache (so constraint-modal exception
|
||
// chips + the test-runner constraint table resolve `@{uuid}` against
|
||
// the wildcard library, not just the local node), sync `consumedBy`
|
||
// claim that fixes the cross-node MOVE-becomes-COPY race in
|
||
// ContextWidget's onDrop, plus the constraint pairing badge work
|
||
// landing alongside on the same branch. Approved with the bundle of
|
||
// bug fixes — see the polish-cleanup PR description.
|
||
// 360 KB — bumped from 340 KB for the WP_PromptCleaner widget
|
||
// (2026-05-25). Adds the CleanerWidget spectrum-dial SFC, the
|
||
// BlocklistModal body-teleported editor, the cleaner mount glue
|
||
// chunk, and shared types/intensity helpers. ~9 KB net gzip across
|
||
// the lazy cleaner chunks; entry stays put. See
|
||
// docs/superpowers/specs/2026-05-25-prompt-cleaner-node-design.md.
|
||
// Bumped 360 -> 380 KB on 2026-05-26 to accommodate the WP_VarToInt /
|
||
// WP_VarToFloat / WP_VarToBool converter nodes. New chunks: var-picker
|
||
// SFC + TS parser mirror + widget glue. ~4 KB net gzip across the lazy
|
||
// chunks; entry stays put. See
|
||
// docs/superpowers/specs/2026-05-26-converter-nodes-design.md.
|
||
// Bumped 380 -> 385 KB on 2026-05-27 for the prompt-template-library
|
||
// round-trip modals. LoadTemplateModal gains the ModulePicker-style
|
||
// chrome (search + category/tags filter popover + scrollable rows) and
|
||
// SaveTemplateModal gains the push-to-library layout (category select +
|
||
// Update-existing / Save-as-new dual action). ~3 KB net gzip across the
|
||
// two lazy assembler modal chunks; entry stays put.
|
||
// NOTE: this gate measures the EXTENSION bundle (`js/`, from
|
||
// build:extension) only — NOT the manager SPA (`web_dist/`). The 2026-05-27
|
||
// Documentation tab lives entirely in src/manager → web_dist, so it does
|
||
// not affect this budget; no bump was needed for it.
|
||
// Bumped 385 -> 387 KB on 2026-05-28 for the injector two-tier row model.
|
||
// Adds the durable general-template row to the InjectorWidget lazy chunk:
|
||
// the inline binding+template editor + refs hint in InjectorRow.vue, the
|
||
// `kind` discriminator + addGeneralRow + general-aware reconcile in
|
||
// InjectorWidget.vue, and the general-row branch in the conflict scanner.
|
||
// ~1.5 KB net gzip in the lazy InjectorWidget chunk (baseline was already
|
||
// at 393968/394240 — only 272 B free — so the bump is required); entry
|
||
// stays put.
|
||
// Bumped 387 -> 388 KB on 2026-05-28 for the kind-aware RefChip. Engine
|
||
// warnings like `constraint_never_applied` wrap NON-wildcard ids (the
|
||
// constraint module's own id + the target wildcard id) as `@{uuid}` in
|
||
// the message text. Pre-fix, RefChip painted every `@{uuid}` as a
|
||
// wildcard chip — the constraint id fell through as a red `?` because
|
||
// the resolver only consulted the wildcard catalog. Adds the
|
||
// `moduleKind` prop + `--wp-refchip-tone` inline style + per-kind
|
||
// PrimeIcon switch in RefChip.vue, the `resolveModuleChip` library-
|
||
// wide search in resolveChip.ts, a `uuidToKind` prop on RichTextPreview
|
||
// wiring through the preview-resolver `kind` field, and a trace-derived
|
||
// `uuidToKindMap` in DebugViewer. ~0.3 KB net gzip across the lazy
|
||
// DebugViewer + _shared + preview-resolver chunks; entry stays put.
|
||
// Bumped 388 -> 393 KB on 2026-05-28 for the WP_SeedList DOM widget.
|
||
// Replaces the three stock widgets (strategy Combo + 2× Boolean
|
||
// override toggles) with a single socketless DOM widget owning the
|
||
// strategy chip group + both override toggles inside one SFC. Adds
|
||
// the SeedListWidget Vue chunk (~4.2 KB gzip) + the seed_list glue
|
||
// chunk (~0.7 KB gzip) for a ~4.9 KB total bump; entry stays put.
|
||
// Same cycle also prefixed every custom DOM widget input name with
|
||
// `wp_*` (modules → wp_modules, rows → wp_rows, viewer → wp_viewer,
|
||
// etc.) so the canvas socket labels read as branded WP widgets — no
|
||
// bundle impact from the rename alone.
|
||
// 2026-05-28: bumped 393 -> 395 KB for the SeedListWidget override
|
||
// lock UI (disabled-attr on strategy chips + `--locked` wrapper class +
|
||
// strategyLocked computed + two new lock-state Vitest cases). Plus the
|
||
// host glue (`setStockWidgetDisabled` + `syncStockWidgetGates` callers
|
||
// in onUpdate/onValueRestored/microtask). Net ~0.5 KB gzip; 2 KB
|
||
// headroom buffer to avoid the "17 bytes from budget" tightness from
|
||
// the previous bump.
|
||
// Bumped 395 -> 405 KB on 2026-06-07 for SP1 Chunk G (in-graph multi-tag
|
||
// pool editor). PoolSection gains grouped quick pills + an ƒ(x) Advanced
|
||
// boolean-expression editor; OptionRow gains per-tag CATEGORY chips; and
|
||
// the shared engine-parity subcat_filter parser (parse/matches/readsAs)
|
||
// is now imported into the wildcard graph editor chunk. ~4 KB net gzip
|
||
// across the lazy ContextWidget chunk; entry stays put. Approved with the
|
||
// SP1 multi-tag + boolean-filter feature (docs/superpowers/specs/
|
||
// 2026-06-06-wildcard-multi-subcategory-boolean-filter-design.md §4.2).
|
||
// Bumped 405 -> 430 KB on 2026-06-11 for SP3 constraint reach UI headroom.
|
||
// SP3 Task 13 lands the TS combineConstraintFactor mirror (+ shared corpus
|
||
// parity test) now; the upcoming reach/constraint-matrix UI phases need the
|
||
// total budget headroom in the lazy ContextWidget chunk. Approved alongside
|
||
// the SP3 constraint feature.
|
||
// Bumped 430 -> 431 KB on 2026-06-18 — two same-day landings share the
|
||
// ceiling (both CSS/glue; the manager-only bulk UI adds nothing to js/):
|
||
// - editor robustness: RichTextInput renderEpoch crash fix + useEditorDraft
|
||
// flush-on-unmount/unload + ErrorBoundary copy + clipboard-shield wired
|
||
// into _shared.ts / main.ts (Ctrl-A/C/V/X guard on editable inputs).
|
||
// - instance-modal scroll/sticky: sticky header + runtime/footer dock +
|
||
// own-scrollbar inner lists (options/values/rules/exceptions) + compact
|
||
// exceptions trash, across all 6 edit modals.
|
||
// Bumped 431 -> 432 KB on 2026-06-18 for the syntax + UI fix batch: inline
|
||
// `{N::a|b}` branch weights (engine + TS resolver mirror), the filter / pick /
|
||
// exclude-null MOD-dot fix, the "X of Y options" + "picks N-M" wildcard
|
||
// subtitle, the library-aware nested-ref check (kills the false BROKEN REF),
|
||
// and the constraint source-missing debug warning + label. ~0.4 KB net gzip
|
||
// across the ContextWidget + conflicts chunks; entry stays put.
|
||
// Bumped 432 -> 435 KB on 2026-06-22 for the canvas constraint-matrix grouping
|
||
// parity. MatrixSection (the ComfyUI instance-modal grid) gains the SPA's
|
||
// grouped-axis layout — column bands, row header chips, solo eyebrow, the
|
||
// labelled "uncategorized" bucket, and frozen headers + both-axis scroll —
|
||
// plus the shared components/shared/matrix-axis module the SPA matrix now
|
||
// imports too. ~1.1 KB net gzip in the lazy ContextWidget chunk; entry stays
|
||
// put. Approved with the matrix-parity feature request.
|
||
// Bumped 435 -> 442 KB on 2026-06-23 for per-iteration seeds modal
|
||
// (T8+T9). ContextLoopWidget gains the SeedListModal + SeedLockRow lazy
|
||
// body (v-if gated) — adds ~5.5 KB net gzip to the ContextLoopWidget
|
||
// lazy chunk. SeedListWidget gains a matching button in T9. Headroom
|
||
// covers both T8 and T9 landings without per-task bump friction.
|
||
// Bumped 442 -> 443 KB on 2026-06-23 for T9 (SeedListWidget seeds
|
||
// button). The SeedListWidget chunk grew ~0.7 KB gzip adding the button
|
||
// template + ref/computed script + seedbtn CSS; T8's headroom estimate
|
||
// was tight. Minimal bump to the actual measured ceiling.
|
||
// Bumped 443 -> 444 KB on 2026-06-23 for T12 (seed-list preview
|
||
// effective base/count/strategy from wired loop). Adds preview.ts pure
|
||
// resolver + graph-walk glue in seed_list.ts + previewStrategy prop in
|
||
// SeedListWidget.vue. ~0.4 KB net gzip in the seed_list widget chunk.
|
||
// Bumped 444 -> 445 KB on 2026-06-23 for T16 (seed modal paste-to-replace).
|
||
// Adds parseSeedLocks in seed-derive + pasteAll/Paste button in SeedListModal.
|
||
// Measured 454900 bytes (244 over the 444 ceiling); minimal bump.
|
||
// Bumped 445 -> 446 KB on 2026-06-24 for UI-C (wire ContextWidget frame edits).
|
||
// Adds imports of frame-cursor / frame-overrides / INSTANCE_FIELDS_PER_KIND into
|
||
// the ContextWidget lazy chunk + the merge-on-open / write-redirect logic.
|
||
// Measured 455772 bytes (92 over the 445 ceiling); minimal bump.
|
||
// Bumped 446 -> 447 KB on 2026-06-24 for RF2 (frame-aware row quick-lock).
|
||
// Adds toggleFrameLock helper in frame-overrides.ts + effectiveLockedSeed +
|
||
// frame branch in toggleLockOnCard + frame-aware isLocked. Net ~168 bytes
|
||
// gzip in the lazy ContextWidget chunk; entry stays put.
|
||
// Bumped 447 -> 448 KB on 2026-06-24 for the symmetric per-frame enable
|
||
// redesign (a `frame_enabled` override map replaces the `disabled_frames`
|
||
// blocklist so a base-off module can be turned ON for select frames). Adds
|
||
// frameEnabledAt / effectiveEnabled / frameEnableOverride / toggleFrameEnabled
|
||
// to frame-overrides.ts, the effective-enabled checkbox + bidirectional
|
||
// on-#k / off-#k badge in ModuleRow, and the .wp-mod-badge--on CSS. Measured
|
||
// 457868 bytes (140 over the 447 ceiling); minimal bump.
|
||
// Bumped 448 -> 449 KB on 2026-06-25 for the per-frame seed-lock correctness
|
||
// work: the Loop's derived-series capture (loop_seeds UI payload + onExecuted
|
||
// store + frameSeedReader preference, so the lock pins the PREVIOUS run's
|
||
// per-frame seed under control_after_generate=randomize) plus the modal
|
||
// Lock-button resolver (lock-seed-ctx provide/inject into SeedLockControls).
|
||
// Landed exactly at the 448 ceiling (458752/458752); bump for headroom.
|
||
// Bumped 449 -> 450 KB on 2026-06-28 for the row context-menu Hold toggle.
|
||
// Adds HOLD_KINDS + isHoldable + toggleHold to ContextWidget plus the quick
|
||
// "Hold across run" / "Release hold" menu item (2-click seed_scope toggle,
|
||
// base-only with a frame-active disabled hint) in the lazy ContextWidget
|
||
// chunk; entry stays put. Measured 459909 bytes (133 over the 449 ceiling);
|
||
// minimal bump.
|
||
// Bumped 450 -> 453 KB on 2026-07-21 for loop bypass frames (#13): the
|
||
// `bypass_frames` config field + the SeedLockRow bypass toggle, the
|
||
// SeedListModal opt-in bypass column, and the ContextLoopWidget "N bypassed"
|
||
// badge. Config field alone landed 34 bytes over 450; the ~3 KB headroom
|
||
// covers the UI additions in the same feature.
|
||
// Bumped 453 -> 461 KB on 2026-07-23 for the chip-UX + library-linkage feature
|
||
// set (issues #1-#9). Workstream B (RefChip hover card: uuid + filter reads-as
|
||
// + live "N of M options match" from the extended preview-resolver) landed the
|
||
// canvas within 10 bytes of the 453 ceiling; the +8 KB gives the remaining
|
||
// workstreams D (library re-link UI) and E (nested-ref propagation) room in the
|
||
// same approved feature set. Explicitly approved.
|
||
// Bumped 461 -> 468 KB on 2026-07-30 for the QoL sweep (P0+P1). The bulk is UI
|
||
// that had to grow: export/import row detail per entity kind, the category
|
||
// IconPicker, the feedback modal, cross-bucket search, collapsible tag pools,
|
||
// and finally `collectUpstreamProducers` + the var-chip producer card, which
|
||
// tipped it 180 bytes over. Explicitly approved by the maintainer, who asked
|
||
// for the budget to be raised as needed rather than features trimmed to fit.
|
||
// Bumped 468 -> 490 KB on 2026-08-02 for the `@`/`$` autocomplete + sub-category
|
||
// filter redesign. The popover rows carry structure now (icon, uuid, option /
|
||
// axis / tag facts, and for `$` the producer line and override badge) instead
|
||
// of one line of text, and the shared filter panel that follows adds the
|
||
// axis-grouped palette with collapse + search, the live match count and the
|
||
// zero-match / unknown-term states. Sized with headroom deliberately: the
|
||
// previous bump left 179 bytes free, which meant every subsequent change had
|
||
// to argue with the gate. Explicitly approved by the maintainer, who asked for
|
||
// the budget to be raised as needed rather than features trimmed to fit.
|
||
// LOWERED 490 -> 420 KB on 2026-08-06, after the webfonts stopped being bundled.
|
||
// Vite library mode ignores `assetsInlineLimit` and base64-inlined both woff2
|
||
// files into a JS chunk; they are now copied to js/assets/fonts/ and <link>ed at
|
||
// runtime (see src/extension/fonts.ts). Measured 492,407 -> 403,055 bytes.
|
||
//
|
||
// Tightened rather than banked, because the gate is what stops it silently
|
||
// regressing: re-inlining the fonts would add ~90 KB, which fits under 490 KB
|
||
// and would have passed unnoticed. It does not fit under 420 KB. The 17 KB of
|
||
// headroom left is deliberate — enough for ordinary work, not enough to hide a
|
||
// whole asset class coming back.
|
||
// RAISED 420 -> 424 KB on 2026-10-02 for the wildcard fallback option (canvas
|
||
// badge + Debug note): dev sat at 429,971 bytes, 109 under the gate, and the
|
||
// feature needed ~200. Approved by the maintainer ("you are allowed to
|
||
// increase the bundle budget if necessary"). 4 KB leaves room for a few more
|
||
// small features while a re-inlined font (~90 KB) still trips the gate.
|
||
// RAISED 424 -> 428 KB on 2026-10-05 for Context Loop sweep mode (Sweep
|
||
// panel in the loop widget chunk, downstream-wildcard walk in boot): dev sat
|
||
// at 430,134 bytes and the feature adds ~4.8 KB. The maintainer treats this
|
||
// budget as a guide to raise when a needed feature does not fit.
|
||
// RAISED 428 -> 436 KB on 2026-10-06 for model-aware pipelines (WP Model Info
|
||
// walker branches + variant rules + its widget glue in boot, the Model Info
|
||
// widget chunk with pins, Assembler toggles and the shared row-primitive
|
||
// buttons, Match variable control in the wildcard modal chunk, LoRA by model
|
||
// preset): the feature adds ~6 KB and tipped dev ~3.2 KB over. Same "guide,
|
||
// not a cap" rule as above.
|
||
// RAISED 436 -> 440 KB on 2026-10-06 for the constraint "rules out all"
|
||
// warning (the constraint factor math and wildcard pool helpers now reach the
|
||
// ContextWidget chunk): dev sat at 446,313 of 446,464 bytes and the check adds
|
||
// ~2.2 KB. Same "guide, not a cap" rule as above.
|
||
// RAISED 440 -> 452 KB on 2026-10-07 for WP Image Filter (pick-and-pass
|
||
// node): its picker modal (~7.6 KB) and node widget (~3.4 KB) are lazy
|
||
// chunks, plus ~1.5 KB of event + widget glue in boot. dev sat at 448,610
|
||
// bytes. Same "guide, not a cap" rule as above.
|
||
// RAISED 452 -> 464 KB on 2026-10-07 for the Image Filter refine step
|
||
// (frame labels, sweep grid, compare, prompt edits, mask painter, Send to
|
||
// Loop): the picker chunk grows ~8 KB and stays lazy. The branch sat at
|
||
// 462,555 bytes before it. Same "guide, not a cap" rule as above.
|
||
// RAISED 464 -> 468 KB on 2026-10-07 for the zoom's Details panel and the
|
||
// frame-click zoom (lazy picker chunk); the branch sat at 476,239 bytes.
|
||
// RAISED 468 -> 472 KB on 2026-10-14 for the Split loading mark in the canvas
|
||
// modals (Load template, Push to library); Dumi asked for it everywhere.
|
||
// RAISED 472 -> 476 KB on 2026-10-14 for negatives on node fixed values and
|
||
// combines (NegativeField in their lazy editor chunks) and the chat round;
|
||
// the branch sat at 483,532 bytes.
|
||
// RAISED 476 -> 480 KB on 2026-10-14 when the AI knowledge round (canvas-facts
|
||
// answer, ~0.6 KB in boot) landed on top of it.
|
||
// Same "guide, not a cap" rule as above.
|
||
// dev's canvas widget lifecycle fix (2026-10-16, ~0.65 KB in boot) fits in
|
||
// the same 480 KB.
|
||
// RAISED 480 -> 496 KB on 2026-10-17 for client-side shape checks on install
|
||
// (review finding H1): the canvas can install community dependencies, so the
|
||
// Zod validators ship as their own lazy chunk (shape-check-*.mjs, ~17 KB
|
||
// gzip) that loads only when something is installed. dev sat at 485,671
|
||
// bytes; the branch at 502,904.
|
||
// RAISED 496 -> 512 KB on 2026-10-27 for the shared component kit (Dumi
|
||
// approved one component per control for canvas + manager): ContextMenu now
|
||
// places itself through kit/floating.ts (branch 508,348 bytes,
|
||
// 444 over), and the canvas twins (Button, Switch, Tabs, Popover, Tooltip)
|
||
// land next in widget chunks, never in boot.
|
||
// RAISED 512 -> 536 KB on 2026-10-29 for WP Toggles (#200) landing on top of
|
||
// WP Note (#199): the toggles widget, its row outputs and the merge command
|
||
// are lazy widget chunks (boot unchanged); the merge sat at 545,077 bytes.
|
||
// RAISED 536 -> 552 KB on 2026-10-29 for WP Toggles' mute / bypass control
|
||
// and WP Node Group (a new frontend-only node + panel), the clean/edit views
|
||
// and the richer Pick one: lazy widget chunks plus a few KB of boot glue
|
||
// (registration, the prompt strip); the branch sat at 552,937 bytes.
|
||
// RAISED 552 -> 576 KB on 2026-10-29 for the WP Note editor: a formatting
|
||
// bar, links to any docs page and section (the page/section catalog, ~5 KB
|
||
// gzip) and icons from the full PrimeIcons list. All of it is in the note's
|
||
// lazy chunks (NoteWidget, NotePeek, note-markdown), loaded only when a
|
||
// note is on the canvas; boot unchanged. dev sat at ~556,000 bytes after #201, the merge at 575,436.
|
||
// RAISED 576 -> 584 KB on 2026-10-29 for WP Bookmark (a frontend-only node
|
||
// that jumps the canvas to a saved spot): its widget and the Bookmarks dock
|
||
// are lazy chunks (~11 KB, plus the kit pieces they share), with ~5 KB of
|
||
// boot glue for the node, the jump, the hidden filter and the one shortcut
|
||
// listener, plus a WP Note that can be a bookmark (the shared jump fields);
|
||
// the branch sat at 595,973 bytes after merging the WP Note editor.
|
||
// RAISED 584 -> 586 KB on 2026-10-29 for the bookmark polish: frameless WP
|
||
// Bookmark (shared with WP Note in _frameless.ts), the free-area measuring
|
||
// for jumps and the dock, the draggable dock and Use this view; boot +1 KB,
|
||
// the rest in the lazy bookmark chunks; the branch sat at 598,327 bytes.
|
||
// RAISED 586 -> 590 KB on 2026-11-02 for bookmarks on the free canvas (the
|
||
// side / bottom panel pane, minimap and zoom controls, the dock's snap
|
||
// spots), the page key probe for shortcuts, and the note's tables, task
|
||
// boxes and callouts (~1.2 KB gzip, in the bookmark and note chunks).
|
||
// RAISED 590 -> 596 KB on 2026-11-02 for kit 0.5.0 (one field box, one
|
||
// Chip, CodeBlock syntax colours, Skeleton shapes; ~2.5 KB gzip on its own,
|
||
// dev at 606,638 bytes) and the loading shapes that replace empty states and
|
||
// spinners in the list pages, editors, pickers and settings (~1.2 KB, mostly
|
||
// in lazy manager chunks); the branch sat at 607,885 bytes.
|
||
// RAISED 596 -> 600 KB on 2026-11-02 for kit 0.6.0: one Button, Modal,
|
||
// Checkbox, switch and colour field for both sides. Button now carries its
|
||
// stylesheet scoped plus the tooltip, ConfirmModal runs on Modal + ModalShell
|
||
// with the focus trap, and Checkbox/Popover grew to cover what WpCheck and the
|
||
// canvas popovers did; WpButton, CloseButton, ConfirmDialog and WpCheck went
|
||
// (net ~4.1 KB gzip: dev 607,885 -> 611,998 bytes).
|
||
// RAISED 600 -> 603 KB on 2026-11-03 for the kit buttons batch A: the
|
||
// sub-category filter picker (shared with the canvas Pool section) now draws
|
||
// its tags, operators and axis rows with Chip and ListRow and its actions
|
||
// with Button, which pulls those pieces and the tooltip into its chunk
|
||
// (dev 613,654 -> 616,336 bytes).
|
||
// RAISED 603 -> 607 KB on 2026-11-03 for the canvas kit buttons (batches A
|
||
// and B): the note editor's toolbar is the kit Toolbar with Buttons, the note
|
||
// and bundle colours RadioGroup swatches (+ ColorField), the Var Picker the kit
|
||
// Combobox with its Popover, the pickers' rows ListRows, and the debug viewer /
|
||
// image filter use Button and WpIconButton, which pull those pieces into the
|
||
// canvas chunks (dev ~616,500 -> 619,558 bytes).
|
||
// RAISED 607 -> 608 KB on 2026-11-03 for the end of the kit migration: every
|
||
// text field (manager and canvas) is the kit Input / Textarea / SearchInput and
|
||
// the last canvas toggles are Chips (kit 0.10.0), which pull those pieces into
|
||
// more chunks (619,558 -> 622,398 bytes).
|
||
// RAISED 608 -> 610 KB on 2026-11-03 for kit 0.11.0: Input and Textarea carry
|
||
// their own scoped styles (so canvas fields look right without local copies)
|
||
// and the editors' menus moved onto Popover / DropdownMenu / Modal
|
||
// (621,933 -> 623,679 bytes). Batch B drops the canvas fields' local copies.
|
||
// RAISED 610 -> 614 KB on 2026-11-03 for the selection-toolbar "?" and pencil
|
||
// (#225: the help dialog chunk and the toolbar commands in the boot chunk),
|
||
// the labels-toggle fix (#249) and kit 0.14's bigger canvas controls
|
||
// (623,679 -> 626,405 bytes).
|
||
// RAISED 614 -> 630 KB on 2026-11-03 for the WP Note add-to-library button
|
||
// (#252): pressing it runs the Import tab's install pipeline (shape check
|
||
// with Zod, migrations, commit, reattach) from the canvas, so those land in
|
||
// the extension build as lazy chunks that load on the press only
|
||
// (626,405 -> 636,864 bytes).
|
||
// RAISED 630 -> 640 KB on 2026-11-04 for pictures in WP Note: the
|
||
// Pictures panel, the canvas re-encode (note-images.ts) and the picture
|
||
// syntax ride in the note's lazy editor chunk (dev was already ~636.9 KB).
|
||
// RAISED 640 -> 650 KB on 2026-11-10: kit 0.14 -> 0.15.3 (colour picker
|
||
// fixes, PostCard samples, overlay-scrollbar room) put the total at ~640.9 KB.
|
||
// RAISED 650 -> 655 KB on 2026-11-11: WP Debug's newer-node support (node
|
||
// cards in Variables, Show node blink, toggle values/.bool) put it at ~650.04 KB.
|
||
// RAISED 655 -> 665 KB on 2026-11-12: every docs screenshot can go in a WP
|
||
// Note (note-assets.json + the kit's ImageGrid/SearchInput in the note's lazy
|
||
// editor chunk) put the total at ~652.9 KB.
|
||
// RAISED 660 -> 670 KB on 2026-11-12: with both of those, WP Toggles' toggle
|
||
// window (Value box, icon picker and colour fields in a lazy chunk) and the
|
||
// toggle looks put the total at ~660.0 KB, 9 bytes under the old line.
|
||
const TOTAL_LIMIT = 670 * 1024; // 670 KB
|
||
// The total budget is a guide, not a cap (Dumi, 2026-10-06), so the gate has
|
||
// two bands: over TOTAL_LIMIT it warns (CI stays green and shows a
|
||
// `::warning` annotation), and only past TOTAL_LIMIT + 5% does it fail. A
|
||
// warning means "raise the budget in this PR with a line above saying why";
|
||
// a failure means something grew by far more than one feature should.
|
||
const TOTAL_FAIL_LIMIT = Math.round(TOTAL_LIMIT * 1.05);
|
||
|
||
function gzipSize(path) {
|
||
return gzipSync(readFileSync(path)).length;
|
||
}
|
||
|
||
function allJsFiles(dir) {
|
||
const out = [];
|
||
for (const name of readdirSync(dir)) {
|
||
const full = join(dir, name);
|
||
if (statSync(full).isDirectory()) {
|
||
out.push(...allJsFiles(full));
|
||
} else if (name.endsWith(".js") || name.endsWith(".mjs")) {
|
||
out.push(full);
|
||
}
|
||
}
|
||
return out;
|
||
}
|
||
|
||
let failed = false;
|
||
|
||
const files = allJsFiles(JS_DIR);
|
||
let total = 0;
|
||
const manifest = { entry: null, total: 0, files: {} };
|
||
console.log(`\nBundle size report (gzipped):\n`);
|
||
for (const file of files) {
|
||
const size = gzipSize(file);
|
||
total += size;
|
||
const rel = file.substring(JS_DIR.length + 1);
|
||
// Strip the rolled-up content hash so PR ↔ base file names match. Vite
|
||
// emits `assets/<name>-<hash>.js` per chunk; the hash changes with any
|
||
// content edit and would otherwise show every chunk as added/removed.
|
||
// Normalize Windows backslashes so the manifest diffs cleanly against
|
||
// CI runs (which always emit forward slashes on Linux).
|
||
// Lazy chunks are `.mjs` (see vite.config.mts); report them under `.js` so
|
||
// manifests from before that switch still diff chunk-for-chunk.
|
||
const stable = rel.replace(/-[A-Za-z0-9_-]{8,}\.m?js$/, ".js").replaceAll("\\", "/");
|
||
manifest.files[stable] = size;
|
||
console.log(` ${rel.padEnd(40)} ${(size / 1024).toFixed(2).padStart(7)} KB`);
|
||
}
|
||
manifest.total = total;
|
||
manifest.budget = TOTAL_LIMIT;
|
||
manifest.failAt = TOTAL_FAIL_LIMIT;
|
||
console.log(` ${"TOTAL".padEnd(40)} ${(total / 1024).toFixed(2).padStart(7)} KB`);
|
||
|
||
const entry = files.find((f) => f.endsWith("main.js"));
|
||
if (entry) {
|
||
const entrySize = gzipSize(entry);
|
||
manifest.entry = entrySize;
|
||
if (entrySize > ENTRY_LIMIT) {
|
||
console.error(`\n✗ Entry main.js gzip ${entrySize} bytes exceeds budget ${ENTRY_LIMIT}`);
|
||
failed = true;
|
||
} else {
|
||
console.log(`\n✓ Entry within budget (${entrySize} / ${ENTRY_LIMIT} bytes gzipped)`);
|
||
}
|
||
}
|
||
|
||
if (total > TOTAL_FAIL_LIMIT) {
|
||
console.error(
|
||
`✗ Total js/ gzip ${total} bytes exceeds budget ${TOTAL_LIMIT} by more than 5% (fails above ${TOTAL_FAIL_LIMIT})`,
|
||
);
|
||
failed = true;
|
||
} else if (total > TOTAL_LIMIT) {
|
||
const msg = `Total js/ gzip ${total} bytes is over the ${TOTAL_LIMIT}-byte budget (fails above ${TOTAL_FAIL_LIMIT}); raise TOTAL_LIMIT in scripts/check-bundle-size.mjs with a note saying why`;
|
||
console.warn(`⚠ ${msg}`);
|
||
if (process.env.GITHUB_ACTIONS) console.log(`::warning title=Bundle size::${msg}`);
|
||
} else {
|
||
console.log(`✓ Total within budget (${total} / ${TOTAL_LIMIT} bytes gzipped)`);
|
||
}
|
||
|
||
if (jsonPath) {
|
||
mkdirSync(dirname(jsonPath), { recursive: true });
|
||
writeFileSync(jsonPath, JSON.stringify(manifest, null, 2));
|
||
console.log(`\nWrote size manifest to ${jsonPath}`);
|
||
}
|
||
|
||
process.exit(failed ? 1 : 0);
|