热门包
符合规范并不保证真实库能够正常运行。即使 JS 引擎通过了 test262 中 99 % 的测试,在生产代码中仍经常出问题,因为库依赖许多边缘的“规范细节”——例如按特定顺序触发 Proxy 陷阱、Function.prototype.toString 形态、棘手输入下的正则表达式行为,以及 Object.keys 排序与计算属性名交互的确切方式。
Phasis 将 204 个广泛使用的库 与 Node.js(V8)逐字节比对验证。这些库位于仓库的 tests/Popular/ 目录下;每当引擎源码或测试套件发生变化,CI 都会运行这些测试。
各类别覆盖范围
| 类别 | 库 |
|---|---|
| 解析器 / AST | acorn 8.16.0, chevrotain 11.0.3, parse5 7.2.1, parsimmon 1.18.1, jsep 1.4.0, postcss-value-parser 4.2.0, acorn-walk 8.3.4, estraverse 5.3.0, escodegen 2.1.0, css-tree 3.0.4, sax 1.4.1, nearley 2.20.1 |
| 模板 / Markdown / HTML | mustache 4.2.0, handlebars 4.7.9, marked 18.0.3, markdown-it 14.1.0 (+ markdown-it-emoji), markdown-table 3.0.4, showdown 2.1.0, cheerio 1.1.2, htmlparser2 11.0.0 |
| 实用工具 / 函数式 | lodash 4.18.1, ramda 0.31.3, remeda 2.17.4, es-toolkit 1.27.0, immutable 5.1.3, immer 10.1.1, redux 5.0.1, deepmerge 4.3.1, dot-object 2.1.5, lodash.merge 4.6.2, lodash.clonedeep 4.5.0, extend 3.0.2, extend-shallow 3.0.2, mixin-deep 2.0.1, merge-options 3.0.4 |
| 对象访问 | dequal 2.0.3, clsx 2.1.1, classnames 2.5.1, get-value 4.0.1, set-value 4.1.0, object.omit 3.0.0, object.pick 1.3.0, is-plain-obj 4.1.0, kind-of 6.0.3 |
| 验证 / Schema | zod 4.4.3, yup 1.4.0, valibot 1.1.0, superstruct 2.0.2, validator 13.12.0, email-validator 2.0.4, ajv 8.17.1, @sinclair/typebox 0.34.42, runtypes 6.7.0, typanion 3.14.0, ow 2.0.0 |
| 日期 / 时间 | dayjs 1.11.20, date-fns 4.1.0, timeago.js 4.0.2, luxon 3.7.3, moment 2.30.2 |
| 数学 / 数字 | bignumber.js 11.1.1, decimal.js 10.6.0, numeral 2.0.6, jsbi 4.3.0, big.js 6.2.2, fraction.js 4.3.7, complex.js 2.4.2, simple-statistics 7.8.8 |
| 哈希 / 加密 | blueimp-md5 2.19.0, crypto-js 4.2.0, fnv-plus 1.3.1, murmurhash3js 3.0.1, hash-sum 2.0.0, jwt-decode 4.0.0, @noble/hashes 2.2.0, tweetnacl 1.0.3, aes-js 3.1.2, bcryptjs 3.0.2, xxhashjs 0.2.2, object-hash 3.0.0 |
| 搜索 / 差异比较 | fuse.js 7.3.0, minisearch 7.1.1, diff 8.0.2, diff-match-patch 1.0.5, fast-deep-equal 3.1.3, fast-equals 5.2.2, fastest-levenshtein 1.0.16, lunr 2.3.9 |
| JSON / 数据格式 | json5 2.2.3, js-yaml 4.1.0, yaml 2.6.1, toml 3.0.0, smol-toml 1.3.1, fast-json-patch 3.1.1, jmespath 0.16.0, jsonata 2.0.6, jsonpath-plus 10.3.0, mingo 6.7.0, sift 17.1.3, fast-json-stable-stringify 2.1.0, safe-stable-stringify 2.5.0, json-stringify-safe 5.0.1, canonicalize 2.1.0, papaparse 5.5.4 |
| 字符串 / 语言学 | he 1.2.0, slugify 1.6.9, camelcase 8.0.0, entities 6.0.1, pluralize 8.0.0, inflection 3.0.2, wcwidth 1.0.1, emoji-regex 10.4.0, unraw 3.0.0, jsesc 3.1.0, lower-case 2.0.2, upper-case 2.0.2, dot-case 3.0.4, pascal-case 3.1.2, snake-case 3.0.4, title-case 3.0.3, xregexp 5.1.1, escape-string-regexp 5.0.0, ansi-regex 6.1.0, strip-ansi 7.1.2, string-width 8.1.0 |
| URL / 网络 | url-parse 1.5.10, qs 6.13.1, query-string 9.1.1, tldts 6.1.69, punycode 2.3.1, linkifyjs 4.3.1, ipaddr.js 2.2.0, uri-js 4.4.1, url-template 3.1.1, bowser 2.11.0 |
| 压缩 / 编码 / 归档 | pako 2.1.0, lz-string 1.5.0, base64-js 1.5.1, JSZip 3.10.1 |
| 颜色 | color-string 2.1.1, d3-color 3.1.0, chroma-js 3.1.2, color-name 2.0.0, tinycolor2 1.6.0, color 5.0.3 |
| 克隆 / 相等性 | rfdc 1.4.1, klona 2.0.6, fast-copy 3.0.2 |
| 格式 / 显示 | ms 2.1.3, bytes 3.1.2 |
| ID / UUID | uuid 10.0.0, hexoid 2.0.0, ulid 3.0.1, cuid2 2.2.2, short-unique-id 5.4.3 |
| 类型检测 / glob | type-detect 4.1.0, picomatch 4.0.2, minimatch 10.1.1, wildcard-match 5.1.4, glob-to-regexp 0.4.1, to-regex 4.0.4, array-uniq 3.0.0, array-unique 0.3.2 |
| Semver / 配置 | semver 7.6.3, compare-versions 6.1.1, semver-compare 1.0.0 |
| 缓存 / 性能 | lru-cache 11.0.2, marky 1.3.0, array-flatten 3.0.0, arr-diff 4.0.0 |
| 异步 / 事件 | eventemitter3 5.0.1, eventemitter2 6.4.10, mitt 3.0.1, p-limit 7.1.1, p-queue 9.0.2, p-defer 5.0.0, p-retry 7.1.0, throttle-debounce 5.0.2, async 3.2.6 |
| 响应式状态 | mobx 6.13.7, xstate 5.23.0, valtio 2.1.5, nanostores 1.0.1, jotai 2.16.1, redux-saga 1.3.0, redux 5.0.1 |
| CSS / 样式 | postcss 8.5.7, stylis 4.3.6, css-tree 3.0.4 |
| 构建 / AST / 编译器 | magic-string 0.30.20, escodegen 2.1.0, acorn-walk 8.3.4, estraverse 5.3.0, @babel/parser 7.28.5, terser 5.46.0, prettier 3.3.3, svelte 5.55.7 (编译器), typescript 6.0.3 |
| MQTT / 协议 | mqtt-packet 9.0.4 |
| GraphQL | graphql-js 16.11.0 |
| 语法高亮 | highlight.js 11.11.1 |
| 测试 / 断言 | chai 6.2.1 |
总计:204 个库都能复现 Node 的精确输出。所有库均固定为最近一次更新时的上游最新版本。
工作原理
每个场景都是一个包含三个文件的 tests/Popular/<lib>/ 目录:
tests/Popular/lodash/
├── lodash.js ← vendored upstream library (untouched, UMD bundle)
├── runner.js ← Phasis-side script that exercises the library
└── oracle.txt ← Node.js output of running runner.js (committed)
tests/Popular/PopularPackagesTest.php 是一个 PHPUnit 数据提供程序测试,它会:
- 将
lodash.js+runner.js加载到一个全新的new Phasis\Engine()中。 - 将
console.log的输出捕获到缓冲区。 - 断言捕获的缓冲区与
oracle.txt逐字节相等。
重新生成基准结果:
node tests/Popular/gen-oracle.js tests/Popular/<lib>
(更新 vendored 库时使用——在真实 Node 下重新运行运行器并覆盖 oracle.txt。)
CI 门禁
工作流程:.github/workflows/popular.yml。
当推送或拉取请求修改 main、src/、tests/Popular/、phpunit.xml.dist、Composer 文件或工作流本身时运行,也可手动触发。包含两个步骤:
- Phasis 端 — 运行 PHPUnit
popular测试套件,通过 Phasis 执行每个库,并与已提交的基准结果进行差异比较。只要有一个字节不同就会失败。 - Node 重新验证 — 对每个库运行
node tests/Popular/gen-oracle.js …,并断言新生成的基准结果与仓库中的版本一致。用于检测“更新了 vendored 库但未更新基准结果”的偏差。
两项检查都必须通过,PR 才能合并。test262 方面的改进若导致 lodash 出问题,就不可接受;lodash 方面的改进若破坏 test262,也同样不可接受。
为什么选择这些库
- acorn — 解析是任何 JS 引擎中最脆弱的环节。它会测试现代 JS 新增的每个语法边界情况。如果 Phasis 能用 acorn 解析任意现代代码,说明运行时是可靠的。
- mustache.js — 模板处理是 Phasis 明确支持的嵌入式用例之一(README 的第一个具体示例是“模板引擎”)。Mustache 会按照真实模板的处理顺序测试迭代、作用域解析和字符串转换。
- lodash — 全球使用最广泛的 JS 实用工具库。其 300 多个函数会间接调用每个标准库方法。若 lodash 能正常工作,通用数据转换 JS 也能正常工作。
- marked — Markdown 渲染工具,实用且能测试正则表达式(大量使用)以及带跨行状态的字符串处理。可暴露 PCRE2(Phasis 的备用引擎)与 V8 的 Irregexp 之间的正则引擎差异。
- dayjs — 日期和时间运算是经典的差一错误来源,没有任何 test262 用例能捕获所有这类问题。dayjs 会测试构造函数的不同形式、跨夏令时等效月份边界的运算,以及格式令牌展开;这些都位于几乎每个 JS 日期库使用的相同代码路径中。
- bignumber.js — 不使用 TypedArrays 的任意精度运算会测试基于字符串的数字解析、大整数乘除循环和舍入模式分派——全部使用纯 JS,因此所有开销都由引擎承担。它可以暴露 Number 与 String 转换中的细微问题。
- json5 — 宽松的 JSON 解析大量依赖字符类正则表达式和有状态分词,可作为正则表达式正确性和字符串迭代边界的良好探针。
- fuse.js — 一个经 Babel 转译的 UMD,能测试
_classCallCheck(每个 ES6 之前转译的类都会使用的this instanceof Ctor模式)以及完整的 Bitap 模糊匹配算法。这是 Babel 转译库共有的结构,因此任何会破坏 Fuse 的问题也会影响半数 npm 生态。 - handlebars — 功能齐全的模板工具,采用先编译后渲染的方式。通过单个超大的
compile()入口测试eval-free 运行时路径、AST 遍历、通过动态查找表分派辅助函数,以及跨 realm 使用instanceof的SafeString品牌检查。这与 mustache.js 更简单的模板遍历器形成对照。 - zod — 运行时 Schema 验证。包含复杂的类层次结构(
ZodString、ZodObject、ZodArray、ZodUnion、……),方法链会返回经过细化的子类;结构化错误格式化要求 JS 端.issues数组的形状与 Node 逐字节一致;还会测试判别符和字面量标签模式。可测试现代 TypeScript 应用中常见的面向对象密集型验证代码。 - typescript — 在嵌入式引擎上运行的真正的 TypeScript 编译器。9 MB 的压缩编译器会重新解析任意 TS、遍历 AST 并生成 JS,是能想象到的最重型纯 JS 负载。如果 Phasis 能将泛型、async/await、枚举和类层次结构转译为与
tsc逐字节相同的结果,说明语言语义是可靠的。 - prettier — 一款遵循既定风格的 JS 格式化工具。格式化包含 JS 的 JS 时,引擎的每个规范边界都会经过格式化代码的同一控制流,构成极具挑战性的工作负载。
- svelte/compiler — Svelte 的独立编译器。解析
.svelte源代码、遍历 AST,并为客户端和 SSR 目标生成 JS。 - terser / @babel/parser / postcss — JS 压缩器、JS 解析器、CSS 后处理器。数万行压缩代码会重新解析任意输入,正是罕见 AST 结构可能出现的地方。
- ajv — JSON Schema 验证器通过
new Function(...)将每个 Schema 即时编译成自定义验证函数。测试大多数 Schema 和模板库所依赖的 Function 构造函数路径。 - mobx — 基于代理的响应式状态。每次读取可观察对象时都会经过 Proxy
get陷阱来注册依赖;每次写入都会触发反应。这是对 Proxy 基础设施、可观察 Map、数组、嵌套对象和 autorun 调度器的压力测试。 - cheerio / htmlparser2 — 构建于快速 HTML 解析器之上的服务器端 jQuery。一个包中包含选择器引擎解析、DOM 风格遍历、属性操作和 HTML 序列化。
- graphql-js / jsonata — GraphQL 参考实现和一种 JSON 查询语言。两者都大量涉及 Schema、验证和递归求值器,是典型的“浏览器中的数据层”代码。
- JSZip — 异步 ZIP 归档构建器。通过
setImmediate驱动的调度来执行任务并生成真实的二进制输出,可测试计时器接口和大量使用Uint8Array的路径。 - moment / luxon — 日期和时间运算。moment 是可变的、经过手工调优的 UMD;luxon 是现代的不可变改写版本。两者结合覆盖了格式化、解析以及时区等效的年月运算。
- mqtt-packet — 纯 JS MQTT 3.1.1 / 5.0 编解码器。字节级打包和解码,以及会测试 Annex-B 语法边界的 Base64 非字母字符类正则表达式。
- xstate / valtio / nanostores / jotai / redux-saga — 现代状态管理方案。状态机、代理状态、原子存储、派生原子、基于生成器的效果运行器——每个库都会测试一种不同的响应式结构。
- escodegen / acorn-walk / estraverse / magic-string — AST 工具。代码生成、遍历和非破坏性源代码编辑,是任何 JS 对 JS 转换器(构建工具、代码改写工具、代码检查器)的基础。
- papaparse / lunr / yaml / sax / css-tree — 纯解析器和分词器。CSV、全文搜索索引、YAML 1.2、流式 SAX 风格 XML 和 CSS AST。语法各不相同,都是测试字符级扫描和正则表达式行为的良好探针。
添加更多
在 tests/Popular/<name>/ 下新建一个目录,包含上述三种文件,然后:
node tests/Popular/gen-oracle.js tests/Popular/<name> # one-time, generates oracle.txt
git add tests/Popular/<name>
下次运行时,PHPUnit 套件会自动发现它;由于改动涉及 tests/Popular/,CI 也会将其纳入检查。
值得考虑添加的候选库:chevrotain(解析器组合器,可测试闭包和正则表达式)、nanoid(加密和随机性边界)、date-fns(覆盖 dayjs 之外的时区功能)。