retrospective.md 5.0 KB

复盘:纯原生 ESM × Lit 3.x,对标 Angular zoneless

本文记录技术选型的动机、取舍与现代对标,作为规则背后的「为什么」。 结论先行:在内部中后台场景,这套无构建方案以更少的心智负担,达成了 Angular zoneless 想达成的目标。

一、我们想要什么(对标面)

新版 Angular 的几个现代卖点,正是内部后台长期缺的东西:

Angular 现代能力 我们要的等价物
zoneless(无 Zone.js) 没有全局猴子补丁,更新精确、可预测
Signals 细粒度响应式,改一个值只重渲依赖它的地方
DI(inject) 依赖注入,组件树拿到服务
Standalone 组件 组件即自定义元素,随处 import 即用
干净路由(无 hash) History 路由,OAuth 友好
组件样式隔离 Shadow DOM 原生隔离

二、Angular vs 本方案:逐项对照

维度 Angular(Zone + Signals) Lit 原生 ESM + Signals
构建 必须 ng build(编译 TS/模板) 无构建,源码即产物
变更检测 Zone.js 打补丁 → 框架调度;zoneless 后靠 Signal 图 无 Zone,Signal 直接驱动订阅者
依赖分发 打包进 bundle Repose 统一托管,一次上传全业务复用
组件模型 装饰器 + 模板 DSL(框架私有) 标准 Web Components + 标准模板字面量
样式隔离 ViewEncapsulation(模拟/Shadow) Shadow DOM 原生
路由 @angular/router 自写 utils/router.js(History;子路径部署弃用 @lit-labs/router)
DI 框架 DI 容器 @lit-labs/context(轻)或直接 import 单例
心智模型 框架概念多(模块/组件/指令/管道…) 浏览器原生 API,概念少
升级成本 框架版本强绑定 只升级 lit 版本号(改 importmap)
产物透明度 打包黑盒 无黑盒,模块即文件

三、为什么「无 Zone」在这里成立

Angular 需要 Zone.js 是因为它要拦截所有异步 API(setTimeout/Promise/XHR/事件), 在异步完成后触发全局变更检测——代价是全局猴子补丁 + 大范围 check。

本方案的响应式来源是显式的 Signal:

  • 状态放进 signal();组件读取时订阅;.set() 时精确通知读过的组件。
  • 没有隐式依赖跟踪全局,没有「任何异步都触发全树 check」。
  • 副作用用 effect() 显式声明。

结论:Signal 本来就是 zoneless 的前提,Lit + signals 是天然的 zoneless 组合。

四、取舍与代价(诚实的部分)

得到 代价
无构建、保存刷新即见 失去 tree-shaking / minify / 代码分割(靠 HTTP/2 + importmap + 缓存缓解)
依赖不打包 浏览器发起的模块请求更多(HTTP/2 多路复用)
标准 Web Components 无框架级 TS 模板类型检查(本地 npm i 仅为提示)
概念少 需要团队懂原生 ESM / 浏览器语义(如 CORS、MIME、History)
Shadow DOM 隔离 全局主题需用 CSS 自定义属性穿透

适用边界:内部中后台、组件复用、快速迭代——预算充足。重 SEO / SSR 的站点仍应上框架。

五、与「传统打包 SPA」的实际收益对比

环节 传统打包 本方案
改一行代码到看见效果 触发 rebuild(秒~分钟级) 刷新浏览器
依赖升级 重新 build 全量 改 importmap 版本号
多项目共享组件 各自打包发 npm Repose 共享,改一处全生效
调试 sourcemap 还原 源码即运行的代码,无映射
部署 上传 dist 上传 src/(无构建产物)

六、可迁移到其他场景的判断表

你的项目 建议
内部工具 / 运营后台 / 数据看板 ✅ 本方案
组件库 / 设计系统 ✅ 本方案(Web Components 天然跨栈复用)
活动页 / 嵌入页(体积敏感、迭代快) ✅ 本方案
内容站 / 电商前台(SEO 首屏) ❌ 用带 SSR 的方案(Astro 等)
超大型多团队应用,强 TS 类型约束 ⚠️ 可用,但需团队接受「无构建期类型检查」的约束

七、经验总结

  1. 构建的收益主要在「优化」,不在「能用」。当网络条件(HTTP/2 + CDN)与缓存补齐后,无构建对内部后台是净收益。
  2. Signal 是响应式的现代答案,它让「无 Zone」不是妥协而是更优——Angular 自己也在往这走。
  3. 标准 > 框架私有:Web Components + 原生 ESM 的产出,十年后仍能跑;框架 DSL 迭代则需跟着升级。
  4. 分层是纪律问题,不是技术问题:无框架约束时,靠规则(本仓)与评审守住「组件只渲染、服务管业务」。
  5. 部署细节是最大的坑:CORS / MIME / History 回退 / base href——这些与代码无关,却决定成败,务必进 checklist。