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

相关文章

  • 监控微信小程序中的慢HTTP请求过程详解

    监控微信小程序中的慢HTTP请求过程详解

    这篇文章主要介绍了监控微信小程序中的慢HTTP请求过程详解,Fundebug 的微信小程序监控插件在 0.5.0 版本已经支持监控 HTTP 请求错误,在小程序中通过wx.request发起 HTTP 请求,如果请求失败,会被捕获并上报,需要的朋友可以参考下
    2019-07-07
  • JS获得一个对象的所有属性和方法实例

    JS获得一个对象的所有属性和方法实例

    下面小编就为大家带来一篇JS获得一个对象的所有属性和方法实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-02-02
  • 原生js轮播特效

    原生js轮播特效

    这篇文章主要为大家详细介绍了原生js轮播特效,简单实用的代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-05-05
  • js+html实现周岁年龄计算器

    js+html实现周岁年龄计算器

    这篇文章主要为大家详细介绍了js+html实现周岁年龄计算器的方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-06-06
  • Js实现累加上漂浮动画示例

    Js实现累加上漂浮动画示例

    这篇文章主要为大家介绍了Js实现累加上漂浮动画示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-11-11
  • JavaScript学习笔记之取值函数getter与取值函数setter详解

    JavaScript学习笔记之取值函数getter与取值函数setter详解

    这篇文章主要介绍了JavaScript取值函数getter与取值函数setter,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-08-08
  • js中对函数设置默认参数值的3种方法

    js中对函数设置默认参数值的3种方法

    这篇文章主要介绍了js中对函数设置默认参数值的3种方法吗,3种方法都具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2015-10-10
  • ES6入门教程之Iterator与for...of循环详解

    ES6入门教程之Iterator与for...of循环详解

    最近在学习ES6,刚刚看到Iterator和for...of循环这一章,所以想要跟大家略微分享一下,下面这篇文章主要给大家介绍了关于ES6入门学习中Iterator与for...of循环的相关资料,不足之处还望大家多多指正,需要的朋友们可以参考学习。
    2017-05-05
  • 带有定位当前位置的百度地图前端web api实例代码

    带有定位当前位置的百度地图前端web api实例代码

    这篇文章主要介绍了带有定位当前位置的百度地图前端web api实例代码 的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2016-06-06
  • js操作输入框提示信息且响应鼠标事件

    js操作输入框提示信息且响应鼠标事件

    注册网站的输入框就有默认提示值,当获取鼠标焦点的时候,默认值被删除,当用户没输入东西焦点离开的时候,又恢复默认提示值
    2014-03-03

最新评论