找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

2121

积分

0

好友

297

主题
发表于 昨天 04:46 | 查看: 3| 回复: 0

我今天等构建结束,等了整整四十五秒。

我盯着那个不停转的转圈圈,思路断了。手机刷了两眼,等终端终于变绿,我已经忘了自己刚才到底在测什么。

我们一直把“编译慢”当成类型安全的门票,默认两百万行代码要检查,慢点很正常。

但 TypeScript 团队不这么想。

过去一年,微软一直在悄悄做一场超大规模的架构重构,代号 Project Corsa。这不是新语法糖,也不是新的严格模式,更不是“再加几个 flag 就完事”。这是一场对编译器本体的外科手术,目的是拆开并重构那颗已经运行了十年的核心引擎。

他们正在把支撑 TypeScript 十年的那套核心逻辑拆分、解耦、重塑。

如果你觉得 TypeScript 5 已经够快了,那你可能还没准备好迎接接下来的变化。这是一个关于团队如何拆掉“巨石应用”,从内部拯救我们于大型代码库构建效率的故事。

1. 五万行代码的巨石问题

想搞懂 Project Corsa,你得先认识一个躲在 node_modules 里的“怪物”。

问题是什么: 很多年里,TypeScript 的核心逻辑——也就是“判断一个字符串到底是不是字符串”的那部分——几乎都塞在一个文件里:checker.ts

它膨胀到了 5 万行以上。更要命的是,它还大量使用内部 Namespaces(一种已经过时的 TypeScript 组织方式),而不是现代的 ES Modules。

后果是什么: 像 V8 这种现代 JavaScript 引擎(Node.js 和 Chrome 背后那位)并不擅长优化“巨型 namespace”。当所有东西都被裹进同一个全局作用域,热路径很难被单独优化,也很难真正做到 tree-shaking 或精细加载。你以为你在跑一个编译器,其实你在拖着一锅“全局命名空间浓汤”运行。

可视化架构(巨石时代):

[ THE OLD COMPILER ]
+--------------------------------------------------+
|  namespace ts {                                  |
|     checker.ts (50k lines)                       |
|     parser.ts                                    |
|     binder.ts                                    |
|     // 所有模块共享可变的全局状态                |
|  }                                               |
+--------------------------------------------------+
Result: 高内存占用,难以优化

Corsa 的解法: 把这块巨石拆开,迁移为标准的 ECMAScript Modules,逐步告别 namespace ts 的老路。

这样做的意义很直白:引擎可以只加载需要的部分;V8 也终于能把关键函数“拎出来单独优化”,不再让它们埋在一锅全局变量里喘不过气。

2. 单态(Monomorphism):对象“长相一致”的速度秘密

这是最深的技术改动,也是最能带来性能收益的地方。

概念: JavaScript 引擎最开心的时候,是对象永远“长得一样”。这叫 单态(Monomorphism)

当一个函数一直接收同一种形状的对象,引擎就能大胆进行优化;可一旦下一次你传进来的对象突然多了个“隐藏属性”,引擎就会犹豫、撤回优化,变成 多态(Polymorphic),性能直接滑进“慢模式”。

旧问题: 老的 TypeScript 编译器在 check 阶段会动态修改对象:跑着跑着就给 AST 节点临时加字段、挂属性。对业务逻辑来说,这叫“方便”;对 JIT 编译器来说,这叫“你在搞我”。结果就是:优化频繁失效,性能被迫保守。

变化: Project Corsa 强制对象形状稳定,不再运行时随手乱改。

基准代码(概念示意):

// 旧编译器(多态 / 更慢)
function checkNode(node: any) {
  // 运行中临时加属性,会直接拖垮性能
  if (needsCheck) {
    node.checkFlag = true;
  }
}

// Corsa 架构(单态 / 更快)
interface Node {
  readonly flags: number; // 一次定义,形状固定不再变化
}

function checkNode(node: Node) {
  // 用位掩码替代对象的动态变更
  const isChecked = node.flags & CheckFlags.Checked;
}

结果: 当对象形状保持稳定,编译器能更接近“贴着硬件跑”的状态。TypeScript 仓库的早期基准数据显示,仅靠这些内部重构,编译速度就可能提升 10% 到 25%

不是你写得更少了,是编译器终于不再被自己的老习惯拖累。对于寻求极致性能的前端工程化方案,这无疑是个重磅利好。

3. 彻底解耦:把类型检查器“拆出来”

以前的版本里,Parser(语法解析)Checker(类型验证) 绑得太紧。

痛点在哪: IDE(比如 VS Code)的体验最受影响。你敲一个字符,IDE 第一时间想知道的是:“语法是不是还成立?”它此刻根本不需要完整的类型推导。但旧架构常常把 Checker 也拖上车处理——于是你想要的即时反馈,变成了“顺便做一次重型体检”。

架构转向: Corsa 把边界划得更清楚,职责拆得更干净。

[ SOURCE CODE ]
|
V
[ PARSER ] --(AST)--> [ BINDER ] --(Symbols)--> [ CHECKER ]
(快)                   (中等)                   (重)

影响是什么:

  • 语法高亮会更“秒回”。
  • 自动补全能更早出现——甚至在类型错误还没算完之前。
  • 构建更轻:只需要“剥掉类型”的工具(比如 esbuild、swc)能参考更清晰的实现边界,不必被一整坨 checker 牵连。

4. 这对你的应用意味着什么?

好消息是:你不需要重写任何业务代码就能吃到 Corsa 带来的红利。这才是它最吸引人的部分——你坐着不动,编译器自我进化。

但你也确实需要提前检查一下项目所依赖的“基础设施”。

变化点: TypeScript 正在转向纯 ES Modules,这意味着扩展编译器的方式会随之改变。如果你写过自定义的 AST Transformer 或 ESLint 规则,或者用过依赖 ts 内部 namespace 的工具链,那些东西可能会迎来一波适配挑战。

警告: 依赖 ts.internal 等非公开内部 API 的老工具或插件,在 TypeScript 7 时代很可能直接无法工作。

行动建议: 去检查一眼你的 package.json 和构建配置,看看有没有对编译器内部实现的深度依赖。

  • 相对安全: 常规构建工具链(如 Vite、Webpack、Angular CLI)。这些主流工具通常会及时跟进官方变化。
  • 相对高风险: 自己编写的 AST transformer、年代久远的自定义 lint 插件、或任何“硬钩内部结构”的私有脚本。

5. 下一步行动

这场变化的本质,是 TypeScript 编译器正在从一个“能跑就行的巨型脚本”,成长为一个符合现代软件工程标准的成熟项目。

你现在能做的一件有对比意义的小事是:

去你的项目终端,运行:

npx tsc --extendedDiagnostics

找到输出结果里的 “Check time(检查耗时)” ,把它记下来。

等 TypeScript 7 正式发布后,在同样的项目上再跑一次这个命令。你会直观地看到 Project Corsa 带来的性能差异——这不是玄学优化,而是在你每一次保存文件、每一次触发构建、每一次无奈等待时,实打实减少的那几十秒。理解这类底层优化原理,也是深入计算机基础知识的一部分。

本文由 云栈社区 整理分享,关注编译器技术与前端工程化演进。




上一篇:Antirez亲述:从抗拒到拥抱,我的AI编程实践与核心思考
下一篇:Qt开发中如何优雅移除焦点虚线框?兼顾美观与可访问性实践
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-16 00:34 , Processed in 0.225988 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表