React Compiler/Incremental Adoption

김동현·2026년 3월 16일

title: 점진적 도입

React Compiler는 점진적으로 도입할 수 있어서, 코드베이스의 특정 부분에서 먼저 사용해볼 수 있어요. 이 가이드에서는 기존 프로젝트에서 컴파일러를 점진적으로 적용하는 방법을 알려드릴게요.
  • 왜 점진적 도입이 권장되는지
  • 디렉토리 기반 도입을 위한 Babel overrides 사용하기
  • 컴파일 옵트인을 위한 "use memo" 지시어 사용하기
  • 컴포넌트를 제외하기 위한 "use no memo" 지시어 사용하기
  • 게이팅을 통한 런타임 기능 플래그
  • 도입 진행 상황 모니터링하기

왜 점진적 도입인가요? {/why-incremental-adoption/}

React Compiler는 여러분의 전체 코드베이스를 자동으로 최적화하도록 설계되었지만, 한 번에 모든 곳에 적용할 필요는 없어요. 점진적 도입은 롤아웃 과정에 대한 제어권을 주어서, 나머지 부분으로 확장하기 전에 앱의 작은 부분에서 컴파일러를 테스트할 수 있게 해줘요.

작은 곳에서 시작하면 컴파일러의 최적화에 대한 신뢰를 쌓는 데 도움이 돼요. 컴파일된 코드로 앱이 올바르게 동작하는지 확인하고, 성능 개선을 측정하고, 여러분의 코드베이스에 특화된 엣지 케이스를 식별할 수 있어요. 이 접근 방식은 안정성이 중요한 프로덕션 애플리케이션에서 특히 유용해요.

점진적 도입은 컴파일러가 찾을 수 있는 React 규칙 위반을 해결하기도 더 쉽게 만들어줘요. 전체 코드베이스의 위반을 한 번에 수정하는 대신, 컴파일러 적용 범위를 넓혀가면서 체계적으로 해결할 수 있어요. 이렇게 하면 마이그레이션이 관리하기 쉬워지고 버그가 발생할 위험을 줄일 수 있어요.

어떤 부분의 코드가 컴파일되는지 제어함으로써, 컴파일러 최적화의 실제 영향을 측정하기 위한 A/B 테스트도 실행할 수 있어요. 이 데이터는 전체 도입에 대한 정보에 기반한 결정을 내리는 데 도움이 되고, 팀에게 그 가치를 보여줄 수 있어요.

점진적 도입 접근 방식 {/approaches-to-incremental-adoption/}

React Compiler를 점진적으로 도입하는 세 가지 주요 접근 방식이 있어요:

  1. Babel overrides - 특정 디렉토리에 컴파일러를 적용해요
  2. "use memo"로 옵트인 - 명시적으로 옵트인한 컴포넌트만 컴파일해요
  3. 런타임 게이팅 - 기능 플래그로 컴파일을 제어해요

모든 접근 방식은 전체 롤아웃 전에 애플리케이션의 특정 부분에서 컴파일러를 테스트할 수 있게 해줘요.

Babel Overrides를 사용한 디렉토리 기반 도입 {/directory-based-adoption/}

Babel의 overrides 옵션을 사용하면 코드베이스의 다른 부분에 다른 플러그인을 적용할 수 있어요. 이건 디렉토리별로 React Compiler를 점진적으로 도입하는 데 이상적이에요.

기본 설정 {/basic-configuration/}

특정 디렉토리에 컴파일러를 적용하는 것부터 시작하세요:

// babel.config.js
module.exports = {
  plugins: [
    // 모든 파일에 적용되는 전역 플러그인
  ],
  overrides: [
    {
      test: './src/modern/**/*.{js,jsx,ts,tsx}',
      plugins: [
        'babel-plugin-react-compiler'
      ]
    }
  ]
};

(여기서 test 필드는 어떤 파일들에 이 설정을 적용할지 결정하는 패턴이에요. ./src/modern/ 폴더 아래의 모든 JS, JSX, TS, TSX 파일에 컴파일러가 적용되는 거죠.)

적용 범위 확장하기 {/expanding-coverage/}

자신감이 생기면, 더 많은 디렉토리를 추가하세요:

// babel.config.js
module.exports = {
  plugins: [
    // 전역 플러그인
  ],
  overrides: [
    {
      test: ['./src/modern/**/*.{js,jsx,ts,tsx}', './src/features/**/*.{js,jsx,ts,tsx}'],
      plugins: [
        'babel-plugin-react-compiler'
      ]
    },
    {
      test: './src/legacy/**/*.{js,jsx,ts,tsx}',
      plugins: [
        // 레거시 코드를 위한 다른 플러그인
      ]
    }
  ]
};

(이렇게 하면 modernfeatures 폴더에는 React Compiler를 적용하고, legacy 폴더에는 다른 설정을 적용할 수 있어요. 기존의 오래된 코드는 천천히 마이그레이션하면서 새로운 코드부터 컴파일러의 혜택을 받을 수 있는 거죠.)

컴파일러 옵션과 함께 사용하기 {/with-compiler-options/}

override마다 컴파일러 옵션도 설정할 수 있어요:

// babel.config.js
module.exports = {
  plugins: [],
  overrides: [
    {
      test: './src/experimental/**/*.{js,jsx,ts,tsx}',
      plugins: [
        ['babel-plugin-react-compiler', {
          // 옵션들 ...
        }]
      ]
    },
    {
      test: './src/production/**/*.{js,jsx,ts,tsx}',
      plugins: [
        ['babel-plugin-react-compiler', {
          // 옵션들 ...
        }]
      ]
    }
  ]
};

(실험적인 코드와 프로덕션 코드에 다른 컴파일러 옵션을 적용할 수 있어요. 예를 들어, 실험적인 폴더에서는 더 공격적인 최적화를 시도하고, 프로덕션에서는 더 보수적인 설정을 사용할 수 있죠.)

"use memo"를 사용한 옵트인 모드 {/opt-in-mode-with-use-memo/}

최대한의 제어를 원한다면, compilationMode: 'annotation'을 사용해서 "use memo" 지시어로 명시적으로 옵트인한 컴포넌트와 훅만 컴파일할 수 있어요.

이 접근 방식은 개별 컴포넌트와 훅에 대한 세밀한 제어를 제공해요. 전체 디렉토리에 영향을 주지 않고 특정 컴포넌트에서 컴파일러를 테스트하고 싶을 때 유용해요.

어노테이션 모드 설정 {/annotation-mode-configuration/}

// babel.config.js
module.exports = {
  plugins: [
    ['babel-plugin-react-compiler', {
      compilationMode: 'annotation',
    }],
  ],
};

지시어 사용하기 {/using-the-directive/}

컴파일하고 싶은 함수의 시작 부분에 "use memo"를 추가하세요:

function TodoList({ todos }) {
  "use memo"; // 이 컴포넌트를 컴파일 대상으로 옵트인

  const sortedTodos = todos.slice().sort();

  return (
    <ul>
      {sortedTodos.map(todo => (
        <TodoItem key={todo.id} todo={todo} />
      ))}
    </ul>
  );
}

function useSortedData(data) {
  "use memo"; // 이 훅을 컴파일 대상으로 옵트인

  return data.slice().sort();
}

(지시어(directive)라는 건 함수 본문의 맨 첫 줄에 문자열 리터럴을 넣는 방식이에요. "use strict"와 비슷한 방식이죠. React Compiler는 이 지시어를 보고 해당 함수를 컴파일 대상으로 인식해요.)

compilationMode: 'annotation'을 사용할 때는 다음을 해야 해요:

  • 최적화하고 싶은 모든 컴포넌트에 "use memo" 추가하기
  • 모든 커스텀 훅에 "use memo" 추가하기
  • 새로운 컴포넌트에도 추가하는 것 기억하기

이렇게 하면 컴파일러의 영향을 평가하는 동안 어떤 컴포넌트가 컴파일되는지 정밀하게 제어할 수 있어요.

게이팅을 통한 런타임 기능 플래그 {/runtime-feature-flags-with-gating/}

gating 옵션을 사용하면 기능 플래그를 사용해서 런타임에 컴파일을 제어할 수 있어요. 이건 A/B 테스트를 실행하거나 사용자 세그먼트에 따라 컴파일러를 점진적으로 롤아웃할 때 유용해요.

게이팅 작동 방식 {/how-gating-works/}

컴파일러는 최적화된 코드를 런타임 체크로 감싸요. 게이트가 true를 반환하면 최적화된 버전이 실행돼요. 그렇지 않으면 원본 코드가 실행돼요.

(쉽게 말해서, 컴파일된 코드와 원본 코드를 둘 다 가지고 있다가 런타임에 어떤 걸 사용할지 결정하는 거예요. 이렇게 하면 문제가 생겼을 때 기능 플래그만 끄면 바로 원본 코드로 돌아갈 수 있어서 안전해요.)

게이팅 설정 {/gating-configuration/}

// babel.config.js
module.exports = {
  plugins: [
    ['babel-plugin-react-compiler', {
      gating: {
        source: 'ReactCompilerFeatureFlags',
        importSpecifierName: 'isCompilerEnabled',
      },
    }],
  ],
};

기능 플래그 구현하기 {/implementing-the-feature-flag/}

게이팅 함수를 내보내는 모듈을 만드세요:

// ReactCompilerFeatureFlags.js
export function isCompilerEnabled() {
  // 여러분의 기능 플래그 시스템을 사용하세요
  return getFeatureFlag('react-compiler-enabled');
}

(여기서 getFeatureFlag는 여러분이 사용하는 기능 플래그 시스템이에요. LaunchDarkly, Split, 자체 구축한 시스템 등 어떤 것이든 사용할 수 있어요. 이 함수가 true를 반환하면 컴파일된 코드가 실행되고, false를 반환하면 원본 코드가 실행되는 거예요.)

도입 문제 해결 {/troubleshooting-adoption/}

도입 중에 문제가 발생하면:

  1. 문제가 있는 컴포넌트를 일시적으로 제외하기 위해 "use no memo"를 사용하세요
  2. 일반적인 문제에 대한 디버깅 가이드를 확인하세요
  3. ESLint 플러그인이 식별한 React 규칙 위반을 수정하세요
  4. 더 점진적인 도입을 위해 compilationMode: 'annotation' 사용을 고려하세요

(특히 "use no memo" 지시어는 정말 유용해요. 특정 컴포넌트에서 문제가 발생했을 때, 그 컴포넌트만 컴파일에서 제외하고 나머지는 계속 컴파일러의 혜택을 받을 수 있거든요. 문제를 해결한 후에 지시어를 제거하면 돼요.)

다음 단계 {/next-steps/}


사이트맵

모든 문서 페이지 개요

profile
프론트에_가까운_풀스택_개발자

0개의 댓글