Metro: 개념, 주요 기능 및 작동 원리

저자: IT Sectr 게시일: 2026-05-19 읽는 시간: 8 분

Metro는 React Native 전용으로 개발되었으며 이 플랫폼에서 모바일 애플리케이션을 빌드하는 데 기본적으로 사용되는 JavaScript 번들러입니다. 범용 번들러와 달리 Metro는 모바일 기기의 제한된 리소스에 최적화되어 있으며 Hermes 엔진 및 Fast Refresh와의 통합을 제공합니다. Metro Documentation (2026)에 따르면, 이 번들러는 전 세계 React Native 프로젝트의 90% 이상을 처리합니다.

핵심 요점

  • Metro는 React Native의 기본 번들러로, iOS 및 Android 모바일 개발에 최적화되어 있습니다.
  • 3단계 아키텍처: Metro는 모듈 해석, 변환, 출력 번들로의 직렬화를 포함합니다.
  • Fast Refresh는 애플리케이션 상태를 잃지 않고 컴포넌트를 핫 리로드하는 메커니즘입니다.
  • Inline Requires는 첫 번째 호출까지 모듈 로딩을 지연시켜 초기 번들을 줄입니다.
  • Hermes는 Meta의 JavaScript 엔진으로, Metro를 사용하여 사전 컴파일된 바이트코드를 생성합니다.

Metro란?

Metro는 Meta 팀이 React Native를 위해 만든 오픈 소스 JavaScript 번들러입니다. 이전 버전의 React Native Packager를 대체하여 이 플랫폼의 표준 빌드 도구가 되었습니다. Metro는 웹 개발용으로 설계되지 않았습니다. 아키텍처는 JSC(JavaScriptCore) 또는 Hermes JavaScript 엔진에서 실행되는 모바일 애플리케이션에만 전적으로 초점을 맞추고 있습니다.

개발 배경 및 위치

Metro는 2018년 기존 React Native Packager를 대체하기 위해 등장했습니다. 주요 개발 이유는 대규모 모바일 애플리케이션에서 수백만 개의 모듈을 효율적으로 처리할 수 있는 번들러의 필요성이었습니다. Webpack과 달리 Metro는 CSS, HTML 또는 이미지를 모듈로 지원하지 않습니다. 이러한 리소스는 별도의 React Native 도구로 처리됩니다. Facebook은 10만 개 이상의 파일을 포함하는 자체 메인 애플리케이션을 빌드하는 데 Metro를 사용합니다.

Metro는 npm 패키지 metro로 배포되며 React Native CLI와 함께 자동으로 설치됩니다. Metro 버전은 React Native 버전에 연결되어 있으므로 번들러 업데이트는 플랫폼 업데이트와 함께 이루어집니다.

Metro 번들러는 어떻게 작동하나요?

Metro는 애플리케이션의 진입점을 입력으로 받아 의존성 그래프를 구축하고, 각 모듈을 변환한 후 결과를 단일 번들로 직렬화합니다. 프로세스는 Resolve(모듈 해석), Transform(변환), Serialize(직렬화)의 세 단계를 거칩니다.

Metro의 빌드 프로세스

js
// 사용자 정의 변환을 위한 Metro 설정 예제
const metroConfig = {
  transformer: {
    babelTransformerPath: require('metro-babel-transformer'),
    async transform({ src, filename, options }) {
      const result = await babelTransform({ src, filename, options });
      return {
        ast: result.ast,
        code: result.code,
        map: result.map,
        dependencies: [],
      };
    },
  },
  serializer: {
    createModuleIdFactory() {
      let nextId = 0;
      const moduleIds = new Map();
      return ({ path }) => {
        if (!moduleIds.has(path)) {
          moduleIds.set(path, nextId++);
        }
        return moduleIds.get(path);
      };
    },
  },
};

Resolve 단계에서 Metro는 별칭과 node_modules를 고려하여 각 가져온 모듈의 위치를 결정합니다. Transform 단계에서 각 파일은 Babel 변환기를 거쳐 JSX, TypeScript 및 기타 확장 기능을 순수 JavaScript로 변환합니다. 최종 Serialize 단계는 변환된 모든 모듈을 하나 이상의 번들 파일로 수집합니다.

Metro 아키텍처

Metro는 각 빌드 단계가 별도 컴포넌트로 구현된 모듈식 아키텍처를 기반으로 구축되었습니다. 이를 통해 번들러 코어를 변경하지 않고 표준 모듈을 사용자 정의 모듈로 교체할 수 있습니다. Metro 아키텍처에는 metro, metro-config, metro-resolver의 세 가지 주요 패키지가 포함됩니다.

Metro의 주요 컴포넌트

Metro Servernpx react-native start 명령으로 시작되는 개발 서버입니다. 실시간으로 모듈 변환 요청을 처리하여 Fast Refresh를 제공합니다. Module Store는 재빌드를 가속화하기 위해 변환된 모듈을 메모리에 저장하는 캐시입니다. Dependency Graph는 파일 변경 시 증분 방식으로 업데이트되는 의존성 그래프입니다.

Watchman은 Metro가 파일 시스템 변경을 감지하는 데 사용하는 Meta의 파일 감시자입니다. Watchman이 없으면 Metro는 모든 변경 시 전체 파일 구조를 다시 스캔해야 하므로 개발 속도가 크게 저하됩니다. Watchman 설치는 모든 규모의 프로젝트에서 Metro를 편안하게 사용하기 위해 필수적입니다.

React Native 프로젝트에서 Metro 설정

설정은 프로젝트 루트의 metro.config.js 파일에서 정의됩니다. 일반적인 파일은 모듈 검색을 위한 추가 폴더, 불필요한 파일을 제외하기 위한 블록리스트, 사용자 정의 변환기를 지정합니다. React Native 0.72+에서는 설정 자동 감지가 사용되지만, 모노레포의 경우 설정이 필수입니다.

React Native를 위한 기본 Metro 설정

js
// metro.config.js
const config = {
  resolver: {
    sourceExts: ['js', 'jsx', 'ts', 'tsx', 'json'],
    nodeModulesPaths: ['node_modules'],
    blockList: [/\.test\.js$/, /__tests__\/.*/],
    extraNodeModules: {
      'shared-components': path.resolve(__dirname, '../shared/src'),
    },
  },
  transformer: {
    minifierConfig: {
      keep_classnames: true,
      keep_fnames: true,
      mangle: { reserved: ['React', 'Component'] },
    },
  },
};

module.exports = mergeConfig(getDefaultConfig(__dirname), config);

blockList는 테스트 파일을 빌드에서 제외하여 번들 크기를 줄입니다. nodeModulesPaths는 패키지 검색을 위한 추가 경로를 지정합니다. 모노레포에서 중요합니다. extraNodeModules는 모노레포 내 여러 프로젝트에서 사용되는 공유 패키지의 별칭을 생성합니다.

Metro 빌드 최적화

Metro는 번들 크기와 빌드 속도를 최적화하기 위한 여러 메커니즘을 제공합니다. Inline Requires는 가장 효과적인 기술로, 최상위 가져오기를 함수 내의 로컬 require 호출로 변환합니다. RAM bundles는 모듈을 증분 방식으로 로드할 수 있습니다. Hermes는 JavaScript를 바이트코드로 컴파일하여 애플리케이션 크기를 20~30% 줄입니다.

Inline Requires 및 Hermes 활성화

js
// metro.config.js — 프로덕션 최적화
const config = {
  transformer: {
    async transform({ src, filename, options }) {
      const inlineRequires = options.dev ? false : true;
      return await defaultTransform({ src, filename, options: { ...options, inlineRequires } });
    },
  },
  serializer: {
    polyfillModuleNames: [],
  },
};

// Hermes 활성화 방법 — build.gradle (Android):
// project.ext.react = [enableHermes: true, bundleInRelease: true]
// iOS의 경우 — Podfile: :hermes_enabled => true

번들 크기 진단을 위해 Metro는 통계 출력과 함께 --bundle-output 플래그를 제공합니다. bundle-visualizer를 사용하여 번들 구성을 분석하고 지연 로드할 수 있는 대형 모듈을 찾으세요. 정기적인 번들 크기 확인은 React Native 프로젝트의 CI/CD 파이프라인의 일부여야 합니다.

델타 번들 및 증분 빌드

Metro는 델타 번들을 지원합니다. 첫 번째 전체 빌드 후 서버가 이전 번들과 새 번들 버전 간의 변경 사항(델타)만 전송하는 메커니즘입니다. 이는 이후 빌드를 획기적으로 가속화합니다. 업데이트 시간이 초에서 수십 밀리초로 단축됩니다. 델타 번들은 개발자가 자주 변경 사항을 저장하고 애플리케이션을 다시 로드하는 개발 단계에서 특히 효과적입니다.

React Native에서 델타 번들을 활성화하려면 npx react-native bundle 명령에 --delta 플래그를 사용합니다. 클라이언트 측에서는 React Native 0.64부터 델타 번들이 지원됩니다. 프로덕션 빌드에서는 델타 번들이 사용되지 않습니다. 대신 최대 시작 성능을 위해 Hermes 바이트코드가 포함된 전체 번들이 사용됩니다. 이는 개발 속도 향상이 첫 번째 전체 빌드 비용을 상쇄하기 때문에 가능합니다.

Hermes와 Metro의 협력

Hermes는 Meta가 React Native 전용으로 개발한 JavaScript 엔진입니다. Metro는 빌드 시 Hermes 바이트코드를 생성하여 애플리케이션이 기기에서 값비싼 JavaScript 컴파일 없이 시작될 수 있도록 합니다. Hermes를 활성화하려면 metro.config.jsenableHermes: true를 추가하고 build.gradle 또는 Podfile을 설정하기만 하면 됩니다. Hermes는 JavaScriptCore와 비교하여 애플리케이션 시작 시간을 30~50% 단축하고 APK 크기를 20~30% 줄입니다.

Hermes 사용 시 제한 사항을 기억하는 것이 중요합니다. 이 엔진은 Proxy, Reflect 및 일부 ES6 기능을 지원하지 않습니다. 대부분의 React Native 애플리케이션은 이러한 기능을 직접 사용하지 않지만, 일부 라이브러리는 충돌할 수 있습니다. Hermes를 활성화하기 전에 공식 호환성 체크리스트를 통해 모든 프로젝트 의존성의 호환성을 확인하세요. Hermes가 활성화되면 Metro는 자동으로 바이트코드 생성 모드로 전환됩니다.

Metro 성능 모니터링

Metro 빌드 효율성을 추적하려면 Flipper(React Native 디버깅 도구)를 통해 제공되는 내장 메트릭을 사용하세요. Metro는 각 단계의 실행 시간과 함께 bundle_request, transform, resolve 이벤트를 게시합니다. 이 데이터를 분석하면 병목 지점을 식별하는 데 도움이 됩니다. 변환 단계가 시간의 70% 이상을 차지하는 경우 문제는 Babel 변환기에 있습니다. --verbose 플래그를 통해 Metro 로깅을 활성화하여 상세 진단을 수행하세요.

자주 묻는 질문

React Native에서 Metro를 Webpack으로 대체할 수 있나요?

기술적으로는 가능합니다. react-native-webpack과 같은 실험적 프로젝트가 존재하지만 공식적으로 지원되지는 않습니다. Metro는 React Native 브리지, Turbo Modules 및 Hermes와 Webpack에서 접근할 수 없는 수준으로 통합되어 있습니다. Metro를 대체하면 Fast Refresh와 공식 지원이 손실됩니다.

Metro가 CSS를 지원하지 않는 이유는?

React Native는 스타일링에 CSS를 사용하지 않으며, 대신 StyleSheet.create를 통한 JavaScript 스타일링을 적용합니다. Metro는 React Native 전용으로 만들어졌기 때문에 CSS 지원이 필요하지 않습니다. React Native Web을 통한 웹 렌더링의 경우 CSS는 Metro 외부의 별도 도구에서 처리됩니다.

Metro는 이미지와 폰트를 어떻게 처리하나요?

Metro는 이미지나 폰트를 모듈로 처리하지 않습니다. 리소스는 require('./image.png')를 통해 가져오지만, Metro는 이를 문자열 의존성으로만 등록합니다. 실제 이미지 로딩은 Image 컴포넌트를 통해 React Native 네이티브 코드에 의해 수행되며, Metro는 리소스를 번들에 복사합니다.

Metro와 Rollup의 차이점은?

Rollup은 모듈 수준 트리 쉐이킹으로 ES 모듈을 생성하여 라이브러리의 번들 크기를 최소화합니다. Metro는 인라인 변환 및 모바일 엔진 최적화를 갖춘 CommonJS 번들을 생성합니다. Rollup은 Fast Refresh를 지원하지 않으며 React Native 네이티브 모듈과 함께 작동할 수 없습니다.

Metro의 콜드 빌드를 어떻게 가속화하나요?

Metro의 콜드 빌드는 node_modules 전체 스캔으로 인해 느려집니다. 해결 방법: 모노레포에는 watchFolders를 추가하고, 병렬 변환에는 maxWorkers를 사용하며, Watchman을 설치하세요. 10,000개 이상의 파일이 있는 프로젝트의 경우 메모리 캐싱을 위해 metro-memory-fs를 고려하세요.

요약

  • Metro는 React Native의 표준 번들러로, 리소스가 제한된 모바일 플랫폼에 최적화되어 있습니다.
  • 3단계 아키텍처(Resolve, Transform, Serialize)는 증분 빌드와 Fast Refresh를 가능하게 합니다.
  • Fast Refresh는 애플리케이션 상태를 잃지 않고 변경된 컴포넌트를 핫 리로드합니다.
  • Inline Requires는 첫 번째 호출까지 모듈 로딩을 지연시켜 초기 번들을 15~30% 줄입니다.
  • Hermes는 Meta의 JavaScript 엔진으로, Metro를 통해 JS를 바이트코드로 컴파일하여 시작을 가속화합니다.
  • Watchman은 파일 수가 많은 프로젝트에서 Metro를 편안하게 사용하기 위해 필수적인 파일 감시자입니다.
  • 모노레포의 경우 올바른 모듈 해석을 위해 watchFoldersextraNodeModules 설정이 필요합니다.

턴키 방식의 모바일 애플리케이션을 개발해 드립니다

IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.

프로젝트 논의

더 읽어보기