用 Next.js 与 Remotion 构建可编程视频 SaaS:template-next-pages 模板深度指南
2026/9/8 17:26:14 网站建设 项目流程

用 Next.js 与 Remotion 构建可编程视频 SaaS:template-next-pages 模板深度指南

【免费下载链接】remotion🎥 Make videos programmatically with React项目地址: https://gitcode.com/GitHub_Trending/re/remotion

导读

本模板(仓库内路径 packages/template-next-pages)是 Remotion 官方为「搭建可编程视频应用」准备的 Next.js 起步工程,它选用 Next.jsPages Router(App Router 版本对应 packages/template-next-app),并预置了 @remotion/player(浏览器端实时预览)与 @remotion/lambda(AWS 无服务器渲染)两套能力。读完本文,你将掌握:如何快速生成该模板、理解它的目录架构与渲染链路、读懂config.mjs/deploy.mjs的全部参数、把「前端表单 → Next.js API 路由 → Lambda 渲染 → 进度轮询 → 视频下载」这条 SaaS 视频生成管线完整跑通。

一、模板定位:一个开箱即用的视频生成 SaaS

在 Remotion 官方脚手架(create-video)的模板注册表 packages/create-video/src/templates.ts 中,该模板的登记信息如下:

  • cliIdnext-pages-dir,即用--next-pages-dir参数创建;
  • 仓库对应目录templateInMonorepotemplate-next-pages(即当前阅读的目录);
  • 类型type: 'video',定位是“面向希望构建能生成视频的应用的人的推荐选择”。

也就是说,这个模板不是演示单个视频如何渲染,而是演示一个完整的视频生成产品应该怎样组织代码:浏览器里用@remotion/player实时播放视频并把“输入参数(如标题文本)”作为inputProps传入,点渲染按钮后由 Next.js API 路由调度@remotion/lambda在 AWS 上后台渲染,再轮询渲染进度、最终提供下载链接。

一个值得注意的约束:该模板显式关闭了 Tailwind 集成开关(allowEnableTailwind: false),在 packages/create-video/src/pkg-managers.ts 中对nextnext-pages-dir等模板做了相同的排除处理,样式体系走原生 CSS Modules,避免脚手架额外注入样式配置。

二、目录结构速览:各模块各司其职

packages/template-next-pages/ ├── src/ │ ├── pages/ # Next.js 页面与 API 路由(Pages Router) │ │ ├── index.tsx # 首页:Player 预览 + 渲染控制台 │ │ ├── _app.tsx # 应用入口,导入全局样式 │ │ └── api/lambda/ │ │ ├── render.ts # POST:发起 Lambda 渲染 │ │ └── progress.ts # POST:查询渲染进度 │ ├── components/ # 前端 UI:RenderControls、按钮、进度条等 │ ├── helpers/ │ │ ├── api-response.ts # API 统一响应包装与错误处理 │ │ └── use-rendering.ts # 渲染状态机(invoking→rendering→done/error) │ ├── lambda/api.ts # 浏览器端调用 API 路由的封装 │ └── remotion/ # 视频端代码(与 Remotion 的 Composition 注册) │ ├── index.ts # registerRoot │ ├── Root.tsx # Composition 注册处 │ └── MyComp/ # 示例视频 Main / NextLogo / Rings / TextFade ├── types/ │ ├── constants.ts # 合成参数(时长/分辨率/帧率/Props schema) │ └── schema.ts # API 请求/响应 schema ├── config.mjs # Lambda 部署与调用共享配置(唯一事实源) ├── deploy.mjs # 部署函数、存储桶与 bundle 的脚本 ├── remotion.config.ts # Remotion 打包器配置 ├── next.config.js # Next.js 配置 ├── .env.example # AWS 密钥环境变量样例 └── vercel.json # Vercel 构建命令(先部署再构建)

目录里最关键的架构决策是types/constants.ts承担“前后端唯一事实源”:它导出 zod 的CompositionProps,前端表单类型、API schema、Player 的inputProps、Lambda 渲染入参全部引用它,避免三处各写一份类型而漂移。

三、快速开始:两种方式拿到工程

