📦

Remotion 코드 분석 — Bundle 시스템과 Webpack/esbuild 통합

bundle()이 React 컴포넌트를 렌더링 가능한 HTML로 변환하는 과정을 소스 코드로 추적

GitHub: remotion-dev/remotion

Remotion의 렌더링은 번들링에서 시작됩니다. React 컴포넌트를 브라우저가 실행할 수 있는 HTML+JS 번들로 만드는 과정을 소스 코드로 추적합니다.


리포지토리 구조

packages/
├── bundler/              # Webpack 기반 번들러
│   ├── src/
│   │   ├── bundle.ts           # bundle() 진입점
│   │   ├── webpack-config.ts    # Webpack 설정 생성
│   │   ├── webpack-caching.ts   # 캐시 전략
│   │   └── index-html.ts        # HTML 템플릿 생성
├── core/                 # 핵심 런타임
│   ├── src/
│   │   ├── Composition.tsx      # <Composition> 컴포넌트
│   │   ├── CompositionManager.tsx  # 등록된 Composition 관리
│   │   ├── register-root.ts     # registerRoot() 진입점
│   │   ├── use-current-frame.ts # useCurrentFrame() Hook
│   │   └── video-config.ts      # fps, width, height 등 설정
├── renderer/             # 로컬 렌더러
│   ├── src/
│   │   ├── render-media.ts      # renderMedia() 진입점
│   │   ├── render-frames.ts     # 프레임 렌더링 루프
│   │   └── stitch-frames-to-video.ts  # FFmpeg 인코딩
├── studio/               # Remotion Studio (개발 서버)
│   ├── src/
│   │   └── start.ts            # Studio 시작점
└── lambda/               # AWS Lambda 렌더링


bundle() 함수의 동작 과정

1. 진입점: packages/bundler/src/bundle.ts

// bundle.ts (간략화)
export const bundle = async (options: BundleOptions) => {
  const webpackConfig = await webpackConfiguration({
    entryPoint: options.entryPoint,  // Root.tsx 경로
    outDir: options.outDir,
    environment: 'production',
  });

  // Webpack 실행
  const stats = await runWebpack(webpackConfig);

  // index.html 생성 (Headless Chrome이 로드할 페이지)
  await createIndexHtml({
    outDir: options.outDir,
    baseDir: '/',
  });

  return options.outDir;
};

핵심은 webpackConfiguration()이 생성하는 Webpack 설정입니다.

2. Webpack 설정: webpack-config.ts

// webpack-config.ts (핵심 부분)
export const webpackConfiguration = (options) => {
  return {
    entry: options.entryPoint,  // 사용자의 Root.tsx
    output: {
      path: options.outDir,
      filename: '[name].bundle.js',
    },
    resolve: {
      extensions: ['.ts', '.tsx', '.js', '.jsx'],
    },
    module: {
      rules: [
        {
          test: /\.tsx?$/,
          use: 'esbuild-loader',  // ts → js 변환은 esbuild!
          options: { loader: 'tsx' },
        },
        {
          test: /\.css$/,
          use: ['style-loader', 'css-loader'],
        },
        // 이미지, 폰트 등 asset loaders...
      ],
    },
  };
};

주목할 점: TypeScript 컴파일에 esbuild-loader를 사용합니다. Webpack의 번들링 능력 + esbuild의 빠른 트랜스파일을 조합한 하이브리드 전략입니다.

3. HTML 템플릿: index-html.ts

// 생성되는 index.html (간략화)
<html>
<head>
  <style>* { margin: 0; padding: 0; }</style>
</head>
<body>
  <div id="remotion-root"></div>
  <script src="/main.bundle.js"></script>
</body>
</html>

이 HTML이 Headless Chrome에서 로드되고, main.bundle.js가 실행되면 React가 #remotion-root에 마운트됩니다.

4. CompositionManager — 메타데이터 수집

// core/src/CompositionManager.tsx
// registerRoot() 실행 시 모든 <Composition>의 메타데이터를 수집
const CompositionManager: React.FC = () => {
  const [compositions, setCompositions] = useState<AnyComposition[]>([]);

  // <Composition>이 렌더될 때마다 등록됨
  const registerComposition = (comp: AnyComposition) => {
    setCompositions(prev => [...prev, comp]);
  };

  // 렌더러가 window.getCompositions()로 이 데이터를 가져감
  useEffect(() => {
    window.getCompositions = () => compositions;
  }, [compositions]);

  return <Context.Provider value={{ registerComposition }}>{children}</Context.Provider>;
};

핵심 메커니즘: 번들이 Chrome에서 실행되면, 모든 <Composition>이 CompositionManager에 등록됩니다. 렌더러는 window.getCompositions()를 호출하여 어떤 비디오를 어떤 설정(fps, 해상도, 길이)으로 렌더링할지 결정합니다.

동작 흐름

1

bundle(entryPoint)가 호출되면 webpackConfiguration()으로 Webpack 설정 생성

2

esbuild-loader가 TSX → JS 트랜스파일, Webpack이 의존성 그래프를 번들링

3

index-html.ts가 #remotion-root + main.bundle.js를 포함하는 HTML 생성

4

registerRoot()가 실행되면 CompositionManager가 모든 <Composition>의 메타데이터를 수집

5

window.getCompositions()를 통해 렌더러가 fps/width/height/durationInFrames를 조회

장점

  • Webpack + esbuild 하이브리드: 호환성(Webpack)과 속도(esbuild) 모두 확보
  • window.getCompositions() 패턴: 브라우저 ↔ Node.js 간 메타데이터 브릿지가 깔끔

단점

  • Webpack 의존: 최초 번들링이 느릴 수 있음 (Vite 마이그레이션 논의 중)

사용 사례

Remotion 커스텀 빌드 파이프라인 구축 시 번들링 과정 이해 번들 크기 최적화: 어떤 로더/플러그인이 적용되는지 파악