Skip to content

Close the cross-module-registration blind spot in display-only elision #169

@vivek7405

Description

@vivek7405

Problem

Display-only component elision drops a component's module (and its customElements.define) from the browser when the analyser judges it purely presentational. That is safe in isolation, but it has a real, undetected correctness hole: cross-module observation of an elided component's registration.

If component A is elided, its tag never registers on the client. Any OTHER shipping code that observes A's tag then breaks silently:

  • customElements.whenDefined('a-tag') never resolves
  • a CSS a-tag:defined { ... } rule never matches
  • an instanceof AClass check is always false
  • an upgraded-member read off document.querySelector('a-tag').someProp is undefined
  • a vendor package that self-registers via customElements.define at import top level, pulled in through a binding import on an elided module, never runs

This is acknowledged in packages/server/src/component-elision.js (around the importsSideEffectNonCorePackage comment), in agent-docs/components.md, and in packages/server/AGENTS.md invariant 7, but it is NOT statically detected (dynamic tag strings and external CSS are unanalyzable) and NOT tested at any layer. Today it relies entirely on author discipline.

Design / approach

The bias must stay conservative (ambiguous ships), so close the hole by SHIPPING when an observation is detectable, never by eliding more:

  1. Conservative detection: when scanning the shipping module set, if any module references a known component tag via whenDefined('<tag>'), an instanceof <Class>, or a CSS selector <tag>:defined, mark that tag's component as must-ship (do not elide). This catches the statically-visible cases (string-literal tags, imported classes, authored CSS) and is verdict-safe (it only ever ships more).
  2. The residual unanalyzable cases (dynamic tag strings, external stylesheet :defined) stay an author-facing caveat, but should at least be pinned by a test that documents the failure so the boundary is explicit.
  3. Self-registering vendor packages reached through an elided binding import: detect a top-level customElements.define in a bare-package's entry where feasible, or document the .server.{js,ts} / interactivity-signal fix and test it.

Acceptance criteria

  • A shipping whenDefined('<tag>'), <tag>:defined CSS rule, or instanceof <Class> referencing an elidable component forces that component to ship (not elided)
  • A test pins the residual unanalyzable case (dynamic tag string) as a documented, author-fixable limitation
  • Unit coverage for each detected signal, including the counterfactual (the component is wrongly elided without the guard)
  • agent-docs/components.md + packages/server/AGENTS.md invariant 7 updated to describe what is now detected vs still author-discipline

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type
No fields configured for issues without a type.

Projects

Status
Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions