You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
NOTE: Instance methods such as "foobar".includes("foo") will not work since that would require modification of existing built-ins (you can use @babel/polyfill for that).
This option adds direct references to the core-js module as bare imports. Thus core-js will be resolved relative to the file itself and needs to be accessible. You may need to specify core-js@2 as a top level dependency in your application if there isn't a core-js dependency or there are multiple versions.
NOTE: Only use require("@babel/polyfill"); once in your whole app. Multiple imports or requires of @babel/polyfill will throw an error since it can cause global collisions and other issues that are hard to trace. We recommend creating a single entry file that only contains the require statement.
先聊下 babel 与 polyfill
ES2015 标准已经发布三年了, 在项目中我们会写 ES2015(或者更高版本) 的代码, 但是代码最终运行的环境(浏览器)通常是不可控的, 因此需要将 ES2015 编译为低版本代码, 来保证所有目标环境可运行
babel 就是用来将高版本编译为低版本的工具, 在不配置额外插件的情况下, babel 仅仅是将 ES2015 的语法(例如
for of
)转换, 而 ES2015 新增的类/方法(例如Set
或者[1, 2].findIndex()
)会保持原样这时候就需要 polyfill 了, 需要在项目入口文件最开头引入
@babel/polyfill
. 但是在项目中, 通常仅用到了有限的 polyfill 内容, 而最新版的@babel/polyfill
包体积有 81.2k(gzipped 27.7k) 大小那么可不可以只 polyfill 代码中用到的内容呢?
假设有如下源码:
接下来试试不同的 polyfill 方案
@babel/plugin-transform-runtime
https://babeljs.io/docs/en/babel-plugin-transform-runtime
首先是使用 transfrom-runtime 这个插件, 它可以仅对代码中用到的类/静态方法进行 polyfill, 但是对于原型链上新增的方法无效
添加 babel 配置
编译后:
编译后的代码仅仅引入了 Set 实现, 但是
findIndex()
没有 polyfill如果你确定不会使用任何原型链上新增的方法, 那么
@babel/plugin-transform-runtime
会是一个不错的选择@babel/preset-env + useBuiltIns
https://babeljs.io/docs/en/babel-preset-env
@babel/preset-env
支持你配置目标环境, 它的useBuiltIns
选项, 有三个可选值 "usage" | "entry" | false(默认值)useBuiltIns: 'entry'
该选项需要在项目中引入
@babel/polyfill
, babel 会自动将@babel/polyfill
分解为更小的、仅目标环境需要的 polyfill 引用首先要在源码第一行添加 polyfill 引用
修改 babel 配置
编译后:
编译后的代码自动引入的 Chrome 40 不支持的所有内容, 包括
Set
和findIndex()
, 它并不会去分析源码用到的哪些内容尝试修改 targets 为 Chrome 60, 编译后:
由于 Chrome 60 已经支持
Set
和findIndex()
了, 因此 polyfill 的内容并不包括它俩useBuiltIns: 'usage'
该选项目前还是实验性的, 我们来试试它打包后是怎样的
首先要去掉源码中的
import '@babel/polyfill'
修改 babel 配置:
编译后:
哇, 看起来这似乎就是我需要的!
但它是分析到我使用了
Array.protoptype.findIndex()
才添加 polyfill 的吗? 来做个试验看看修改源码:
这次我没有去调用 Array 原型链的 findIndex, 而且调用了自己实现的 String 原型链的 findIndex
编译后:
😂原来它是直接匹配的方法名, 添加了同名的 polyfill
useBuiltIns 结论
useBuiltIns: 'entry'
是按目标环境去 polyfill 的, 不关心代码中是否使用, 可以保证在目标环境一定可用useBuiltIns: 'usage'
目前还是实验性的配置, 它会分析代码调用, 但是对于原型链上的方法仅仅按照方法名去匹配, 可以得到更小的 polyfill 体积. 但是它不会去分析代码依赖的 npm 包的内容, 如果某个 npm 包是需要一些 polyfill 的, 那这些 polyfill 并不会被打包进去为什么原型链上的方法不能根据是否用到, 然后按需去 polyfill 呢?
主要是因为 JavaScript 动态类型的特性, 有些变量/实例的类型是运行时才能确定的, 而 babel 仅仅是对代码的静态编译, 因此它并不能确定
findIndex()
到底是不是Array.protoptype.findIndex()
, 例如:data 的类型由运行时接口返回的内容决定, 所以 babel 不能实现原型链方法按需 polyfill
TypeScript 具备静态类型, 可以按需 polyfill 吗?
结论是不能! 关于 polyfill 的讨论可以看看 microsoft/TypeScript#3101
TypeScript 可以用
--lib
参数指定要依赖的库, 搭配ts-polyfill
可以对依赖的库进行 polyfill, 但是指定依赖时不能详细到某个方法, 只能ESNext.Array
如果非要只 polyfill
Set
和findIndex
呢?可以手动引入
core-js
中相应的实现, 譬如:不推荐这种做法, 除非追求最小的 polyfill 大小, 你必须清楚的知道项目中用到了哪些内容. 但在实际项目中, 尤其多人开发的项目, 通常很难去控制
The text was updated successfully, but these errors were encountered: