Skip to content

fix(create-plugin): 让脚手架产物的 npm test 从第一次就能跑 (#3716) - #3733

Merged
yinlianghui merged 3 commits into
mainfrom
claude/issue-3716-create-plugin-test-stack
Aug 8, 2026
Merged

fix(create-plugin): 让脚手架产物的 npm test 从第一次就能跑 (#3716)#3733
yinlianghui merged 3 commits into
mainfrom
claude/issue-3716-create-plugin-test-stack

Conversation

@yinlianghui

Copy link
Copy Markdown
Collaborator

Fixes #3716

前提复核(在 origin/main = 4e93e40d 上重核,非分诊时的 0cf8f0f

卡片的三条事实全部成立,且逐条跑成了真实失败,不是读代码推断的:

断言 复核结果
模板写 test: 'vitest run' 脚本 src/index.ts:140
生成的 devDependencies 只有五项 :154-160,无 @testing-library/react / @testing-library/jest-dom / jsdom
示例测试 import testing-library :362
生成的 vite.config.tstest 整文件 grep environment / jsdom / setupFiles 零命中

修复前的生成器生成一个插件、只按它自己声明的依赖搭 node_modules(离线软链,不联网装),vitest run 的真实输出:

FAIL  src/HeatMapImpl.test.tsx [ src/HeatMapImpl.test.tsx ]
Error: Cannot find package '@testing-library/react' imported from .../src/HeatMapImpl.test.tsx
     10| import { render, screen } from '@testing-library/react';

把三个库补进那份 node_modules、但保留原样的 vite.config.ts(仍无 test 段),第二层失败随即露出 —— 印证卡片「即便补上依赖,默认 node 环境仍渲染不了」这一条:

FAIL  src/HeatMapImpl.test.tsx > HeatMap > should render
ReferenceError: document is not defined

改了什么(路线 A,按分诊裁决)

  1. 生成的 devDependencies@testing-library/react@testing-library/jest-domjsdom
  2. 生成的 vite.config.ts 增加 test: { globals: true, environment: 'jsdom', setupFiles: ['./vitest.setup.ts'] }
  3. 新增生成物 vitest.setup.ts,注册 jest-dom 的 matcher;
  4. 模板从 src/index.ts 抽到新文件 src/templates.ts(纯函数,无副作用),使产物本身可被单测断言 —— index.ts 在 import 时就 program.parse(),任何测试都无法 import 它来看它生成了什么,只能去 grep 源码字符串,而那正是「改坏了还绿着」的写法。抽出后 index.ts 里的写盘逻辑收敛成一个循环,buildPluginFiles() 是「一个插件包含哪些文件」的唯一真相。

同一包内 README.md 的产物树补上第 9 个文件(本 PR 使它少一行,属于本次改动直接造成的失真,故一并修)。

版本区间的来源(分诊裁决 #2:不许现编)

三条全部有仓内锚点,逐字抄:

依赖 区间 锚点
@testing-library/react ^16.3.2 仓根 package.json devDependencies(apps/console 同值)
@testing-library/jest-dom ^7.0.0 仓根 package.json devDependencies(apps/console 同值)
jsdom ^30.0.1 仓根 package.json devDependencies

没有「无锚点、取当前 major」的条目。@testing-library/dom 故意不声明:它是 @testing-library/react 16 的 peer,由本仓 .npmrcauto-install-peers=true 装上 —— apps/console 也正是只声明这三个而非四个。

这些字面量写在 .ts 里,不在 #3711 那条版本声明门禁的扫描面上,所以给它加了门禁templates.test.ts 读仓根 package.json,断言模板里的三个区间与仓根逐字相等。以后谁升了仓根的 RTL 而没同步模板,这条测试红,并在失败信息里指到 src/templates.ts

两个不显眼但承重的选择

  • globals: true 不是装饰@testing-library/react 只在 afterEach 作为全局存在时才注册它的自动 cleanup()dist/index.js: if (typeof afterEach === 'function'))。不开 globals,示例测试今天照样绿,但作者写第二个测试的那天开始 DOM 静默泄漏。这也与仓内 15 个包的 test 段一致。
  • jest-dom 走 /vitest 子入口:裸入口 import '@testing-library/jest-dom' 扩展的是全局 expect,一旦作者把 globals 关掉,matcher 注册就静默失效;/vitest 入口显式 import { expect } from 'vitest',与 globals 开关解耦。

钉子(9 条,packages/create-plugin/src/__tests__/templates.test.ts

不是 grep 源码,而是断言在生成器写盘用的同一份 file map 上。其中两条是结构性的,比字符串匹配值钱:

  • 生成的示例测试里每一个裸 import,都必须是生成的 package.json 声明过的依赖 —— 这就是本 bug 的一般化形式:以后谁往示例测试里再加一个没声明的 import,红;
  • vite.config.tssetupFiles 指的那个路径,必须是生成器真的会写出来的文件 —— 防的是「配置指向一个不存在的 setup 文件」这种半拉子状态。

反向验证(方向先判、再跑)

预判是常规的「红」方向:把三处改动回退(去掉三个依赖、去掉 test 段、不再写 setup 文件),9 条里应有 5 条转红。实测 7 条红,预判的条数错了(我把 vite.config 的三条断言当成两条数,又漏数了 file map 那条),方向没错。

留绿的两条值得写下来,因为它们正是「因为什么都没产出所以还绿着」的形状:

  • has its jest-dom matchers registered by the setup file —— 它断言的是 buildVitestSetup() 这个函数的返回值,而回退只是不再把它写进 file map,函数本身还在,于是照样绿。真正能抓住「setup 文件不再被写出」的是它旁边那两条 map 级断言(points setupFiles at a file the generator actually writes、file map 清单),所以这条是被配对覆盖的,不是唯一的钉子。
  • keeps every path inside the generated plugin directory —— 与本次回退无关的路径穿越断言。

产物一致性(裁决 #4

node dist/index.js heat-map 真的生成一遍,9 个文件齐全(含 vitest.setup.ts),然后用只含它自己声明的依赖的离线 node_modules 跑它自己的 vitest run

 RUN  v4.1.10 .../packages/plugin-heat-map
 Test Files  1 passed (1)
      Tests  1 passed (1)

链进去的实际版本 —— jsdom 30.0.1@testing-library/react 16.3.2@testing-library/jest-dom 7.0.0vitest 4.1.10 —— 全部落在模板声明的区间内。未做联网 pnpm install(裁决说不必,也确实慢且易 flaky);build 侧三个包(vite / @vitejs/plugin-react / vite-plugin-dts)链的是仓内现有版本,高于模板声明的区间,这一点见下。

不在本 PR 范围,但本 PR 造成或撞见的

  1. content/docs/utilities/create-plugin.mdx 需要跟进(属 create-plugin.mdx 描述的是一个不存在的脚手架:提示词、产物目录、dev 脚本、配置文件、版本与依赖清单全部与真实生成器不符 #3715 席位,本 PR 按裁决未碰):该页「Generated Structure」树现在少了第 9 个产物 vitest.setup.ts;而且该页有一句把「manifest literal」指向 packages/create-plugin/src/index.ts,本 PR 之后那份字面量在 src/templates.ts。已在 create-plugin.mdx 描述的是一个不存在的脚手架:提示词、产物目录、dev 脚本、配置文件、版本与依赖清单全部与真实生成器不符 #3715 下留评说明。
  2. 生成的 build 侧 devDependencies 区间落后本仓实际工具链 1–2 个 majorvite ^7.3.1 vs 仓根 ^8.2.0@vitejs/plugin-react ^4.2.1 vs 仓内插件普遍 ^6.0.5vite-plugin-dts ^4.5.4 vs ^5.0.3typescript ^5.9.3 vs ^6.0.3vitest ^4.0.18 vs ^4.1.10),另开 issue,未在本 PR 动 —— 本 PR 只负责它新增的那三条有锚点。顺带记录:生成的 vite.config.ts__dirname,vite 8 的 native configLoader 已就此告警。

本地验证

pnpm exec vitest run packages/create-plugin/            # 9 passed
pnpm --filter @object-ui/create-plugin type-check       # 0 errors
pnpm --filter @object-ui/create-plugin lint             # clean
pnpm --filter @object-ui/create-plugin build            # tsup OK
node scripts/check-control-bytes.mjs                    # OK (3689 files)

注:pnpm --filter @object-ui/create-plugin test 这条跑不了 —— 它是包目录 cwd 启动 vitest,被 scripts/vitest-invocation-guard.mjs(objectui#3378)按设计拒绝。上面用的是它指定的仓根跑法。


Generated by Claude Code

The generator wrote `src/<Pascal>Impl.test.tsx` importing
`@testing-library/react` and asserting with `toBeInTheDocument()`, plus a
`test: 'vitest run'` script, while the generated `devDependencies` declared
neither library and the generated `vite.config.ts` had no `test` block. All
three failure modes stacked, so `pnpm test` in a freshly scaffolded plugin was
red on the very first run.

- declare `@testing-library/react`, `@testing-library/jest-dom` and `jsdom`,
  each range copied verbatim from this monorepo's own root manifest rather
  than invented
- add `test: { globals: true, environment: 'jsdom', setupFiles: [...] }` to the
  generated Vite config (`globals` is load-bearing: RTL only registers its
  automatic cleanup when `afterEach` exists as a global)
- write `vitest.setup.ts` registering the jest-dom matchers, via the `/vitest`
  entry point so it does not depend on a global `expect`
- move the templates to `src/templates.ts` so the generated artifacts can be
  pinned without executing the CLI (`index.ts` calls `program.parse()` at
  import time), and pin them: every bare import in the generated example test
  must be a declared dependency, `setupFiles` must name a file the generator
  writes, and the three ranges must equal the repo root's

Fixes #3716

Co-Authored-By: Claude <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectui Ignored Ignored Aug 8, 2026 10:42am

Request Review

@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Main entry (gzip) 28.1 KB 350 KB
Entry file index-BEAgjw06.js
Status PASS

📦 Bundle Size Report

Package Size Gzipped
app-shell (index.js) 8.66KB 3.13KB
app-shell (runtime-config.js) 7.42KB 2.32KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 7.57KB 2.97KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 1.17KB 0.53KB
auth (AuthProvider.js) 22.10KB 4.37KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.13KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.64KB 2.21KB
auth (SocialSignInButtons.js) 9.60KB 3.89KB
auth (UserMenu.js) 3.40KB 1.22KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 35.76KB 9.11KB
auth (createAuthenticatedFetch.js) 4.37KB 1.69KB
auth (index.js) 2.35KB 1.07KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 4.91KB 0.87KB
auth (useIsWorkspaceAdmin.js) 1.61KB 0.85KB
collaboration (CommentThread.js) 26.07KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.65KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 480.72KB 105.64KB
core (index.js) 2.96KB 1.13KB
create-plugin (index.js) 9.84KB 3.18KB
data-objectstack (index.js) 137.51KB 35.11KB
fields (index.js) 230.90KB 56.84KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (currency.js) 1.22KB 0.64KB
i18n (i18n.js) 4.32KB 1.77KB
i18n (index.js) 2.65KB 1.06KB
i18n (pickLocalized.js) 1.70KB 0.83KB
i18n (provider.js) 9.48KB 3.27KB
i18n (useObjectLabel.js) 26.14KB 6.07KB
i18n (useSafeTranslation.js) 4.52KB 1.96KB
layout (index.js) 38.53KB 10.71KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.74KB
mobile (index.js) 1.50KB 0.62KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.71KB 0.42KB
mobile (useResponsiveConfig.js) 1.36KB 0.63KB
mobile (useSpecGesture.js) 4.32KB 1.64KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 8.75KB 3.06KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 3.67KB 1.12KB
permissions (evaluator.js) 4.41KB 1.44KB
permissions (index.js) 0.91KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.52KB
permissions (usePermissions.js) 1.55KB 0.71KB
plugin-ai (index.js) 15.71KB 3.79KB
plugin-calendar (index.js) 44.98KB 12.37KB
plugin-charts (index.js) 61.04KB 17.31KB
plugin-chatbot (index.js) 180.09KB 42.72KB
plugin-dashboard (index.js) 115.50KB 29.96KB
plugin-designer (index.js) 210.51KB 42.51KB
plugin-detail (index.js) 232.79KB 57.42KB
plugin-editor (index.js) 2.46KB 1.10KB
plugin-form (index.js) 112.10KB 27.10KB
plugin-gantt (index.js) 162.55KB 39.57KB
plugin-grid (index.js) 186.61KB 49.34KB
plugin-kanban (index.js) 48.30KB 13.28KB
plugin-list (index.js) 105.12KB 25.48KB
plugin-map (index.js) 16.81KB 5.24KB
plugin-markdown (index.js) 13.72KB 4.69KB
plugin-report (index.js) 40.58KB 10.58KB
plugin-timeline (index.js) 25.76KB 7.33KB
plugin-tree (index.js) 8.50KB 2.88KB
plugin-view (index.js) 84.03KB 20.55KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.71KB 3.53KB
providers (index.js) 0.44KB 0.22KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.67KB 2.37KB
react (LazyPluginLoader.js) 3.77KB 1.33KB
react (SchemaRenderer.js) 19.28KB 6.38KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 1.02KB 0.55KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 4.09KB 1.74KB
sdui-parser (index.js) 4.47KB 2.03KB
sdui-parser (parse.js) 10.04KB 2.82KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 4.69KB 1.48KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 0.99KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 0.20KB 0.18KB
types (crud.js) 0.20KB 0.18KB
types (data-display.js) 0.20KB 0.18KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.87KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-retry.js) 4.32KB 2.02KB
types (index.js) 2.71KB 1.34KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 2.59KB 1.31KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (spec-report.js) 5.05KB 1.93KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 0.20KB 0.18KB
types (ui-action.js) 3.40KB 1.71KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

…ed source

The pin only read the example test, so an undeclared import added to any other
template — including the side-effect `import 'pkg';` form the generated Vitest
setup file uses — would not have been caught. It now walks every generated
`.ts`/`.tsx` file, folds subpath specifiers onto their package name (so
`@testing-library/jest-dom/vitest` is checked against the declared
`@testing-library/jest-dom`) and skips Node builtins (the generated Vite config
imports `path`, which nothing has to declare).

Verified by probe: planting `import 'chai-dom';` in the setup template turns it
red with "vitest.setup.ts imports chai-dom, which is not declared".

Co-Authored-By: Claude <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Main entry (gzip) 28.1 KB 350 KB
Entry file index-BEAgjw06.js
Status PASS

📦 Bundle Size Report

Package Size Gzipped
app-shell (index.js) 8.66KB 3.13KB
app-shell (runtime-config.js) 7.42KB 2.32KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 7.57KB 2.97KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 1.17KB 0.53KB
auth (AuthProvider.js) 22.10KB 4.37KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.13KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.64KB 2.21KB
auth (SocialSignInButtons.js) 9.60KB 3.89KB
auth (UserMenu.js) 3.40KB 1.22KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 35.76KB 9.11KB
auth (createAuthenticatedFetch.js) 4.37KB 1.69KB
auth (index.js) 2.35KB 1.07KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 4.91KB 0.87KB
auth (useIsWorkspaceAdmin.js) 1.61KB 0.85KB
collaboration (CommentThread.js) 26.07KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.65KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 480.72KB 105.64KB
core (index.js) 2.96KB 1.13KB
create-plugin (index.js) 9.84KB 3.18KB
data-objectstack (index.js) 137.51KB 35.11KB
fields (index.js) 230.90KB 56.84KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (currency.js) 1.22KB 0.64KB
i18n (i18n.js) 4.32KB 1.77KB
i18n (index.js) 2.65KB 1.06KB
i18n (pickLocalized.js) 1.70KB 0.83KB
i18n (provider.js) 9.48KB 3.27KB
i18n (useObjectLabel.js) 26.14KB 6.07KB
i18n (useSafeTranslation.js) 4.52KB 1.96KB
layout (index.js) 38.53KB 10.71KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.74KB
mobile (index.js) 1.50KB 0.62KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.71KB 0.42KB
mobile (useResponsiveConfig.js) 1.36KB 0.63KB
mobile (useSpecGesture.js) 4.32KB 1.64KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 8.75KB 3.06KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 3.67KB 1.12KB
permissions (evaluator.js) 4.41KB 1.44KB
permissions (index.js) 0.91KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.52KB
permissions (usePermissions.js) 1.55KB 0.71KB
plugin-ai (index.js) 15.71KB 3.79KB
plugin-calendar (index.js) 44.98KB 12.37KB
plugin-charts (index.js) 61.04KB 17.31KB
plugin-chatbot (index.js) 180.09KB 42.72KB
plugin-dashboard (index.js) 115.50KB 29.96KB
plugin-designer (index.js) 210.51KB 42.51KB
plugin-detail (index.js) 232.79KB 57.42KB
plugin-editor (index.js) 2.46KB 1.10KB
plugin-form (index.js) 112.10KB 27.10KB
plugin-gantt (index.js) 162.55KB 39.57KB
plugin-grid (index.js) 186.61KB 49.34KB
plugin-kanban (index.js) 48.30KB 13.28KB
plugin-list (index.js) 105.12KB 25.48KB
plugin-map (index.js) 16.81KB 5.24KB
plugin-markdown (index.js) 13.72KB 4.69KB
plugin-report (index.js) 40.58KB 10.58KB
plugin-timeline (index.js) 25.76KB 7.33KB
plugin-tree (index.js) 8.50KB 2.88KB
plugin-view (index.js) 84.03KB 20.55KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.71KB 3.53KB
providers (index.js) 0.44KB 0.22KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.67KB 2.37KB
react (LazyPluginLoader.js) 3.77KB 1.33KB
react (SchemaRenderer.js) 19.28KB 6.38KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 1.02KB 0.55KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 4.09KB 1.74KB
sdui-parser (index.js) 4.47KB 2.03KB
sdui-parser (parse.js) 10.04KB 2.82KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 4.69KB 1.48KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 0.99KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 0.20KB 0.18KB
types (crud.js) 0.20KB 0.18KB
types (data-display.js) 0.20KB 0.18KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.87KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-retry.js) 4.32KB 2.02KB
types (index.js) 2.71KB 1.34KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 2.59KB 1.31KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (spec-report.js) 5.05KB 1.93KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 0.20KB 0.18KB
types (ui-action.js) 3.40KB 1.71KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

CI's `check-type-check-coverage.mjs` caught what the package-scoped
`pnpm type-check` could not: `tsconfig.json` excludes `**/*.test.ts` (correctly
— it is the build config), so the new `templates.test.ts` was read by no `tsc`
invocation at all. An unchecked test can assert a contract the compiler never
checked and then read as evidence that the contract holds.

Adds `tsconfig.test.json` on the `packages/types` pattern (emit-free, `paths`
dropped, `types: ["node"]` for the manifest read) and chains it from
`type-check`, which is the script CI runs. Zero errors; the guard now reports
23/38 packages compiling their tests, up from 22.

Co-Authored-By: Claude <noreply@anthropic.com>

Copy link
Copy Markdown
Collaborator Author

补记两个 commit,以及 CI 抓到的一条本地跑法抓不到的问题。

750fcba — 把"未声明的 import"这条钉子从示例测试扩到全部产物源文件。
原来只读 src/PascalImpl.test.tsx,于是往别的模板里加一个未声明的 import 照样绿 —— 包括生成的 setup 文件用的副作用形式 import 'pkg';(原正则只匹配带 from 的形式,根本看不见它)。现在遍历产物 map 里每个 .ts/.tsx,把子路径 specifier 折回包名(@testing-library/jest-dom/vitest@testing-library/jest-dom 校验),并跳过 Node 内置模块(生成的 vite.config 里那个 path,谁也不需要声明它)。

反证跑过,不是想当然:往 setup 模板里种一个 import 'chai-dom';,红在
vitest.setup.ts imports chai-dom, which is not declared

2aedc05 — CI 的 Type Check 红,不是类型错,是覆盖缺口。
scripts/check-type-check-coverage.mjs 指出:packages/create-plugin/tsconfig.json 按设计 exclude 了 **/*.test.ts(它是 build 配置),于是新加的测试文件不被任何 tsc。这正是那条门禁存在的理由(objectui#2911 / objectstack#4118):没被编译过的测试可以断言一份编译器从未检查过的契约,然后被当作"契约成立"的证据 —— 而本 PR 的钉子里恰好有若干条断言是靠类型正确性站住的。

值得记下来的是为什么本地没抓到:我确实手动用一份临时 tsconfig 编过这个文件(0 error),但只把它当"确认我没写错",没把"没有任何常驻程序读它"本身当成缺陷;而包内 pnpm --filter @object-ui/create-plugin type-check 那会儿是绿的,恰恰因为它读不到这个文件。绿得毫无信息量,和门禁描述的形状一模一样。

修法照 packages/types/tsconfig.test.json 的既有形状:新增 emit-free 的 tsconfig.test.json(清掉根 paths,types: ["node"] 给那条读仓根 manifest 的断言),并挂到 type-check 上 —— 门禁明确要求挂在 CI 真跑的那个脚本上,而不是某个 CI 从不调用的旁路脚本。0 error;门禁现在报 23/38 packages compile their tests,此前 22。

补充的本地验证:

node scripts/check-type-check-coverage.mjs   # 23/38,exit 0
pnpm --filter @object-ui/create-plugin type-check   # tsc --noEmit && tsc -p tsconfig.test.json,0 error
node scripts/check-lint-coverage.mjs         # 45/45
pnpm install --frozen-lockfile               # 通过(只改了 scripts,lockfile 不受影响)

Generated by Claude Code

@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Main entry (gzip) 28.1 KB 350 KB
Entry file index-BEAgjw06.js
Status PASS

📦 Bundle Size Report

Package Size Gzipped
app-shell (index.js) 8.66KB 3.13KB
app-shell (runtime-config.js) 7.42KB 2.32KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 7.57KB 2.97KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 1.17KB 0.53KB
auth (AuthProvider.js) 22.10KB 4.37KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.13KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.64KB 2.21KB
auth (SocialSignInButtons.js) 9.60KB 3.89KB
auth (UserMenu.js) 3.40KB 1.22KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 35.76KB 9.11KB
auth (createAuthenticatedFetch.js) 4.37KB 1.69KB
auth (index.js) 2.35KB 1.07KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 4.91KB 0.87KB
auth (useIsWorkspaceAdmin.js) 1.61KB 0.85KB
collaboration (CommentThread.js) 26.07KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.65KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 480.72KB 105.64KB
core (index.js) 2.96KB 1.13KB
create-plugin (index.js) 9.84KB 3.18KB
data-objectstack (index.js) 137.51KB 35.11KB
fields (index.js) 230.90KB 56.84KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (currency.js) 1.22KB 0.64KB
i18n (i18n.js) 4.32KB 1.77KB
i18n (index.js) 2.65KB 1.06KB
i18n (pickLocalized.js) 1.70KB 0.83KB
i18n (provider.js) 9.48KB 3.27KB
i18n (useObjectLabel.js) 26.14KB 6.07KB
i18n (useSafeTranslation.js) 4.52KB 1.96KB
layout (index.js) 38.53KB 10.71KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.74KB
mobile (index.js) 1.50KB 0.62KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.71KB 0.42KB
mobile (useResponsiveConfig.js) 1.36KB 0.63KB
mobile (useSpecGesture.js) 4.32KB 1.64KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 8.75KB 3.06KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 3.67KB 1.12KB
permissions (evaluator.js) 4.41KB 1.44KB
permissions (index.js) 0.91KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.52KB
permissions (usePermissions.js) 1.55KB 0.71KB
plugin-ai (index.js) 15.71KB 3.79KB
plugin-calendar (index.js) 44.98KB 12.37KB
plugin-charts (index.js) 61.04KB 17.31KB
plugin-chatbot (index.js) 180.09KB 42.72KB
plugin-dashboard (index.js) 115.50KB 29.96KB
plugin-designer (index.js) 210.51KB 42.51KB
plugin-detail (index.js) 232.79KB 57.42KB
plugin-editor (index.js) 2.46KB 1.10KB
plugin-form (index.js) 112.10KB 27.10KB
plugin-gantt (index.js) 162.55KB 39.57KB
plugin-grid (index.js) 186.61KB 49.34KB
plugin-kanban (index.js) 48.30KB 13.28KB
plugin-list (index.js) 105.12KB 25.48KB
plugin-map (index.js) 16.81KB 5.24KB
plugin-markdown (index.js) 13.72KB 4.69KB
plugin-report (index.js) 40.58KB 10.58KB
plugin-timeline (index.js) 25.76KB 7.33KB
plugin-tree (index.js) 8.50KB 2.88KB
plugin-view (index.js) 84.03KB 20.55KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.71KB 3.53KB
providers (index.js) 0.44KB 0.22KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.67KB 2.37KB
react (LazyPluginLoader.js) 3.77KB 1.33KB
react (SchemaRenderer.js) 19.28KB 6.38KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 1.02KB 0.55KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 4.09KB 1.74KB
sdui-parser (index.js) 4.47KB 2.03KB
sdui-parser (parse.js) 10.04KB 2.82KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 4.69KB 1.48KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 0.99KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 0.20KB 0.18KB
types (crud.js) 0.20KB 0.18KB
types (data-display.js) 0.20KB 0.18KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.87KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-retry.js) 4.32KB 2.02KB
types (index.js) 2.71KB 1.34KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 2.59KB 1.31KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (spec-report.js) 5.05KB 1.93KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 0.20KB 0.18KB
types (ui-action.js) 3.40KB 1.71KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@yinlianghui
yinlianghui marked this pull request as ready for review August 8, 2026 10:59
@yinlianghui
yinlianghui added this pull request to the merge queue Aug 8, 2026
Merged via the queue into main with commit f4f42b4 Aug 8, 2026
19 checks passed
@yinlianghui
yinlianghui deleted the claude/issue-3716-create-plugin-test-stack branch August 8, 2026 10:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies documentation Improvements or additions to documentation tests

Projects

None yet

2 participants