Skip to content

perf: optimize CSS-in-JS performance with build-time Tailwind pre-gen… - #548

Merged
ayshadogo merged 2 commits into
Dfunder:mainfrom
Unclebaffa:perf/css-in-js-performance
Aug 27, 2026
Merged

perf: optimize CSS-in-JS performance with build-time Tailwind pre-gen…#548
ayshadogo merged 2 commits into
Dfunder:mainfrom
Unclebaffa:perf/css-in-js-performance

Conversation

@Unclebaffa

Copy link
Copy Markdown
Contributor

[Performance] CSS-in-JS Optimization & Build-Time Tailwind Pre-generation


📌 Summary of Changes

This PR addresses the interaction jank, layout thrashing, and visible frame drops caused by runtime CSS/class generation and dynamic style evaluations across the StellarAid web application.

Although the application relies on Tailwind CSS rather than a runtime CSS-in-JS engine (e.g., Emotion / Styled Components), performance bottlenecks were identified stemming from:

  1. Per-render template-literal class string construction and string concatenation allocating new memory references on every interaction tick.
  2. Missing twMerge conflict resolution, allowing conflicting utility classes to compound in the DOM and cause recalculation overhead.
  3. Runtime inline style={{}} object allocations for static gradients, backgrounds, and meter bars.
  4. Incomplete Tailwind content paths risking class purging and un-purged CSS fallbacks.
  5. Tailwind version conflict in package.json (@tailwindcss/postcss v4 dependency colliding with Tailwind v3 configuration).

All styling has now been migrated to build-time pre-generated Tailwind classes with a centralized cn() utility (clsx + tailwind-merge), and automated CI gates have been instituted.


🛠️ Detailed Implementation Breakdown

1. Canonical Class-Name Merging Utility (lib/cn.ts)

  • Implemented lib/cn.ts:
    • Combines clsx for conditional boolean logic with tailwind-merge for conflict resolution (e.g., ensuring dynamic className props override base utilities cleanly).
  • Added Unit Test Suite lib/tests/cn.test.ts:
    • 4 test cases covering class combination, falsy values, Tailwind conflict overrides, and array/object inputs.

2. Tailwind Configuration & Build-Time Optimization

  • tailwind.config.ts:
    • Added missing source directory paths to the content array: hooks/, stores/, lib/, utils/, constants/, and types/ to prevent premature purging of utilities.
  • package.json:
    • Removed unused @tailwindcss/postcss (Tailwind v4) dependency to eliminate version discrepancies with Tailwind v3.3.0.

3. Elimination of Runtime Inline Style Objects

  • app/globals.css:
    • Extracted heavy multi-radial and repeating linear gradients into pre-compiled CSS classes: .hero-mesh-gradient and .hero-grid-texture.
  • app/components/landing/Hero.tsx:
    • Replaced inline multi-gradient style={{ background: ... }} and style={{ backgroundImage: ... }} with .hero-mesh-gradient and .hero-grid-texture.

4. Refactoring PasswordStrengthIndicator to Tailwind

  • app/components/common/PasswordStrengthIndicator.tsx:
    • Refactored from 100% inline JavaScript styling (style={{ backgroundColor: color, ... }}) to static Tailwind color mapping (STRENGTH_BAR_CLASSES, STRENGTH_TEXT_CLASSES).
    • Retained inline style strictly for the data-driven percentage width.
    • Added accessible role="meter" and ARIA labels.

5. Component Class Composition Standardization (cn())

Replaced ad-hoc string concatenation, template literals, and clsx() calls across 16 core UI and layout components:

  • app/components/ui/Button.tsx
  • app/components/ui/Input.tsx
  • app/components/ui/Skeleton.tsx
  • app/components/ui/Breadcrumb.tsx
  • app/components/common/ButtonSpinner.tsx
  • app/components/common/Modal.tsx
  • app/components/common/Lightbox.tsx
  • app/components/common/Spinner.tsx
  • app/components/common/ErrorMessage.tsx
  • components/common/VerifiedBadge.tsx
  • app/components/layout/Header.tsx
  • app/components/layout/Navbar.tsx
  • app/components/layout/NotificationBell.tsx
  • app/explore/components/ExploreProjects.tsx
  • components/landing/HowItWorks.tsx
  • components/landing/CategoriesShowcase.tsx

6. TypeScript & Build Configuration Fixes

  • tsconfig.json:
    • Added "types": ["node"] to prevent the TS compiler/IDE from attempting to auto-discover ambient type definitions from transitive testing packages (@types/sinonjs__fake-timers, @types/sizzle).
  • types/freighter.d.ts & lib/stellar/freighter.ts:
    • Harmonized global Window.freighter declarations and updated Freighter SDK calls for v6 compatibility.
  • vitest.config.ts:
    • Configured pool: 'threads' for deterministic cross-platform test runs.

7. CI Pipeline (.github/workflows/ci.yml)

  • Added a full continuous integration workflow covering:
    1. npm run type-check (tsc --noEmit)
    2. npm run lint (next lint)
    3. npm run format:check (prettier --check)
    4. npm run test (vitest run)
    5. npm run build (next build)

🧪 Verification & Test Results

All 5 quality and performance gates passed with zero errors:

Check Command Result
Type Check npm run type-check Passed (0 TypeScript errors)
Lint npm run lint Passed (0 ESLint errors)
Format npm run format:check Passed (All files match Prettier)
Unit Tests npm test Passed (8/8 tests passed in 2 suites)
Production Build npm run build Passed (All 34/34 pages generated successfully)

📂 Key Files Modified / Added

  • lib/cn.ts (new)
  • lib/__tests__/cn.test.ts (new)
  • .github/workflows/ci.yml (new)
  • app/globals.css
  • tailwind.config.ts
  • package.json
  • tsconfig.json
  • vitest.config.ts
  • app/components/common/PasswordStrengthIndicator.tsx
  • app/components/common/ButtonSpinner.tsx
  • app/components/common/ErrorMessage.tsx
  • app/components/common/Lightbox.tsx
  • app/components/common/Modal.tsx
  • app/components/common/Spinner.tsx
  • app/components/landing/Hero.tsx
  • app/components/layout/Header.tsx
  • app/components/layout/Navbar.tsx
  • app/components/layout/NotificationBell.tsx
  • app/components/ui/Breadcrumb.tsx
  • app/components/ui/Button.tsx
  • app/components/ui/Input.tsx
  • app/components/ui/Skeleton.tsx
  • app/explore/components/ExploreProjects.tsx
  • components/common/VerifiedBadge.tsx
  • components/landing/CategoriesShowcase.tsx
  • components/landing/HowItWorks.tsx

Closes #522

@drips-wave

drips-wave Bot commented Aug 26, 2026

Copy link
Copy Markdown

@Unclebaffa Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@Unclebaffa
Unclebaffa force-pushed the perf/css-in-js-performance branch from df49f36 to d207aa7 Compare August 26, 2026 18:49

@ayshadogo ayshadogo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

@ayshadogo
ayshadogo merged commit 6f54373 into Dfunder:main Aug 27, 2026
1 check passed
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.

[Performance] CSS-in-JS Performance

2 participants