用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/puk0806/gugbab-claude --skill bundling-compiler命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
DDD(Domain-Driven Design) 아키텍처 핵심 패턴 - 유비쿼터스 언어, 서브도메인, 바운디드 컨텍스트, Aggregate, Entity/VO, 도메인 서비스/이벤트, 레이어드 아키텍처
대규모 React/Next.js 프로젝트를 layer-first(types/·utils/·hooks/·api/·components/ 밑에 도메인이 반복되는 구조)에서 domain-first(feature/도메인 우선) 구조로 전환하는 설계 기준과 절차. Feature-Sliced Design 2.1 정본(layers 6종·slices·segments·import 규칙·@x 크로스임포트·public API), FSD를 쓰지 않는 경량 대안(features + shared 2~3계층 + ESLint import/no-restricted-paths), Next.js App Router 공존 전략(route group `()`·private folder `_`·colocation), Turborepo/Nx 모노레포에서 폴더↔패키지 승격 기준, colocation과 배럴 파일 성능 트레이드오프, 도메인 경계 역추출(import 그래프·change coupling·용어 클러스터), 전환 실패 패턴(shared 비대화·entities 남용·순환 의존·도메인=라우트 착각·조기 추상화). 도메인 개념 자체(바운디드 컨텍스트·유비쿼터스 언어)는 `architecture/ddd` 스킬을 참조한다.
소스 파일 수천 개 규모 프론트엔드 코드베이스를 멈추지 않고 점진 재구조화하는 실행 전략 - Strangler Fig / Branch by Abstraction / Parallel Change, ts-morph·jscodeshift codemod, PR 분할·검증 게이트·되돌리기, 테스트 없는 코드의 안전망, 작업 순서 설계와 위반 수 기반 진행 추적
| name | bundling-compiler |
| description | tsup/Vite/Turbopack 번들러 선택 기준, React Compiler, Tree Shaking, 코드 스플리팅 패턴 |
| disable-model-invocation | true |
소스: https://tsup.egoist.dev | https://vitejs.dev | https://nextjs.org/docs | https://react.dev/learn/react-compiler 검증일: 2026-06-20
프로젝트 타입?
├─ 라이브러리 (npm 배포용)
│ └─ 단순 TS/JS → tsup (추천)
│
└─ 애플리케이션
├─ Next.js → Turbopack (내장, 기본값)
└─ SPA/기타 → Vite
| 도구 | 용도 | Dev 속도 | 설정 복잡도 |
|---|---|---|---|
| tsup | 라이브러리 빌드 | - | ⭐ 매우 간단 |
| Vite | SPA 앱 | ⭐⭐⭐ 빠름 | ⭐⭐ |
| Turbopack | Next.js 앱 | ⭐⭐⭐⭐ 매우 빠름 | ⭐⭐ (내장) |
// tsup.config.ts
import { defineConfig } from 'tsup'
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'], // ESM + CommonJS 동시 빌드
dts: true, // TypeScript 선언 파일 생성
clean: true, // 빌드 전 dist/ 정리
sourcemap: true,
splitting: false, // 라이브러리는 대개 false
treeshake: true,
})
export default defineConfig({
entry: {
index: 'src/index.ts',
utils: 'src/utils/index.ts',
types: 'src/types/index.ts',
},
format: ['esm', 'cjs'],
dts: true,
outExtension({ format }) {
return { js: format === 'esm' ? '.mjs' : '.cjs' }
},
})
{
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
},
"./utils": {
"types": "./dist/utils.d.ts",
"import": "./dist/utils.mjs",
"require": "./dist/utils.cjs"
}
},
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"sideEffects": false
}
// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
import path from 'path'
export default defineConfig({
plugins: [react()],
resolve: {
alias: { '@': path.resolve(__dirname, './src') }
},
build: {
outDir: 'dist',
sourcemap: true,
},
server: {
port: 3000,
}
})
export default defineConfig({
build: {
lib: {
entry: 'src/index.ts',
name: 'MyLibrary',
formats: ['es', 'cjs'],
fileName: (format) => `my-library.${format}.js`
},
rollupOptions: {
external: ['react', 'react-dom'], // peer deps 제외
output: {
globals: { react: 'React', 'react-dom': 'ReactDOM' }
}
}
}
})
// next.config.js - Next.js 16+에서는 기본값
/** @type {import('next').NextConfig} */
const nextConfig = {}
export default nextConfig
// Next.js 15: CLI 플래그로 활성화 (next dev --turbopack)
// Next.js 16+: 기본값. 커스터마이징만 turbopack 키 사용
const nextConfig = {
turbopack: {
// resolveAlias, rules 등 커스터마이징 시에만 설정
},
}
| 항목 | Webpack | Turbopack |
|---|---|---|
| 언어 | JavaScript | Rust |
| Dev 시작 | 느림 | 매우 빠름 |
| HMR | 느림 | 거의 즉각 |
| 플러그인 호환 | 전체 | 제한적 (재구현 필요) |
| 프로덕션 빌드 | 안정 | Next.js 16에서 안정화 (기본값) |
Turbopack 제약: 일부 Webpack 플러그인 미지원 → 대안 확인 필요
v1.0 안정화: 2025년 10월 | 출처: https://react.dev/learn/react-compiler
// Next.js 15+ (reactCompiler는 top-level 옵션, experimental 아님)
const nextConfig = {
reactCompiler: true,
}
// Vite (@vitejs/plugin-react v5 이하)
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [
react({
babel: {
plugins: ['babel-plugin-react-compiler'],
},
}),
],
})
// Vite 8+ (@vitejs/plugin-react v6 — babel 옵션 제거됨, @rolldown/plugin-babel 사용)
import react, { reactCompilerPreset } from '@vitejs/plugin-react'
import babel from '@rolldown/plugin-babel'
export default defineConfig({
plugins: [react(), babel(reactCompilerPreset())],
})
// ❌ React Compiler 없이: 수동 최적화 필요
const sortedItems = useMemo(
() => items.sort((a, b) => a.name.localeCompare(b.name)),
[items]
)
const handleClick = useCallback(() => onSelect(id), [onSelect, id])
const MemoizedComponent = memo(MyComponent)
// ✅ React Compiler 활성화 시: 자동 처리됨 (수동 최적화 제거 가능)
const sortedItems = items.sort((a, b) => a.name.localeCompare(b.name))
const handleClick = () => onSelect(id)
// memo 제거 가능
// ❌ Rules of React 위반 시 컴파일러가 해당 컴포넌트 최적화 건너뜀
function BadComponent() {
// 조건부 Hook 호출 (규칙 위반)
if (someCondition) {
const [state, setState] = useState(0) // ❌
}
}
// ✅ 올바른 패턴 (컴파일러가 최적화 가능)
function GoodComponent({ condition }: { condition: boolean }) {
const [state, setState] = useState(0)
return condition ? <div>{state}</div> : null
}
// next.config.js
import { createVanillaExtractPlugin } from '@vanilla-extract/next-plugin'
const withVanillaExtract = createVanillaExtractPlugin()
export default withVanillaExtract({
// 다른 Next.js 설정
})
// styles.css.ts
import { style, styleVariants } from '@vanilla-extract/css'
export const base = style({
display: 'flex',
padding: '12px',
})
export const variants = styleVariants({
primary: { backgroundColor: 'blue', color: 'white' },
secondary: { backgroundColor: 'gray', color: 'black' },
})
// 컴포넌트에서 사용
import { base, variants } from './styles.css'
function Button({ variant = 'primary' }: { variant: keyof typeof variants }) {
return <button className={`${base} ${variants[variant]}`}>Click</button>
}
특징: 빌드 타임에 static CSS 생성 → 런타임 오버헤드 없음
주의 (2026-08-26 갱신): vanilla-extract의 Turbopack 지원은 Next.js 16.x 이상에서만 제공되며(
@vanilla-extract/next-plugin2.5.0+), 기본값이 꺼져 있어createVanillaExtractPlugin({ unstable_turbopack: { mode: 'auto' } })처럼 명시해야 켜진다. 공식 문서는 "experimental — non-major 버전에서도 breaking change 가능"으로 경고한다. Next.js 15.x 이하는 Webpack만 지원. 상세는frontend/vanilla-extract스킬 참조.
// package.json: 부수 효과 없음을 번들러에 알림
{
"sideEffects": false
}
// CSS가 있는 경우
{
"sideEffects": ["**/*.css", "./src/polyfills.ts"]
}
// ✅ ESM: Tree Shaking 가능
export function add(a: number, b: number) { return a + b }
export function subtract(a: number, b: number) { return a - b }
// 사용 측에서 add만 import → subtract는 번들에서 제거됨
import { add } from '@myorg/utils'
// ❌ CJS: Tree Shaking 불가
module.exports = { add, subtract }
// → 전체가 번들에 포함됨
// ❌ 배럴 파일이 tree shaking을 방해하는 경우
// index.ts
export * from './heavy-module' // side effect가 있으면 전체 포함
// ✅ named export 명시
export { HeavyComponent } from './heavy-module'
// 또는 직접 경로로 import
import { HeavyComponent } from '@myorg/ui/heavy-module'
import { lazy, Suspense } from 'react'
// 라우트 기반 스플리팅
const Dashboard = lazy(() => import('./pages/Dashboard'))
const Settings = lazy(() => import('./pages/Settings'))
function App() {
return (
<Suspense fallback={<PageSkeleton />}>
<Routes>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/settings" element={<Settings />} />
</Routes>
</Suspense>
)
}
import dynamic from 'next/dynamic'
// SSR 비활성화 (브라우저 전용 컴포넌트)
const Chart = dynamic(() => import('../components/Chart'), {
ssr: false,
loading: () => <ChartSkeleton />,
})
// 조건부 로드
const PDFViewer = dynamic(() => import('../components/PDFViewer'))
라우트 단위 스플리팅: 필수 (페이지별 독립 청크)
컴포넌트 단위 스플리팅: 선택적 (무거운 컴포넌트만)
라이브러리 단위 스플리팅: 자동 (번들러가 처리)
❌ 피해야 할 것: 너무 잘게 쪼개기 (HTTP 요청 오버헤드)
✅ 기준: 30KB 이상인 컴포넌트 또는 특정 조건에서만 사용하는 컴포넌트