Skip to content

First-party chrome deserves a (micro) framework — the zero-dependency rule only needs to protect author HTML #287

Description

@yayashuxue

Context

The repo is deliberately zero-framework, zero-runtime-dependency. That posture is load-bearing for the author/agent-generated reader HTML (supply-chain surface, arbitrary HTML coexistence, BYOK copy-files portability). But since the cross-origin iframe shell migration (#217), the trust boundary is explicit: author HTML lives in an iframe on another origin; everything outside it is first-party product UI.

That first-party surface is now ~2,500+ lines of hand-rolled imperative DOM, and it grows with every PR:

file lines what
server/shell.js ~830 comment rails, pins, frame messaging
server/manage.js ~360 Share panel
server/chrome.js + chrome.css ~800 top bar
server/signin.js / onboard.js ~490 auth + onboarding modals
/me (inline in worker/worker.js) ~600 catalog: tabs, folders, stars, sort, batch select, 3 modals

The /me docs-hub work (PR #286) made the cost concrete: tab state, selection sets, folder filtering, and modals are all manual classList.toggle + a hand-rolled applySearch() re-computation — classic framework territory, with none of the zero-dep benefits applying (this code is ours, not the author's).

Real constraints (what a framework must satisfy)

  1. Inline-able: bin/tdoc-bundle is string substitution into the worker; pages run under nonce + strict-dynamic CSP, no CDN.
  2. BYOK portability: deploy = copy files; no npm install, no build chain for self-hosters.
  3. Agent-maintainable: plain, greppable code; static-guard tests (me-management.test.js etc.) slice source by string.

This rules out React+Vite-style stacks, but not a vendored micro-framework.

Proposal (two independent steps)

  1. Extract /me out of worker.js into server/me.js via the existing bundle-placeholder mechanism (chrome.js/shell.js already work this way). Purely mechanical, no behavior change; move the string-slicing guard tests along with it. Worth doing regardless of step 2.
  2. Vendor Preact + htm (~5KB total, tagged templates, no JSX, no build step) as server/vendor/, inlined by tdoc-bundle like everything else. Scope: first-party chrome only — /me, Share panel, eventually the comment rails. The reader HTML and frame-probe.js stay framework-free forever. No rewrite of working code: first use it for the next new component or when /me next grows.

Non-goals

  • No framework, ever, inside author documents.
  • No npm runtime dependencies, no build-tool requirement for BYOK deploys.
  • No big-bang rewrite of shell.js.

Not urgent — filed to capture the design discussion from PR #286 before it evaporates.

🤖 Generated with Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions