Skip to content

fix(cli): 生成的临时 app 从 Tailwind 3 全套迁到 v4,dev 的编程式 postcss 改接 @tailwindcss/postcss (#3852) - #3889

Merged
yinlianghui merged 1 commit into
mainfrom
claude/issue-3852-cli-tailwind-v4
Aug 9, 2026
Merged

fix(cli): 生成的临时 app 从 Tailwind 3 全套迁到 v4,dev 的编程式 postcss 改接 @tailwindcss/postcss (#3852)#3889
yinlianghui merged 1 commit into
mainfrom
claude/issue-3852-cli-tailwind-v4

Conversation

@yinlianghui

Copy link
Copy Markdown
Collaborator

Fixes #3852

packages/cli 的两个生成器写出的样式面此前是完整的 Tailwind 3 三件套,而仓内与 @object-ui/components 都已在 v4(components 的 peerDependencies.tailwindcss^4.2.1)。#3827 / PR #3854 把这三个键钉成显式 TAILWIND_V3_DEFERRED 记账并指向本单 —— 本 PR 有意识地翻转那些钉子。

实测到的两个后果

1. 仓内 objectui dev 的 CSS 管线今天是死的,而且比 issue 描述的更彻底。
commands/dev.ts 的 monorepo 分支把 require('tailwindcss')(configPath) 当 PostCSS 插件调用,v4 下这条路径只会抛 "moved to @tailwindcss/postcss";异常被 try/catch 吞成一行黄字警告,于是 css.postcss 根本没被设上,Vite 退回去搜配置文件、往上找到仓根的 postcss.config.mjs,而 @tailwindcss/postcss 从仓根解析不到 —— 浏览器拿到的是 HTTP 500:

Failed to load PostCSS config (searchPath: /home/user/objectui-3852/.objectui-tmp):
  [Error] Loading PostCSS Plugin failed: Cannot find module '@tailwindcss/postcss'

终端只有一行警告,进程退出码 0,服务照常起。

2. 仓外一次干净安装 ERESOLVE。 生成清单声明 tailwindcss ^3.4.19,与它依赖的 @object-ui/components 的 v4 peer 冲突;#3827@object-ui/* 变成真能解析之后这条冲突就上膛了。

改动

  • src/index.css 改为仓内惯用的 v4 CSS-first 写法(@import 'tailwindcss' + @custom-variant dark + @source + @theme),参照 packages/components/src/index.cssexamples/console-starter/src/index.css。两个生成器合用一个 builder —— 此前两份 CSS 除 body 上三个 utility 外逐字节相同。@theme 的 token 集与 components 的 @theme 逐条对齐,含 v3 config 一直缺、而生成的 src/Layout.tsx 自己就在用的 8 个 sidebar-* token(bg-sidebar-primarydata-[state=open]:bg-sidebar-accent …)。
  • postcss.config.js'@tailwindcss/postcss': {}(同 packages/components/postcss.config.js)。
  • 不再生成 tailwind.config.js v4 下没有 @config 指向它时它就是死文件,仓内本身零个 tailwind.config.*;v3 content 的四条扫描面等价迁为 @source,workspace 两条绝对 glob(components / plugin-*)语义不变,仓外另补 ../node_modules/@object-ui/*/dist/**/*.js —— v4 不自动扫被 gitignore 的 node_modules,这是 v3 content 同样缺、v4 才有办法补的一条。
  • 清单:tailwindcss ^3.4.19^4.3.3(锚仓根),新增 @tailwindcss/postcss ^4.3.3(锚仓内 6 处一致声明);DEPENDENCY_ANCHORS 去掉 deferred-tailwind-v4 这一整类。
  • commands/dev.ts 改接 @tailwindcss/postcss,并由 @object-ui/cli 自己声明这两个插件包 —— 仓根只声明 tailwindcss、不声明 @tailwindcss/postcss,从 cwd 解析在本仓必然失败(实测 MODULE_NOT_FOUND);从 components 的 node_modules 里捞正是 packages/cli 的 createTempAppWithRouting 生成的 app import 了未声明的 lucide-react,且其工具链区间落后仓内一到三个 major #3827 点名的"在消费端糊"的做法,所以在生产端声明。加载失败不再吞成警告,而是带修法响亮报错并拒绝起服务。
  • serve.ts / build.ts 同路径核查:两者没有 monorepo 分支,始终走生成的 postcss.config.js,因此本 PR 换掉那份配置就同时修好了它们真实被用到的仓外路径;它们在仓内另有一个与 Tailwind 无关的更深缺陷(见文末越界发现),已另行立单而不在本 PR 处理。

浏览器实证(dogfood)

同一份探针页(h-16 bg-background border-b px-4 / bg-sidebar-primary size-8 rounded-lg / 只存在于 packages/components/srcmin-h-[150px] / 只存在于 packages/plugin-chatbot/srcsm:h-[360px]),由同一个正在跑的 objectui dev 服务出,Chromium 读 computed style:

探针 修前 修后
/src/index.css HTTP 500,document.styleSheets 0 条规则 HTTP 200,422,304 B,首行 /*! tailwindcss v4.3.3 */,89 条顶层规则
终端 一行黄字警告,exit 0 无警告
h-16 高度 0px 64px
bg-background rgba(0, 0, 0, 0) rgb(2, 8, 23)
px-4 0px 16px
border-b 颜色 rgb(0, 0, 0) rgb(30, 41, 59)
bg-sidebar-primary rgba(0, 0, 0, 0) rgb(29, 78, 216)(= hsl(224.3 76.3% 48%))
size-8 / rounded-lg 1264px × 0px / 0px 32px × 32px / 8px
min-h-[150px](仅 components/src) 0px 150px
sm:h-[360px](仅 plugin-chatbot/src) 0px 360px
body 背景 / 前景 / min-height / 字体平滑 透明 / 黑 / 0px / auto rgb(2, 8, 23) / rgb(248, 250, 252) / 900px / antialiased

一处诚实的限定:这次 in-repo 运行里,@tailwindcss/postcss 的自动 source 检测(base = 调用时的 cwd = 仓根)也会扫到仓内其它包(探针外可见 h-[260px] 这类只属于 packages/app-shell/src 的类也被编出),所以上表最后两行不能单独证明我写的 workspace @source glob 生效。glob 形状是另外用离线编译 fixture 单独验的:绝对路径 glob、目录位 plugin-* 通配、以及 node_modules/@object-ui/*/dist/**/*.js(自动检测永不扫 node_modules,因此这条只能由显式 @source 命中)三者都实测通过。显式 @source 仍然必要:自动检测的 base 取决于调用时的 cwd,不保证是 workspace 根。

单元测试里没有"真编译一遍"的门禁,原因也是实测的:@import 'tailwindcss' 由插件按样式表自身所在目录解析,fixture 旁边没有 node_modules 就报 Can't resolve 'tailwindcss' in …/app/src。这一端因此留给上面的浏览器实证,单测只钉形状与语义。

反向验证(方向先判后跑)

预判先写下再跑,跑完逐条对上:

  • 还原两份 pre-fix 源码 → 新增门禁 8 条转红并逐一点名:@tailwind base; 在、v3 插件键在、tailwind.config.js 被写出、@source 全无、@theme token 期望 35 个实得 0 个、^3.4.19 与 peer ^4.2.1 不同 major、锚表少 @tailwindcss/postcss
  • 同一次还原暴露了一条方向如预期的:resolves every theme token through a variable it declares itself 在 pre-fix 输入上是绿的 —— 因为那份 CSS 根本没有 @theme,被引用集合为空,空集没有未声明成员。这正是 fix(create-plugin): 清掉脚手架的未用 lucide 声明,并让生成的 schema 接口真的可达 (#3755, #3759) #3826 说的"因为什么都没产出而绿",已就地补上 referenced.length > 20 的非空断言,并把这条原因写进注释。
  • @tailwindcss/postcss 从 CLI 的 node_modules 移开(模拟坏安装)→ 退出码 1、带修法的报错、127.0.0.1:5854 无人监听;此前同类失败是"警告 + exit 0 + 无样式"。

验证

  • pnpm exec vitest run packages/cli/src/__tests__/ --maxWorkers=2 → 3 files / 63 passed
  • pnpm --filter @object-ui/cli type-check → 干净;末次编辑后全仓 pnpm exec turbo run type-check --concurrency=278/78 successful
  • pnpm --filter @object-ui/cli build 后按 fix(cli): 生成的临时 app 补齐 lucide-react 与七个 plugin 声明,两处清单区间锚到仓内 #3854 先例核 dist 深度:dist/"@tailwindcss/postcss": "^4.3.3"tailwindcss: "^4.3.3"'@tailwindcss/postcss': {}@import 'tailwindcss' 都在;@tailwind base'tailwind.config.js'3.4.19require('tailwindcss') 全部零命中(^4.1.18 的那处命中属 init.ts 的脚手架,与本单无关且本来就是 v4)
  • 改动文件控制字节 grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f]' 零命中;起过的 dev server(5852/5853/5854/5855)全部按 PID 关净,临时 fixture 与 .objectui-tmp 已删

Generated by Claude Code

…dcss/postcss (#3852)

生成器写出的样式面此前是完整的 v3 三件套(`src/index.css` 的 `@tailwind
base/components/utilities` 指令、`postcss.config.js` 的 `tailwindcss: {}` 插件键、
一份 v3 `tailwind.config.js`),而仓内与 `@object-ui/components` 都已在 v4
(components 的 peer 是 `tailwindcss ^4.2.1`)。#3827 把这三个键钉成显式
`TAILWIND_V3_DEFERRED` 记账指向本单,本单翻转那些钉子。

两个后果都实测过:

- 仓内 `objectui dev` 不出样式。`commands/dev.ts` 的 monorepo 分支把
  `require('tailwindcss')(configPath)` 当 PostCSS 插件调用,v4 下这条路径只会抛
  "moved to @tailwindcss/postcss",异常被 try/catch 吞成一行黄字警告 ——
  `css.postcss` 没被设上,Vite 退回搜配置文件,`/src/index.css` 最终 500:
  `Failed to load PostCSS config … Cannot find module '@tailwindcss/postcss'`。
  浏览器里 stylesheet 0 条规则,`h-16` 高 0px,`bg-background` 透明。
- 仓外一次干净安装 ERESOLVE:生成清单的 `tailwindcss ^3.4.19` 与它依赖的
  `@object-ui/components` 的 v4 peer 冲突(#3827 让 `@object-ui/*` 变成真能解析
  之后此冲突就上膛了)。

改动:

- `src/index.css` 改为仓内惯用的 v4 CSS-first 写法(`@import 'tailwindcss'` +
  `@custom-variant dark` + `@source` + `@theme`),两个生成器共用一个 builder
  (此前两份 CSS 除 body 三个 utility 外逐字节相同)。`@theme` 的 token 集与
  `packages/components/src/index.css` 逐条对齐 —— 含 v3 config 一直缺、而生成的
  `src/Layout.tsx` 自己就在用的 8 个 `sidebar-*` token。
- `postcss.config.js` 写 `'@tailwindcss/postcss': {}`;不再生成
  `tailwind.config.js`(v4 下无 `@config` 指向即死文件,仓内本身零个
  `tailwind.config.*`),v3 的 `content` 四条扫描面等价迁为 `@source`,workspace
  两条绝对 glob 语义不变;仓外补 `../node_modules/@object-ui/*/dist/**/*.js`
  (v4 不自动扫 gitignore 掉的 node_modules)。
- 清单 `tailwindcss` → `^4.3.3`、新增 `@tailwindcss/postcss ^4.3.3`,两者锚回仓内;
  `DEPENDENCY_ANCHORS` 去掉 `deferred-tailwind-v4` 这一类。
- `commands/dev.ts` 改接 `@tailwindcss/postcss`,由 `@object-ui/cli` 自己声明这两个
  插件包(仓根只声明 tailwindcss,不声明 @tailwindcss/postcss,从 cwd 解析在本仓
  必然失败);加载失败不再吞成警告,而是带修法响亮报错并拒绝起服务。

反向验证(方向先判后跑):还原两份 pre-fix 源码后,新增 8 个门禁转红并逐一点名
(`@tailwind base;`、v3 插件键、被写出的 `tailwind.config.js`、缺失的 `@source`、
35 个 token 全缺、`^3.4.19` 与 peer `^4.2.1` 不同 major);其中
"resolves every theme token" 一条在 pre-fix 输入上是"因为什么都没产出而绿",
已按 #3826 的教训补上非空断言。把插件包移开模拟坏安装:退出码 1、带修法报错、
不起服务(此前:警告 + exit 0 + 无样式)。

Co-authored-by: Claude <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 9, 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 9, 2026 12:08am

Request Review

@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Main entry (gzip) 28.1 KB 350 KB
Entry file index-CjQhjOao.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) 482.39KB 106.34KB
core (index.js) 2.96KB 1.13KB
create-plugin (index.js) 10.08KB 3.26KB
data-objectstack (index.js) 139.61KB 35.99KB
fields (index.js) 230.82KB 56.70KB
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) 27.59KB 6.63KB
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.33KB 42.79KB
plugin-dashboard (index.js) 117.21KB 30.27KB
plugin-designer (index.js) 210.51KB 42.51KB
plugin-detail (index.js) 236.17KB 58.82KB
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) 187.63KB 49.66KB
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

