Skip to content

chore(config): delete three Tailwind config files nothing reads (#4065, #4066) - #4349

Merged
yinlianghui merged 1 commit into
mainfrom
claude/issue-4065-4066-dead-tailwind-configs
Aug 11, 2026
Merged

chore(config): delete three Tailwind config files nothing reads (#4065, #4066)#4349
yinlianghui merged 1 commit into
mainfrom
claude/issue-4065-4066-dead-tailwind-configs

Conversation

@yinlianghui

@yinlianghuiyinlianghui commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Closes#4065
Closes#4066

Deletes three Tailwind configuration files that nothing in the repo reads. No dependency is added and no setting is ported, because measurement says there is nothing live in any of them.

Both cards were triaged with an explicit delete ruling, and this PR implements exactly that.

#4065 — root postcss.config.mjs

Triage ruling on #4065:

Resolving the card's vestigial-vs-latent-trap question: vestigial, measurably. Two mechanical facts close it: (1) every root script builds through per-package filters (pnpm --filter ... / turbo run build) — nothing processes CSS at the root, and there are no root sources to process; (2) any package that built CSS without its own nearer config would discover this one and fail on the first unresolvable plugin — so no working consumer can exist today by construction. A file whose only possible consumers would already be broken is residue, not a trap. Fix = delete postcss.config.mjs; do not add the two devDependencies (that would wire in a config nothing needs).

Premise re-verified on origin/main @ f046f885a — the file is still present, and the root still declares neither plugin. Node's own resolver, from each package.json:

### package.json ### apps/console/package.json
@tailwindcss/postcss UNRESOLVABLE @tailwindcss/postcss .pnpm/@tailwindcss+postcss@4.3.3/...
postcss UNRESOLVABLE postcss .pnpm/postcss@8.5.26/...
tailwindcss .pnpm/tailwindcss@4.3.3/... tailwindcss .pnpm/tailwindcss@4.3.3/...
autoprefixer .pnpm/autoprefixer@10.5.4/... autoprefixer .pnpm/autoprefixer@10.5.4/...

Rather than rely on the ruling's by-construction argument alone, I enumerated every possible consumer. There are none:

  • the root has zero.css/.html files (git ls-tree at depth 1), and every root build script runs through a per-package filter (pnpm --filter / turbo run);
  • of the 10 tracked .css files, the 5 packages that build CSS through Vite each carry their ownpostcss.config.* (apps/console, apps/site, packages/components, packages/runner, and the two console examples), which stops postcss-load-config's upward walk before it reaches the root;
  • packages/app-shell ships src/styles.cssraw — its build is plain tsc, and exports['./styles.css'] points at the source file — so no PostCSS runs over it at all;
  • packages/fields has CSS and no postcss config, but scripts/build-css.mjs calls postcss([tailwindPostcss()]) with an explicit plugin array, so it performs no config discovery;
  • packages/plugin-calendar sets vitest css: true and has no postcss config of its own, but imports no .css file, so the CSS pipeline never fires.

This is the same enumeration scripts/__tests__/helpers/build-program.ts already records, as a deliberately documented known blind spot:

POSTCSS CONFIG DISCOVERY IS NOT MODELLED, and this one is a KNOWN BLIND SPOT rather than a safe narrowing (...) Measured: no package does BOTH today. (...) So the root config is genuinely outside every build program right now, which is why no input entry is owed for it. But that is a COINCIDENCE of two facts, not a structural guarantee: adding one import './index.css' to packages/fields/src would pull the root postcss config into the build program, turbo would not hash it, and this guard would not notice.

Deleting the file retires that blind spot instead of continuing to document it: with no root config, there is nothing for the upward walk to find.

#4066 — the two tracked tailwind.config.* files

Triage ruling on #4066:

Resolving the card's delete-vs-@config question: delete, measurably. Read on main, both configs set nothing a stylesheet doesn't already cover: theme.extend is empty in both, plugins is empty in both, the content arrays are superseded by each app's @source directives, and darkMode: ['class'] (byo-backend only) is inert alongside everything else.

Premise re-verified: @config still has zero occurrences across every .css file in the repo; counter-probe that the scan works, @import 'tailwindcss' matches 9 stylesheets, including both apps' own src/index.css.

I re-measured each setting against the app's live v4 CSS entry rather than taking the ruling on trust. Per-setting disposition, all three "already covered / nothing to port":

Settingapps/consoleexamples/byo-backend-consoleDisposition
theme.extend{}{}Empty — nothing to port. Both entries already carry a populated @theme block.
plugins[][]Empty — nothing to port. console loads @plugin '@tailwindcss/typography' from its CSS entry.
content['./index.html', './src/**/*.{js,ts,jsx,tsx}']['./index.html', './src/**/*.{ts,tsx}']Superseded by the @source directives already in each src/index.css (37 hits in console's, 15 in byo's).
darkMode: ['class']n/apresentAlready provided, not merely dead: both entries @import '@object-ui/app-shell/styles.css', which declares @custom-variant dark (&:where(.dark, .dark *)); — the v4 spelling of exactly that setting.

The darkMode row is the one worth stating explicitly, because "inert" and "already provided" are different facts and only the second makes deletion safe without a port. Porting it would have been the wrong move: it is not missing.

Incidental, and retired with the file: apps/console/tailwind.config.js is a .js file containing TypeScript syntax (import type { Config }, satisfies Config). Two things were hiding that parse bomb, and both are now moot — eslint.config.js ignores **/tailwind.config.js for precisely this reason ("Tailwind configs are authored in TypeScript despite the .js extension"), and the file was never in any TS program either, since both apps' tsconfigs include only src (plus dev for console).

One nice side effect: packages/cli/src/__tests__/app-generator.test.ts already describes this repo as one that "has been on Tailwind 4 (and carried zero tailwind.config.* files) since its own migration". That sentence was false on main. It is true now.

Verification

CSS is provably unchanged — byte-identical, from real builds. Each app was built twice with vite build, once with the three files restored and once with them deleted, and the emitted CSS assets compared by sha256:

=== byo: before(restored) vs after(deleted) ===
IDENTICAL (content hash + hashed filename)
=== console: before(restored) vs after(deleted) ===
IDENTICAL (content hash + hashed filename)

No normalization was needed and none was applied. Vite's asset filenames embed a content hash rather than a timestamp, so identical content yields identical filenames — the comparison covers 4 CSS assets for console (index-PgjYDqEe.css, plugin-dashboard-DnNKJB60.css, plugin-map-5lRITB8H.css, ui-components-BL3SEdAz.css) and 2 for byo (index-DYuRB4AA.css, dist-kzrx2K5g.css), and the filenames themselves are part of the evidence.

A second, independent probe compiled each app's src/index.css directly through the same @tailwindcss/postcss plugin its own postcss.config.js registers, from the app directory as cwd. Same verdict, at full byte granularity:

console b8f6b8ec225eaeb4e67e24bc99f4ee25b128f9e28484161239db74d455563c2a 434744 bytes (before and after)
byo d5fa401cf682bcb9922cb9a6d8a93240808fd7d11315cabf004de0d735e42079 346514 bytes (before and after)
console: BYTE-IDENTICAL
byo: BYTE-IDENTICAL

Reverse verification, with the expected direction stated first. The usual "revert the fix and watch the tests go red" shape does not apply here, and forcing it would have been a fabrication: the claim under test is that these files are inert, so restoring them must leave the CSS identical and move only what objectui doctor reports. Both halves came out as predicted — the CSS hashes above are the restored-vs-deleted comparison, and the doctor warnings returned verbatim on restore.

objectui doctor (the #4064-fixed one), before and after.

apps/console and examples/byo-backend-console — the #4066 warning is gone in both, and both are now fully clean:

before: ⚠️ tailwind.config.js exists but nothing opts into it — Tailwind 4 ignores a JS
config unless a stylesheet declares `@config`. Anything it sets (theme,
content/@source paths, plugins) has no effect today. ...
Found 1 issue(s).
after: ✓ CSS entry runs `@import 'tailwindcss'`
✓ CSS entry declares `@source` scanning paths
Everything looks good! ✨

Repo root — and here the result is partial, which I am reporting rather than smoothing over:

before: ✓ Tailwind CSS ^4.3.3 installed
x Tailwind CSS 4 needs @tailwindcss/postcss, which is neither declared nor
installed here. ...
✓ PostCSS config uses @tailwindcss/postcss
Found 1 issue(s).
after: ✓ Tailwind CSS ^4.3.3 installed
x Tailwind CSS 4 needs @tailwindcss/postcss, which is neither declared nor
installed here. ...
Found 1 issue(s).

The ✓ PostCSS config uses @tailwindcss/postcss line disappears with the file, as expected. The xdoes not, and cannot: reading packages/cli/src/commands/doctor.ts, that finding is gated on the root package.json declaring tailwindcss while declaring no @tailwindcss/postcss — it is driven by the manifest, not by postcss.config.mjs. The root's own tailwindcss and autoprefixer devDependencies are the remaining half of the same vestigial surface, and removing them is outside both the ruling ("do not add the two devDependencies" rules on additions only) and this PR's scope, so it is filed separately as #4350 rather than smuggled in here. No regression either way: 1 issue before, 1 issue after.

Gates and tests.

  • node scripts/check-changeset-presence.mjsNo source of a released package changed in this range, so no changeset is owed. (3 files changed, 0 under any released package's src/). Substantively true as well as mechanically: apps/console's published files list is ["dist","plugin.ts","plugin.js","plugin.d.ts","README.md"], so tailwind.config.js was never in the tarball, and examples/byo-backend-console is private.
  • node scripts/check-control-bytes.mjs — OK, 4068 tracked text files scanned.
  • vitest run scripts/__tests__/turbo-build-inputs.test.ts scripts/__tests__/doc-version-claims.test.ts2 files, 38 tests passed. These are the tests that model the repo's build programs, including the one whose comment names the root postcss config.
  • vitest run packages/cli/4 files, 105 tests passed (doctor, app-generator, cli-bin).
  • pnpm --filter @object-ui/console lint — 0 errors (206 pre-existing warnings); pnpm --filter @object-ui/example-byo-backend-console lint — 0 errors (14 pre-existing warnings).
  • pnpm --filter @object-ui/console --filter @object-ui/example-byo-backend-console type-check — both Done, after building each app's dependency closure first.

No repo tests cover the three deleted paths directly — they were untested precisely because nothing loaded them. The @config-vs-content behavior they were misread as configuring is already pinned by packages/cli/src/__tests__/doctor.test.ts, which builds its own temp fixtures and is unaffected.

Scope

Three deletions, 28 lines, nothing added:

 apps/console/tailwind.config.js | 12 ------------
examples/byo-backend-console/tailwind.config.ts | 10 ----------
postcss.config.mjs | 6 ------
3 files changed, 28 deletions(-)

No CSS entry was edited, because no port was owed. Deliberately left alone and filed as #4350 (finding, unassigned) rather than fixed here: the root tailwindcss/autoprefixer devDependencies noted above; the now-vestigial **/tailwind.config.js ignore in eslint.config.js; and the scripts/__tests__/helpers/build-program.ts comment, whose blind-spot narrowing stays true in principle but now names a file that no longer exists.

Related

#4198 is an open finding about this exact root postcss.config.mjs — "a dormant fifth instance of the #3514 class — outside every build program only by coincidence". This PR retires that instance by a route none of its three options considered: with no config at the root, postcss-load-config's upward walk has nothing to arrive at, which is strictly stronger than its option B (give packages/fields its own config so the walk stops earlier). Its class concern survives — build-program.ts still does not model postcss discovery — so I commented there rather than assuming it can be closed, and left the disposition to triage.


Generated by Claude Code

#4066)
Root `postcss.config.mjs` (#4065) and the two tracked `tailwind.config.*`
files (#4066) are dead configuration left over from the Tailwind v4
migration. All three are removed; no dependency is added and no setting is
ported, because nothing in them is live.
#4065 — root `postcss.config.mjs`
It registers `@tailwindcss/postcss` and `autoprefixer`, and the repo root
declares neither `@tailwindcss/postcss` nor `postcss`; under pnpm's isolated
node_modules neither resolves from the root either. Any consumer that
discovered this config would fail on its first plugin, so no working consumer
can exist. Enumerated, no consumer exists at all:
- the root has zero `.css`/`.html` files, and every root build script runs
through a per-package filter (`pnpm --filter` / `turbo run`);
- the 5 packages that build CSS through Vite each carry their own
`postcss.config.*`, which stops postcss-load-config's upward walk;
- `packages/app-shell` ships `src/styles.css` raw (`build` is `tsc`, and
`exports['./styles.css']` points at the source), so no PostCSS runs;
- `packages/fields/scripts/build-css.mjs` passes an explicit plugin array to
`postcss([tailwindPostcss()])`, so it performs no config discovery;
- `packages/plugin-calendar` sets vitest `css: true` but imports no `.css`.
This is the same enumeration `scripts/__tests__/helpers/build-program.ts`
already records as a known blind spot ("no package does BOTH today"). Deleting
the file retires that blind spot rather than merely documenting it.
#4066 — `apps/console/tailwind.config.js`, `examples/byo-backend-console/tailwind.config.ts`
Tailwind 4 loads a JS config only when a stylesheet opts in with `@config`,
and `@config` has zero occurrences across the repo (counter-probe: `@import
'tailwindcss'` matches 9 stylesheets, including both apps'). Measured against
each app's live v4 CSS entry, neither file sets anything to port:
- `theme.extend` is empty in both, `plugins` is empty in both;
- the v3 `content` arrays are superseded by the `@source` directives already
in each `src/index.css`;
- byo's `darkMode: ['class']` is already provided by
`packages/app-shell/src/styles.css`, which both entries import and which
declares `@custom-variant dark (&:where(.dark, .dark *));` — the v4
spelling of that exact setting.
`apps/console/tailwind.config.js` also held TypeScript syntax (`import type`,
`satisfies Config`) in a `.js` file, which is why `eslint.config.js` ignores
`**/tailwind.config.js`. It was never in any TS program either — both apps'
tsconfigs include only `src` (and `dev`). The parse bomb goes with the file.
Verification: both apps' emitted CSS is byte-identical before and after, via
real `vite build` runs — same sha256 and the same content-hashed asset
filenames (4 assets for console, 2 for byo). No changeset is owed:
`check-changeset-presence.mjs` reports 0 files under any released package's
`src/`, and `tailwind.config.js` was never in `apps/console`'s published
`files` list.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Qqyix2QcnpUC9XeYVDzx3
@vercel

vercelBot commented Aug 11, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectuiIgnoredIgnoredAug 11, 2026 7:17pm

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Main entry (gzip)29.6 KB350 KB
Entry fileindex-Djpc87rx.js
StatusPASS

📦 Bundle Size Report

PackageSizeGzipped
app-shell (index.js)9.56KB3.59KB
app-shell (runtime-config.js)7.42KB2.32KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)8.92KB3.41KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)1.17KB0.53KB
auth (AuthProvider.js)22.10KB4.37KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.13KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.64KB2.21KB
auth (SocialSignInButtons.js)9.60KB3.89KB
auth (UserMenu.js)3.40KB1.22KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)35.76KB9.11KB
auth (createAuthenticatedFetch.js)4.37KB1.69KB
auth (index.js)2.35KB1.07KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)4.91KB0.87KB
auth (useIsWorkspaceAdmin.js)1.61KB0.85KB
collaboration (CommentThread.js)26.07KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.65KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)489.12KB108.41KB
core (index.js)3.04KB1.15KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)150.04KB39.79KB
fields (index.js)228.37KB56.62KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (i18n.js)4.32KB1.77KB
i18n (index.js)3.35KB1.38KB
i18n (pickLocalized.js)1.70KB0.83KB
i18n (provider.js)23.12KB7.62KB
i18n (useDisplayLocale.js)2.33KB1.20KB
i18n (useObjectLabel.js)27.59KB6.63KB
i18n (useSafeTranslation.js)4.52KB1.96KB
layout (index.js)38.98KB10.85KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.74KB
mobile (index.js)1.50KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.71KB0.42KB
mobile (useResponsiveConfig.js)1.36KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)8.75KB3.06KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)3.67KB1.12KB
permissions (evaluator.js)4.41KB1.44KB
permissions (index.js)0.91KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.52KB
permissions (usePermissions.js)1.55KB0.71KB
plugin-ai (index.js)15.71KB3.79KB
plugin-calendar (index.js)45.23KB12.45KB
plugin-charts (index.js)62.18KB17.67KB
plugin-chatbot (index.js)180.33KB42.79KB
plugin-dashboard (index.js)121.56KB31.56KB
plugin-designer (index.js)210.91KB42.67KB
plugin-detail (index.js)238.95KB59.76KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)114.58KB27.68KB
plugin-gantt (index.js)164.14KB39.98KB
plugin-grid (index.js)188.00KB49.94KB
plugin-kanban (index.js)48.60KB13.41KB
plugin-list (index.js)110.10KB26.74KB
plugin-map (index.js)18.05KB5.80KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)40.60KB10.58KB
plugin-timeline (index.js)26.21KB7.52KB
plugin-tree (index.js)8.50KB2.88KB
plugin-view (index.js)84.03KB20.55KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.71KB3.53KB
providers (index.js)0.44KB0.22KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.67KB2.37KB
react (LazyPluginLoader.js)3.77KB1.33KB
react (SchemaRenderer.js)23.71KB7.96KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)1.23KB0.66KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)4.09KB1.74KB
sdui-parser (index.js)4.47KB2.03KB
sdui-parser (parse.js)10.04KB2.82KB
sdui-parser (types.js)0.29KB0.24KB
sdui-parser (validate.js)4.69KB1.48KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)0.20KB0.18KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)0.20KB0.18KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.87KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-retry.js)4.32KB2.02KB
types (index.js)3.05KB1.52KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)0.20KB0.18KB
types (ui-action.js)3.40KB1.71KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

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

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants

@yinlianghui@claude