fix(create-plugin): 清掉脚手架的未用 lucide 声明,并让生成的 schema 接口真的可达 (#3755, #3759) - #3826
Conversation
…s schema interface reachable (#3755, #3759) Two declared-but-unreachable artifacts in the generated plugin, both on the blind side of the import gate #3733 added: that gate rejects an import nothing declares, and never looked for a declaration nothing imports. #3755 — the generated `dependencies` no longer pin `lucide-react`. It sat at `^0.563.0` with no generated source importing it, so every scaffolded plugin installed lucide 0.563.x for code that never referenced it: two majors behind the 23 in-repo declarations (all `^1.28.0`), and unable to float even within `0.x`, because a `0.x` caret does not cross minors (`>=0.563.0 <0.564.0`). Removed rather than re-anchored — this repo declares an icon library where it imports one (of 24 manifests mentioning it, 23 import it; none pre-declares it for unwritten code), so `pnpm add lucide-react` lands the current version by construction and no anchor table has to keep an unused entry honest. The map is now exactly the four `workspace:*` platform packages, which cannot drift. #3759 — the generated `src/index.tsx` re-exports the schema interface from `src/types.ts`. The `exports` map exposes exactly one key (`.`), so the entry is a consumer's only door, and nothing walked through it: no generated source imported `./types`, and `<pkg>/types` / `<pkg>/dist/types` are closed by that same map. The interface is the plugin's schema contract and it shipped dead — while the generator's own docs page tells authors to "export your schema types ... make it importable rather than internal". Named type-only re-export, the form all four in-repo plugins with a `src/types.ts` use. That interface now extends `BaseSchema` from `@object-ui/types` rather than re-declaring a subset of the base node. Unreachable it was dead weight; published it would be a second dialect of a node the protocol defines, silently omitting `name`, `label`, `visible` and the rest (AGENTS.md #0.1). Only the `type` literal stays local. It also makes the generated `@object-ui/types` dependency a used declaration. Both halves are pinned structurally, not by string match: no versioned runtime dependency may be declared that no generated source imports (`workspace:*` exempt — it cannot drift), and no generated `src/**` module may be unreachable from the entry. Each gate would pass over an empty result on today's templates, so each is paired with a self-test planting the removed defect back and asserting the rule names it. Verified on the real artifact: scaffolded a plugin with the built CLI, then `vite build` + `vitest run` green inside it, with `HeatsmokeSchema` present in the emitted `dist/index.d.ts`.
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
|
✅ 验收通过(objectui 分片 PM,session_01GTRjn8xBqp75dk7kFupVRt)—— undraft + auto-merge。 说明:实施 dev 在容器重启中丢失,其 PR body 即完整报告,PM 按 body + git 实物独立核验。 #3759 方向反转裁定:采纳方向 1(entry 导出),推翻我给的方向 2 缺省。 认领评论开的分叉条件(「实读后判方向 1 更当须给证据」)被充分满足:该产品判断仓内已做过并写进文档 —— 验证质量:两道新门皆对空集断言故各配「种回缺陷」自检(PR #5046 教训);反向验证三例含配对自检保持绿的设计说明;冒烟用真 CLI scaffold 到 Generated by Claude Code |
Fixes #3755
Fixes #3759
两条都是 create-plugin 生成产物里「声明了但不可达」的死产物,且都落在 PR #3733 那道 import 闸门的盲侧 —— 它只拒绝「未声明的 import」,从不反过来查「没人 import 的声明」。#3742 / PR #3754 已落 main,本 PR 在其现状上动,未回退其锚点表(那张表管 devDependencies,与本 PR 的两处面不相交)。
核验基线:
origin/main@5147d9305(worktree/home/user/objectui-3755,git worktree add ... origin/main,未依赖 FETCH_HEAD)。两单前提实测均仍成立:templates.ts:125仍是'lucide-react': '^0.563.0';仓内 23 处声明全为^1.28.0;grep "from './types"空;exports仅.一个键。取舍与否决窗
分诊席与 PM 的干净缺省是两单都走方向 2(删除)。实读之后我对两单给出不同结论,依据如下 —— 这正是 dispatch note 授权的分叉("若 dev 实读后判方向 1 更当,须给证据")。
#3755 → 方向 2(删除),与缺省一致
lucide-react从生成的dependencies移除,该 map 现在恰为四条workspace:*。证据:
buildIndexFile/buildImplFile/buildTypesFile/buildTestFile全部不碰)。0.x的 caret 不跨 minor,^0.563.0等价于>=0.563.0且小于0.564.0,连0.x内的后续版本都拿不到。lucide-react的 manifest 里 23 个真的 import 它(两种引号都数过 —— 只用单引号 grep 会漏掉 calendar/gantt/kanban 的双引号写法,初查时我漏过一次),没有任何包为「还没写的代码」预声明图标库。所以脚手架这条未用声明在仓内是孤例。^1.28.0就必须同步把 PR fix(create-plugin): 把脚手架 build 侧 devDependencies 锚到仓内工具链,并把整张清单钉进 parity 测试 #3754 的锚点表从 devDependencies 扩到dependencies,即为一条永远没人 import 的声明维护一行锚点。删掉之后作者要图标就pnpm add lucide-react,在本 workspace 里装到的自然是当前版本,与 23 个兄弟包一致 —— 不需要任何表。补充说明(如实):
@object-ui/components并不再导出 lucide 图标,所以不存在「改用 components 取图标」这条替代路径;删除后的效果就是作者自己按需装。#3759 → 方向 1(补 entry 导出),与缺省相反
生成的
src/index.tsx增加一行export type { PascalSchema } from './types';,src/types.ts产物保留。之所以推翻「删除」,是因为这条产品判断在仓内已经做过并且写进了文档,不需要维护者重新拍:
create-plugin 自己的文档页把它写成 Best Practice ——
content/docs/utilities/create-plugin.mdx:也就是说脚手架违反的是它自己那页文档给作者的建议。删掉产物等于把这条建议也一并作废。
content/docs/guide/plugin-development.md把types.ts写进 plugin anatomy(文件表一行:"types.ts| Schema interfaces extendingBaseSchemafrom@object-ui/types."),其 worked example 的 entry 末尾就是export type { BoardSchema, BoardProps, BoardColumn, BoardItem } from './types';。仓内 4 个带
src/types.ts的插件(charts / editor / kanban / markdown)全部从 entry 导出它,且 4 个的exportsmap 都只有.—— 说明 entry re-export 正是本仓让 schema 类型可达的既有手法,create-plugin 生成的 src/types.ts 是死产物:没有任何生成源文件 import 它,exports map 又只暴露.,消费者拿不到那个 Schema 接口 #3759 正文里的方向 3(给exports加./types子路径)确实是多余的。「写了但 entry 不导出」这个形态在仓内是 0 例,脚手架产出的是一个仓内任何地方都不存在的形状。
create-plugin 生成的 src/types.ts 是死产物:没有任何生成源文件 import 它,exports map 又只暴露
.,消费者拿不到那个 Schema 接口 #3759 正文自己也记了这一点:被 create-plugin.mdx 描述的是一个不存在的脚手架:提示词、产物目录、dev 脚本、配置文件、版本与依赖清单全部与真实生成器不符 #3715 删掉的旧文档虚构的export * from './types'「恰好比真实模板更合理」。用具名 type-only 导出而非
export *:4 个在仓插件用的都是具名形式(kanban 显式列了 6 个名字),且export *会让作者以后往types.ts里加的每个类型都自动变成公共面。代价是作者新增类型要同时在 entry 补名字 —— 这是有意的,公共面应当是一次自觉动作。#3759 的连带项:
types.ts改为extends BaseSchema(这一条最需要否决窗)这不是顺手扩范围,而是方向 1 的前置条件。原本那个手写的
{ type; id?; className? }在不可达状态下只是死重量;一旦 entry 导出它,它就成了每个脚手架插件已发布的 schema 契约面 —— 那时候发布一份@object-ui/types已经定义过的 base node 的手抄子集,就是 AGENTS.md 戒律 #0.1 说的「一份严格契约胜过 N 种方言」,而且这份子集静默丢掉了BaseSchema其余全部字段(name、label、visible…)。所以:import type { BaseSchema } from '@object-ui/types';+extends BaseSchema,只把type窄化成注册键(packages/plugin-markdown/src/types.ts是最近的模型);id?/className?删掉(BaseSchema 已有),不与extends并存;@object-ui/types依赖变成被使用的声明。否决窗:如果维护者认为脚手架不该预置 schema 类型面,那么正确的动作是把 #3759 退回方向 2(删
buildTypesFile与src/types.ts),此时extends BaseSchema这一条自动随之消失,并且需要同步改create-plugin/README.md:28与plugin-development.md的 anatomy 表。若只想否决extends BaseSchema而保留 entry 导出,我不建议:那会把一份 base-node 方言发布给每个脚手架插件。新增的钉子:两道都做了「非空」自检
两条规则都是结构性的,不是字符串 grep:
workspace:*豁免 —— 它按定义解析到本 workspace 当前版本,不会漂);src/**模块可以从 entry 不可达(entry 是exportsmap 暴露的唯一入口)。关键点:这两条在修好之后的模板上都是对空集断言(已经没有 versioned 运行时依赖了;已经没有不可达模块了)。按 PR #5046 那个教训,「因为什么都没产出所以绿」不是闸门。所以每条各配一个自检:把删掉的缺陷原样种回去,断言规则点得出它的名字。
catches an unused versioned runtime dependency when one is present—— 种回'lucide-react': '^0.563.0',断言返回['lucide-react'];并反向确认规则不误伤真的被 import 的 versioned 依赖(否则它就变成「禁止 versioned」而非「禁止未使用」)。reports the schema module as unreachable when the entry stops re-exporting it—— 把 entry 的 re-export 行剥掉,断言src/types.ts被点名。另外
derives the published schema interface from the protocols BaseSchema钉住上面那条连带项,否则它无人看守、会被静默改回去。fixture 三分类的实际落点(与派单预设不同,如实报告)
派单要求把「
src/types.ts存在」那条断言整条替换。这条要求预设了 #3759 走方向 2。实际走方向 1 之后,src/types.ts仍然被写出,那条 exact-key-list 断言依旧成立且依旧正确,因此它属于三分类里的「不动」而非「换掉」—— 真正变的不是它的 verdict,而是它从来没有断言过可达性(这正是 #3759 点出的弱闸门)。所以做法是给它补一个可达性兄弟,而不是替换它。若当初照字面替换,就会在方向 1 下删掉一条仍然有效的覆盖。反向验证(方向先判后跑,三例全部与预判一致)
预判写在跑之前:两个 manifest/产物级闸门各应变红,而与之配对的规则自检应当保持绿(它们判的是规则本身,不是当前 manifest)。
A. 把
'lucide-react': '^0.563.0'加回DEPENDENCIES—— 预判 2 红:B. 剥掉 entry 的
export type { ... } from './types';—— 预判 2 红:C. 把
types.ts退回手写接口(去掉extends BaseSchema) —— 预判 1 红:三例中配对的自检都如预判保持绿:A 里
catches an unused versioned …因为种植 spread 成了 no-op 而仍返回['lucide-react'];B 里reports the schema module as unreachable …因为.replace()成了 no-op 而仍返回['src/types.ts']。这是设计使然,不是漏检。验证
单测(仓库根,路径过滤,不加
--):改前基线 12 passed,新增 7 条(4 条闸门 + 2 条自检 + 1 条 BaseSchema 钉子)。
pnpm --filter '@object-ui/create-plugin^...' build报No projects matched the filters—— 如实记录原因:该包只依赖 chalk / commander / fs-extra / prompts,没有 workspace 依赖,测试也只 import node builtins 与../templates,所以这一步没有可建的上游,不存在 TS2307 假红的风险面。type-check + build:
生成产物冒烟(用真 CLI 走一遍,不是只断言数据):仓内既有测试不编译生成产物(全是纯数据断言),所以这一步实跑了一次而非复用。用构建出的 CLI 在 worktree 内 scaffold 出
packages/plugin-heatsmoke,pnpm install后:关键一步 —— #3759 的修复在产物层成立,不只是源码层。生成的
dist/index.d.ts:dist/types.d.ts一并 emit,内容为export interface HeatsmokeSchema extends BaseSchema。即消费者import type { HeatsmokeSchema } from '@object-ui/plugin-heatsmoke'现在真的解析得到 —— 改前这个 import 无路可走。生成的dependencies实测为四条workspace:*,exports键实测为['.']。冒烟产物与被它改动的
pnpm-lock.yaml已清除并还原,git status只剩本 PR 的三个文件。消费半径扫描(按规则被消费的地方扫,不是按被改的包):
0.563在仓内(除 lockfile 与无关的向量 fixture)已只出现在本 PR 自己的注释/自检里;content/**无任何脚手架依赖区间声明(create-plugin.mdx明确写了「Its dependency ranges are not listed here on purpose」),故 #3711 版本声明闸门与doc-version-claims均无需同步改动;create-plugin/README.md:28的types.ts # Schema definitions在方向 1 下依旧准确,无需改。门禁自查:
changeset 档位
patch,与同族先例 PR #3754(#3742)和 #3716 一致 —— 生成产物变化对用户可见,但不改 create-plugin 自身 API。本仓major由 objectstack 对齐节奏决定,不在此声明。越界发现(未在本 PR 修)
packages/cli/src/utils/app-generator.ts的createTempAppWithRouting()生成的 layoutimport(:591-592)了lucide-react,而它写出的package.json(:963起)显式声明了react-router-dom却没有lucide-react—— 与 #3716 完全同类的缺陷(生成源 import 未声明的依赖),只是位于packages/cli而非create-plugin,PR #3733 的闸门伸不到那里;同时它的工具链区间落后本仓一到三个 major(vite ^5.0.0vs 仓根^8.2.0、typescript ~5.7.3vs^6.0.3、@vitejs/plugin-react ^4.2.1vs^6.0.5、@object-ui/react|components ^0.1.0而本仓已在 major 17),与 #3742 同类。已按 Prime Directive #10 单独建 issue(见 report),未在本 PR 处理。Generated by Claude Code