如何在同一仓库内让新模块用 Vite、旧模块用 Grunt
解读
面试官真正想考察的是:
- 你是否理解双构建体系共存带来的路径解析、依赖隔离、产物输出、脚本命令、CI/CD 五类冲突
- 能否给出可落地的渐进式迁移方案,而不是“一刀切”重写
- 对国内常见场景(如私有 Nexus、企业微信/钉钉机器人通知、 Jenkins/蓝绿发布)是否有工程化经验
知识点
- Monorepo 策略:pnpm workspace / Yarn workspace / Nx / Lerna,锁定node_modules结构,避免依赖版本漂移
- 路径别名隔离:Vite 用resolve.alias,Grunt 用grunt-contrib-requirejs的paths或browserify的aliasify,保证新旧模块互相不穿透
- 产物输出隔离:Vite 默认dist,Grunt 传统build;统一在gitignore里忽略,并在package.json的files字段白名单发布
- 脚本命令命名规范:国内团队普遍采用npm run dev:vite、npm run dev:grunt区分,CI 阶段用npm run build:all串行或并行
- 环境变量开关:借助cross-env设置BUILDER=vite|grunt,让postbuild钩子做差异化上传(OSS、CDN、Docker 镜像)
- 共享底层能力:把ESLint/Stylelint/Prettier抽成**@scope/lint-config包,供两种构建消费,保证代码质量网关**唯一
- 灰度发布:在Nginx层按Cookie/Header分流,旧模块map到grunt-legacy.xxx.js,新模块map到vite-modern.xxx.js,实现0 downtime切换
- 性能监控:接入Sentry或阿里 ARMS,在sourcemap上传阶段区分project=legacy与project=vite,方便回滚
答案
“我去年在某头部电商金融项目做过类似改造,核心思路是**‘目录隔离+脚本双轨+产物双出口+CI 并行’**:
-
目录隔离
在Monorepo根目录下建packages/legacy与packages/modern,分别放 Grunt 与 Vite 代码;tsconfig、eslint、postcss配置全部下沉到各自包,根目录只做最小化继承,避免幽灵依赖 -
脚本双轨
根package.json定义:"scripts": { "dev:legacy": "pnpm --filter legacy run grunt:dev", "dev:modern": "pnpm --filter modern run vite", "build:all": "pnpm --parallel --filter './packages/**' run build" }本地开发时,终端 1跑npm run dev:legacy(监听8080),终端 2跑npm run dev:modern(监听5173),Nginx用proxy_pass按路径前缀转发
-
产物双出口
统一在CI里把legacy/dist与modern/dist拷贝到release/${BUILD_NUMBER}/static下,Jenkins调用ossutil一次性上传,CDN路径带v=legacy|modern版本号,回滚只需切换CDN 目录软链 -
渐进式迁移
先迁移活动页这类低频迭代模块,验证2 个 Sprint无PV 下跌后,再迁移核心下单链路;每迁移一个模块,就把该模块从Gruntfile.js的files 数组里删除,Vite 配置里新增rollupOptions.input,保证构建产物不会重复打包 -
风险兜底
在Nginx层加feature-toggle:map $cookie_builder $js_root { default //static-legacy.example.com; vite //static-modern.example.com; }一旦Vite 产物出现白屏,运维把Cookie 开关切回Grunt,1 分钟内完成回滚
通过这套方案,我们把70 万行遗产代码的首屏 JS 体积从1.8 MB降到480 KB,本地冷启动从45 s降到3 s,线上故障率保持0,并且零裁员完成技术栈过渡。”
拓展思考
- 微前端是否值得引入:若旧模块是jQuery+artTemplate,新模块是Vue3+TS,可用qiankun做运行时集成,但沙箱隔离会带来30% 性能损耗,在ToB 后台场景可接受,ToC 高并发场景建议构建时集成
- 双构建导致sourcemap上传量翻倍,可只在主干分支保留完整 map,功能分支用hidden-source-map,减少Sentry 套餐费用
- 国内私有 npm常出现vite 插件同步延迟,可搭cnpm镜像并配置VITE_PLUGIN_PROXY=https://registry.npmmirror.com**,避免**CI 拉包失败
- 未来彻底下线 Grunt的判定指标:连续3 个版本无legacy 目录提交,且监控大盘显示Grunt 产物请求量<1%,即可在迭代评审会上提出下线计划,删除相关仓库、脚本、域名、CDN 目录,完成技术债清零