从 PDR 到落地:用 Codex 完成一次 Rspack 升级

最近我把一个有接近 10 年历史的移动端老项目,从 roadhog / Webpack 3 升级到了 Rspack。这个项目不算新:React 16、dva、antd-mobile v2/v5 混用、Less、CSS Modules、SVG sprite、EJS HTML 模板、CDN publicPath、旧式 alias 和移动端兼容策略都在里面。

这类升级最怕的不是"配置不会写",而是旧构建链路里有大量隐式行为。直接让 AI 生成一个 rspack.config.js 很容易跑通一个 demo,却破坏真实项目里的样式、图标、HTML 模板或部署路径。所以这次我没有从"写代码"开始,而是先让另一个 AI 扫描项目并生成 PDR。

我给它的提示词很简单:

text 复制代码
给我提供一份该项目构建工具升级到rspack 的pdr,提供给AI使用,并将 pdr 写入到 docs 目录中

这个 PDR 后来放在 docs/rspack-upgrade-pdr.md。它的价值不是告诉 AI 每一行代码怎么写,而是先把迁移边界讲清楚:旧构建里有哪些行为必须对齐,哪些依赖必须移除,哪些能力要用 Rspack 原生实现,哪些事情不应该顺手重构。

这个 PDR 也不是一次性生成后就不动了。迁移过程中我会不断让 AI 更新 PDR,把新的判断补进去。尤其有两条原则被反复强调:

  1. 必须升级到 Rspack 最新版本,可以配套升级相关工具链。
  2. 尽量利用 Rspack 去对齐 Babel 和 Webpack 配置;Rspack 无法直接对齐的地方,就在项目里自己写代码、loader 或插件来补齐。

这两条很重要。第一条避免了"为了少改而停在旧版本"的短期方案;第二条避免了"为了兼容旧行为继续套旧 Webpack/Babel 链路"的迁移陷阱。对一个 10 年历史的老项目来说,升级不是把旧配置搬家,而是用新工具重新表达旧行为。

拿到 PDR 后,我在 Codex 里开启了 /goal 模式,把这份文档直接变成持续执行目标:

text 复制代码
/goal 完成 [rspack-upgrade-pdr.md](docs/rspack-upgrade-pdr.md) 这个目标

这个动作很关键。普通问答更像一次请求一次响应,而 /goal 模式会让 Codex 围绕一个明确目标持续推进:读文档、拆任务、改代码、验证、处理新暴露的问题,直到目标真正收敛。

为什么先写 PDR

构建升级是典型的"上下文密集型"任务。老项目里真正重要的信息通常散落在不同位置:

  • .webpackrc.js 里有入口、Less theme、Babel 插件和 roadhog 行为。
  • webpack.config.js 里有 publicPath、DefinePlugin、HTML 模板注入、externals、SVG sprite、PostCSS 和压缩逻辑。
  • webpack.ide.js 这类文件可能只是为了 IDE alias,但删错了会影响开发体验。
  • 业务代码里还依赖 componentsassetsutils 这类非相对路径。

PDR 的作用,是把这些隐式知识变成执行约束。比如这次 PDR 明确要求:

  • 不能保留 roadhog / Webpack 3 双构建链路。
  • Rspack 原生优先,不为了兼容旧配置而继续套 Webpack 插件。
  • 旧行为必须对齐,包括 HTML 模板、Less、CSS Modules、SVG symbol、externals、alias、CDN 路径。
  • TypeScript 支持要打开,但不能强迫老 JS 业务代码一起迁移。
  • 包管理器切到 pnpm,Node 版本要求跟随最新 Rspack。

这些约束非常适合交给 Codex。PDR 负责定义"什么算完成",Codex 负责在真实仓库里把目标落地。

Codex 做的不只是生成配置

这次迁移里,Codex 的价值主要体现在三件事上。

第一,它会先读项目,而不是直接套模板。它从旧 roadhog / Webpack 配置里提取行为,再映射到新的 rspack.config.js:入口仍然是 src/index.js,输出仍然是 dist,production 和 test 的 CDN publicPath 保持不变,HTML 仍然复用 src/index.ejs,DefinePlugin 注入的 __DEV____TEST____PROD__ 等变量也继续保留。

第二,它会在构建中处理真实问题,而不是只给建议。迁移过程中遇到的问题并不少:

  • antd-mobile-v2 的 Less 使用了即将废弃的 inline JavaScript backtick 表达式。
  • Rspack 下 Less 规则拆分后,部分全局样式和 _base.less 没有按旧行为生效。
  • CSS Modules 的 localIdentName 需要和旧项目输出对齐。
  • CustomIcon 里的 SVG symbol 在 Rspack 下没有按原 SVG viewBox 正确缩放。
  • dayjs 默认英文,需要和原来的中文语境对齐。
  • IDEA 无法识别 alias,需要把 Rspack alias 同步到 tsconfig.json
  • 新版 Node 对 CommonJS require('@rspack/core') 加载 ESM 给出 ExperimentalWarning。

这些都不是 PDR 能完全预判的细节。Codex 的处理方式是每次只缩小一个问题:读代码、定位配置、做最小修改、跑构建验证,再继续下一个问题。

第三,它能把"不要这么做"的约束执行到代码里。比如 Less 的 warning 不能靠屏蔽日志解决,于是 Codex 针对 antd-mobile-v2 的 Less 包做预处理,并补了 Less 自定义函数来替代 inline JavaScript;SVG 问题也没有改业务图标,而是补了项目内 rspack-svg-symbol-loader,让 symbol 保留 viewBox、移除会干扰缩放的宽高属性。

迁移后的结构

最终核心脚本切到了 Rspack:

json 复制代码
{
  "start": "rspack dev",
  "build": "rspack build",
  "build:test": "ENV=test rspack build",
  "typecheck": "tsc --noEmit"
}

rspack.config.js 里主要保留了这些能力:

  • builtin:swc-loader 处理 JS / JSX / TS / TSX。
  • transformImport 对齐原来 babel-plugin-import 的按需导入行为。
  • CssExtractRspackPlugin 抽离 CSS。
  • HtmlRspackPlugin 配合一个模板参数适配器继续渲染旧 EJS。
  • Rspack asset modules 处理图片和普通 SVG。
  • 项目内 SVG symbol loader 对齐旧 svg-sprite-loader 的业务表现。
  • Less、PostCSS、pxtorem、CSS Modules 按旧项目规则拆分。
  • tsconfig.json 维护和 Rspack 一致的 alias,供 TypeScript 和 IDEA 使用。

在兼容策略上,项目也开始放弃过老 WebView,不再继续为 iOS 8 / Android 4 这类环境兜底。入口里的全量 core-js/stableregenerator-runtime/runtime 可以被移除,SWC target 和 autoprefixer 目标也随之上调。这个决策不是"为了新而新",而是先明确产品兼容边界,再让构建产物跟着边界收敛。

Codex 适合做这种升级的原因

这次体验下来,我觉得 Codex 最适合的不是一次性写一个大补丁,而是处理这种需要持续判断的工程任务。

它能把 PDR 变成执行清单。每个条目不是一句"已迁移",而是落到真实文件和真实命令上:配置怎么写、依赖怎么换、脚本怎么跑、产物怎么检查。

它能在仓库里保持上下文。比如修 Less 时需要同时理解 antd-mobile-v2、less-loader、CSS Modules 和 _base.less;修 CustomIcon 时需要同时看 SVG loader、React 组件和 antd-mobile v2 的 icon class;修 alias 时需要同时看 Rspack resolve.aliastsconfig.json

它也能把验证作为工作的一部分。每次调整后都跑最小必要命令,比如 pnpm typecheckpnpm buildpnpm build:test,并根据输出继续修。构建升级里最有价值的不是"AI 觉得没问题",而是每一步都有工具输出支撑。

更重要的是,Codex 能接受"不能这么修"的工程约束。不能直接屏蔽 warning,不能为了跑通引入 Webpack 旧插件,不能为了迁移重构业务代码,不能随手改部署路径。这些约束在普通聊天式 AI 里很容易被忽略,但对一个在仓库里执行任务的编码 Agent 来说,它们必须变成实际行为。

一个更有效的 AI 升级流程

这次迁移给我的最大启发是:复杂工程任务可以拆成两类 AI 工作。

第一类是规划型 AI:扫描项目,生成 PDR,提炼风险、边界、验收标准。它不急着写代码,而是先把"完成"的定义讲清楚。

第二类是执行型 AI:像 Codex 这样进入仓库,最好用 /goal 模式把 PDR 设成持续目标,然后按 PDR 逐项落地,遇到真实错误就调试,最后用构建和类型检查验证。

这比直接丢一句"帮我升级到 Rspack"更稳定。前者让 AI 有明确的任务合同,后者让 AI 有真实的工程反馈。PDR 负责减少方向性错误,Codex 负责减少落地过程中的手工摩擦。

最后得到的不是一份看起来正确的配置,而是一条可维护的新构建链路:Rspack 接管开发和生产构建,旧 roadhog / Webpack 3 行为被显式迁移,历史样式和图标问题被逐项处理,IDE 和类型检查也跟着对齐。

这才是我认为 AI 编程工具真正有价值的地方:不是替代工程判断,而是把工程判断执行得更完整、更快,并且每一步都能被验证。

这篇文章我也是让AI生成的 😄

相关推荐
程序员鱼皮1 小时前
提示词工程已死,Loop Engineering 称王!保姆级教程 + 项目实战
前端·后端·ai编程
小爷毛毛_卓寿杰2 小时前
给 Embedding 模型也加一块“游乐场“—— Xinference 是怎么把 vector 变成肉眼可见的体验的
前端
忆江南2 小时前
iOS 性能优化全面详解
前端
lichenyang4532 小时前
HAP / HAR / HSP 到底啥区别?顺带把「导入」那点疑惑讲清楚
前端
基德爆肝c语言2 小时前
MySQL表的操作
前端·数据库·mysql
秃头网友小李2 小时前
前端难点:Element Plus 样式覆盖 —— :deep()、CSS 变量与滚动状态类名
前端·vue.js
the_answer2 小时前
XSS 与 CSRF 深度解析
前端
打呵欠的猫2 小时前
AI 生成的代码你敢直接上线吗?我总结出 3 条铁律
前端·ai编程
极速蜗牛2 小时前
我在 Taro 小程序项目里实践的 API First + AI 编程方式
前端·人工智能·后端