Skip to content

feat(exports): main/client entry points 분리#10

Merged
ywkim merged 5 commits intomainfrom
feat/client-server-entry-separation
Jan 4, 2026
Merged

feat(exports): main/client entry points 분리#10
ywkim merged 5 commits intomainfrom
feat/client-server-entry-separation

Conversation

@ywkim
Copy link
Copy Markdown
Contributor

@ywkim ywkim commented Jan 4, 2026

요약

업계 표준 패턴 적용으로 fancall 패키지 구조를 재설계했습니다. 서버 안전 코드와 클라이언트 전용 코드를 명확히 분리하여 React Server Components(RSC) 환경과 호환성을 개선했습니다.

목적

다음 문제를 해결합니다:

  • 클라이언트 전용 컴포넌트와 서버 안전 코드가 main entry에 혼재되어 서버 컴포넌트에서 import 시 'use client' 지시어 누락으로 인한 런타임 에러 발생 가능
  • 패키지 차원에서 명시적인 서버/클라이언트 경계 미정의로 인한 불명확한 API

주요 변경 사항

📦 Entry Point 분리

Main entry (fancall):

  • 서버 안전 코드만 export
  • LiveRoomRepository (React hooks 없음)
  • TypeScript 타입 및 Zod 스키마
  • i18n 리소스 (JSON + 상수)
  • 'use client' 배너 없음 → 서버에서 직접 사용 가능

Client entry (fancall/client) (NEW):

  • 클라이언트 전용 컴포넌트만 export
  • AgentCall, StartCallSection
  • 'use client' 배너 자동 주입 (vite.config.ts)
  • React hooks 사용 컴포넌트 격리

🗂️ 구조 변경

변경 전 (PR #6) 변경 후 (표준 패턴)
fancall → 클라이언트 + 서버 혼재 fancall → 서버 안전만
fancall/schemas → 타입 일부만 제거 (main으로 통합)
fancall/locale → i18n만 제거 (main으로 통합)
- fancall/client → UI 컴포넌트

🔄 Import 패턴 변경

// Before (PR #6)
import { AgentCall } from "fancall"
import type { LiveRoom } from "fancall/schemas"
import { FANCALL_NS } from "fancall/locale"

// After (표준 패턴)
import { AgentCall } from "fancall/client"  // ← 변경됨
import type { LiveRoom } from "fancall"      // ← 변경됨
import { FANCALL_NS } from "fancall"         // ← 변경됨

🏗️ 기술적 근거

aiolia-core + React RFC #227 패턴 준용:

  • 메인 엔트리: 서버 안전 인프라 (BaseApiService, BaseCrudRepository)
  • 클라이언트 엔트리: 'use client' 지시어 포함 컴포넌트
  • 조건부 banner 주입: vite.config.ts에서 rollupOptions.output.banner로 클라이언트 엔트리에만 'use client' 추가

검증 완료:

✓ dist/client.mjs → "use client"; (첫 줄)
✓ dist/index.mjs → 배너 없음 (서버 안전)
✓ npm run format → 통과
✓ npm run lint:fix → 통과
✓ npm run type-check → 통과
✓ npm run build:lib → 성공

테스트 체크리스트

  • 빌드 성공 (vite build)
  • 타입 검사 통과 (tsc --noEmit)
  • ESLint 검사 통과 (eslint src --fix)
  • Prettier 포매팅 통과
  • dist/client.mjs에 'use client' 배너 확인
  • dist/index.mjs에 배너 없음 확인
  • package.json exports 구조 검증

Breaking Change 영향

라이브러리 사용자는 import 경로를 다음과 같이 업데이트해야 합니다:

사용 목적 Before After
UI 컴포넌트 from "fancall" from "fancall/client"
타입/스키마 from "fancall/schemas" from "fancall"
i18n from "fancall/locale" from "fancall"
Repository from "fancall" from "fancall"

개선 효과

Before (문제)

서버 컴포넌트에서 Repository 사용 시:

// app/[id]/opengraph-image.tsx (서버)
import { CompanionProfileRepository } from "@/repositories"
   @/repositories에서 "fancall/schemas" import
     schemas가 main에 포함되면서 UI 컴포넌트까지 로드
      서버에서 React hooks 포함 코드 실행 위험

After (해결)

// app/[id]/opengraph-image.tsx (서버)
import { CompanionProfileRepository } from "@/repositories"
   @/repositories에서 "fancall" import
     main entry: 서버 안전 코드만 (Repository, 타입)
      UI 컴포넌트 자동 제외

🤖 Generated with Claude Code


ywkim and others added 5 commits January 4, 2026 14:36
클라이언트 전용 컴포넌트를 별도 entry point로 분리:
- AgentCall, StartCallSection을 client.ts에서 export
- React hooks를 사용하는 UI 컴포넌트 격리

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
React hooks(useTranslation)를 사용하므로 클라이언트 전용 마커 필수:
- 서버 컴포넌트에서 직접 import 시 런타임 에러 방지
- React RFC #227 준수

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
BREAKING CHANGE: 클라이언트 컴포넌트 import 경로 변경 필요
- AgentCall, StartCallSection → fancall/client로 이동
- LiveRoomRepository, 타입, 스키마, i18n은 main에 유지

설계 철학 (aioia-core + React RFC #227):
- Main entry: 서버 안전 인프라 (React hooks 없음)
- Client entry: UI 컴포넌트 ('use client' 지시어)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
schemas entry 제거하고 client entry 추가:
- index: 서버 안전 코드 (배너 없음)
- client: 클라이언트 전용 ('use client' 배너 주입)

aioia-core PR #38 패턴 적용:
- rollupOptions.output.banner로 조건부 배너 주입
- dts 플러그인에 client.ts 포함

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
BREAKING CHANGE: Import 경로 변경
- schemas 서브패스 제거 (main으로 통합)
- locale 서브패스 제거 (main으로 통합)
- client 서브패스 추가 (UI 컴포넌트)

Before:
  import { AgentCall } from "fancall"
  import type { LiveRoom } from "fancall/schemas"
  import { FANCALL_NS } from "fancall/locale"

After:
  import { AgentCall } from "fancall/client"
  import type { LiveRoom } from "fancall"
  import { FANCALL_NS } from "fancall"

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This PR introduces significant changes by separating the fancall package's entry points into server-side and client-side, improving compatibility with React Server Components (RSC) environments. The application of industry-standard patterns to clarify the package structure is impressive. In particular, using the banner option in vite.config.ts to dynamically inject the 'use client' directive only into client entry points is a very clean and efficient solution. Overall, this is an excellent refactoring that will greatly enhance code quality. As one suggestion, please consider aligning the export style of the newly added client.ts file with other entry points like index.ts to improve consistency, as detailed in the specific comment.

Comment thread frontend/src/client.ts
@ywkim ywkim merged commit e0c224b into main Jan 4, 2026
3 checks passed
@ywkim ywkim deleted the feat/client-server-entry-separation branch January 4, 2026 06:15
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jan 4, 2026

🎉 This PR is included in version 0.4.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant