توسيع Tailwind عبر مستودعات Monorepo
شارك ملف tailwind.config.js واحدًا بين حزم متعددة في مستودع Monorepo، واستخدم الإعدادات المسبقة للرموز المشتركة، وأدر الإضافات الخاصة بكل مساحة عمل.
توسيع Tailwind عبر مستودعات Monorepo درس مجاني في Tailwind CSS Academy على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Tailwind CSS Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Tailwind CSS Academy 4 دروس في المجموع.
بعض أجزاء هذا الدرس لم تُترجم بعد وتظهر باللغة الإنجليزية.
Monorepo Basics for Tailwind
A monorepo is a single repository containing multiple packages or applications, managed with tools like Turborepo, Nx, or pnpm workspaces. When multiple apps in a monorepo use Tailwind, sharing configuration becomes important. Without sharing, each app duplicates color tokens, fonts, and plugin configurations — diverging gradually until the UI is inconsistent across products.
monorepo/
├── apps/
│ ├── web/ # Next.js marketing site
│ └── dashboard/ # React admin app
├── packages/
│ ├── ui/ # Shared component library
│ └── tailwind-config/ # ← Shared Tailwind config
├── package.json # Workspace root
└── turbo.jsonCreating a Shared Config Package
Extract the Tailwind configuration into a dedicated package, typically called @repo/tailwind-config or @acme/tailwind-config. This package exports a base configuration object that each consuming app imports and extends. The shared package lives in packages/tailwind-config/ with its own package.json marking it as an internal dependency.
// packages/tailwind-config/package.json
{
"name": "@acme/tailwind-config",
"version": "0.0.1",
"private": true,
"main": "./tailwind.config.js",
"devDependencies": {
"tailwindcss": "^3.4.0"
}
}
// packages/tailwind-config/tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
theme: {
extend: {
colors: {
brand: { 500: '#3b82f6', 900: '#1e3a8a' },
},
},
},
plugins: [],
};Consuming the Shared Config
Each app imports the shared config using require and spreads or merges it with app-specific overrides. The app's tailwind.config.js adds its own content paths (since content paths are always app-specific) and any extensions unique to that application. The shared config handles all common theme tokens and plugins.
// apps/web/tailwind.config.js
const sharedConfig = require('@acme/tailwind-config');
/** @type {import('tailwindcss').Config} */
module.exports = {
// Merge shared config
...sharedConfig,
// App-specific content paths (NEVER shared — paths differ per app)
content: [
'./src/**/*.{js,ts,jsx,tsx}',
'./public/**/*.html',
],
theme: {
...sharedConfig.theme,
extend: {
...sharedConfig.theme.extend,
// App-specific extensions
backgroundImage: {
'hero-gradient': 'linear-gradient(to bottom, #eff6ff, #ffffff)',
},
},
},
};Using Tailwind Presets
Tailwind's preset system is the officially supported mechanism for sharing configs. A preset is an object passed to the presets array in the consuming config. Unlike spreading the config object, presets are merged intelligently by Tailwind — theme extensions are deep-merged, plugins are concatenated, and content arrays are combined without manual spreading.
// packages/tailwind-config/tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
theme: {
extend: {
colors: { brand: { 500: '#3b82f6' } },
},
},
plugins: [require('@tailwindcss/forms')],
};
// apps/dashboard/tailwind.config.js
module.exports = {
presets: [require('@acme/tailwind-config')], // ← official preset
content: ['./src/**/*.{js,ts,jsx,tsx}'],
theme: {
extend: {
// Deep-merged with preset's theme.extend automatically
spacing: { 18: '4.5rem' },
},
},
};Shared UI Package Content Paths
A critical monorepo pitfall: if you have a shared packages/ui component library that exports Tailwind-classed components, the consuming app must include that package's files in its content array. Otherwise the JIT engine does not scan the shared components, and the classes used there get purged from the production build.
// apps/web/tailwind.config.js
module.exports = {
presets: [require('@acme/tailwind-config')],
content: [
// App's own files
'./src/**/*.{js,ts,jsx,tsx}',
// ⬇ CRITICAL: include shared UI package files
'../../packages/ui/src/**/*.{js,ts,jsx,tsx}',
],
};Workspace Dependencies Setup
In a pnpm or npm workspace monorepo, add the shared config package as a dev dependency using the workspace protocol. This creates a symlink to the local package without publishing it to npm. The consuming app's package.json lists @acme/tailwind-config: workspace:* and the build tools resolve it to the local package automatically.
// apps/web/package.json
{
"name": "web",
"devDependencies": {
"@acme/tailwind-config": "workspace:*",
"tailwindcss": "^3.4.0"
}
}
// Install all workspace packages from the monorepo root:
pnpm install
# or
npm install --workspacesTurborepo Caching for Tailwind Builds
In a Turborepo monorepo, configure the turbo.json pipeline to cache Tailwind build outputs. Because the shared config is a dependency of each app's build, changes to packages/tailwind-config correctly invalidate the build cache for all consuming apps. This prevents stale cached CSS from shipping when the design system updates.
// turbo.json
{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "dist/**", "!.next/cache/**"]
},
"type-check": {
"dependsOn": ["^build"]
}
}
}
# Build only what has changed since last run:
npx turbo build
# Turbo caches CSS output and invalidates when tailwind-config changesHandling Content Path Differences
Content paths are the one configuration that cannot be shared — they must be local to each app. Different apps have different directory structures. Avoid temptation to put content paths in the shared config; doing so would either miss files or scan too broadly. The shared config should export only theme, plugins, and presets. Content is always defined locally in each consuming app's config.
// packages/tailwind-config/tailwind.config.js
// ⚠ DO NOT include content paths here
module.exports = {
// content: [] ← Leave this OUT of the shared config
theme: {
extend: { colors: { brand: { 500: '#3b82f6' } } },
},
plugins: [],
};
// Each app defines its own content:
// apps/web: './src/**/*.{js,ts,jsx,tsx}'
// apps/dashboard: './pages/**/*.tsx', './components/**/*.tsx'Versioning the Shared Config
Even though the shared config package is private (never published to npm), treat it with version discipline. Bump its version in package.json on every breaking change — removing a color, renaming a token, removing a plugin. Consumers of the preset can then pin to a version and upgrade deliberately rather than having breaking changes silently propagate to all apps at once.
// packages/tailwind-config/package.json
{
"name": "@acme/tailwind-config",
"version": "1.3.0", // ← bump on breaking changes
"private": true,
"main": "./tailwind.config.js"
}
// apps/dashboard/package.json — pin to a specific version
{
"devDependencies": {
"@acme/tailwind-config": "workspace:^1.2.0" // pin minor version
}
}Testing Shared Config Changes
Before merging changes to the shared Tailwind config, run a visual regression test on all consuming apps. A change to a brand color or a removed spacing value affects every app simultaneously. Build all apps in CI (turbo build) and run screenshot comparison on key pages. Treat config changes as cross-app breaking changes and communicate them in changelogs.
# Run all affected builds when tailwind-config changes
npx turbo build --filter='...[origin/main]'
# Turborepo detects which apps depend on the changed package
# and builds only those apps
# Run visual regression on changed apps:
npx playwright test --project=web
npx playwright test --project=dashboardStorybook Integration in Monorepos
If you use Storybook in the shared UI package to document components, configure Storybook to use the same shared Tailwind preset. Add the Storybook Tailwind addon (@storybook/addon-styling-webpack or framework equivalent) and point it to the shared config. This ensures components render in Storybook with the same tokens they use in the apps.
// packages/ui/.storybook/main.js
module.exports = {
addons: ['@storybook/addon-styling-webpack'],
framework: '@storybook/react-webpack5',
};
// packages/ui/.storybook/preview.js
import '../src/styles/globals.css'; // imports Tailwind
// packages/ui/tailwind.config.js
module.exports = {
presets: [require('@acme/tailwind-config')],
content: ['./src/**/*.{js,ts,jsx,tsx}'],
};Quick Check
Test your understanding of Tailwind CSS Mastery concepts from this lesson.
Lesson Recap
In this lesson you learned: creating a shared Tailwind config package using the official preset system for intelligent deep-merging, including shared UI package files in content paths to prevent class purging, and treating config changes as cross-app breaking changes with versioning and visual regression tests. Next up we plan a complete Tailwind design system for the capstone project.
تعلم HTML مع معلم ذكاء اصطناعي — مجانًا
اكتب وقم بتشغيل أكوادك الفعلية في المتصفح، واحصل على مساعدة فورية من معلم ذكاء اصطناعي متاح 24/7، واستمر من حيث توقفت على الويب أو في التطبيق.
- الدورات
- 30
- الدروس
- 120
الأسئلة الشائعة
هل درس «توسيع Tailwind عبر مستودعات Monorepo» مجاني؟
نعم — نص درس «توسيع Tailwind عبر مستودعات Monorepo» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Tailwind CSS Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Tailwind CSS Academy 4 دروس في المجموع.
ماذا ستتعلم في «توسيع Tailwind عبر مستودعات Monorepo»؟
شارك ملف tailwind.config.js واحدًا بين حزم متعددة في مستودع Monorepo، واستخدم الإعدادات المسبقة للرموز المشتركة، وأدر الإضافات الخاصة بكل مساحة عمل. تتمرن على Tailwind CSS Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Tailwind CSS Academy؟
لا تُشترط خبرة سابقة. Tailwind CSS Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.
كم من الوقت يستغرق درس «توسيع Tailwind عبر مستودعات Monorepo»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Tailwind CSS Academy هذا؟
نعم. كل درس في Tailwind CSS Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- تنظيم الملفات والمجلدات
- التعايش مع CSS القديم
- وحدات CSS وTailwind
- توسيع Tailwind عبر مستودعات Monorepo