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。