微前端?县城做题家在上海搞大项目的一地鸡毛实录

产品和代码之间
2025-12-17 06:51
阅读 1758

大家好,我是老张(不是那个卖烤红薯的老张),一个从三线小县城一路“卷”到上海的小镇做题家。目前在一家中型互联网公司远程办公——虽然说是远程,但其实就租了个离公司步行十分钟的房子,毕竟“远程”两个字听起来高级点,实际不过是老板省了办公室空调费罢了。

平时不用 VS Code,Vim 是我的命根子(别问为什么,问就是 :wq 有信仰)。最近半年被拉进一个“史诗级”重构项目:把一个单体前端应用拆成微前端架构。说白了,就是领导看了几篇 GitHub 热榜文章,拍脑袋说:“我们要解耦!要独立部署!要‘乐高式开发’!” —— 于是,我这个刚搞定 CSS 动画帧率优化的“交互小能手”,就被扔进了微前端的深水区。

今天不吹技术牛逼,就说说这一路踩过的坑、熬过的夜、和产品经理互相伤害的故事。如果你也在县城老家刷 GitHub 想跳槽来大城市搞大项目,这篇文章可能就是你的前车之鉴。


起因:不是我想搞微前端,是 deadline 追着我跑

事情得从去年双11说起。我们公司那个主站,是个典型的“祖传代码”:React + Ant Design + 五年没人敢动的业务逻辑,打包出来快 8MB,首屏加载慢得像用 2G 刷抖音。更惨的是,五个业务团队共用一个 repo,改个按钮颜色都能引发 merge conflict 大战。

某天晨会,CTO 拿着手机刷 GitHub Trending,突然拍桌:“你们看看人家 qiankun 星标都 20k+ 了!我们还在搞 monolith?太 low 了!”
于是,微前端立项。目标很明确:各业务模块独立开发、独立部署、互不影响。理想很丰满,现实嘛……后面你就知道了。

作为团队里“对前端动画和交互比较敏感”的人(其实就是被排期时没跑掉),我成了微前端落地的主要 implementer。说实话,当时内心 OS 是:“我连 Webpack 配置都还没吃透,你让我搞微前端?”


第一关:资源隔离?别闹了,JS 全局变量比亲戚还亲

微前端最怕什么?样式污染全局状态冲突。我们主应用用的是 React 17,而一个老保险模块还在用 Vue 2 + jQuery(别笑,真有)。第一次集成测试那天,我信心满满地跑起本地 dev server,结果页面一加载——按钮全变蓝了,下拉框疯狂闪烁,控制台报错:

Uncaught TypeError: Cannot read property 'map' of undefined

查了半天,发现是子应用偷偷往 window 上挂了个 config 对象,结果主应用也用了同名变量,直接覆盖了。那一刻我真的想砸电脑。

后来我们定了三条“军规”:

  1. 所有子应用必须沙箱化:qiankun 的 sandbox: { strictStyleIsolation: true } 必开,虽然性能有点损耗,但至少 CSS 不会串门。
  2. 禁止往 window 挂东西:谁再这么干,团建请全组喝奶茶。
  3. 公共资源统一管理:比如 lodash、moment.js 这些,由主应用提供,子应用通过 shared 机制消费,避免重复加载。

说到资源,这里有个血泪教训:子应用的静态资源路径必须绝对路径!否则在主应用路由下加载子应用时,图片、字体全 404。我们后来统一约定所有子应用部署到 /subapp-xxx/ 路径下,并在构建时注入 publicPath

// webpack.config.js
output: {
  publicPath: process.env.NODE_ENV === 'production' 
    ? 'https://cdn.yourcompany.com/subapp-insurance/' 
    : '/'
}

不然线上用户看到的页面,就是一堆占位图配文字:“加载失败,请联系客服”——而客服根本不知道前端改了架构。


第二关:GitHub 不是万能的,但没它真不行

微前端涉及多个 repo 协同,这时候 GitHub 就成了我们的“救命稻草”。每个子应用单独一个 repo,主应用一个 repo,再加一个 shared-components 库。但问题来了:如何同步依赖版本?

一开始我们各自升级 React,结果主应用 React 17,子应用 React 18,一集成就报 hooks 错误。后来学乖了,在 GitHub 上建了个 frontend-monorepo-spec 文档,明确规定:

依赖 版本 负责人
React 17.0.2 主应用团队
Ant Design 4.24.0 UI 组件组
qiankun 2.10.10 架构组

每次升级都要 PR + 团队评审。虽然流程繁琐,但至少避免了“我在本地跑得好好的,上线就崩”的经典场景。

另外,GitHub Actions 也帮了大忙。我们给每个子应用配了 CI,只要 push 到 main 分支,自动构建并推送到 CDN。主应用通过配置文件动态加载最新子应用地址:

// apps.json
[
  {
    "name": "insurance",
    "entry": "https://cdn.yourcompany.com/subapp-insurance/latest/index.html"
  }
]

这样,子应用发版再也不用等主应用重新部署——产品经理终于不用半夜打电话骂我了(感动)。


第三关:用户体验?别忘了前端是给人用的!

很多人搞微前端只关心架构,却忘了用户根本不在乎你是不是微前端。他们只关心:页面快不快?动效流不流畅?会不会白屏?

我们第一次上线,子应用切换时整个页面 reload,产品经理当场暴怒:“这还不如以前呢!” 后来我们做了三件事:

  1. 预加载子应用:在主应用空闲时(比如用户看 banner 广告时),悄悄 fetch 子应用的 entry HTML 和 JS。
  2. 骨架屏兜底:子应用加载期间,显示对应模块的骨架屏,避免白屏。
  3. 动画过渡:用 CSS transform 做淡入淡出,而不是生硬的 display: none/block。毕竟我可是靠动画吃饭的人(笑)。

性能方面,我们用 Lighthouse 测了一波:

指标 单体应用 微前端(优化后)
FCP 2.8s 2.1s
TTI 5.3s 3.9s
Bundle Size 7.8MB 主应用 1.2MB + 按需加载

关键点在于:主应用轻量化,子应用按路由懒加载。用户进首页,只加载首页相关子应用,其他模块等点击再加载。

不过浏览器兼容性还是个坑。qiankun 依赖 Proxy,IE11 直接躺平。最后我们不得不为 IE 用户降级:走传统 iframe 方案(别打我,业务需求…)。还好现在 IE 流量不到 0.3%,勉强能接受。


调试?Vim + Chrome DevTools 才是真·生产力

作为 Vim 党,我坚决不用 IDE 的图形化调试器。微前端调试最烦的是:子应用的 sourcemap 在主应用里找不到

解决方案?简单粗暴:

  1. 本地开发时,所有子应用启动在不同端口(3001, 3002...)
  2. 主应用配置 proxy,把 /subapp-insurance 代理到 http://localhost:3001
  3. Chrome DevTools 里 Sources 面板手动添加 workspace folder,映射到本地子应用源码

这样就能直接打断点、看变量,和单体应用体验差不多。唯一的问题是:每次新加子应用,都得改主应用的 proxy 配置——运维同事说我改配置的频率比他改 nginx 还勤。


总结:微前端不是银弹,但也不是毒药

折腾半年,项目终于稳定上线。现在各团队可以并行开发,保险模块上周五晚上加班发版,完全不影响电商模块第二天搞 618 活动。虽然偶尔还有样式冲突的小 bug,但比起以前“牵一发动全身”的恐惧,已经幸福太多。

几点真心话:

  • 别为了微前端而微前端:如果团队就三个人,业务也不复杂,老老实实用 monorepo 吧。
  • 自动化是生命线:CI/CD、依赖管理、错误监控,缺一不可。
  • 用户体验永远第一:架构再漂亮,用户觉得卡,等于零。

最后,感谢 GitHub 上那些开源作者,没有 qiankun、single-spa 这些项目,我们可能还在手动拼 HTML。也感谢我那台服役五年的 MacBook,上周五凌晨三点还在跑 webpack,风扇声比蚊子叫还响——但它没炸,真争气。

如果你也在县城刷 GitHub,梦想着来上海搞大项目,我想说:技术没有高低贵贱,县城做题家也能写出优雅的代码。只是记得,别信领导嘴里的“简单重构”,那往往意味着一个月的加班和无数杯瑞幸。

好了,我去改产品经理刚提的“微前端里加个粒子动效”需求了。他说“就改一行代码”。呵呵。

(完)

评论 0

最热最新
暂无评论
产品和代码之间Lv.1
0
影响力
0
文章
0
粉丝