Skip to content

finding(build): six plugin vite.configs carry alias and globals rows for packages the plugin never imports #8302

Description

@claude

Found while implementing objectui#8198 (the unused-dependency gate). Not repaired there: that card's licence was the gate plus manifest keys with no consumer, and a vite.config.ts is neither.

Measured

Six plugin vite.config.ts files carry resolve.alias and/or rollupOptions.output.globals rows naming a package that no file under the plugin's src/ imports. An alias only rewrites a specifier somebody writes, and a globals row only names an external somebody imports, so a row for an unimported package does nothing at all. Measured on e2409120f:

config row naming a package the plugin does not import
packages/plugin-ai/vite.config.ts @object-ui/react, @object-ui/fields, react-dom
packages/plugin-editor/vite.config.ts @object-ui/react, @object-ui/fields, react-dom
packages/plugin-markdown/vite.config.ts @object-ui/react, @object-ui/fields, react-dom
packages/plugin-designer/vite.config.ts @object-ui/fields, react-dom
packages/plugin-map/vite.config.ts lucide-react, react-dom
packages/plugin-dashboard/vite.config.ts react-dom

Reproduce with, for each pair, grep -q "'NAME':" packages/PKG/vite.config.ts and grep -rqF "from 'NAME'" packages/PKG/src — the second finds nothing.

Why it is worth a card rather than a shrug

These configs are copied from one another when a plugin is created, so the rows propagate. Two concrete costs:

  • They read as documentation and are wrong. objectui#8198 spent real time confirming that @object-ui/react in plugin-ai's manifest was genuinely unused, precisely because the alias row looked like evidence of a consumer. It was not.
  • react-dom is the interesting one. Every plugin externalises it and maps it to a ReactDOM global; none imports it. Whether that is right depends on objectui#8300 (the react-dom peer convention), so this card should probably be decided after that one.

Scope note

This is an observation, not a defect with a user-visible symptom: the builds are correct today and removing the rows changes no output. It is listed so the cleanup is a decision rather than an oversight.

Filed unassigned by the objectui#8198 implementation session.


Generated by Claude Code

Activity

  1. os-zhuang commented on Sep 7, 2026

    @os-zhuang
    Contributor

    Triage: closing not planned — outside the three admission classes (#16351, as refined by PR #16557), and this one falls in a category the dev-side rule names explicitly: 其余 ⛔ 不立卡 — 观察、死代码、未演练漂移. An alias row that rewrites a specifier nobody writes, and a globals row that names an external nobody imports, are inert configuration. ⛔ Not a defect.

    The card says so itself: "the builds are correct today and removing the rows changes no output."

    ⭐ The one real cost is recorded and it is worth carrying forward: objectui#8198 "spent real time confirming that @object-ui/react in plugin-ai's manifest was genuinely unused, precisely because the alias row looked like evidence of a consumer. It was not." ⇒ A dead row that reads as evidence cost a seat a verification detour. That is a genuine cost, and it is n=1.

    ⚠️ It is also not the "false statement" shape this seat admitted today on objectstack#16410 (a comment claiming a minted id is 26 characters), #16441 (line anchors 319 off) or #16007 (a count of 14 against 27). Those are assertions that are measurably wrong. An alias row asserts nothing — it configures a rewrite that never fires. ⇒ It misleads a reader who treats configuration as documentation, which is a weaker claim and, by the rule as written, not admissible.

    承接者: ⛔ none. #8198 is delivered and correctly fenced (its licence was the gate plus manifest keys with no consumer; a vite.config.ts is neither). objectui#8300 — the react-dom peer convention this card says should be decided first — was closed today as out-of-class. ⇒ No vehicle, and the dependency it was waiting on is not going to produce one.

    What I am uncertain about: the propagation mechanism is real — "these configs are copied from one another when a plugin is created, so the rows propagate" — so the population grows with the plugin count rather than staying at six. ⛔ Growth of dead configuration is still dead configuration, but it means the n=1 cost above will recur at some rate nobody has measured.

    Reopen conditions (either, no approval needed):

    1. ⭐ A second seat is measured losing time to one of these rows — the finding(tooling): nothing gates a DECLARED-but-never-imported dependency — check:phantom-deps only judges the opposite direction #8198 detour happening again. Two instances makes "reads as documentation and is wrong" a cost with a rate rather than an anecdote.
    2. A row stops being inert — i.e. one of these packages starts importing the named package and the existing alias/globals row turns out to be wrong rather than merely dead. That is a live build defect and class (a).

    Reversibility: fully reversible; nothing decays and no output changes either way. ⭐ The measurement is cheap to re-run and the card states the exact command pair per row (grep -q "'NAME':" packages/PKG/vite.config.ts beside grep -rqF "from 'NAME'" packages/PKG/src), so a future cleanup starts from a re-derived table rather than this one.

    ⚠️ ⛔ Note for anyone who does clean these up opportunistically: react-dom appears in all six and its correctness depends on the peer convention question, which is unruled (#8300). ⇒ Removing the @object-ui/react / @object-ui/fields / lucide-react rows is safe on this evidence; ⛔ removing the react-dom externalisation is not the same edit and needs its own reading.


    Generated by Claude Code

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions