javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > JS Polyfill函数

JS 生态系统加速Polyfill函数使用实例探索

作者:大家的林语冰 人猫神话

这篇文章主要介绍了JS 生态系统加速Polyfill函数使用实例探索,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

引言

长话短说:一大坨人气爆棚的 npm 软件包的依赖比它们需要的软件包多 6-8 倍。其中大部分都是多余的 polyfill(功能补丁),这是 node_modules 文件夹过度肥胖的关键原因之一。eslint 生态系统似乎是最倒霉的倒霉蛋。

本期《前端翻译计划》共享的是“加速 JS 生态系统系列博客”,包括但不限于:

Polyfill 暴走

我们研究了运行时性能,私以为瞄一下 Node 模块安装时间会很有趣。关于各种算法优化,或使用更高性能的系统调用,已经写了一大坨博客,但为什么我们首先会遭遇此问题呢?为什么每个 node_modules 文件夹都过度么肥胖?所有这些依赖来自何方?

这一切都始于我有一个朋友注意到,它的项目依赖树有些奇葩。每当它更新一个依赖时,它就会引入几个新的依赖,且随着后续每次更新,依赖的总数与日俱增。

├─┬ arraybuffer.prototype.slice 1.0.2
│ └─┬ define-properties 1.2.1
│ └── define-data-property 1.1.0
├─┬ function.prototype.name 1.1.6
│ └─┬ define-properties 1.2.1
│ └── define-data-property 1.1.0
├─┬ globalthis 1.0.3
│ └─┬ define-properties 1.2.1
│ └── define-data-property 1.1.0
├─┬ object.assign 4.1.4
│ └─┬ define-properties 1.2.1
│ └── define-data-property 1.1.0
├─┬ regexp.prototype.flags 1.5.1
│ ├─┬ define-properties 1.2.1
│ │ └── define-data-property 1.1.0
│ └─┬ set-function-name 2.0.1
│ └── define-data-property 1.1.0
├─┬ string.prototype.trim 1.2.8
│ └─┬ define-properties 1.2.1
│ └── define-data-property 1.1.0
├─┬ string.prototype.trimend 1.0.7
│ └─┬ define-properties 1.2.1
│ └── define-data-property 1.1.0
└─┬ string.prototype.trimstart 1.0.7
└─┬ define-properties 1.2.1
└── define-data-property 1.1.0

平心而论,一个包可能依赖额外的依赖理由充分。在这里,我们开始注意到一个模式:新的依赖都是 JS 函数的 polyfill,这些函数一直被普遍支持。举个栗子,Object.defineProperties 方法是作为 2013 首个公共 Node 0.10.0 版本的一部分。甚至 IE9(Internet Explorer 9)也支持它。虽然但是,一大坨软件包依赖 polyfill 来实现。

在引入 define-properties 的各种包中,有 eslint-plugin-react。它引起了我的注意,因为它在 React 生态系统中人气爆棚。为什么它会为 Object.defineProperties 引入 polyfill?这在所有 JS 引擎都内置了。

没有 polyfill 的 polyfill

阅读包的源码发现了更奇葩的事情:polyfill 函数直接导入和调用,而不是在运行时环境中修补缺失的功能。polyfill 的重点是对用户代码透明。它应该检查需要打补丁的函数或方法是否可用,并且当且仅当需要时才添加它。当不需要 polyfill 时,它不直接躺平。对我而言奇怪的是,这些函数像库中的函数一样直接使用。

// 为何 defined 函数直接导入?
var define = require('define-properties')

// 更糟糕的是,为何它被直接调用了?
define(polyfill, {
  getPolyfill: getPolyfill,
  implementation: implementation,
  shim: shim
})

相反,它们应该直接调用 Object.definePropertiespolyfill 的重点是环境补丁,而不是直接调用。将其与 Object.defineProperties 的 polyfill 比较应该是什么是这样:

// 检查当前环境是否已经支持 Object.defineProperties
// 如果是,那我们直接躺平就欧了
if (!Object.defineProperties) {
  // Patch in Object.defineProperties here
}

讽刺的是,使用 define-properties 的高频热点是在其他 polyfill 内部,它们加载了更多 polyfilldefine-properties 包依赖更多的依赖,而不仅仅是它本身。

var keys = require('object-keys')
// ...
var defineDataProperty = require('define-data-property')
var supportsDescriptors = require('has-property-descriptors')()

var defineProperties = function (object, map) {
  // ...
}

module.exports = defineProperties

在 eslint-plugin-react 内部,该 polyfill 通过 Object.entries() 的 polyfill 加载来处理其配置:

const fromEntries = require('object.fromentries') // <- 为何它直接就使用了?
const entries = require('object.entries') // <- 为何它直接就使用了?
const allRules = require('../lib/rules')

function filterRules(rules, predicate) {
  return fromEntries(entries(rules).filter(entry => predicate(entry[1])))
}

const activeRules = filterRules(allRules, rule => !rule.meta.deprecated)

整理小结

在撰写本文时,安装 eslint-plugin-react 总共需要引入高达 97 个依赖。我很好奇其中有多少是 polyfill,并开始在本地将它们逐个打补丁。完成所有操作后,依赖总数断崖式下跌至 15 个。原来的 97 个依赖项中,有 82 个不再需要。

巧合的是,在各种 eslint 预设中同样流行的 eslint-plugin-import 也显示出类似问题。安装后,node_modules 文件夹将塞满 87 个软件包。经过另一次本地清理之后,我将这个数字减少到了 17 个。

填满每个人的磁盘空间

现在您可能想知道自己是否深受其害。我进行了快速搜索,基本上您能想到的所有人气爆棚的 eslint 插件或预设都难逃毒手。出于某种原因,这整个考验让我想起了不久前此行业发生的 is-even/is-odd 事件。

拥有如此多的依赖使得审核项目的依赖难上加难。这也浪费空间。举个栗子:删除项目中的所有 eslint 插件和预设就删除了 220 包。

pnpm -r rm eslint-plugin-react eslint-plugin-import eslint-import-resolver-typescript eslint-config-next eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-plugin-prettier prettier eslint-config-prettier eslint-plugin-react-hooks
Scope: all 8 workspace projects
.                                        | -220 ----------------------

也许我们一开始就不需要那么多依赖。我想起了 Erlang 编程语言的创建者的这句精彩的名言:

您只想要一根香蕉,但您得到的是一只拿着香蕉的大猩猩和整个丛林。

免责声明

本文属于是语冰的直男翻译了属于是,略有删改,仅供粉丝参考,英文原味版请传送 Speeding up the JavaScript ecosystem - Polyfills gone rogue[1]

 https://marvinh.dev/blog/speeding-up-javascript-ecosystem-part-6 

以上就是JS 生态系统加速Polyfill函数使用实例探索的详细内容,更多关于JS Polyfill函数的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文