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

 更新时间:2024年01月21日 10:59:55   作者:大家的林语冰 人猫神话  
这篇文章主要介绍了JS 生态系统加速Polyfill函数使用实例探索,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

引言

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

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

  • PostCSS,SVGO 等等
  • 模块解析
  • 使用 eslint
  • npm 脚本
  • draft-js emoji 插件
  • polyfill 暴走
  • 桶装文件崩溃
  • Tailwind CSS

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函数的资料请关注脚本之家其它相关文章!

相关文章

  • window.open不被拦截的简单实现代码(推荐)

    window.open不被拦截的简单实现代码(推荐)

    下面小编就为大家带来一篇window.open不被拦截的简单实现代码(推荐) 。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-08-08
  • TypeScript中遍历对象键的方法

    TypeScript中遍历对象键的方法

    在日常的TypeScript开发中,经常需要遍历对象的键来执行各种操作,,在本文中,我们将深入研究这个问题,并提供几种解决方案,以便在遍历对象键时更安全、更灵活地操作,文中有详细的代码讲解,需要的朋友可以参考下
    2023-11-11
  • JavaScript数据结构之数组的表示方法示例

    JavaScript数据结构之数组的表示方法示例

    这篇文章主要介绍了JavaScript数据结构之数组的表示方法,从数据结构线性表的角度分析了数组的原理并结合实例形式分析了javascript数组的定义与使用方法,需要的朋友可以参考下
    2017-04-04
  • 彻底搞懂JavaScript中的apply和call方法(必看)

    彻底搞懂JavaScript中的apply和call方法(必看)

    下面小编就为大家带来一篇彻底搞懂JavaScript中的apply和call方法(必看)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-09-09
  • JS更改select内option属性的方法

    JS更改select内option属性的方法

    这篇文章主要介绍了JS更改select内option属性的方法,涉及JavaScript动态操作页面select元素属性的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-10-10
  • javascript随机将第一个dom中的图片添加到第二个div中示例

    javascript随机将第一个dom中的图片添加到第二个div中示例

    此代码的是一个简单的例子,将第一个div中的五张图片中,提取随机两张显示到第二个div中,具体实现如下,感兴趣的朋友可以参考下
    2013-10-10
  • js实现简单拼图小游戏

    js实现简单拼图小游戏

    这篇文章主要为大家详细介绍了js实现简单拼图小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • JavaScript异步编程常见面试题汇总

    JavaScript异步编程常见面试题汇总

    本文将带大家学习异步编程这一块内容,鉴于异步编程是js中至关重要的内容,所以我们将学习异步编程涉及到的重点和难点,同时这一块内容也是面试常考范围,希望对大家有所帮助
    2023-02-02
  • 无间断滚动marquee的详细用法解析

    无间断滚动marquee的详细用法解析

    无间断滚动marquee的详细用法解析...
    2006-08-08
  • 微信小程序使用echarts获取数据并生成折线图

    微信小程序使用echarts获取数据并生成折线图

    这篇文章主要介绍了微信小程序使用echarts获取数据并生成折线图,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-10-10

最新评论