A modern monorepo setup using pnpm workspaces with Svelte, Storybook, and Tailwind CSS v4.
svelte-storybook-tailwind-monorepo/
├── apps/
│ ├── main-app/ # SvelteKit application
│ └── storybook/ # Storybook application
└── packages/
├── ui/ # Svelte component library
└── tailwind-theme/ # Custom Tailwind v4 theme package
The @some-org/tailwind-theme
package provides:
Theme Package (packages/tailwind-theme/
):
@theme
directive with custom CSS variables@source
scanning for all UI packagesComponent Library (packages/ui/
):
bg-brand-600
)Applications (apps/main-app/
, apps/storybook/
):
# Install dependencies
pnpm install
# Start main app
pnpm run dev:main-app
# Start Storybook
pnpm run dev:storybook
# Build all packages
pnpm run build:packages
packages/tailwind-theme/src/theme.css
)@theme {
/* Custom colors */
--color-brand-500: #3b82f6;
--color-brand-600: #2563eb;
/* ... more variables */
}
/* Centralized source scanning */
@source '../../*/src/**/*.{svelte,js,ts}';
/* Exclude test and config files for better performance */
@source not '../../*/src/**/*.test.{js,ts}';
@source not '../../*/src/**/*.spec.{js,ts}';
@source not '../../*/src/**/*.config.{js,ts}';
@source not '../../*/src/**/*.d.ts';
apps/main-app/src/app.css
)@import "tailwindcss";
@import "@some-org/tailwind-theme/theme.css";
@plugin '@tailwindcss/forms';
@plugin '@tailwindcss/typography';
The Problem: Utility classes work fine when used directly (<div class="bg-brand-500">
), but components from UI packages don't get theme styles applied.
The Root Cause: Without @source
, Tailwind only scans the current app's files. It never discovers classes used in your UI package components, so those utility classes are never generated.
The Solution: The @source
directive tells Tailwind to scan additional file paths for class names.
const variantClasses = {
primary: "bg-brand-600 text-white hover:bg-brand-700",
};
/* Include all component files */
@source '../../*/src/**/*.{svelte,js,ts}';
/* Exclude non-component files for better performance */
@source not '../../*/src/**/*.test.{js,ts}';
@source not '../../*/src/**/*.spec.{js,ts}';
@source not '../../*/src/**/*.config.{js,ts}';
@source not '../../*/src/**/*.d.ts';
Benefits:
@theme
directive doesn't work from imported packagesSolution: Import the theme CSS directly, not as a JavaScript plugin
Solution: Use @source
directive with correct relative paths to scan UI packages
Solution: Centralize all @source
directives in the theme package using glob patterns
Solution: Use @source not
to exclude test files, config files, and type definitions
The current setup automatically scans all packages matching packages/*/src/**/*.{svelte,js,ts}
.
To add a new UI package:
packages/your-ui-package/
@import '@some-org/tailwind-theme/theme.css';
bg-brand-500
, text-brand-900
, etc.No additional configuration needed!
Issue: Utility classes like bg-brand-500
work directly but UI package components have no styles.
Diagnosis:
# Check if @source directive is present
grep -r "@source" packages/tailwind-theme/src/
# Verify CSS generation
pnpm run build:packages
# Look for your component classes in the generated CSS
Solution: Ensure @source
directive includes your UI package paths.
Issue: Tailwind builds are slow in large monorepos.
Solution: Add exclusions for non-component files:
@source not '../../*/src/**/*.test.{js,ts}';
@source not '../../*/src/**/*.config.{js,ts}';
@source not '../../*/src/**/*.d.ts';
Issue: Some utility classes disappear after production builds.
Common Causes:
bg-${color}-500
won't workSolution: Use complete class names and verify @source coverage.
Key Changes:
tailwind.config.js
with CSS @theme
directive@source
instead of content
arraypnpm run dev:main-app
- Start main applicationpnpm run dev:storybook
- Start Storybookpnpm run build:main-app
- Build main applicationpnpm run build:storybook
- Build Storybookpnpm run build:packages
- Build all packagespnpm run lint
- Lint all packagespnpm run format
- Format all packages