Add live bundle analyzer page to sx-docs

Demonstrates Phase 1 dep analysis in action: computes per-page component
bundles for all sx-docs pages using the deps.sx transitive closure
algorithm, showing needed vs total components with visual progress bars.

- New page at /plans/bundle-analyzer with Python data helper
- New components: ~bundle-analyzer-content, ~analyzer-stat, ~analyzer-row
- Linked from Phase 1 section and Plans nav
- Added sx/sx/ to tailwind content paths

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-06 12:23:58 +00:00
parent d6ca185975
commit e36a036873
6 changed files with 124 additions and 1 deletions

67
sx/sx/analyzer.sx Normal file
View File

@@ -0,0 +1,67 @@
;; Bundle analyzer — live demonstration of Phase 1 component dependency analysis.
;; Shows per-page component bundles vs total, visualizing payload savings.
;; @css bg-green-100 text-green-800 bg-violet-600 bg-stone-200 text-violet-600 text-stone-600 text-green-600 rounded-full h-2.5 grid-cols-3
(defcomp ~bundle-analyzer-content (&key pages total-components total-macros)
(~doc-page :title "Page Bundle Analyzer"
(p :class "text-stone-600 mb-6"
"Live analysis of component dependency graphs across all pages in this app. "
"Each bar shows how many of the "
(strong (str total-components))
" total components a page actually needs, computed by the "
(a :href "/specs/deps" :class "text-violet-700 underline" "deps.sx")
" transitive closure algorithm.")
(div :class "mb-8 grid grid-cols-3 gap-4"
(~analyzer-stat :label "Total Components" :value (str total-components)
:cls "text-violet-600")
(~analyzer-stat :label "Total Macros" :value (str total-macros)
:cls "text-stone-600")
(~analyzer-stat :label "Pages Analyzed" :value (str (length pages))
:cls "text-green-600"))
(~doc-section :title "Per-Page Bundles" :id "bundles"
(div :class "space-y-3"
(map (fn (page)
(~analyzer-row
:name (get page "name")
:path (get page "path")
:needed (get page "needed")
:direct (get page "direct")
:total total-components
:pct (get page "pct")
:savings (get page "savings")))
pages)))
(~doc-section :title "How It Works" :id "how"
(ol :class "list-decimal pl-5 space-y-2 text-stone-700"
(li (strong "Scan: ") "Regex finds all " (code "(~name") " patterns in the page's content expression.")
(li (strong "Resolve: ") "Each referenced component's body AST is walked to find transitive " (code "~") " references.")
(li (strong "Closure: ") "The full set is the union of direct + transitive deps, following chains through the component graph.")
(li (strong "Bundle: ") "Only these component definitions are serialized into the page payload. Everything else is omitted."))
(p :class "mt-4 text-stone-600"
"The analysis handles circular references (via seen-set), "
"walks all branches of control flow (if/when/cond/case), "
"and includes macro definitions shared across components."))))
(defcomp ~analyzer-stat (&key label value cls)
(div :class "rounded-lg border border-stone-200 p-4 text-center"
(div :class (str "text-3xl font-bold " cls) value)
(div :class "text-sm text-stone-500 mt-1" label)))
(defcomp ~analyzer-row (&key name path needed direct total pct savings)
(div :class "rounded border border-stone-200 p-4"
(div :class "flex items-center justify-between mb-2"
(div
(span :class "font-mono font-semibold text-stone-800" name)
(span :class "text-stone-400 text-sm ml-2" path))
(div :class "text-right"
(span :class "font-mono text-sm"
(span :class "text-violet-700 font-bold" (str needed))
(span :class "text-stone-400" (str " / " total)))
(span :class "ml-2 inline-block px-1.5 py-0.5 rounded text-xs font-medium bg-green-100 text-green-800"
(str savings "% saved"))))
(div :class "w-full bg-stone-200 rounded-full h-2.5"
(div :class "bg-violet-600 h-2.5 rounded-full transition-all"
:style (str "width: " pct "%")))))