babel学习笔记
先是看到前端早读课【第1065期】再见,babel-preset-2015,听说现在有了babel-preset-env,别的什么preset都不需要了,还可以通过useBuiltIns设置成usage,只需要install一下babel-polyfill,其他全交给babel处理就行了。
看完屁颠屁颠得去拿自己项目开刀把preset换了,把import "babel-polyfill"删了,把babel-transform-runtime啊,preset-2015啊,preset-stage-2啊这些不再需要的包都卸了,结果各种报错,心灰意冷。。。肯定是自己哪儿弄错了,算了还是忙别的去吧有空再折腾。。。
前两天又看到前端早读课推了一篇很长的【第1089期】babel到底该如何配置。边看,边跟着做了一遍,作者真的很用心,在github上放了配套的demo,看完之后我靠叫一个豁然开朗,回头再瞅瞅那边《再见babel-preset-2015》,多少有些遗漏细节,甚至有些误导人。
经过一番折腾,总算是把自己项目里的babel配置调整好了,所有js文件从原来的1.85m缩小到1.62m。效果还挺好的。折腾了不少时间,改动其实就一个地方,就是配置文件.babelrc,记录一下自己折腾的过程。
plugins: ["transform-runtime"] 与 babel-polyfill
最开始没弄清楚配置文件里的"plugins": ["transform-runtime"]是干嘛的,《babel到底该如何配置》说得非常清楚,babel就是通过其各种plugins来实现将指定的js转换成自己想要的样子,比如只要转换箭头函数,就只需要先安装对应的plugin
npm install --save-dev babel-plugin-transform-es2015-arrow-functions
然后加到plugins里面
"plugins": ["transform-es2015-arrow-functions"]
这样babel就能转换箭头函数了。
transform-runtime插件和babel-polyfill所实现的结果一样,可以转换像Object.assign啊,Array.prototype.includes啊这类在es原生对象上的扩展方法,但实现的原理完全不同。babel-polyfill是直接在对象的prototype上进行同名方法扩展来实现和es6相同的功能,所以只需要全局引入一次babel-polyfill,自己的代码就不用做任何处理就能在低版本浏览器上执行了。
而transform-runtime插件做的事情,是改写每一个用到es6扩展方法的地方,让其实现es6方法相同的功能。举个例子:
在使用babel-polyfill的时候,js里需要这么写:
import "babel-polyfill"; let arrayLike = { '0': 'a', '1': 'b', '2': 'c', length: 3 }; let arr2 = Array.from(arrayLike);
然后就没然后了,甚至都不用执行babel,只要install过babel-polyfill就够了。因为babel-polyfill中会用ES3的方式实现一遍Array.from方法,所以,之后整个项目用到Array.prototype.includes的时候,都不会再需要babel做任何事情,直接在低版本上浏览器执行includes方法吧,安全省心。
换成是用"transform-runtime"插件就是另外一回事儿了。我们的js文件里不需要引入babel-polyfill,但babel这时候就要开始干活了,他会把这段代码改写成:
import _Array$from from 'babel-runtime/core-js/array/from'; let arrayLike = { '0': 'a', '1': 'b', '2': 'c', length: 3 }; let arr2 = _Array$from(arrayLike); // ['a', 'b', 'c']
用babel-runtime里的方法去实现Array.from,然后把js文件里所有用到Array.from的地方全都替换掉。
本以为那这两种方式取其一就行了。但后来发现transform-runtime是不会去替换Array.prototype.includes这中实例方法的,所以还得全局引入babel-polyfill,这样一来transform-runtime感觉彻底变成了一个多余的东西,除非整个项目里不用es6的原生类实例方法。所以最终,直接卸了transform-runtime。
presets 和 "presets": ["env"]
presets的用处也是看《babel到底该如何配置》搞清楚的,大致就是plugins的各种组合。也就是说,没有presets也无所谓,但是要非常清楚项目里用到了那些es6甚至更高级的功能,然后找到相应的plugin引入到plugins配置项里,这样也OK,但估计不太会有人吃饱了撑的干这种事情。
之前的presets有2015,2016,stage-1~4(对应处于提案的四个阶段的各个功能)等等,其实就是把相应的功能对应的plugins组合一下起个名字。比如要用es6的所有功能,只要在presets里配置一下
"presets": ["es2015"]
如果要用es6和所有处于提案第二阶段的功能
"presets": ["es2015","stage-2"]
好了,到这里,说说那个困扰我不少时间的babel-preset-env,我以为这个preset只要告诉他要支持那个版本的浏览器,他就会把相关的所有的plugins都引入进来,所以屁颠屁颠把其他preset和所有plugins都删了。结果打包的时候报错了。原因是我在项目里用了Vuex里推荐的处于stage-3阶段的对象展开运算符
...mapState({})
但是,babel-preset-env里没有对应的babel-plugin-transform-object-rest-spread这个plugin!
所以,要么在plugins里把这个plugin再加上,要么再把stage-3(或者stage-2)加到presets里面。这感觉和想象中的不一样啊,说好的一个env搞定一切的呢。。。
babel-polyfill 和 useBuiltIns
第一篇中说只需要安装babel-polyfill就行了,然后我直接把import "babel-polyfill"这句话删了,然后IE9上就各种开始报错,明显没自动把polyfill打包进去嘛。后再看了一下官网,还是说要import的,只是搭配useBuiltIns,打出来的包能小一些。
后来再去看第一篇作者自己的博客,评论里有相同的问题,然后才知道作者在说[email protected]的功能。。。