Files
2nd/10_Wiki/Topics/Frontend/성능 최적화가 필수적인 대규모 다중 테마 플랫폼.md
Antigravity Agent f8b21af4be Wiki cleanup: error-doc removal, dedup merge, link normalization
10_Wiki/Topics 대규모 정리:
- 오류 캡처/미완성 stub 문서 227개 제거
- 교차폴더 중복 43클러스터 병합 (63파일 → redirect)
- 링크명 정규화: 깨진 링크 수정·redirect 직결·개념 매핑 ~2,400건
- 카테고리 MOC 6개 신규 생성
- Graph 섹션 미해결 related-keyword 링크 10,058건 제거

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 23:52:15 +09:00

239 lines
7.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
id: wiki-2026-0508-성능-최적화가-필수적인-대규모-다중-테마-플랫폼
title: 성능 최적화가 필수적인 대규모 다중 테마 플랫폼
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Multi-theme Platform Performance, White-label SaaS Optimization, CSS Variable Theming]
duplicate_of: none
source_trust_level: A
confidence_score: 0.85
verification_status: applied
tags: [frontend, performance, theming, white-label, css-variables, design-tokens, case-study]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: TypeScript / CSS
framework: Next.js 15, Tailwind CSS v4, Vanilla Extract, Style Dictionary
---
# 성능 최적화가 필수적인 대규모 다중 테마 플랫폼
## 매 한 줄
> **"매 다중 테마 platform — 매 50+ 의 tenant brand 의 동시 serving — 매 CSS 의 cardinality explosion, 매 build size, 매 runtime switching 의 3중 문제"**. 매 naive approach (매 brand 별 separate CSS bundle) 의 매 build time exponential 폭증 + 매 tenant 의 추가 의 redeploy. 매 modern 해결 (2026): CSS custom properties + design token system + runtime theming + edge-cached CSS.
## 매 핵심
### 매 Multi-tenant Theming 의 challenge
- **Build complexity** — 매 brand × variant × feature flag 의 polynomial 의 CSS variant.
- **Bundle size** — 매 tenant 별 CSS 의 ship → 매 cache miss.
- **Runtime switching** — 매 user 의 brand toggle (preview, white-label admin).
- **Style isolation** — 매 tenant A 의 CSS 의 tenant B 의 affect X.
- **Brand consistency** — 매 design token 의 single source of truth.
### 매 Modern Architecture (2026)
1. **Design token JSON** — 매 brand 별 token (color, spacing, typography, radius).
2. **Token build** (Style Dictionary, Tokens Studio) → CSS variables.
3. **Single CSS bundle** — 매 모든 brand 의 fallback variable.
4. **Runtime theme injection** — 매 `<html data-brand="acme">` + 매 brand-specific `:root` block.
5. **Edge caching** — Cloudflare Workers 의 brand-aware CSS serving.
### 매 Performance Pillar
- **CSS variable 의 사용** — 매 brand swap 의 매 reflow 의 X (매 paint 만).
- **Container queries** — 매 component-scoped responsive, 매 tenant layout 의 격리.
- **CSS containment** — 매 brand widget 의 layout boundary.
- **Server-rendered initial brand** — 매 FOUC 의 방지.
## 💻 패턴
### Pattern 1: Design Token → CSS Variables
```json
// tokens/acme.json
{
"color": {
"primary": { "value": "#ff5500" },
"background": { "value": "#ffffff" },
"text": { "value": "#222222" }
},
"radius": { "md": { "value": "8px" } }
}
```
```js
// build/style-dictionary.config.js
module.exports = {
source: ['tokens/**/*.json'],
platforms: {
css: {
transformGroup: 'css',
buildPath: 'dist/css/',
files: [{
destination: 'tokens.css',
format: 'css/variables',
options: { outputReferences: true },
}]
}
}
};
```
```css
/* dist/css/tokens.css (compiled) */
[data-brand="acme"] {
--color-primary: #ff5500;
--color-background: #ffffff;
--radius-md: 8px;
}
[data-brand="globex"] {
--color-primary: #0066ff;
--color-background: #f0f4f8;
--radius-md: 4px;
}
```
### Pattern 2: Runtime Brand Switching (no reflow)
```tsx
// app/providers/BrandProvider.tsx
'use client';
import { useEffect } from 'react';
export function BrandProvider({ brand, children }: { brand: string, children: React.ReactNode }) {
useEffect(() => {
document.documentElement.dataset.brand = brand;
}, [brand]);
return <>{children}</>;
}
```
### Pattern 3: SSR Brand Detection (FOUC 방지)
```tsx
// app/layout.tsx
import { headers } from 'next/headers';
export default async function RootLayout({ children }: { children: React.ReactNode }) {
const host = (await headers()).get('host') ?? '';
const brand = await resolveBrand(host); // acme.example.com → "acme"
return (
<html lang="en" data-brand={brand}>
<body>{children}</body>
</html>
);
}
```
### Pattern 4: Tailwind v4 with CSS Variables (2026)
```css
/* app.css — Tailwind v4 의 native CSS variable */
@import "tailwindcss";
@theme {
--color-primary: var(--color-primary);
--color-bg: var(--color-background);
--radius-md: var(--radius-md);
}
```
```tsx
<button className="bg-primary text-white rounded-md px-4 py-2">
Click me
</button>
```
### Pattern 5: Edge-Cached Brand CSS
```ts
// middleware.ts (Next.js)
import { NextResponse } from 'next/server';
export function middleware(req: Request) {
const host = new URL(req.url).hostname;
const brand = brandMap[host] ?? 'default';
const res = NextResponse.next();
res.headers.set('x-brand', brand);
res.headers.set('Cache-Control', 'public, max-age=3600, s-maxage=86400');
res.headers.set('Vary', 'Host');
return res;
}
```
### Pattern 6: Vanilla Extract (zero-runtime CSS-in-TS)
```ts
// theme.css.ts
import { createGlobalTheme, createThemeContract } from '@vanilla-extract/css';
export const vars = createThemeContract({
color: { primary: null, bg: null },
radius: { md: null },
});
createGlobalTheme('[data-brand="acme"]', vars, {
color: { primary: '#ff5500', bg: '#fff' },
radius: { md: '8px' },
});
```
### Pattern 7: Container Queries 의 격리
```css
.tenant-widget {
container-type: inline-size;
container-name: widget;
}
@container widget (min-width: 600px) {
.card { display: grid; grid-template-columns: 1fr 1fr; }
}
```
### Pattern 8: Critical CSS Extraction
```ts
// 매 SSR 시 매 brand 별 critical CSS 의 inline
import critical from 'critical';
await critical.generate({
base: 'dist/',
src: `index-${brand}.html`,
inline: true,
width: 1300,
height: 900,
});
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| 5+ tenants | Design tokens + CSS variables |
| Runtime preview | `data-brand` attribute swap |
| White-label SaaS | SSR brand resolution + edge cache |
| Tightly-controlled brands | Vanilla Extract / Linaria |
| Marketing sites | Tailwind v4 + token import |
| FOUC prevention | SSR + inline critical CSS |
| Performance budget | Lighthouse CI per brand |
**기본값**: Design tokens (Style Dictionary) → CSS variables → Tailwind v4 utilities → SSR brand attribute → edge-cached.
## 🔗 Graph
- 부모: [[웹 프론트엔드 성능 최적화|Frontend Performance Optimization (FE 성능 최적화)]]
- 변형: [[Theming]]
- 응용: [[유지보수 가능하고 확장 가능한 CSS 아키텍처 설계]] · [[CSS_Architecture_and_Styling|Tailwind CSS]]
- Adjacent: [[Edge Computing]]
## 🤖 LLM 활용
**언제**: 매 token system 의 schema 설계, 매 tenant 추가 시 의 build pipeline 의 review, FOUC 의 troubleshoot.
**언제 X**: 매 brand 의 actual color palette 의 결정 — 매 design 의 영역.
## ❌ 안티패턴
- **Brand 별 separate CSS bundle**: 매 build matrix 폭발, 매 cache miss.
- **JavaScript 의 inline style 의 swap**: 매 매 element 의 매 re-render.
- **CSS-in-JS runtime overhead**: 매 매 component mount 의 style serialization.
- **Token 의 CSS 의 hardcoded duplication**: 매 token 의 single source of truth 의 위반.
- **Brand resolution 의 client-only**: 매 FOUC, 매 layout shift.
## 🧪 검증 / 중복
- Verified (Style Dictionary docs, Tailwind v4 release notes, Vanilla Extract docs, Vercel multi-tenant template 2026).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — design token pipeline, runtime theming, edge caching, FOUC prevention |