I HATE FLYING BUGS logoFE Chapter

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로 변환하고 있습니다.

현재 구조

  1. Multiple codegen configurations:

    • Root codegen.ts - 메인 GraphQL과 Hub GraphQL 처리
    • 각 앱별 개별 codegen.yml 파일들 (lms-web, crm-web, cms-web 등)
  2. near-operation-file-preset 사용:

    preset: 'near-operation-file',
    presetConfig: {
      extension: '.generated.tsx',
      baseTypesPath: '~@mildang/graphql-artifact',
    },
    plugins: ['typescript-operations', 'typescript-react-apollo']
  3. Generated files structure:

    • 각 GraphQL operation 파일 근처에 .generated.tsx 파일 생성
    • 예: useMe.tsuseMe.generated.tsx
  4. Usage pattern:

    import { useUseMeQuery } from './useMe.generated';
    
    const useMe = () => {
      const { data, loading, error } = useUseMeQuery();
      // ...
    };

문제점

  1. 파일 분산: 각 operation마다 생성되는 파일로 인한 프로젝트 구조 복잡성
  2. 중복 타입 정의: 유사한 타입들이 여러 파일에 걸쳐 중복 생성
  3. Import 복잡성: 생성된 파일들의 import path 관리 어려움
  4. Bundle size: 불필요한 Apollo hooks 코드 중복
  5. Type safety: Runtime에서만 확인 가능한 일부 타입 에러들
  6. Development experience: 자동완성과 타입 추론의 한계

Decision

GraphQL Code Generator를 near-operation-file-preset에서 **client-preset**으로 마이그레이션하기로 결정했습니다.

마이그레이션 결정 이유

  1. 코드 구조의 복잡성 해결:

    • 현재 각 GraphQL operation마다 .generated.tsx 파일이 생성되어 프로젝트 전체에 수백 개의 generated 파일이 분산
    • 파일 탐색과 유지보수에 상당한 비용 발생
    • @mildang/graphql 내부 패키지로 중앙화하여 관리 포인트 단일화
  2. 타입 안전성 강화 필요:

    • 현재 runtime에서만 확인 가능한 GraphQL operation 오류들
    • client-preset의 TypedDocumentNode는 컴파일 타임에 스키마 검증 제공
    • IDE에서 GraphQL 쿼리 문법 오류 즉시 감지 가능
  3. 개발 생산성 향상:

    • 현재 generated hooks의 import path 관리 복잡성 (상대 경로 의존)
    • Fragment 재사용 시 복잡한 import 구조
    • @mildang/graphql로 통일된 import로 개발자 경험 개선
  4. 성능 및 번들 크기 최적화:

    • 현재 각 operation별로 중복 생성되는 Apollo hooks 코드
    • Tree-shaking이 제대로 작동하지 않는 구조적 문제
    • client-preset은 필요한 부분만 import하는 구조로 번들 크기 감소
  5. 미래 호환성 확보:

    • near-operation-file-preset은 legacy 방식으로 분류
    • GraphQL Codegen 팀이 client-preset을 현재 권장 방식으로 지정
    • 향후 업데이트와 새로운 기능 지원 보장

새로운 구조

  1. 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: [],
        },
      },
    };
  2. Internal package structure:

    • @mildang/graphql - 새로운 내부 패키지
    • 모든 GraphQL operations와 타입들을 중앙 집중화
    • Fragment 기반 코드 분할
  3. 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

장점

  1. Type Safety: TypedDocumentNode를 통한 컴파일 타임 GraphQL operation 검증
  2. Code Organization: 단일 생성 디렉토리로 파일 구조 단순화 및 import path 일관성
  3. Bundle Size: Tree-shaking 개선 및 중복 코드 제거
  4. Maintenance: GraphQL Codegen의 현재 권장 방식으로 지속적인 지원 보장

단점

  1. Breaking Changes: 모든 기존 GraphQL hooks 사용 코드 수정 필요
  2. Learning Curve: 새로운 패턴 적응을 위한 개발팀 교육 시간 필요

References