Skip to content

feat(css): complete Tailwind v4 generation flow alignment (fixes #648)#650

Draft
diyor28 wants to merge 2 commits into
mainfrom
codex/issue-648-tailwind-v4-generation-flow
Draft

feat(css): complete Tailwind v4 generation flow alignment (fixes #648)#650
diyor28 wants to merge 2 commits into
mainfrom
codex/issue-648-tailwind-v4-generation-flow

Conversation

@diyor28

@diyor28 diyor28 commented Mar 1, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR completes Tailwind v4 generation-flow alignment in iota-sdk and also introduces a canonical shared setup to reduce future drift.

Fixes #648

What Changed

1) Canonical root pipeline

  • Added a single pipeline config file: styles/tailwind/pipeline.config.json.
    • Defines input, generated intermediate, output artifact, and source globs in one place.
  • Refactored scripts/build-tailwind-css.mjs to be the canonical pipeline entrypoint.
    • Supports --generate-only, --minify, --clean, and passthrough tailwind flags.
    • Reads source globs/config from pipeline.config.json.
    • Generates deterministic @source directives in styles/tailwind/main.generated.css.
    • Runs Tailwind CLI compile from generated input when not in --generate-only mode.
  • Updated Justfile to call only this script:
    • just css -> node scripts/build-tailwind-css.mjs --minify ...
    • just css-clean -> node scripts/build-tailwind-css.mjs --clean

2) Shared PostCSS config wiring

  • Added styles/tailwind/postcss.shared.mjs with createTailwindPostcssConfig() helper.
  • Updated modules/bichat/presentation/web/postcss.config.js to consume shared helper.
  • Updated docs/postcss.config.mjs to consume shared helper (with autoprefixer: false), so plugin wiring stays consistent across targets.

3) Tailwind dependency/version drift controls

  • Root and BiChat web package manifests now pin:
    • tailwindcss@4.1.18
    • @tailwindcss/cli@4.1.18
    • @tailwindcss/postcss@4.1.18
  • Added pnpm.overrides in both root and BiChat web package.json to enforce those versions.
  • Updated corresponding lockfiles.

4) Previous migration deltas retained

  • tailwind.config.js keeps v4 model (removed v3 content block for root flow).
  • styles/tailwind/main.generated.css remains generated-only (gitignored).
  • Setup/install messaging updated for explicit v4 CLI usage.

Verification

  • node scripts/build-tailwind-css.mjs --generate-only
  • just css
  • pnpm run build:css (root canonical command path) ✅
  • pnpm -C modules/bichat/presentation/web run build
  • rg -n "@tailwind base|@tailwind components|@tailwind utilities" styles modules .github (no matches) ✅

Environment-limited check

  • go vet ./... ⛔ blocked locally by macOS/Xcode license prompt:
    • You have not agreed to the Xcode license agreements...

Risk / Rollback

  • Runtime CSS artifact paths are unchanged.
  • Rollback path is straightforward by reverting this PR.

Notes

  • A separate PR in ../applets was not necessary for this change because config-sharing and pipeline centralization are fully contained in iota-sdk.

@coderabbitai

coderabbitai Bot commented Mar 1, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/issue-648-tailwind-v4-generation-flow

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@diyor28 diyor28 left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Codex PR review — feat(css): complete Tailwind v4 generation flow alignment (DRAFT)

