clawseal 모노레포에서 새 패키지를 추가하거나 기존 구조를 이해할 때 따라야 하는 규칙들. pnpm workspace, Turborepo 설정, 패키지 네이밍, exports 필드, tsup 빌드 설정, 공유 tsconfig/eslint-config 상속 방법을 다룬다. 새 패키지 scaffolding, 패키지 간 의존성 추가, 빌드 순서 이슈, workspace 구조 질문이 나올 때마다 반드시 이 스킬을 참조한다.
clawseal는 pnpm 모노레포 + Turborepo 기반 프로젝트다. 새 패키지를 추가하거나 기존 구조를 건드릴 때 이 컨벤션을 벗어나면 빌드 순서가 꼬이거나 타입 체크가 누락된다.
.nvmrc 참조). node:sqlite를 외부 플래그 없이 사용하기 위함.corepack enable && corepack prepare [email protected] --activate로 활성화.packageManager 필드는 루트 package.json에 명시돼 있으므로 바꾸지 않는다.pnpm-workspace.yaml 선언:
apps/* → 배포 가능한 애플리케이션 (desktop, web, mcp)
packages/* → 공유 라이브러리 (core, analytics, ui, eslint-config, ...)
packages/ssota-apps/* → 사용자용 앱 플러그인 (wordcard 등)
새 패키지를 어디 넣을지 판단 기준:
apps/packages/packages/ssota-apps/| 종류 | 네이밍 패턴 | 예시 |
|---|---|---|
| 공개 가능 라이브러리 | @ssota/{name} | @ssota/core |
| 워크스페이스 공용 (UI·설정·analytics 등) | @workspace/{name} | @workspace/ui, @workspace/eslint-config, @workspace/typescript-config, @workspace/analytics, @workspace/analytics-mixpanel |
| ssota 앱 | @workspace/ssota-apps-{name} | @workspace/ssota-apps-wordcard |
| 앱 (desktop/web) | clawseal-{name} | clawseal-desktop |
package.json 최소 구조{
"name": "@ssota/my-package",
"version": "0.0.1",
"private": true,
"type": "module",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
},
"scripts": {
"build": "tsup",
"dev": "tsup --watch",
"typecheck": "tsc --noEmit",
"test": "vitest run"
},
"devDependencies": {
"@workspace/typescript-config": "workspace:*",
"tsup": "^8.x",
"typescript": "5.9.3"
}
}
서브패스 export가 필요하면 (예: 브라우저 안전한 부분 분리) exports에 추가:
"./my-client": {
"types": "./dist/my-client.d.ts",
"import": "./dist/my-client.js"
}
tsconfig.json{
"extends": "@workspace/typescript-config/base.json",
"include": ["src"],
"exclude": ["node_modules", "dist"]
}
@workspace/typescript-config/react-library.json@workspace/typescript-config/nextjs.json@workspace/typescript-config/base.jsontsup.config.tsimport { defineConfig } from "tsup"
export default defineConfig({
entry: ["src/index.ts"],
format: ["esm"],
dts: true,
clean: true,
sourcemap: true,
})
서브패스가 있으면 entry에 추가: entry: ["src/index.ts", "src/my-client.ts"]
turbo.json의 핵심 규칙:
"build": { "dependsOn": ["^build"] }
^build는 "내 의존성들이 먼저 빌드돼야 한다"는 의미다.
@ssota/core를 의존하는 패키지를 추가하면 Turbo가 자동으로 순서를 잡아준다.
수동 빌드 순서가 필요할 때 (targeted build):
pnpm --filter @ssota/core build
pnpm --filter @workspace/analytics build
pnpm --filter clawseal-desktop build
전체 빌드:
pnpm run build # turbo build
테스트/린트/타입체크 실행:
pnpm run test # turbo test (전체)
pnpm run typecheck # turbo typecheck
pnpm --filter web lint # 린트는 패키지별로 실행 (turbo lint는 일부 패키지에서 불안정)
새 패키지에서 ESLint 설정을 상속할 때:
// packages/my-lib/eslint.config.js
import { config } from "@workspace/eslint-config/react-internal"
export default config
@workspace/eslint-config/next-js의 nextJsConfig@workspace/eslint-config/react-internal의 config@workspace/eslint-config/base의 configpackage.json, tsconfig.json, tsup.config.ts, vitest.config.ts워크스페이스 내 패키지를 의존성으로 추가할 때는 workspace:*를 사용한다:
pnpm --filter @ssota/my-package add @ssota/core@workspace:*
workspace:*는 "현재 워크스페이스의 최신 버전"을 의미하며,
빌드 전에 반드시 의존 패키지가 빌드돼 있어야 dist/의 타입과 코드를 읽을 수 있다.