js框架基准测试
这是一个简单的针对多个JavaScript框架的基准测试。该基准测试创建一个包含随机条目的大型表格,并测量各种操作的时间,包括渲染持续时间。
安全建议
目前这个仓库中有186个实现。我当然不可能对所有这些实现进行安全评估。npm ci
和npm install
可以执行任意命令,因此应该只对您信任的包执行。因此,我在一个专用的虚拟私有Linux服务器上构建,这样我就不必在我的笔记本电脑上为所有这些实现安装包。每个Chrome版本都有一个预构建的build.zip可供下载,这样您就可以避免安装所有实现的包。
(我不知道这个仓库中有任何(试图)恶意包的案例,所以请将其仅作为一般警告。)
这个仓库中的服务器实现应该只在您的本地机器上启动,并且访问应该限制在您的本地机器上。我建议不要启动可以从互联网公开访问的服务器。
关于基准测试
为每个框架测试以下操作:
- 创建行:页面加载后创建1,000行的持续时间(无预热)。
- 替换所有行:替换表格中所有1,000行的持续时间(有5次预热迭代)。
- 部分更新:对于10,000行的表格,更新每10行文本的时间(有5次预热迭代)。
- 选择行:响应点击行而突出显示一行的持续时间。(有5次预热迭代)。
- 交换行:在1,000行的表格中交换2行的时间。(有5次预热迭代)。
- 删除行:从1,000行的表格中删除一行的持续时间。(有5次预热迭代)。
- 创建多行:创建10,000行的持续时间(无预热)
- 向大表格追加行:在10,000行的表格上添加1,000行的持续时间(无预热)。
- 清除行:清除填充了10,000行的表格的持续时间。(无预热)
- 就绪内存:页面加载后的内存使用情况。
- 运行内存:添加1,000行后的内存使用情况。
- 更新内存:对1,000行的表格点击5次更新后的内存使用情况。
- 替换内存:点击5次创建1,000行后的内存使用情况。
- 重复清除内存:创建和清除1,000行5次后的内存使用情况。
- 更新内存:对1,000行的表格点击5次更新后的内存使用情况。
- 启动时间:加载和解析JavaScript代码以及渲染页面的持续时间。
- 持续交互:Lighthouse指标TimeToConsistentlyInteractive:悲观的TTI - 当CPU和网络都确实非常空闲时。(没有超过50ms的CPU任务)
- 脚本启动时间:Lighthouse指标ScriptBootUpTtime:解析/编译/评估页面所有脚本所需的总毫秒数
- 主线程工作成本:Lighthouse指标MainThreadWorkCost:在主线程上花费的总时间,包括样式/布局等。
- 总字节权重:Lighthouse指标TotalByteWeight:加载到页面中的所有资源的网络传输成本(压缩后)。
对于所有基准测试,测量的持续时间包括渲染时间。您可以在这篇文章和wiki中阅读一些详细信息。从Chrome 118开始,整体性能是作为加权几何平均值计算的。
官方结果
官方结果发布在官方结果页面上。 我的博客有一些关于这个基准测试的文章。 这个基准测试的旧结果在我的博客上概述(第1轮、第2轮、第3轮、第4轮、第5轮、第6轮、第7轮和第8轮)。
结果快照
当前可能没有相同质量的快照(即结果可能是针对混合浏览器版本的,每个基准测试的运行次数可能不同)可以在这里看到
键控vs非键控框架
一些框架如React、Vue.js或Angular允许您通过分配"key"属性(或对于Angular,在*ngFor中指定"trackBy")来在数据项和DOM节点之间创建1:1的关系。如果您使用数据的某个标识符作为键,您就得到了"键控"模式。对数据的任何更新都将更新相关的DOM节点。如果您重新排序列表,DOM节点将相应地重新排序。
另一种模式是"非键控",这是例如vue.js默认用于列表的模式。在这种模式下,对数据项的更改可以修改之前与其他数据相关联的DOM节点。这可能更高效,因为可以避免昂贵的DOM操作(例如,首先删除旧节点然后添加新节点),现有的DOM节点会更新以显示新数据。对于React和Angular,使用项目索引作为键使用这些框架的"非键控"模式。
根据您的要求,"非键控"模式可能是性能提升,也可能导致严重问题,因此必须仔细选择模式并检查框架是否支持该模式。
在这里阅读更多:https://www.stefankrause.net/wp/?p=342
1 运行所有框架的预构建二进制文件
这个仓库中目前有186个实现。安装(和维护)这些可能具有挑战性,但这里有简化的说明如何开始。请参阅上面的安全建议,了解为什么这可能是一个好主意。
1.1 先决条件
安装_node.js (>=v20.9.0)_。如果您想让自己轻松一些,可以使用nvm。基准测试已在node v20.9.0上测试。 请确保以下命令在尝试构建之前可以工作:
> npm
npm -version
10.1.0
> node --version
v20.9.0
1.2 下载预构建的二进制文件并启动服务器
构建所有框架可能具有挑战性。有一种新方法可以跳过这一步,只运行基准测试而不构建所有实现。
从检出标记的发布版本开始。选择您想要的版本(例如chrome 100):
git clone https://github.com/krausest/js-framework-benchmark.git
cd js-framework-benchmark
git checkout chrome100 -b release
npm ci && npm run install-local
从https://github.com/krausest/js-framework-benchmark/releases下载该版本的build.zip 并将build.zip放入js-framework-benchmark目录,然后解压预构建文件:
unzip build.zip
现在您已准备好启动http-server。让服务器在后台运行
npm start
1.3 运行基准测试并处理错误
在新的控制台窗口中,您现在可以运行基准测试:
npm run bench
这将需要一些时间(在我的机器上目前大约需要12小时)。最后创建结果表:
npm run results
在浏览器中打开js-framework-benchmark/webdriver-ts-results/table.html并查看结果。您可以使用链接http://localhost:8080/webdriver-ts-results/dist/index.html打开结果表
当基准测试运行不成功时,以下是您应该做的。假设基准测试向控制台打印了以下内容:
================================
以下基准测试失败:
================================
执行frameworks/non-keyed/ef-js和基准测试04_select1k失败:未找到绘制事件
运行未完全成功 基准测试出现错误
您现在必须像这样重新运行那些失败的基准测试:
npm run bench -- --framework non-keyed/ef-js --benchmark 04_
然后您可以继续创建结果表npm run results
。
另一种解决方法是删除您无法运行或不感兴趣的框架的文件夹。
2 旧的和困难的方式:构建框架并运行基准测试
2.1 先决条件
安装_node.js (>=v16.14.2)。如果您想让自己轻松一些,可以使用nvm并安装yarn。基准测试已在node v16.14.2上测试。 对于某些框架,您还需要_java(>=8,例如ubuntu上的openjdk-8-jre)。 请确保以下命令在尝试构建之前可以工作:
> npm
npm -version
8.5.0
> node --version
v16.14.2
> echo %JAVA_HOME% / echo $JAVA_HOME
> java -version
java version "1.8.0_131" ...
> javac -version
javac 1.8.0_131
2.2 开始安装
如上所述,为所有框架构建和运行基准测试可能具有挑战性,因此我们逐步开始...
安装全局依赖 这只安装一些顶级依赖项,用于构建框架和本地Web服务器。
npm ci
然后安装服务器:
npm run install-server
我们在根目录中启动本地Web服务器
npm start
验证本地Web服务器是否正常工作: 尝试打开http://localhost:8080/index.html。如果你看到类似下图的内容,说明你走对了方向:
现在打开一个新的终端窗口,保持Web服务器在后台运行。
2.3 构建和查看单个框架
我们现在尝试构建第一个框架。转到vanillajs参考实现目录
cd frameworks/keyed/vanillajs
安装依赖
npm ci
构建框架
npm run build-prod
构建过程中不应出现任何错误,然后我们可以在浏览器中打开框架: http://localhost:8080/frameworks/keyed/vanillajs/
有些框架如binding.scala或ember不能直接这样打开,因为它们的URL中需要包含'dist'或'target/web/stage'等路径。你可以在之前打开的index.html中找到正确的URL,或查看package.json中js-framework-benchmark下是否有customURL属性表示URL。
2.4 运行单个框架的基准测试
基准测试使用自动化的基准测试驱动程序,通过chromedriver来测量使用chrome时间线的每个操作的持续时间。以下是为单个框架运行的步骤:
cd ../../..
cd webdriver-ts
安装依赖
npm ci
构建基准测试驱动程序
npm run compile
现在为vanillajs-keyed框架运行基准测试驱动程序:
npm run bench keyed/vanillajs
只需靠背观看chrome运行基准测试。 如果没有报错,那么表格的html应该没问题,你对keyed或non-keyed的分类也应该是正确的。
你应该保持chrome窗口可见,否则似乎可能会跳过绘制事件导致结果错误。终端会显示各种日志语句。
该运行的结果将保存在webdriver-ts/results
目录中。我们可以查看单个结果:
cat results/vanillajs-keyed_01_run1k.json
{"framework":"vanillajs-keyed","benchmark":"01_run1k","type":"cpu","min":135.532,"max":154.821,"mean":143.79166666666666,"median":141.022,"geometricMean":143.56641695989177,"standardDeviation":8.114582360718808,"values":[154.821,135.532,141.022]}
如你所见,创建1000行的平均持续时间为144毫秒。
你还可以检查实现是否符合规则:
npm run isKeyed keyed/vanillajs
如果发现任何问题,它会报告ERROR。
2.5 构建结果表格
安装库:
cd ..
cd webdriver-ts-results
npm ci
cd ..
cd webdriver-ts
在webdriver-ts目录中执行以下命令:
npm run results
现在应该已经创建了一个结果表格,可以在http://localhost:8080/webdriver-ts-results/dist/index.html打开。 表格中除了第一个表格右端的vanillajs-keyed列外,其他都是空的。
2.6 [可选] 更新index.html文件
这只是重建用于显示表格的文件,不包括结果。
npm run index
2.7 [可选] 构建和运行所有框架的基准测试
这不适合胆小的人。在运行此命令之前,请阅读安全建议。 你可以通过以下命令构建所有框架:
cd ..
npm run rebuild-all
下载完整个互联网后,它开始构建。基本上在构建过程中不应该有任何错误,但我不能保证依赖项不会出问题。
现在你可以通过在根目录中执行以下命令来为所有框架运行基准测试:
npm run bench-all
之后,你可以在http://localhost:8080/webdriver-ts/table.html查看所有结果。
3 提示和技巧
- 你可以通过传递目录名来运行多个实现(切换到webdriver-ts目录):
npm run bench keyed/angular keyed/react
。 - 你可以使用前缀选择多个框架和基准测试进行运行,如以下在webdriver-ts目录中的示例:
npm run bench -- --benchmark 01_ 02_ --framework keyed/vanillajs keyed/react-hooks
运行所有包含angular或bob的框架(即所有angular版本和bobril)以及所有ID包含01或02的基准测试 - 内存基准测试假设chrome安装在某些特定路径。如果不匹配,请使用
npm run bench -- --chromeBinary /usr/bin/google-chrome
- 如果你无法编译或运行某个框架,只需将其移出frameworks目录并重新运行
- 可以通过在webdriver-ts目录中运行
npm run isKeyed
来检查实现是否为keyed或non-keyed。你可以像webdriver测试运行程序一样限制要检查的框架,例如npm run isKeyed keyed/svelte
。如果基准测试实现分类不正确,程序会报告错误。
4. 贡献新的实现
4.1 真实实现的示例说明
感谢@dsvorc41提供以下描述: TL;DR:
- 安装所有根级依赖
cd js-framework-benchmark/
- 运行
npm ci
或npm i
- 运行
npm run install-local
- 为你想要的框架创建一个新目录,例如 Fast 框架:
mkdir /frameworks/keyed/fast
- 根据该框架的适当方式设置你的新目录,例如:
- 设置 prettier、eslint、依赖项(如
@microsoft/fast-element
)等 - 在你的文件夹根目录创建
index.html
,这是你的应用将被服务的地方touch /frameworks/keyed/fast/index.html
- 注意:你的 html 文件必须使用全局 CSS 样式
<link href="/css/currentStyle.css" rel="stylesheet" />
- 设置 prettier、eslint、依赖项(如
- 提供页面服务 - 测试你的 html 页面是否在浏览器中正确加载
- 例如,在某处放置
<h1>Hello World - Fast Framework</h1>
- 从根目录运行服务器:
npm start
- 在浏览器中访问你的页面(URL 遵循文件夹结构):
http://localhost:8080/frameworks/keyed/fast/index.html
- 注意:始终从根目录启动服务器很重要,因为这样你才能访问所有应用必须共享的全局 CSS
- 注意 2:避免使用 Shadow DOM - 如果你的框架依赖 Shadow Dom(如 Fast 框架),你应该将其关闭。否则你将无法访问全局 CSS。
- 例如,在某处放置
- 添加"操作触发器" - 所有应用必须具有的按钮(参见
frameworks/keyed/vanillajs/index.html
)- 注意:操作触发器只是用于运行基准测试的按钮(添加行、删除行、交换行等)。这些按钮可以是静态 HTML,也可以用你选择的框架动态渲染(使用 JS)
- 确保你的 HTML 元素具有与 VanillaJS 相同的类和结构,否则基准测试将无法在页面上找到你的元素,并且你将无法获得全局 CSS(Bootstrap)
- 添加下面的 html 示例并打开页面。你应该看到页面上格式良好的元素,就像上面的 GIF 图像中一样。
- 操作触发器示例
<body> <div id="main"> <div class="container"> <div class="jumbotron"> <div class="row"> <div class="col-md-6"> <h1>VanillaJS-"keyed"</h1> </div> <div class="col-md-6"> <div class="row"> <div class="col-sm-6 smallpad"> <button type="button" class="btn btn-primary btn-block" id="run" > 创建 1,000 行 </button> </div> <div class="col-sm-6 smallpad"> <button type="button" class="btn btn-primary btn-block" id="runlots" > 创建 10,000 行 </button> </div> <div class="col-sm-6 smallpad"> <button type="button" class="btn btn-primary btn-block" id="add" > 追加 1,000 行 </button> </div> <div class="col-sm-6 smallpad"> <button type="button" class="btn btn-primary btn-block" id="update" > 更新每第 10 行 </button> </div> <div class="col-sm-6 smallpad"> <button type="button" class="btn btn-primary btn-block" id="clear" > 清空 </button> </div> <div class="col-sm-6 smallpad"> <button type="button" class="btn btn-primary btn-block" id="swaprows" > 交换行 </button> </div> </div> </div> </div> </div> <table class="table table-hover table-striped test-data"> <!-- 你的动态内容应该在这里渲染 --> </table> </div> </div> </body>
- 生成用于渲染的虚拟数据
- 参见
frameworks/keyed/fast/src/utils/build-dummy-data.ts
作为示例 - 注意:
id
是一个重要属性,必须初始化为1
,并持续递增。只有在页面重新加载时id
才会重置回1
- 否则每次创建新行时它应该继续递增。做其他任何事情都会导致基准测试尝试查找具有特定 ID 的元素时出错。相信我,我是吃过亏才知道的。
- 参见
- 你的应用需要支持几个与上面列出的"操作触发器"相对应的操作。这里有一个来自 Fast 框架的例子
frameworks\keyed\fast\src\App.ts
和frameworks\keyed\fast\src\components\Table.ts
:- 代码示例:
export class BenchmarkApp extends FASTElement { createOneThousandRows() {} createTenThousandRows() {} appendOneThousandRows() {} updateEveryTenthRowLabel() {} deleteAllRows() {} swapTwoRows() {} deleteSingleRow(rowId: number) {} } export class Table extends FASTElement { selectRow(rowId: number) {} }
- 注意:你的应用不需要使用相同名称的方法 - 你应该编写符合语言习惯的代码,并遵循你所选框架的最佳实践。上面的例子只是为了让你了解必须支持哪些操作,但你选择如何实现这些方法可能因框架而异。
- 代码示例:
- 手动测试你的应用 - 在运行基准测试之前先做这个
- 打开你的页面并点击按钮,确保你的应用能添加 1000 行,然后删除它们,或交换它们,或添加/删除 10,000 行。
- 要做到这一点,你可能需要监视你的本地文件并将它们编译成某种类型的捆绑包,比如
frameworks\keyed\fast\dist\bundle.js
,该捆绑包将通过你的 HTML 文件中的 script 标签加载 - 例如,在 Fast 文件夹中,我们有 webpack 监视我们的文件:
"dev": "rimraf dist && webpack --config webpack.config.js --watch --mode=development",
- 这意味着我们有两个终端标签运行
- 一个用于根文件夹中的服务器
npm start
- 另一个在我们的本地文件夹中,webpack 正在监视文件
- 一个用于根文件夹中的服务器
- 为你的框架运行单个基准测试
- 一旦你手动验证了一切按预期工作,运行单个基准测试并确保所有测试都在运行
- 如果你忘记了什么,某个基准测试可能会失败 - 例如,它无法在页面上找到元素或类似情况
- 保持根文件夹中的服务器运行
npm start
,并在另一个终端标签中,同样从根文件夹运行npm run bench -- --framework keyed/fast
(或者你的框架是什么,如keyed/react
、keyed/angular
等)。 - 基准测试运行器将多次打开和关闭 Chrome。整个过程将持续几分钟。
- 可选:运行 VanillaJS 的基准测试作为比较
npm run bench -- --framework keyed/vanillajs
- 构建报告
npm run results
- 在浏览器中打开报告(注意:如果你想查看此页面,服务器必须仍在运行)
http://localhost:8080/webdriver-ts-results/table.html
4.2 构建应用
对于贡献来说,基本上只需要为你的框架创建一个新目录,该目录支持 npm install
和 npm run build-prod
,然后可以在浏览器中打开。所有其他步骤都是可选的。让我们通过复制 vanillajs 来模拟这个过程。
cd ../frameworks/keyed
cp -r vanillajs super-vanillajs
cd super-vanillajs
然后我们编辑 super-vanillajs/index.html 以获得正确的 index.html:
<title>Super-VanillaJS-"keyed"</title>
...
<h1>Super-VanillaJS-"keyed"</h1>
在大多数情况下,你需要 npm install
和 npm run build-prod
,然后检查它是否在浏览器中正常工作,地址是 http://localhost:8080/frameworks/keyed/super-vanillajs/。
(当然,在现实中,你更可能会删除 javascript 源文件,并在那里使用你的框架,而不仅仅是更改 html 文件。)
4.3 将你的新实现添加到结果表中
(注意:不再需要更新 common.ts,super-vanillajs 在结果表中已经可见)
你的 package.json 必须包含一些基准测试的信息。由于你复制了它,重要的部分已经存在:
...
"js-framework-benchmark": {
"frameworkVersion": "",
"frameworkHomeURL": ""
},
...
这个有点特殊,因为 vanillajs 没有版本,也没有涉及框架。如果你使用像 react 这样的普通框架,它带有版本信息,并且框架应该有一个 URL。对于大多数框架,你会在 package.json 中为你的框架添加一个依赖项。如果你指定包名,基准测试可以从 package.json 和 package-lock.json 自动确定正确的版本信息,如下所示:
"js-framework-benchmark": {
"frameworkVersionFromPackage": "react"
"frameworkHomeURL": "https://www.reactjs.org"
},
现在基准测试将从 react 目录中的 package-lock.json 获取已安装的 react 版本,并使用该版本号来计算正确的版本字符串。
如果你的库有多个重要的包,如 react + redux,你可以将它们用冒号分隔,如 "react:redux"。
如果你不是从 npm 获取框架,你可以硬编码一个版本,如 "frameworkVersion": "0.0.1"
。
js-framework-benchmark 的其他重要但可选属性如下例所示:
"customURL": "/target/web/stage",
"useShadowRoot": true
如果需要,你可以设置一个可选的不同 URL,或指定你的 DOM 使用 shadow root。
4.4 提交你的实现
请查看 https://github.com/krausest/js-framework-benchmark/wiki/Process-for-merging-a-pull-request 了解如何合并拉取请求的信息。
我们非常欢迎贡献。请遵循以下规则:
- 将你的目录命名为 frameworks/[keyed|non-keyed]/[框架名称]
- 你目录中的 package.json 必须包含一些重要信息,请参见上面的 4.2 节。
- 每个贡献必须能通过在目录中运行
npm install
和npm run build-prod
命令来构建。build-prod 的具体操作由你决定。通常还会有一个npm run dev
命令用于创建开发版本。 - 每个实现都必须使用根 css 目录中提供的 bootstrap。
- 所有 npm 依赖项都应该本地安装(即列在你的 package.json 中)。Http-server 或其他本地 web 服务器不应作为本地依赖项。它是从根目录安装的,以允许访问 bootstrap。
- 请在 package.json 中使用固定版本号,不要使用范围。否则构建迟早会出问题 - 相信我。我认为使用 npm-check-updates 进行更新效果最好,它可以保持版本格式。
- Webdriver-ts 必须能够运行该贡献的性能测试。这意味着所有按钮(如"创建 1,000 行")必须有正确的 id,例如像 vanillajs 中那样。使用 shadow DOM 对 webdriver 来说是一个真正的痛苦。你的实现越接近 polymer,我就越有可能让该贡献正常工作。
- 不要更改 index.html 中的 id,因为自动化基准测试依赖于这些 id。
- 请只推送你的框架文件夹中的文件(不包括 index.html 或 results.json)
- 请确保你的实现通过测试工具的验证。切换到根目录并执行检查
npm run rebuild-ci [keyed|non-keyed]/[框架名称]
。如果你的框架无法构建、基准测试无法运行或行为与规定不符,它会打印出错误。如果对实现不满意,它会打印一个大的 ERROR 进行解释。一些常见错误包括:- 你的 package.json 缺少一些必需字段
- 分类不正确(Keyed/NonKeyed)
- 你的 /dist 中有 gzip 压缩文件(不幸的是,当这些文件存在时,web 服务器会优先选择它们)
- 请不要提交任何结果文件 webdriver-ts/table.html、webdriver-ts-results/src/results.ts 或 webdriver-ts-results/table.html。我通常会在合并后运行基准测试并发布更新的(临时)结果。
- 可以使用最新稳定版 Chrome 的 Web 功能和语言级别(babel-preset-env "last 1 chrome versions")
- vanillajs 实现和其他一些实现包含了试图通过 JavaScript 代码近似重绘持续时间的代码。实现不需要包含该测量。记住:真正的测量是由自动测试驱动程序通过检查 Chrome 时间线条目来完成的。
- 请不要过度优化。如果你采用框架的惯用风格,这个基准测试最有用。我们已经明确了什么样的实现被认为是正确的规则,并将在实现处理事情错误(错误)或看起来像是捷径(注释)时添加错误或注释。
- html 必须与参考实现 vanillajs 创建的完全相同。它还必须包括所有 aria-hidden 属性。否则,该实现将被视为错误,并标记为问题 #634。
- 有键实现必须通过测试驱动程序中的
npm run isKeyed
测试,否则它们就是错误的。请注意,这个测试可能不是充分的,但对于有键是必要的(我们不时发现新的漏洞)。对于这种情况,有错误 #694。 - 在客户端代码中使用请求动画帧调用,特别是当仅对某些基准操作应用时,被认为是不良风格,会被应用注释 #796。请注意,框架可以自由选择是否使用 RAF。
- 手动 DOM 操作(如直接在选定行上设置 danger 类)引发了一些有争议的讨论。根据你使用的框架,这可能是惯用风格,也可能不是。无论如何,它都会被应用注释 #772。
- 实现应该在状态中保持选定的行(即不是每行的标志,而是表格的一个引用、id 或索引),并使用该信息进行渲染。为每行保留选择标志可能更快,但被认为是不良风格。因此,这些实现会得到注释 #800。
- 显式事件委托是另一个引发许多讨论的领域。在客户端代码中使用显式事件委托的实现会得到注释 #801。框架本身可以自由使用事件委托。
有用的提示:
- 不要以 vanillajs 作为参考开始你的实现。它使用直接 DOM 操作(因此有注释 #772),仅作为性能基准,而不是最佳实践实现。相反,选择一个与你的框架相似的框架。
- 不要忘记通过在 HTML 中的某处添加以下内容来预加载字形图标:
<span class="preloadicon glyphicon glyphicon-remove" aria-hidden="true"></span>
,否则你将获得糟糕的性能。 - 小心不要在你的 /dist 目录中留下 gzip 压缩文件。不幸的是,当这些文件存在时,web 服务器会优先选择它们,我们无法改变这一点(这意味着你可能在观察一个过时的构建)。
这项工作源自 Richard Ayotte 在 https://gist.github.com/RichAyotte/a7b8780341d5e75beca7 上发布的基准测试,并添加了更多框架和更多操作。感谢这项伟大的工作。
感谢 Baptiste Augrain 使基准测试更加复杂并添加框架。
历史
在 github 或 npm 上超过一年没有重大活动的框架将被移除(自动提交如 dependabot 和小更新,如文档编辑,将被忽略)。
2023-12-10
以下框架在 Chrome 120 之后被归档。它们的最后结果包含在 Chrome 120 结果 中。
- petite-vue
2023-11-07
以下框架在 Chrome 119 之后被归档。它们的最后结果包含在 Chrome 119 结果 中。
- sifrr
2023-10-22
以下框架在 Chrome 118 之后被归档。它们的最后结果包含在 Chrome 118 结果 中。
- 1more
- bdc
- choo
- domdiff
- domvm
- endorphin
- etch
- forgo
- fullweb-helpers
- fullweb-template
- heresy
- hullo
- lighterhtml
- neverland
- resonatejs
- sledgehammer
- uhydro
2020-7-9
- etch 最后一次提交 2018 年 9 月 12 日
- hyperoop 最后一次重大提交 2018 年 12 月 23 日
- faster-dom(将被新的 revact 实现替代)
- plastiq(将被新的 Hyperdom 实现替代)
- rawact 最后一次提交 2018 年 12 月 3 日
- react-djinn 最后一次 NPM 发布 2019-05-03(Github 组织和仓库不再可用)
- react-lite 最后一次提交 2019 年 3 月 29 日
- redux-combiner 最后一次提交 2018 年 5 月 14 日
- surplus 最后一次提交 2019 年 1 月 5 日
- gruu 最后一次提交 2019 年 6 月 23 日
- lite-html 最后一次提交 2018 年 9 月 7 日
2019-9-16
- angular-light 最后一次提交 2017 年 11 月 30 日
- nx. 最后一次提交 2017 年 2 月
- maik-h 最后一次提交 2017 年 12 月 15 日
- rivets 最后一次提交 2016 年 10 月 22 日
- tsers. 最后一次提交 2016 年 6 月 19 日