ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Remotion Render Server Template:用 Express 搭建可提交、可查询、可取消的 React 视频渲染服务

Remotion Render Server Template:用 Express 搭建可提交、可查询、可取消的 React 视频渲染服务 Remotion Render Server Template用 Express 搭建可提交、可查询、可取消的 React 视频渲染服务【免费下载链接】remotion Make videos programmatically with React项目地址: https://gitcode.com/GitHub_Trending/re/remotion本模板仓库目录 packages/template-render-server提供了一整套“把 Remotion 视频渲染能力做成 HTTP 服务”的参考实现基于 Express.js 暴露三个核心端点分别用于启动新的渲染任务、查询正在进行的渲染进度、取消运行中的渲染并配套 Docker 镜像、示例合成与本地开发脚本。读完本文你将掌握渲染任务从入队、串行执行、进度上报到完成/失败/取消的完整状态机设计以及remotion/renderer、remotion/bundler服务端 API 的落地用法可以据此快速搭建自己的视频生成后端。模板能做什么该模板本质是一个“渲染即服务”的最小可运行骨架其完整源码仅由两个服务端文件构成server/index.tsExpress 应用入口负责 HTTP 路由与请求校验server/render-queue.ts渲染队列实现封装任务状态机、串行调度与取消逻辑。对应的一段 Remotion 示例视频工程位于 remotion/服务端渲染的目标合成是注册在 remotion/Root.tsx 中、id 为HelloWorld的合成。服务端暴露以下核心端点方法路径作用POST/renders创建一个新的渲染任务返回jobIdGET/renders/:id查询某个渲染任务的状态与进度DELETE/renders/:id取消某个排队中或正在渲染的任务快速体验按 README 中 Getting Started 的流程先安装依赖npm install以监听模式启动开发版渲染服务tsx watch会在代码变更时自动重启npm run dev生产环境直接运行npm start启动后在另一个终端里即可用 curl 走通“创建 → 查询 → 取消”全流程# 1. 创建任务titleText 将作为 inputProps 传给 Remotion 合成 curl -X POST http://localhost:3000/renders \ -H Content-Type: application/json \ -d {titleText:My first server render} # 2. 用返回的 jobId 查询进度 curl http://localhost:3000/renders/jobId # 3. 取消一个排队中/渲染中的任务 curl -X DELETE http://localhost:3000/renders/jobId创建成功后约一段时间800 帧、30fps 的 1080p H.264 视频GET /renders/:jobId返回completed状态并附上可下载地址http://localhost:3000/renders/jobId.mp4——这是因为服务端同时用express.static把输出目录挂载在了/renders路径下。任务状态机queued → in-progress → completed / failed渲染队列的核心是JobState这个可辨识联合类型完整定义见 render-queue.tsinterface JobData { titleText: string; } type JobState | { status: queued; data: JobData; cancel: () void } | { status: in-progress; progress: number; // 0 ~ 1 的渲染进度 data: JobData; cancel: () void; } | { status: completed; videoUrl: string; data: JobData } | { status: failed; error: Error; data: JobData };据此可画出完整生命周期queued任务刚被createJob()创建尚未开始渲染此阶段cancel()只做一件事——把任务从jobsMap 中删除见 render-queue.tsin-progressprocessRender()开始时置入onProgress回调会持续刷新progress字段此阶段cancel()会触发由makeCancelSignal()生成的取消信号completed渲染成功写入视频下载地址videoUrlfailed渲染抛出异常时兜底捕获并记录error。HTTP 层的查询与取消逻辑与之严格对应。以 server/index.ts 的取消端点为例app.delete(/renders/:jobId, (req, res) { const jobId req.params.jobId; const job queue.jobs.get(jobId); if (!job) { res.status(404).json({ message: Job not found }); return; } if (job.status ! queued job.status ! in-progress) { res.status(400).json({ message: Job is not cancellable }); return; } job.cancel(); res.json({ message: Job cancelled }); });即任务不存在返回404已完成/已失败的任务不允许取消并返回400只有queued或in-progress状态才可取消。三个端点均围绕同一个jobs: Mapstring, JobState读写状态天然保证查询到的就是当前最新快照。在源码里实现取消的底层机制任务状态从queued翻转为in-progress时代码先调用makeCancelSignal()拿到一对{ cancel, cancelSignal }其签名定义见 renderer 包源码然后把cancelSignal直接传给renderMedia见 render-queue.tsconst { cancel, cancelSignal } makeCancelSignal(); // ... 更新状态为 in-progress并把 cancel 存入 job await renderMedia({ cancelSignal, serveUrl, composition, inputProps, codec: h264, onProgress: (progress) { /* 刷新进度 */ }, outputLocation: path.join(rendersDir, ${jobId}.mp4), });从源码结构可以推断对 in-progress 任务调用cancel()会令renderMedia中止并抛错随后任务落入catch分支被标记为failed——因此“取消”动作在状态机上最终会以failed状态落定这是使用本模板时值得注意的语义。串行调度用 Promise 链实现单并发渲染队列模板刻意选择“每次只渲染一个任务”的串行策略实现非常轻量见 render-queue.ts 与 L109-L126const jobs new Mapstring, JobState(); let queue: Promiseunknown Promise.resolve(); const queueRender async ({ jobId, data }) { // 先把任务标为 queued jobs.set(jobId, { status: queued, data, cancel: ... }); const render queue.then(() processRender(jobId)); queue render.catch(() undefined); // 失败不中断后续任务 };要点维护一个全局串行链queue每个新任务都追加到链尾processRender必然在前一个任务 settle 之后才开始链上追加的是.catch(() undefined)后的 promise因此某个任务渲染失败不会阻塞后续排队任务createJob()用 Node 内置randomUUID()生成jobId并把titleText作为数据传入见 render-queue.ts。该实现清晰演示了“任务队列”与“渲染结果”两种关注点的分离HTTP 层只负责入队和查询调度细节全部收敛在makeRenderQueue返回的{ createJob, jobs }中。服务启动链路ensureBrowser → bundle → listen服务端主流程集中在 server/index.tsasync function main() { await ensureBrowser(); // 确保 Chromium 浏览器可用 const remotionBundleUrl REMOTION_SERVE_URL ? REMOTION_SERVE_URL : await bundle({ entryPoint: path.resolve(remotion/index.ts), onProgress(progress) { console.info(Bundling Remotion project: ${progress}%); }, }); const app setupApp({ remotionBundleUrl }); app.listen(PORT, () { console.info(Server is running on port ${PORT}); }); }三个关键环节ensureBrowser()来自remotion/renderer渲染视频必须依赖 Chromium这一步确认/准备浏览器环境服务才会继续启动bundle()来自remotion/bundler把 remotion/index.ts内部调用registerRoot(RemotionRoot)打包成服务端可消费的 bundle通过onProgress打印打包进度环境变量分流若设置了REMOTION_SERVE_URL则跳过打包、直接使用现成 bundleDocker 镜像正是靠这一点省去运行时打包。此外端口也由环境变量控制const { PORT 3000, REMOTION_SERVE_URL } process.env;默认监听3000端口。需要说明的是remotion/cli的配置文件对 Node.js API 不生效——正如 remotion.config.ts 头部注释所强调的使用 Node.js API 时应把codec、imageFormat、overwrite等选项直接传给 API而不是依赖配置文件。参数化渲染从 HTTP body 到 inputPropsPOST /renders接受 JSON body服务端只读取并校验titleText字段见 server/index.tsapp.post(/renders, async (req, res) { const titleText req.body?.titleText || Hello, world!; if (typeof titleText ! string) { res.status(400).json({ message: titleText must be a string }); return; } const jobId queue.createJob({ titleText }); res.json({ jobId }); });注意两点未传titleText时默认取Hello, world!传入的值会被包装成inputProps见 render-queue.ts在selectComposition与renderMedia两处都透传给 Remotion 合成HelloWorld合成并非单参数。它通过 zod 声明了完整的 props schema见 remotion/HelloWorld.tsxexport const helloWorldCompSchema z.object({ titleText: z.string(), titleColor: zColor(), // 来自 remotion/zod-types logoColor1: zColor(), logoColor2: zColor(), });模板刻意只暴露了titleText一个 HTTP 字段其余 props 沿用 Root.tsx 中声明的defaultProps。读者可轻松扩展把校验逻辑改为对整份 schema 做z.parse即可实现“任意 props 均可由 API 驱动”的完整参数化渲染。渲染目标合成 HelloWorld服务端通过selectComposition({ serveUrl, id: compositionId, inputProps })在 bundle 中定位 id 为HelloWorld的合成并获取其配置宽高、时长、fps再由renderMedia执行实际渲染。合成的定义如下属性值含义idHelloWorld被selectComposition检索的合成标识durationInFrames800总时长30fps 约 26.7 秒fps30帧率width/height1920/1080全高清画幅schemahelloWorldCompSchemazod 声明的 props 校验defaultPropstitleText等未显式传入时的兜底值合成本身是 Remotion 经典动画编排Logo 在约 25 帧后开始弹入、随后上移 150pxTitle从第 35 帧Sequence from{35}入场Subtitle从第 75 帧入场临近结尾800 帧 - 25 帧起整体淡出见 HelloWorld.tsx。本地开发配套命令模板在 package.json 的scripts中集中了全部开发命令npm run dev # tsx watch server —— 渲染服务watch 模式代码热重启 npm start # tsx server —— 渲染服务生产模式 npm run build # remotion bundle —— 预打包 Remotion 工程 npm run remotion:studio # remotion studio —— 启动 Remotion Studio 预览合成 npm run remotion:upgrade # remotion upgrade —— 升级所有 Remotion 相关依赖在本地验证视频本身是否正确不启动服务端也可以直接渲染npx remotion render运行后会得到示例视频输出配合remotion:studio可在浏览器里逐帧预览、调试HelloWorld合成后再把它接回服务端。Remotion 工程侧的渲染选项由 remotion.config.ts 集中声明Config.setRspack(true); // 使用 Rspack 打包速度更快 Config.setVideoImageFormat(jpeg); // 视频帧图像格式 Config.setOverwriteOutput(true); // 输出已存在时直接覆盖Docker 化部署镜像内自带浏览器与预构建产物模板自带 Dockerfile开箱即用docker build -t remotion-render-server . docker run -d -p 3000:3000 remotion-render-server这个镜像的构建顺序很能说明 Remotion 服务端部署的关键约束逐层拆解如下基础镜像取node:lts-bookworm安装 Chromium 系统依赖——libnss3、libgbm-dev、libasound2、libxrandr2等一整套无头浏览器所需的共享库npm install安装依赖后用npx remotion browser ensure在镜像内下载/就绪 Remotion 需要的浏览器版本对应服务端启动时的ensureBrowser()npx remotion bundle提前把合成打进build目录通过ENV REMOTION_SERVE_URLbuild让服务端跳过运行时打包、直接消费镜像内的构建产物mkdir -p renders预创建输出目录最后CMD [npm, start]以生产模式启动服务。对部署方而言值得注意两点容器内需持久化/app/renders否则重启丢产物对外建议把3000端口映射出来以便下载videoUrl。在仓库中继续深入服务端 HTTP 路由与请求校验packages/template-render-server/server/index.ts队列状态机与渲染调度packages/template-render-server/server/render-queue.ts合成注册与默认 propspackages/template-render-server/remotion/Root.tsx 、packages/template-render-server/remotion/HelloWorld.tsx打包配置packages/template-render-server/remotion.config.tsDocker 化部署packages/template-render-server/Dockerfile底层取消信号实现packages/renderer/src/make-cancel-signal.ts扩展方向小结本模板以约两百行源码把 Remotion 服务端渲染的关键链路全部打通可直接照此扩展的典型方向包括透传完整 zod schema 实现全参数化渲染并把selectComposition前置到入队阶段以尽早校验 props把进程内Map 串行 Promise 链替换为 Redis/数据库 并发 Worker以支持横向扩容与断点恢复通过环境变量注入codec、分辨率、fps 等renderMedia选项或接入remotion/lambda实现无服务器渲染。License 方面需注意Remotion 本身对公司实体部分场景要求购买授权具体条款见仓库根目录 LICENSE.md。【免费下载链接】remotion Make videos programmatically with React项目地址: https://gitcode.com/GitHub_Trending/re/remotion创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表