news 2026/9/21 2:40:52

Redwood 构建指南:深入理解 `yarn rw build` 的 API 与 Web 双端生产构建流程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Redwood 构建指南:深入理解 `yarn rw build` 的 API 与 Web 双端生产构建流程

Redwood 构建指南:深入理解yarn rw build的 API 与 Web 双端生产构建流程

【免费下载链接】redwoodRedwoodGraphQL项目地址: https://gitcode.com/gh_mirrors/re/redwood

本文基于 Redwood 官方文档 Builds 展开,系统讲解 Redwood 框架生产构建的全过程:API 侧如何被转译进./api/dist、Web 侧如何被 Vite 打包进./web/dist,并顺带还原zip-it-and-ship-it在 Netlify 上的 Lambda 打包实践。读完本文,你将掌握yarn rw build各选项的准确含义、底层构建任务的实际执行顺序,以及如何在本地复现 Netlify 的构建与函数打包流程。

构建概览:一条命令,两个产物目录

Redwood 是一个前后端一体的全栈框架,一个项目中同时包含api(服务端)与web(浏览器端)两个 side。生产构建命令将它们分别处理,最终产出两套相互独立的构建产物:

Side构建工具产物目录产物用途
apiBabel(由 esbuild 驱动)./api/dist服务端代码、GraphQL 服务、Serverless 函数
webVite./web/dist静态资源、SPA / SSR 页面

这个结论同时被 Builds 文档与 cli-commands.md 的 build 小节 明确记载:"We use Babel to transpile the api side into./api/distand Vite to package the web side into./web/dist."

在命令行中,build子命令支持限定构建范围,位置参数side..表示可以传入一个数组(yargs 的 variadic positional arguments):

yarn rw build # 默认构建 api 与 web 两侧 yarn rw build api # 只构建 API 侧 yarn rw build web # 只构建 Web 侧 yarn rw build api web # 显式指定构建两侧

对应的命令定义位于 packages/cli/src/commands/build.js:command = 'build [side..]'description = 'Build for production'。命令还通过.middleware()检查 Node 版本,版本不满足要求时会直接报错退出,这是rw build在生产机与 CI 上稳定运行的第一道保障。

rw build的完整参数表

与 Builds 配套的 CLI 参考文档 cli-commands.md 记录了基础参数,而命令的实际实现 build.js 中还包含文档表格之外的重要选项。合并两者,得到完整的参数说明:

参数 / 选项类型默认值说明
sidearray['api', 'web']要构建的 side,可选值为apiweb,可同时传多个
--verbose, -vbooleanfalse输出更多构建信息,同时让 Listr 任务渲染器进入 verbose 模式
--prerenderbooleantrueWeb 构建完成后是否执行预渲染;对未标记 prerender 路由的项目会给出提示
--prisma, --dbbooleantrue是否生成 Prisma Client;在 api 侧存在schema.prisma且构建 api 或存在预渲染路由时生效

其中--prisma--prerender在 buildHandler.js 的 handler 签名中有默认值定义。注意一个实用的细节:--prerender的默认值是true,如果只想"纯打包"不做预渲染,需要显式传--no-prerender;同理--prisma对应--no-prisma

API 侧构建:Babel 转译与./api/dist

构建流程:先清空,再转译

API 侧的构建入口是 packages/internal/src/build/api.ts。整个流程分为两步:

  1. cleanApiBuild():直接调用fs.remove(rwjsPaths.api.dist)清空旧的./api/dist目录(见 api.ts 第 38-41 行),保证产物目录内不会残留上次构建的过期文件;
  2. buildApi()/transpileApi():通过 esbuild 的build()API 转译全部 API 源码文件(见 api.ts 第 19-26 行)。

值得注意的是,文档中"api side is transpiled by Babel"的描述在实现上更精确地说应该是:esbuild 负责文件遍历与打包编排,Babel 负责真正的代码转换。esbuild 通过自定义插件runRwBabelTransformsPlugin(见 api.ts 第 43-72 行),对每个.js/.ts/.tsx/.jsx文件调用@redwoodjs/babel-config提供的transformWithBabel,并把转换后的代码以loader: 'js'交还给 esbuild 输出。

esbuild 关键构建选项

getEsbuildOptions() 揭示了产物形态的关键约束:

  • platform: 'node'target: 'node20':产物面向 Node.js 20 运行环境;
  • bundle: false:API 侧不做依赖打包,node_modules 中的依赖在部署时按需安装或由平台处理;
  • format:根据项目配置动态选择esmcjsprojectSideIsEsm('api')),即项目可以按 ESM 或 CJS 风格产出;
  • sourcemap: true:同时生成.js.map外部 sourcemap 并写入sourceMappingURL注释,便于线上排查错误;
  • outdir: rwjsPaths.api.dist:产物统一输出到./api/dist

GraphQL Schema 校验前置步骤

在真正开始转译 API 代码之前,构建任务还会先执行loadAndValidateSdls对 GraphQL SDL 文件做一次校验(见 buildHandler.js 第 71-74 行)。如果 schema 定义存在错误,构建会在产出任何 API 代码前就失败,从源头拦截有问题的 GraphQL 层。

Web 侧构建:Vite 打包与./web/dist

构建入口与两种模式

Web 侧构建由独立的可执行文件 packages/vite/bins/rw-vite-build.mjs 驱动,buildHandler通过execa以子进程方式调用它,并把process.cwd切换到 web 目录。这样做的原因在 buildHandler.js 的注释 中写得很清楚:postcss / tailwind 等工具依赖正确的 cwd 才能解析配置,而把 cwd 变化隔离在子进程中,可以避免影响构建进程内其他并行的任务。

根据是否启用 Streaming SSR,构建走两条不同路径:

  • 普通 SPA 模式experimental.streamingSsr.enabled为 false):调用buildWeb(),即 packages/vite/src/build/build.ts 中的 buildWeb,本质是调用 Vite 的build(),并显式传入configFile: rwjsPaths.web.viteConfig(即web/vite.config.{js,ts})与envFile: false
  • Streaming SSR 模式:调用buildFeServer(),产物面向服务端渲染场景。

rw-vite-build.mjs启动时会做三重防御性检查:必须传入--webDir、目录必须真实存在、目录内必须有package.json,否则直接报错退出(见 rw-vite-build.mjs 第 17-32 行)。

产物目录与 200.html 约定

普通 SPA 模式下,构建产物输出到./web/dist。构建完成后还有一步容易被忽略的收尾:复制index.html200.html(见 buildHandler.js 第 119-129 行)。这是为 Serverless / 静态托管平台的 SPA fallback 准备的——当用户直接访问/some/route这类深层路径时,平台会回退到200.html再由前端路由接管。Streaming SSR 模式不使用index.html,因此会跳过这一步骤。

Web 构建前还会清理旧的./web/distweb预构建目录(cleanWebBuild,见 build.ts 第 12-16 行),确保产物干净一致。

构建前的准备任务:Prisma Client 与代码生成

rw build不是简单地"翻译源码",在正式构建之前,buildHandler.js 会按序执行一系列准备任务:

  1. 生成 Prisma Client(条件:--prisma开启、存在api/db/schema.prisma、且本次构建涉及 api 侧或有预渲染路由):通过generatePrismaCommand构造prisma generate命令并在 api 目录执行;
  2. 为 GraphQL Fragments / Trusted Documents 生成类型(条件:redwood.tomlgraphql.fragmentsgraphql.trustedDocuments开启):调用generate()运行 codegen,生成 possible types 与 trusted document store 的哈希,供运行时使用。

这一顺序在构建测试 packages/cli/src/commands/tests/build.test.js 中有明确断言,完整任务序列为:

Generating Prisma Client... Verifying graphql schema... Building API... Building Web...

预渲染(Prerender):Web 构建后的可选步骤

--prerender开启且构建范围包含 web 侧时,构建主流程结束后会触发triggerPrerender()(见 buildHandler.js 第 134-154 行):

  • 它先用detectPrerenderRoutes()扫描Routes文件中标记了prerender的路由;
  • 若没有任何路由标记prerender,则打印提示 "You have not marked any routes to 'prerender' in your Routes",并不会报错;
  • 若存在预渲染路由,则以独立子进程运行yarn rw prerender

之所以用独立子进程,注释里给出了重要原因:由于 Node 的模块缓存(require module caching),必须在独立进程里运行才能正确加载刚生成的 Prisma Client

对应地,测试 build.test.js 第 77-92 行 验证了"只构建 web + 开启 prerender + 无预渲染路由"场景下,控制台会依次打印Starting prerendering...与未标记 prerender 的警告。

在 Netlify 上:本地复现 Lambda 打包流程

Builds 文档专门给出了在本地模拟 Netlify 构建步骤的命令,这是理解 Serverless 部署形态的关键:

yarn rw build api cd api yarn zip-it-and-ship-it dist/functions/ zipballs/

原理

  • yarn rw build api只构建 API 侧,产物位于./api/dist,其中每个 GraphQL 服务、每个自定义函数都会被转译为一个独立文件放在./api/dist/functions下;
  • zip-it-and-ship-it会逐个解析dist/functions/下的 Lambda 函数文件,为每个 Lambda 函数生成一个 zip 包,zip 包内包含该函数运行所需的全部依赖,输出到zipballs/目录。

这正是 Serverless 部署的核心诉求:平台只安装每个函数自己需要的依赖,而不是把整个项目的node_modules都塞进去,从而显著减小函数体积、加快冷启动。

前置安装

@netlify/zip-it-and-ship-it需要作为 api side 的开发依赖安装:

yarn workspace api add -D @netlify/zip-it-and-ship-it

关于 zip 的产物最终如何被 AWS Lambda / Netlify Functions 消费,可进一步参阅 deploy/serverless 文档(即原文档中指向的 "AWS Serverless Deploy" 说明)。

从源码看函数的产出方式

API 侧转译后的目录结构由findApiFiles()与 esbuild 的 entryPoints 决定(见 api.ts 第 74-96 行):所有 API 源文件都被作为独立 entry point 转译到api/dist,函数目录对应api/src/functions,因此每个函数在dist/functions中都有独立产物,这正是 zip-it-and-ship-it 能按函数粒度打包的前提。

与部署环节的衔接

rw build的产物是部署的输入,Redwood 针对不同平台的部署命令本质上都是"先构建、再按平台规则上传/打包":

  • Serverless 平台(Netlify / Vercel / AWS Lambda):如上文所述,API 侧按函数粒度 zip,Web 侧上传./web/dist静态资源,并依赖200.html实现 SPA fallback;
  • Baremetal / Docker 自托管:需要完整的服务端产物,部署模板中同样会先执行 build 步骤。

Redwood 还提供了yarn rw deploy <provider>命令族(见 packages/cli/src/commands/deploy),这些命令在内部都会以rw build的产物为基础完成上传,而 deploy/helpers.js 中也能看到对 build 命令的引用,印证了"构建是部署前置依赖"这一关系。

小结:一次构建的全景时间线

综合文档与源码,一次完整的yarn rw build(双端、默认参数、存在 schema.prisma)实际执行的是:

  1. 生成 Prisma Client(如需要);
  2. 为 Fragments / Trusted Documents 生成类型(如配置开启);
  3. 校验 GraphQL schema(api 侧);
  4. 清空并转译 API 代码到./api/dist(Babel + esbuild,Node 20 目标);
  5. 通过rw-vite-build.mjs子进程构建 Web 到./web/dist,并复制出200.html(非 SSR 模式);
  6. 若有预渲染路由,子进程执行yarn rw prerender

如需在本地观察每一步的具体行为,可加--verbose运行;想跳过 Prisma Client 生成则用--no-prisma,想跳过预渲染则用--no-prerender。相关源码与测试可继续深入阅读 buildHandler.js、build/api.ts、rw-vite-build.mjs 以及 build.test.js。

【免费下载链接】redwoodRedwoodGraphQL项目地址: https://gitcode.com/gh_mirrors/re/redwood

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/21 2:40:29

威胁情报与资产测绘联动:分行业落地指南与攻防实战解析

简介&#xff1a;《威胁情报下资产测绘的关键行业分析》是一份解决方案型演示文稿&#xff0c;面向网络安全工程师、威胁情报分析人员及行业信息化管理者。内容围绕威胁情报落地资产治理展开&#xff0c;覆盖资产梳理、僵尸/双非系统清理、备案体系、漏洞评估、等级保护、立体化…

作者头像 李华
网站建设 2026/9/21 2:32:17

从选型到自建:一套开源科研AI工作台的完整实践

如果现在有人问我&#xff0c;科研AI到底该选哪个&#xff0c;我的答案挺干脆&#xff1a;过去两年&#xff0c;我把市面上的主流AI工具、开源模型、本地部署方案都折腾过一遍&#xff0c;最后真正留在日常科研工作里的&#xff0c;只有一个平台。不是因为它名字最大&#xff0…

作者头像 李华
网站建设 2026/9/21 2:30:50

研发项目管理软件怎么选?12款主流工具横向对比与选型指南

做研发项目管理软件选型这件事&#xff0c;我前后经历过好几轮。从最初团队十来个人的时候大家挤在Excel里填进度&#xff0c;到现在几十号人并行推进多条产品线&#xff0c;工具换了好几茬&#xff0c;踩过的坑能写满一页纸。每次遇到团队问我“到底该用哪款研发项目管理软件”…

作者头像 李华
网站建设 2026/9/21 2:29:14

全渠道客服系统选型实战:畅远系统体验与避坑指南

做客服系统选型的这几个月&#xff0c;我被问得最多的一句话就是&#xff1a;“到底有没有靠谱的全渠道客服系统推荐&#xff1f;”问的人里有电商运营负责人&#xff0c;有SaaS公司的售后主管&#xff0c;也有刚把客服团队扩到三十人的创业公司老板。大家的需求其实都差不多&a…

作者头像 李华