Read-only review. Reviewed fully despite DRAFT status (CI is skipped, so there's currently no automated signal on correctness). 4 inline comments above. This is SDK-level infra consumed by every downstream app, so the design coupling matters.

🟠 Notable (inline)

  • runTailwind hangs forever if pnpm isn't on PATH — no error handler (build-tailwind-css.mjs:113).
  • Undocumented path coupling between pipeline.config.json sources and the generated CSS location (pipeline.config.json:6).
  • New cross-package-boundary import from docs/ into ../styles/tailwind (docs/postcss.config.mjs:1).
  • CJS module.exports in an ESM package (tailwind.config.js:2).

Additional findings

  • Violates the issue's own acceptance criteria: docs/content/bichat/index.mdx:334-336 still contains the v3 directives @tailwind base; @tailwind components; @tailwind utilities;. Issue #648 explicitly requires "no remaining v3-only directives in migrated entry files," and the PR's verification checklist claims rg "@tailwind base|@tailwind utilities" found nothing — so that search missed docs/. This ships a broken v4 example to downstream applet authors.
  • No tests for the pipeline script. createSourceBlock (dedup/sort), removeGeneratedSourceBlock (a lazy [\s\S]*? regex over CSS), and the --generate-only output are untested — and this script is the sole source of truth for the CSS the entire Go backend embeds. Add golden-file tests.
  • build:css:watch inconsistency (package.json:7): it omits --minify, but just css --watch always prepends --minify — the two watch entry points produce different artifacts.
  • Stale docs: docs/content/architecture/frontend-stack.mdx:191 still describes the v3 model ("configured at tailwind.config.js") and doesn't mention pipeline.config.json / @source.

Process

  • Don't leave DRAFT until CI is green — the PR description's just css ✅ is not a substitute for go vet/build verification in CI, which is currently skipped.

stdio: "inherit",
});

child.on("close", (code) => {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Major (correctness) — runTailwind only listens for close, so a failed spawn hangs forever.

spawn() emits an error event (not close) when the binary can't be launched (e.g. pnpm not on PATH). This Promise only handles close, so in that case error fires, close never does, and the Promise never settles — a silent hang in CI and local builds.

Fix: add child.on("error", reject) alongside the close handler.

"generated": "styles/tailwind/main.generated.css",
"output": "modules/core/presentation/assets/css/main.min.css",
"sources": [
"../../cmd/**/*.{go,templ,html,js,ts,tsx}",

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Major (design) — load-bearing, undocumented path coupling between this config and the generated CSS.

These sources entries are written verbatim as @source directives into styles/tailwind/main.generated.css. Tailwind v4 resolves @source relative to the CSS file's location (styles/tailwind/), not relative to pipeline.config.json. The script does no normalization — it passes the ../../... prefixes raw. This only works because the config and the generated CSS happen to share a directory; point --config at a config elsewhere and every ../../ source silently resolves to the wrong place.

Fix: resolve source paths relative to the config file and re-relativize to the generated output file, or at minimum document this constraint with a comment in the JSON.

Comment thread docs/postcss.config.mjs
},
};
export default config;
import { createTailwindPostcssConfig } from "../styles/tailwind/postcss.shared.mjs";

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Major (design) — new cross-package-boundary import.

docs/ is a standalone Next.js package with its own package.json/node_modules. This reaches up and across into a sibling directory (../styles/tailwind/postcss.shared.mjs) that isn't declared as a dependency anywhere, so the coupling is invisible to tooling and only works because CI checks out the whole repo. postcss.shared.mjs is ~3 lines.

Fix: inline the config in docs/postcss.config.mjs, or publish postcss.shared.mjs as a proper importable package — don't introduce a silent cross-boundary import.

Comment thread tailwind.config.js
@@ -1,10 +1,6 @@
/** @type {import('tailwindcss').Config} */
module.exports = {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Minor (sloppy) — CommonJS module.exports in a "type": "module" package.

package.json declares "type": "module", so .js files are ESM by Node's native resolver — but this file uses module.exports. Tailwind's jiti loader tolerates it today, but any tool loading it via native ESM will fail, and the downstream docs already recommend tailwind.config.cjs to consumers (docs/content/getting-started/npm-package.mdx:28).

Fix: rename to tailwind.config.cjs and update the @config references (styles/tailwind/input.css, modules/core/presentation/assets/css/main.css).

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Migrate iota-sdk Tailwind pipelines to v4-compatible generation flow

1 participant