一周狂揽40K+ Star⭐ 的 Pretext 到底有多变态?

0 阅读7分钟

这周的前端圈,可以说是被一个叫 Pretext 的项目彻底刷屏了。

短短几天,GitHub 狂揽 41K+ Stars ⭐⭐⭐

很多刚入行的小伙伴看完官方那个极简的 Readme 可能一头雾水:不就是一个算文本长宽高的 JS 库吗?为啥能火成这样?CSS 的 word-wrapflex 难道不够用吗?

v2_741bc7c1a79445528b75ddc1980d6ccd@46958_img_gif.gif

v2_c43f8b79c3f6400d9a995d5f0adc869d@46958_img_gif.gif

v2_715e9ba3c8aa4ea7b8e1bc5b41f87ead@46958_img_gif.gif

但如果是被各种复杂表格、虚拟列表、Canvas 渲染折磨过的老兵,看到 Pretext 的那一刻,绝对会有一种激动的。

因为这个库,极其优雅地干掉了前端性能优化里最恶心、最顽固的问题——强制同步布局(Forced Synchronous Layout)导致的重排(Reflow)。

今天,咱们不念官方文档,结合我这几年的填坑血泪史,聊聊这个 41K Star 的怪物到底解决了什么世界级痛点,以及我们在真实的业务里该怎么用它。


那些年用过的 getBoundingClientRect

前端开发有个大难题:一串动态文本渲染出来到底有多高?

设想一个极度真实的业务场景: 你在做一个拥有十万条数据的 虚拟滚动列表(Virtual List)。为了让列表丝滑,你只能渲染视口内的那 20 条数据。 但问题来了,每条数据里的用户评论长度是不固定的。有的人发了一句 哈哈😁,有的人发了 800 字的写字楼小作文。 在渲染之前,你必须提前知道每一行的高度,才能计算出整个虚拟列表的滚动条位置和绝对定位的 top 值。

在 Pretext 出现之前,我们是怎么做的? 用的往往是最原始、极其粗暴的 离屏 DOM 测量法(Offscreen Measurement)

// 极其恶心的传统测量法:DOM 测算
function measureTextHeightOldWay(text, width, fontSize) {
  // 1. 创建一个隐藏的 div
  const hiddenDiv = document.createElement('div');
  hiddenDiv.style.visibility = 'hidden';
  hiddenDiv.style.position = 'absolute';
  hiddenDiv.style.width = `${width}px`;
  hiddenDiv.style.fontSize = `${fontSize}px`;
  hiddenDiv.innerText = text;

  // 2. 强行塞入 DOM 树
  document.body.appendChild(hiddenDiv);

  // 3. 读取高度(灾难的开始!!!)
  const height = hiddenDiv.offsetHeight; // 或者 getBoundingClientRect()

  // 4. 销毁 DOM
  document.body.removeChild(hiddenDiv);

  return height;
}

代码看着没毛病? 但如果在初始化时,你在一个循环里把这段代码跑了 1000 次,你的页面会当场卡死白屏!

为什么?因为浏览器底层是一个极度慵懒的系统。你操作 DOM 节点,它通常会先攒着,等这一帧结束再一次性绘制。 但当你调用了 offsetHeight 或者 getBoundingClientRect 时,浏览器为了给你一个最精确的值,会被迫打断所有的优化,立刻在主线程里重新计算整个页面的布局(Reflow)。

你循环调用 1000 次,浏览器就被迫重排 1000 次。这种 布局抖动(Layout Thrashing) 是前端性能的头号杀手。


Pretext 的降维打击 - 不碰 DOM,纯数学演算

而 Pretext 的核心卖点,就写在它的第一句介绍里:纯 JavaScript/TypeScript 库,避免了对 DOM 进行测量。

image.png

它完全抛弃了把元素塞进 DOM 里量一下的蠢办法。 你要算这段文字占据多少像素?好,你告诉我字体、字号、容器宽度,我直接在 JS 内存里,通过底层的文本排版算法,硬生生给你出来!

咱们直接上代码,看看接入 Pretext 之后,世界变得有多清爽:

// 使用 Pretext
import { measureText } from 'pretext';

function measureTextHeightNewWay(text, containerWidth) {
  // 没有任何 DOM 操作!直接传入参数计算
  const metrics = measureText(text, {
    fontFamily: 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto',
    fontSize: 14,
    lineHeight: 1.5,
    maxWidth: containerWidth,
    // 甚至支持复杂的换行策略
    wordBreak: 'break-word', 
  });

  // 直接拿到精准的宽高和行数!
  return metrics.height; 
}

对比一下,这带来了什么工程级别的质变?

快到离谱: 因为不触碰任何 DOM API,不会引起一丝一毫的浏览器重排。同样的测量 1000 条数据,用传统 DOM 法可能需要 300ms(掉帧卡顿),用 Pretext 只需要 2ms。

解锁 Web Worker 潜能: 以前因为要操作 DOM,测量文本的脏活必须在浏览器的主线程(UI 线程)干,极容易阻塞页面。现在它是纯 JS 计算了,你完全可以把这十万条文本高度的计算逻辑,扔到 Web Worker 里去并行跑!主线程依然丝滑如初。

跨平台降维打击: 因为纯 JS/TS,它不仅能在浏览器 DOM 里跑,它还能在 Canvas 游戏引擎里跑,在 Node.js 服务端渲染(SSR)里跑,甚至未来能在 React Native 里跑。

Pretext vs getBoundingClientRect 性能对比

image.png

更多好玩的demo 👉:https://chenglou.me/pretext/

image.png

看似比较简单,实则硬核的技术深水区

其实纯 JS 测算文本这个想法,很多前端老手都想过。为什么直到 2026 年,才被 Pretext 彻底做成了一个 40K+ Star 的杀手级项目?

因为文本排版(Text Layout)是一个深不见底的黑洞。

你以为算个宽度就是 字符数 × 字体宽度? 太天真了。你需要考虑英文单词的断词(换行不能把单词截断)、需要考虑阿拉伯语的从右到左(RTL)、需要考虑中文的标点符号避头尾规则、更别提那些五花八门的 Emoji(有的 Emoji 占好几个字节,但在屏幕上只是一个字符)。

更变态的是,不同浏览器(Chrome / Safari)底层的字体引擎(HarfBuzz 等)渲染规则都有细微差异。

Pretext 的作者 chenglou(做过 React Core,写过 ReasonML 的真大神👍👍👍)用了一种极其聪明且符合现在 AI 时代的方法:将浏览器自身的字体引擎作为基准进行迭代对齐。

image.png

它没有去傻傻地重写一套从零开始的渲染引擎,而是找到了一套能与主流浏览器高度拟合的纯数学计算逻辑。精度极高,且极其轻量。

这不是在造轮子,这是在用极客思维给现有的前端标准打补丁。


那么,哪些场景该果断接入 Pretext?

虽然我把它吹爆了,但作为一个老油条,我必须负责任地告诉你:不要脑子一热,把项目里所有的普通 CSS 排版都换成它。 CSS 引擎依旧是渲染标准流最稳定、最简单的方案。

Pretext 是属于极端场景。 遇到以下三种情况,直接掏出它:

复杂数据看板 / 大规模动态虚拟列表: 前面提到的,需要提前精确知道变长文本高度,来进行复杂绝对定位 计算的场景。

Canvas / WebGL 富文本渲染: 用过 Canvas 的人都知道,Canvas 里的 fillText 极其原始,根本不支持自动换行。以前我们在 Canvas 里画多行文本简直是噩梦,现在可以直接用 Pretext 算好每一行的位置,然后精确绘制。

基于 Node.js 的海报/PDF 自动生成系统: 服务端没有 DOM 环境,以前为了算一下文本会不会超出海报边界,还得专门在服务端起一个无头浏览器(Puppeteer),贼耗服务器资源。现在直接 Node.js 引入 Pretext 纯端计算,一台 2 核机器能顶过去 8 核的并发量。


这才是前端该有的样子🤔

这两年,前端圈充满了大模型、AI 生成代码的焦虑,似乎一切不加个 AI 前缀就不够前沿。

但看到 Pretext 这种纯粹为了解决计算机图形学底层痛点、一行一行扣性能、追求极致优雅的开源项目,短短几天收获 40K+ Star,我心里其实是挺欣慰的。

它证明了一件事:在花里胡哨的概念之外,这个世界上永远有那些扎根在工程最深处、被真实痛点折磨的开发者。

真正高级的前端工程能力,不是你接了多少个最新的大模型 API,而是当系统出现肉眼可见的卡顿时,精准地指出那句隐藏在万行代码里的 offsetHeight,然后用纯粹的数学与算法,把页面性能拉升两个数量级。

周末了,别只顾着看个热闹,去把 Pretext 拉下来,在本地建个 Canvas 或者虚拟列表的 Demo 跑一跑。

那种看着耗时从 300 毫秒断崖式下跌到 2 毫秒的爽感,才是写代码真正的乐趣😁。