跳转到正文

热门包

符合规范并不保证真实库能够正常运行。即使 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>/ 目录:

Text
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 数据提供程序测试,它会:

  1. 将 lodash.js + runner.js 加载到一个全新的 new Phasis\Engine() 中。
  2. 将 console.log 的输出捕获到缓冲区。
  3. 断言捕获的缓冲区与 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 文件或工作流本身时运行,也可手动触发。包含两个步骤:

  1. Phasis 端 — 运行 PHPUnit popular 测试套件,通过 Phasis 执行每个库,并与已提交的基准结果进行差异比较。只要有一个字节不同就会失败。
  2. 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 之外的时区功能)。