Skip to content

fix(styles): ship tw-animate-css as a runtime dependency - #16

Merged
fx merged 2 commits into
mainfrom
fix/tw-animate-css-dependency
Aug 11, 2026
Merged

fix(styles): ship tw-animate-css as a runtime dependency#16
fx merged 2 commits into
mainfrom
fix/tw-animate-css-dependency

Conversation

@fx

@fx fx commented Aug 11, 2026

Copy link
Copy Markdown
Owner

The bug

@import '@fx/ui/styles/globals.css' — the documented integration path — fails to compile for every consumer:

Error: Can't resolve 'tw-animate-css' in node_modules/@fx/ui/dist/styles

globals.css is published and re-parsed inside the consumer's Tailwind build, so every bare specifier it names resolves from the consumer's node_modules. tw-animate-css was declared in devDependencies, so it never reaches them.

The fix

Promote it to a runtime dependency — the same treatment @tailwindcss/typography and @fontsource/jetbrains-mono already get, for exactly the same reason. globals.css is unchanged.

Verified end to end against a packed tarball

bun pm pack on this branch, installed into a clean consumer that declares no tw-animate-css of its own, then compiled with the Tailwind CLI. Same harness, only the @fx/ui version differs:

published 1.0.0 this branch
tw-animate-css in consumer node_modules absent present transitively
@tailwindcss/cli compile failsCan't resolve 'tw-animate-css' succeeds

The compiled output carries the utilities the import exists to provide — animate-in, fade-in, zoom-in-95, slide-in-from-top-2 — alongside the theme tokens, prose classes, and JetBrains Mono.

Regression guard

src/styles/__tests__/globals.test.ts reads globals.css, extracts every package it @imports or @plugins, and asserts each is declared as a runtime dependency and not left in devDependencies. The next thing added to globals.css cannot repeat this.

Against the current main it fails on precisely tw-animate-css and passes @fontsource/jetbrains-mono and @tailwindcss/typography, so it is a verified guard rather than an assumed one.

Tailwind itself is exempt via a documented allowlist: it is the compiler running the build, so it is necessarily already installed and cannot be supplied from here. A references at least one external package assertion guards the guard, so a regex that silently stops matching cannot turn the suite into a no-op.

Note on Collapsible

Worth recording, since it is easy to "clean up" by mistake: globals.css deliberately defines its own collapsible-down/collapsible-up keyframes against Base UI's --collapsible-panel-height. tw-animate-css bundles keyframes of the same name targeting Radix, Bits, and Reka variables, which would not work here. The local definitions must stay. Documented in the README alongside the animation utilities.

Test plan

  • bun run test — 476 tests across 35 files, Type Errors: no errors
  • bun run lint — matches the main baseline
  • bun run build — clean
  • Packed-tarball consumer build, A/B against published 1.0.0 (above)

globals.css is published and re-parsed inside the consumer's Tailwind
build, so every bare specifier it names resolves from the consumer's
node_modules. tw-animate-css was a devDependency, so it never reached
them and `@import "@fx/ui/styles/globals.css"` failed outright with
"Can't resolve 'tw-animate-css'" — the documented integration path did
not work for anyone.

Promote it to a runtime dependency, the same treatment
@tailwindcss/typography and @fontsource/jetbrains-mono already get for
the same reason.

Add a test that reads globals.css and asserts every package it imports
is declared as a runtime dependency, so the next addition cannot repeat
this. Tailwind itself is exempt: it is the compiler running the build,
so it is necessarily present and cannot be supplied from here.
Copilot AI lite review requested due to automatic review settings August 11, 2026 02:10

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes consumer Tailwind compilation failures by ensuring tw-animate-css is installed transitively when consumers import @fx/ui/styles/globals.css, and adds a regression test to prevent future globals.css imports/plugins from being left in devDependencies.

Changes:

  • Promotes tw-animate-css from devDependencies to dependencies so consumer builds can resolve it.
  • Adds a Vitest guard that parses src/styles/globals.css for @import/@plugin bare specifiers and asserts they’re runtime dependencies.
  • Documents the shipped animation utilities and clarifies why Collapsible keeps local keyframes.

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 2 comments.

File Description
src/styles/__tests__/globals.test.ts New regression test to ensure globals.css’s external imports/plugins are runtime dependencies.
README.md Documents animation utilities and the Collapsible keyframes rationale.
package.json Moves tw-animate-css to runtime dependencies so consumers can resolve it.
bun.lock Lockfile update reflecting the dependency move.
Suppressed comments (1)

src/styles/tests/globals.test.ts:50

  • Same issue as above for devDependencies: Object.keys(packageJson.devDependencies) will throw if the field is missing. Default to {} to keep failures actionable.
  it.each(referencedPackages())('does not leave %s in devDependencies only', (name) => {
    expect(Object.keys(packageJson.devDependencies)).not.toContain(name)
  })

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/styles/__tests__/globals.test.ts Outdated
Comment thread src/styles/__tests__/globals.test.ts
Derive the test's own directory from import.meta.url rather than
__dirname, so reading globals.css does not depend on the runner
supplying CommonJS globals to an ESM package.

Default the manifest lookups to an empty object as well, so a missing
dependencies field fails on the assertion naming the undeclared package
instead of throwing a TypeError that hides it.
@fx
fx requested a lite review from Copilot August 11, 2026 02:13

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 4 changed files in this pull request and generated no new comments.

@fx
fx merged commit 8f9d443 into main Aug 11, 2026
2 checks passed
@fx
fx deleted the fix/tw-animate-css-dependency branch August 11, 2026 02:28
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.

2 participants