Copy link
Copy Markdown
Collaborator Author

✅ 验收(PM,session session_01GTRjn8xBqp75dk7kFupVRt)

实物核验:头 c9813e800,6 文件 +514/−276(两生成器 v4 全套 + dev.ts + 锚表/钉子 + changeset + lockfile 新增 @tailwindcss/postcss);dev.ts 响亮失败段全读 —— 插件由 CLI 自己声明并解析(仓根不声明 @tailwindcss/postcss,cwd 解析实测 MODULE_NOT_FOUND,设计注释写透)、加载失败 exit 1 带修法拒绝起服务(「拒绝无样式起服务:那种失败在浏览器里是静默的」);trailer 0(commit trailer 用仓内一致的通用署名,无模型标识)。
CI 终态(独立复核,dev 报告未附此节):20 检查全部 completed,18 success + 2 skipped,零失败。

裁定要点:

转 ready 并挂 auto-merge。越界 #3890(alias 表死清单,与 Tailwind 无关的第二个「dev 空白」根因)/#3891(doctor 误报)/#3892(init 脚手架化石区间,可复用 platformPackageRange())归分诊席;#3893(finding)入维护者决策箱与 #3884 并案。


Generated by Claude Code

@yinlianghui
yinlianghui marked this pull request as ready for review August 9, 2026 00:15
@yinlianghui
yinlianghui added this pull request to the merge queue Aug 9, 2026
Merged via the queue into main with commit 8277053 Aug 9, 2026
21 checks passed
@yinlianghui
yinlianghui deleted the claude/issue-3852-cli-tailwind-v4 branch August 9, 2026 00:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants