Remotion LabRemotion Lab
PlayerPlayer 與 Remotion 的程式碼共享

Player 與 Remotion 的程式碼共享

了解如何在 Remotion Player、Remotion Studio 與伺服器端渲染之間共享元件程式碼,以及 Webpack bundle 的注意事項。

Player 與 Remotion 的程式碼共享

使用 Remotion 開發時,你通常會希望讓同一套元件程式碼能夠同時服務於三個場景:

  1. Remotion Studio — 開發預覽與調整
  2. <Player> 元件 — 嵌入 React 應用程式的互動式播放器
  3. 伺服器端渲染(SSR) — 透過 Node.js API 輸出影片檔案

這三個場景雖然目的不同,但核心的 Remotion 元件完全可以共享,不需要重複撰寫。

建議的專案結構

將你的 Remotion 元件集中放置在一個子目錄中,讓應用程式的其他部分和 Remotion 渲染管線都能引用:

src/
├── remotion/
│   ├── index.ts          # Remotion 進入點(包含 registerRoot)
│   ├── Root.tsx           # 列出所有 Composition
│   └── MyComp.tsx         # 實際的影片元件
└── app/
    └── App.tsx            # 你的 React 應用程式

remotion/MyComp.tsx 中的元件就是可以被三個場景共同使用的程式碼。

在 Player 中使用元件

直接從 remotion/ 目錄匯入元件,傳入 <Player>component prop:

import { Player } from '@remotion/player';
import { MyComp } from './remotion/MyComp';
 
export const App: React.FC = () => {
  return (
    <Player
      component={MyComp}
      durationInFrames={120}
      compositionWidth={1920}
      compositionHeight={1080}
      fps={30}
      inputProps={{ title: '我的影片' }}
    />
  );
};

<Player> 不需要 bundle,它直接使用 React 元件。

在伺服器端渲染中使用元件

SSR 流程則需要先打包(bundle)你的 remotion/index.ts,再進行渲染:

import { bundle } from '@remotion/bundler';
import { renderMedia, selectComposition } from '@remotion/renderer';
import path from 'path';
 
const bundleUrl = await bundle({
  entryPoint: path.resolve('./src/remotion/index.ts'),
});
 
const composition = await selectComposition({
  serveUrl: bundleUrl,
  id: 'MyComp',
  inputProps: { title: '我的影片' },
});
 
await renderMedia({
  composition,
  serveUrl: bundleUrl,
  codec: 'h264',
  outputLocation: 'out/video.mp4',
  inputProps: { title: '我的影片' },
});

Bundle 的注意事項

Player 與 SSR 使用不同的 Webpack 設定

<Player> 直接在你的應用程式 Webpack bundle 中執行元件,而 SSR 的 bundle() 則會產生一個獨立的 Webpack bundle。兩者的設定是分開的。

如果你自訂了 Webpack 設定,需要分別在兩處套用:

// remotion.config.ts — 影響 bundle() 與 Remotion Studio
import { Config } from '@remotion/cli/config';
 
Config.overrideWebpackConfig((currentConfig) => {
  return {
    ...currentConfig,
    // 你的自訂設定
  };
});
// 應用程式的 webpack/vite 設定 — 影響 <Player>
// 例如 next.config.js、vite.config.ts 等

避免在 bundle 中呼叫 bundle()

bundle() 是 Node.js API,不可在已打包的瀏覽器端程式碼中呼叫。如果你需要在前端觸發渲染,應透過後端 API 進行,而不是直接在 React 元件裡呼叫 bundle()

詳見在打包程式碼中呼叫 bundle()

元件必須與 Webpack 相容

因為 SSR 打包會使用 Webpack 處理你的元件,請確認元件中所有使用的語法與套件都能被 Webpack 正確處理。純 React / TypeScript 程式碼通常沒有問題,但需要特別注意:

  • 僅限 Node.js 的模組(如 fspath)不能在元件中直接使用
  • 使用動態 import() 時需確認 Webpack 支援
  • CSS Modules、SVG 等特殊資源格式需要對應的 Webpack loader

共享型別定義

若你的元件接受 Props,建議將 Props 型別定義抽離到獨立檔案,方便 Player 端與渲染端共同引用:

// remotion/types.ts
export type MyCompProps = {
  title: string;
  subtitle?: string;
  durationInFrames: number;
};
// remotion/MyComp.tsx
import type { MyCompProps } from './types';
 
export const MyComp: React.FC<MyCompProps> = ({ title, subtitle }) => {
  // ...
};
// app/App.tsx
import type { MyCompProps } from './remotion/types';
import { MyComp } from './remotion/MyComp';
import { Player } from '@remotion/player';
 
const props: MyCompProps = {
  title: '共享型別',
  durationInFrames: 120,
};
 
export const App: React.FC = () => (
  <Player
    component={MyComp}
    durationInFrames={props.durationInFrames}
    compositionWidth={1920}
    compositionHeight={1080}
    fps={30}
    inputProps={props}
  />
);

使用 Zod Schema 驗證 Props

搭配 @remotion/zod-types,你可以讓 Props 驗證在三個場景中保持一致:

import { z } from 'zod';
 
export const myCompSchema = z.object({
  title: z.string(),
  subtitle: z.string().optional(),
});
 
export type MyCompProps = z.infer<typeof myCompSchema>;

Remotion Studio 會自動根據 Schema 產生可互動的 Props 編輯面板。詳見 Schema 驗證

相關資源