Remotion LabRemotion Lab
疑難排解Webpack 動態引入問題

Webpack 動態引入問題

解釋在 Remotion 中使用 Webpack 動態引入資產時的限制,以及使用 staticFile() 和正確表達式的解決方法

Webpack 動態引入問題

問題說明

在 Remotion 中,您可能嘗試根據幀號動態引入不同的圖片或資產。然而,Webpack 的靜態分析機制使得某些動態引入方式無法運作。

錯誤範例

以下程式碼看起來合理,但會導致錯誤:

import { Img, useCurrentFrame } from "remotion";
 
export const DynamicImports: React.FC = () => {
  const frame = useCurrentFrame();
  const img = "./assets/image" + frame + ".png";
 
  return <Img src={require(img)} />;
};

執行時會出現:

Error: Cannot find module './image0.png'

即使檔案實際存在,這個錯誤仍然會發生。原因是 Webpack 需要透過靜態程式碼分析來決定要打包哪些資產,而將路徑字串存入變數再傳入 require() 的寫法無法被靜態分析。

解決方案一:使用 staticFile()(推薦)

最推薦的做法是將資產放入 public/ 資料夾,並使用 staticFile() 函式引用:

import { Img, useCurrentFrame, staticFile } from "remotion";
 
export const DynamicImports: React.FC = () => {
  const frame = useCurrentFrame();
 
  return <Img src={staticFile(`image${frame}.png`)} />;
};

staticFile() 不依賴 Webpack 打包機制,因此沒有靜態分析的限制。

檔案結構:

my-remotion-project/
├── public/
│   ├── image0.png
│   ├── image1.png
│   ├── image2.png
│   └── ...
└── src/
    └── MyComp.tsx

詳情請參閱 靜態資產引入指南staticFile() API 文件

解決方案二:將表達式放在 require() 內部

若您仍需使用 Webpack 的 require(),可以將動態表達式直接放在 require()import() 的呼叫中,而非預先組合成字串:

import { Img, useCurrentFrame } from "remotion";
 
export const DynamicImports: React.FC = () => {
  const frame = useCurrentFrame();
 
  // 正確:表達式在 require() 內部
  return <Img src={require("./assets/image" + frame + ".png")} />;
};

在這種情況下,Webpack 會自動將 assets/image 資料夾中所有的 .png 檔案打包,即使某些檔案從未被用到。

注意: 這表示所有匹配的圖片都會被打包進產出物,可能增加打包體積。

完全動態的資產路徑

如果要引入的資產路徑完全未知,例如透過 Input Props 傳入:

import { getInputProps, Img } from "remotion";
 
// 這樣無法運作!
const DynamicAsset: React.FC = () => {
  const inputProps = getInputProps(); // { "imageSrc": "./assets/img0.png" }
  return <Img src={require(inputProps.imageSrc as string)} />;
};

這無法運作,因為 Webpack 完全不知道要打包哪些資產。

方法一:強制打包整個資料夾

透過在 require() 中放入部分靜態路徑前綴,讓 Webpack 打包整個資料夾:

import { getInputProps, Img } from "remotion";
 
const DynamicAsset: React.FC = () => {
  const inputProps = getInputProps(); // { "imageSrc": "img0.png" }
 
  // 可以運作!Webpack 會打包整個 ./assets/ 資料夾
  return <Img src={require(("./assets/" + inputProps.imageSrc) as string)} />;
};

方法二:使用 staticFile()(最推薦)

將資產放入 public/ 資料夾,完全避免 Webpack 的限制:

import { getInputProps, Img, staticFile } from "remotion";
 
const DynamicAsset: React.FC = () => {
  const inputProps = getInputProps(); // { "imageSrc": "img0.png" }
 
  return <Img src={staticFile(inputProps.imageSrc)} />;
};

各方案比較

方案適用情境優點限制
staticFile()所有情況無靜態分析限制、支援動態路徑檔案需放在 public/ 資料夾
表達式在 require()有固定路徑前綴時可使用既有的資產結構會打包整個資料夾,增加體積

仍有困難?

如果您在引入資產時仍遇到問題,歡迎在 Discord 提問或在 GitHub 提交 Issue。

參見