模板工程自身位于 monorepo 的 packages/template-next-pages 目录下。要在自己的机器上建独立项目,官方提供两条路径:

  1. 使用 GitHub 的 “Use this template” 把它克隆到自己的账号下,然后安装依赖:
    npm i
  2. 直接用 Remotion 官方脚手架命令创建(这也是模板注册表cliId: 'next-pages-dir'的用法):
    npx create-video@latest --next-pages-dir

依赖清单可在 package.json 中查看:运行时核心是remotion@remotion/player@remotion/lambdanextreact/react-domzod;在 monorepo 内它们以workspace:*形式互相引用,独立脚手架后会自动解析为发布版本。UI 辅助依赖还有@remotion/google-fonts@remotion/shapes@remotion/paths

四、常用命令与脚本映射

模板 README 给出的命令都可以在 package.json 的scripts中找到对应:

用途命令脚本/说明
启动 Next.js 开发服务器npm run devnext dev,浏览器访问首页预览 Player
打开 Remotion Studionpm run remotion(或npx remotion studio单独在 Studio 中编辑/预览视频
本地渲染视频npm run render(或npx remotion render无需 AWS,直接在本地用 Chromium 渲染
升级 Remotionnpx remotion upgraderemotion@remotion/*升级到最新版
部署 Lambdanpm run deploy(或node deploy.mjs部署函数、存储桶与 site bundle
构建与静态启动npm run build/npm startnext build/next start

此外 remotion.config.ts 对渲染器做了两项全局设置:Config.setRspack(true)使用 Rspack 作为打包器;Config.setVideoImageFormat("jpeg")让本地渲染的帧图片格式采用 JPEG(体积更小、渲染更快)。注意该文件内注释强调:使用 Node.js API(如 Lambda 的renderMediaOnLambda)时配置文件不生效,参数需直接传给 API。

五、模板背后的渲染链路(页面 → API → Lambda)

模板默认只渲染当前帧浏览器预览与完整云端渲染双模式。核心链路为:

index.tsx (Player 实时预览 + 表单修改 inputProps) │ └─ 点击 "Render video" └─ use-rendering.ts (状态机) └─ src/lambda/api.ts → POST /api/lambda/render └─ pages/api/lambda/render.ts └─ renderMediaOnLambda() [@remotion/lambda] └─ 返回 { renderId, bucketName } └─ 每秒轮询 POST /api/lambda/progress └─ pages/api/lambda/progress.ts └─ getRenderProgress() └─ done → { url, size } → 提供下载按钮

5.1 首页:Player 与输入框共用同一份 Props

在 src/pages/index.tsx 中,text状态被useMemo转成inputProps,既传给Player做实时预览,也传给RenderControls发起渲染:

const [text, setText] = useState<string>(defaultMyCompProps.title); const inputProps: z.infer<typeof CompositionProps> = useMemo(() => { return { title: text }; }, [text]); <Player component={Main} inputProps={inputProps} durationInFrames={DURATION_IN_FRAMES} fps={VIDEO_FPS} compositionHeight={VIDEO_HEIGHT} compositionWidth={VIDEO_WIDTH} controls autoPlay loop initiallyMuted />

Player直接把 Remotion 组件<Main />当作 React 组件渲染进普通网页,这正是 Remotion 官方推荐的实时预览体验;由于Player 与云端渲染消费的是同一份inputProps,所见即所得

5.2 渲染状态机:四种状态驱动 UI

src/helpers/use-rendering.ts 用一个可辨识联合类型表达状态:

  • init:初始态(等待用户输入);
  • invoking:正在调用渲染接口;
  • rendering:拿到renderId/bucketName,已开始轮询进度;
  • done:拿到产物url与体积size
  • error:任一环节失败,展示error.message

轮询部分(use-rendering.ts)是 while 循环:每次调用getProgress(),依据返回的判别字段进入error/done/progress分支,progress 分支await wait(1000)后继续查询,即每秒刷新一次进度。

对应地,RenderControls.tsx 根据状态切换 UI:init/invoking/error显示输入框与 “Render video” 按钮;rendering/done显示 ProgressBar 与下载按钮。

5.3 API 路由实现与统一响应包装

模板把 API 的“校验 + 响应包装”抽象成一个高阶函数 executeApi:

export const executeApi = <Res, Req extends ZodType>(schema: Req, handler: (...) => Promise<Res>) => async (req: NextApiRequest, res: NextApiResponse<ApiResponse<Res>>) => { try { const parsed = schema.parse(req.body); // zod 校验请求体 const data = await handler(req, parsed, res); res.status(200).json({ type: "success", data }); } catch (err) { res.status(500).json({ type: "error", message: (err as Error).message }); } };

所有接口的响应统一为{ type: "success", data } | { type: "error", message }(见 src/helpers/api-response.ts),浏览器端封装 src/lambda/api.ts 据此做类型收窄:type === "error"时直接 throw。

发起渲染src/pages/api/lambda/render.ts 关键参数:

const result = await renderMediaOnLambda({ codec: "h264", functionName: speculateFunctionName({ diskSizeInMb: DISK, memorySizeInMb: RAM, timeoutInSeconds: TIMEOUT, }), region: REGION as AwsRegion, serveUrl: SITE_NAME, // 指向部署的 site bundle 名 composition: body.id, // 要渲染的 Composition id inputProps: body.inputProps, // 标题文本等 framesPerLambda: 10, downloadBehavior: { type: "download", fileName: "video.mp4" }, });

注意functionName不是硬编码,而是通过speculateFunctionName()根据DISK/RAM/TIMEOUT计算——这保证了API 路由找到的正是deploy.mjs部署出来的那个函数,二者永远使用同一份config.mjs,修改配置后只要重新部署即可保持一致。

查询进度src/pages/api/lambda/progress.ts 调用getRenderProgress(),把低层状态翻译成前端友好的三态:

  • fatalErrorEncountered{ type: "error", message }
  • done{ type: "done", url, size }
  • 否则 →{ type: "progress", progress: Math.max(0.03, overallProgress) }(下限 0.03,保证进度条不会停留在 0 造成“没反应”的错觉)。

请求与响应的 zod schema 集中在 types/schema.ts:RenderRequest校验{ id, inputProps }ProgressRequest校验{ bucketName, id }

六、视频端:Composition 注册与示例动画

Remotion 侧入口 src/remotion/index.ts 调用registerRoot(RemotionRoot);Root.tsx 注册了两个 Composition:

  • MyComp:1280×720、30fps、200 帧,即主示例视频;
  • NextLogo:140×140、300 帧,Logo 独立动画。

参数常量集中在 types/constants.ts:COMP_NAME = "MyComp"DURATION_IN_FRAMES = 200VIDEO_WIDTH = 1280VIDEO_HEIGHT = 720VIDEO_FPS = 30,Props schema 为{ title: string },默认标题 “Next.js and Remotion”。

示例视频本体 src/remotion/MyComp/Main.tsx 是一段很典型的 Remotion 动画代码:用spring驱动 Logo 退场(damping: 200delay2 * fps帧开始),用两个Sequence控制“Logo/光环”与“标题淡入”的时间轴;字体来自@remotion/google-fonts/InterloadFont()(400/700 字重)。标题文字的“擦除式”进场由 TextFade.tsx 实现——它把spring进度经interpolate映射为 mask 渐变的左右端点,产生从左到右渐显的动效。

这一整块src/remotion正是「改变视频模板后需要重新部署 bundle」的那部分代码,与后面的部署流程直接相关。

七、config.mjs:Lambda 渲染的共享配置

config.mjs 是整个云端渲染的“唯一事实源”,导出 5 个值:

变量默认值含义
REGION"us-east-1"AWS 区域,编辑器可提示全部合法值(AwsRegion类型)
SITE_NAME"my-next-app"site bundle 在存储桶中的名称,也是serveUrl
RAM3009Lambda 内存(MB)
DISK10240Lambda/tmp磁盘(MB,即 10 GB)
TIMEOUT240单次函数调用超时(秒)

RAMDISKTIMEOUT三个值会在deploy.mjsdeployFunction()和 API 路由的speculateFunctionName()两处同时使用:前者按此规格创建函数,后者据此推导函数名。因此若直接修改config.mjs,必须重新运行部署脚本,保证实际函数规格与函数名同步更新。

八、deploy.mjs:一键完成“函数 + 存储桶 + Bundle”部署

deploy.mjs 依次执行三件事:

  1. deployFunction({ createCloudWatchLogGroup: true, memorySizeInMb: RAM, region: REGION, timeoutInSeconds: TIMEOUT, diskSizeInMb: DISK })—— 创建(或复用)渲染函数,输出函数名与(created)/(already existed)
  2. getOrCreateBucket({ region })—— 创建(或复用)S3 存储桶,Lambda 渲染的中间产物与最终视频都存放在此;
  3. deploySite({ bucketName, entryPoint: path.join(process.cwd(), "src", "remotion", "index.ts"), siteName: SITE_NAME, region: REGION })—— 将src/remotion/index.ts作为入口打包并上传 bundle。

脚本开头会做环境变量守卫(deploy.mjs):若同时缺失AWS_ACCESS_KEY_ID/REMOTION_AWS_ACCESS_KEY_ID(及对应的 secret 变量),则提示先去完成 Lambda 设置并以退出码 0 结束,而不是在未配置密钥时报晦涩的 AWS 错误。运行:node deploy.mjsnpm run deploy

README 特别提醒:以下三种变更之后都应重跑该脚本

  • 修改了视频模板(src/remotion下的 Composition 代码);
  • 修改了config.mjs(区域、内存、超时、site 名等);
  • 将 Remotion 升级到了新版本。

这也与脚本结尾的提示文案一一对应(deploy.mjs)。

九、启用 AWS Lambda 云端渲染(三步走)

  1. 复制环境变量样例并填充密钥:将 .env.example 复制为.env
    REMOTION_AWS_ACCESS_KEY_ID="" REMOTION_AWS_SECRET_ACCESS_KEY=""

    在 AWS 上完成 IAM/凭据开通后填入这两个变量。.env*.local已被 .gitignore 忽略,密钥不会进入版本库。deploy 脚本与 API 路由(render.ts)同时兼容AWS_*REMOTION_AWS_*两种变量名,并给出缺失时的中文指引式报错。

  2. 按需编辑config.mjs的区域、内存与超时等参数。
  3. 运行node deploy.mjs,脚本会创建渲染函数与存储桶并上传 bundle,直到输出 “You now have everything you need to render videos!”。

如果你计划把前端部署到 Vercel,模板自带的 vercel.json 已把构建命令设为node deploy.mjs && next build——即在构建前端之前先确保云端函数与 bundle 就绪,避免线上访问渲染接口时发现函数尚未创建。

十、本地渲染与 Studio:不需要 AWS 也能出片

云端渲染适用于生产环境;日常开发迭代可以用两种本地方式:

  • npx remotion studio打开 Remotion Studio,逐帧编辑动画、调试合成参数(时长/尺寸/帧率在 types/constants.ts 修改);
  • npx remotion render在本地用无头 Chromium 直接输出 MP4,适合 CI 与无 AWS 环境下的快速验证。

前端、Studio、本地渲染、Lambda 渲染复用同一套 Composition 代码与常量定义,这也是本模板前后端一致的架构基础。

十一、小结:模板给你划好的三条边界

读完本模板能清晰看到 Remotion 官方对“视频生成 SaaS”推荐的工程边界:

  1. 视频内容与产品解耦src/remotion只负责“画面”,通过 zod Props 与外部交互,替换业务视频只需改这个目录并重跑node deploy.mjs
  2. 前端与渲染解耦:Next.js API 路由薄薄一层,负责鉴权/参数校验/调度,云端渲染细节收敛在@remotion/lambda
  3. 配置集中config.mjs+.env分别管理非敏感参数与密钥,deploy.mjs与 API 路由永远基于同一份配置推导函数名与参数,避免“部署 A 规格、调用 B 规格”的错位。

License 方面,Remotion 对部分实体企业使用另有要求,详见仓库根目录 LICENSE.md。

【免费下载链接】remotion🎥 Make videos programmatically with React项目地址: https://gitcode.com/GitHub_Trending/re/remotion

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询