babel-loader
babel-loader 是webpack和babel之前的桥梁,配置对应的plugins去结合babel将ES6+语法转译成ES5语法
babel工作原理
babel是一个转译器,babel转译过程,parsing、transforming、generating
以ES6转译ES5代码为例,babel转译的具体过程如下:
1、parsing,ES6代码经过babylon转译成AST语法树
2、transforming,通过plugin将转译的AST语法树在进行遍历转译
(如果这个阶段不使用任何插件,那么babel会原样输出代码。)
3、babel-generator将编译好的AST树生成ES5代码
那其实babel的工作都是依赖于plugin去处理的
vuecli搭建的项目中,会有一个babel.config.js文件,官方建议在这里配置,另外你可以运行vue ui查看更多的配置项
//babek.config.js
module.exports = {
presets: ['@vue/app'],
plugins: []
}
//.babelrc
{
"presets":[
"@babel/preset-env"
],
"plugins":[
]
}
@vue/app是@vue/babel-preset-app的缩写,对应的依赖在package-lock中看到
那这里配置的@vue/babel-preset-ap其实是和@babel/preset-env作用是一样的包括很多的plugins去处理ES6+的语法如果不包含的在plugins里扩充。
注意很重要的一点就是,babel只是转译新标准引入的语法,比如ES6的箭头函数转译成ES5的函数,Class转成函数;而新标准引入的新的原生对象,部分原生对象新增的原型方法,新增的API等(如Proxy、Set等),这些babel是不会转译的。需要自己去引入polyfill来解决
例如
module.exports = {
presets: [
['@vue/app', {
polyfills: [
'es6.promise',
'es6.symbol'
]
}]
]
}
babel-polyfill
那经常采用的是babel-polyfill是core-js和regenerator-runtime两者的集合,从babel7.4开始推荐引入
core-js是核心解决polyfill的集合,但有个缺点是不满足ES6的generator函数,regenerator-runtime可以解决,所以采用core-js和regenerator-runtime的结合。
需要注意的是babel-polyfill文件比较大,假设只用一部分功能的时候,配置需要按需引入
那babel-polyfill存在的问题:
1) 污染全局环境:要做到兼容只能挂在到全局上,所以要看使用场景,如果做一个独立的系统则无所谓;如果是第三方的库,这个是引入使用的时候你重新定义了比如Promise这样的东西,就会导致覆盖污染全局等问题
解决
需要应用babel-runtime:首先安装@babel/plugin-transform-runtime和@babel/runtime这两个插件,通过plugin-transform-runtime来配置就不会污染全局环境
// .babelrc babel-polyfill按需引入
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage",
"corejs": 3
}
]
],
"plugins": [
//在这里面做配置
[
"@babel/plugin-transform-runtime",
{
"absoluteRuntime": false,
"corejs": 3,
"helpers": true,
"regenerator": true,
"useESModules": false
}
]
]
}
transform-runtime如何处理的
1、将代码中用到的ES6+的新对象和静态方法由core-js导出对应的对象和方法替换
2、当使用generators或async函数时,用babel-runtime/regenerator导出的函数取代(类似polyfill分成regenerator和core-js两个部分)
3、把Babel生成的辅助函数改为用babel-runtime/helpers导出的函数来替代(babel默认会在每个文件顶部放置所需要的辅助函数,如果文件多的话,这些辅助函数就在每个文件中都重复了,通过引用babel-runtime/helpers就可以统一起来,减少代码体积)