ADR 3: Migrate GraphQL Codegen from near-operation-file-preset to client-preset
우리 프로젝트는 현재 GraphQL Code Generator의 `near-operation-file-preset`을 사용하여 GraphQL operations를 TypeScript 타입과 Apollo React hooks로 변환하고 있습니다.
Date: 2025-07-25
Status
Proposed
Context
우리 프로젝트는 현재 GraphQL Code Generator의 near-operation-file-preset을 사용하여 GraphQL operations를 TypeScript 타입과 Apollo React hooks로 변환하고 있습니다.
현재 구조
-
Multiple codegen configurations:
- Root
codegen.ts- 메인 GraphQL과 Hub GraphQL 처리 - 각 앱별 개별
codegen.yml파일들 (lms-web, crm-web, cms-web 등)
- Root
-
near-operation-file-preset 사용:
preset: 'near-operation-file', presetConfig: { extension: '.generated.tsx', baseTypesPath: '~@mildang/graphql-artifact', }, plugins: ['typescript-operations', 'typescript-react-apollo'] -
Generated files structure:
- 각 GraphQL operation 파일 근처에
.generated.tsx파일 생성 - 예:
useMe.ts→useMe.generated.tsx
- 각 GraphQL operation 파일 근처에
-
Usage pattern:
import { useUseMeQuery } from './useMe.generated'; const useMe = () => { const { data, loading, error } = useUseMeQuery(); // ... };
문제점
- 파일 분산: 각 operation마다 생성되는 파일로 인한 프로젝트 구조 복잡성
- 중복 타입 정의: 유사한 타입들이 여러 파일에 걸쳐 중복 생성
- Import 복잡성: 생성된 파일들의 import path 관리 어려움
- Bundle size: 불필요한 Apollo hooks 코드 중복
- Type safety: Runtime에서만 확인 가능한 일부 타입 에러들
- Development experience: 자동완성과 타입 추론의 한계
Decision
GraphQL Code Generator를 near-operation-file-preset에서 **client-preset**으로 마이그레이션하기로 결정했습니다.
마이그레이션 결정 이유
-
코드 구조의 복잡성 해결:
- 현재 각 GraphQL operation마다
.generated.tsx파일이 생성되어 프로젝트 전체에 수백 개의 generated 파일이 분산 - 파일 탐색과 유지보수에 상당한 비용 발생
@mildang/graphql내부 패키지로 중앙화하여 관리 포인트 단일화
- 현재 각 GraphQL operation마다
-
타입 안전성 강화 필요:
- 현재 runtime에서만 확인 가능한 GraphQL operation 오류들
client-preset의 TypedDocumentNode는 컴파일 타임에 스키마 검증 제공- IDE에서 GraphQL 쿼리 문법 오류 즉시 감지 가능
-
개발 생산성 향상:
- 현재 generated hooks의 import path 관리 복잡성 (상대 경로 의존)
- Fragment 재사용 시 복잡한 import 구조
@mildang/graphql로 통일된 import로 개발자 경험 개선
-
성능 및 번들 크기 최적화:
- 현재 각 operation별로 중복 생성되는 Apollo hooks 코드
- Tree-shaking이 제대로 작동하지 않는 구조적 문제
client-preset은 필요한 부분만 import하는 구조로 번들 크기 감소
-
미래 호환성 확보:
near-operation-file-preset은 legacy 방식으로 분류- GraphQL Codegen 팀이
client-preset을 현재 권장 방식으로 지정 - 향후 업데이트와 새로운 기능 지원 보장
새로운 구조
-
Unified codegen configuration:
import type { CodegenConfig } from '@graphql-codegen/cli'; const config: CodegenConfig = { schema: 'schema.json', documents: ['src/**/*.{ts,tsx}'], generates: { 'packages/graphql/src/': { preset: 'client', plugins: [], }, }, }; -
Internal package structure:
@mildang/graphql- 새로운 내부 패키지- 모든 GraphQL operations와 타입들을 중앙 집중화
- Fragment 기반 코드 분할
-
New usage pattern:
import { useQuery } from '@apollo/client'; import { graphql } from '@mildang/graphql'; const GET_ME_QUERY = graphql(/* GraphQL */ ` query GetMe { me { id name } } `); const useMe = () => { const { data, loading, error } = useQuery(GET_ME_QUERY); // TypeScript가 자동으로 타입 추론 };
Consequences
장점
- Type Safety: TypedDocumentNode를 통한 컴파일 타임 GraphQL operation 검증
- Code Organization: 단일 생성 디렉토리로 파일 구조 단순화 및 import path 일관성
- Bundle Size: Tree-shaking 개선 및 중복 코드 제거
- Maintenance: GraphQL Codegen의 현재 권장 방식으로 지속적인 지원 보장
단점
- Breaking Changes: 모든 기존 GraphQL hooks 사용 코드 수정 필요
- Learning Curve: 새로운 패턴 적응을 위한 개발팀 교육 시간 필요