再也不怕面试官问我webpack系列1—初识babel
做好前端工程化,就必须懂webpack。本文是webpack学习系列文章,记录笔者的学习笔记,和各位共勉,一起学好前端工程化。
webpack学习笔记系列,本文是《Webpack+Babel入门与实战》一书的精读及知识点记录整理。
1. 认识babel
1.1 是什么?
Babel是一个工具集,主要用于将ES6版本的JS代码转换为ES5等向后兼容的JS代码,从而使代码可以运行在低版本浏览器或其他环境中。
1.2. 做什么?
babel主要做两部分工作
- 语法转化 例如箭头函数、const、let、class类语法、async等新语法
- 补齐API 新的API可分成两类,一类是Promise、Map、Symbol、Proxy、Iterator等全局对象及对象自身的方法,如Object.assign,Promise.resolve;另一类是新的实例方法,如数组实例方法[1,4,-5,10].find((item)=>item < 0)。
1.3. 基本使用
一个完整的Babel转码工程通常包括如下文件。
1)Babel配置文件。 babel.config.js或.babelrc或.babelrc.js或直接写在package配置中
2)Babel相关的npm包。 @babel/core => Babel核心npm包。 @babel/preset-env => 这个npm包提供了ES6转ES5的语法转换规则,我们需要在Babel配置文件里指定使用它。
3)需要转码的JS文件。
4)Babel默认只转化新语法,对新的API需要通过Polyfill来补齐。
2. babel配置
2.1 配置项
babel主要配置项就是plugins、presets这两个数组,我们分别称它们为插件数组和预设数组。
预设
预设是一组Babel插件的集合,例如babel-preset-es2015就是所有处理ES2015的二十多个Babel插件的集合。如果逐个书写,需要写大量的配置,而预设帮我们解决了这个问题。
Babel官方已经针对常用的环境做了如下这些preset包。
1)@babel/preset-env.
2)@babel/preset-react.
3)@babel/preset-typescript. 等等
所有的预设也都需要先安装npm包到node_modules后才可以使用。
2.2 执行顺序
plugins插件数组和presets预设数组是有顺序要求的。如果两个插件或预设都要处理同一个代码片段,那么会根据插件和预设的顺序来执行。规则如下。
1)插件比预设先执行。
2)插件执行顺序是插件数组元素从前向后依次执行。
3)预设执行顺序是预设数组元素从后向前依次执行。
2.3 传递参数
如果要给插件或预设设置参数,那么元素就不能写成字符串了,而要改写成一个数组。数组的第一项是插件或预设的名称字符串,第二项是对象,该对象用来设置第一项代表的插件或预设的参数。例如给@babel/preset-env设置参数。
{
"presets": [
"@babel/preset-env",
{
"useBuiltIns": "entry"
}
]
}
2.4 presets的选择
对标准的ES6语法进行转换以前要用到那么多的预设,而现在只需要一个@babel/preset-env就可以了。
在实际开发过程中,我们通常有以下几个需要:
- 使用@babel/preset-env对标准的ES6语法进行转换
- 类型检查
- 对React等预设对特定语法进行转换。
总结起来,Babel官方提供的预设,我们实际会用到的其实就只有四个。
1)@babel/preset-env.
2)@babel/preset-flow. => 针对js的静态类型检查器
3)@babel/preset-react.
4)@babel/preset-typescript.
对于一个普通的Vue工程,在Babel官方提供的预设中只需要配一个@babel/preset-env就可
2.5 插件的选择
虽然Babel 7官方有九十多个插件,不过其中大多数都已经整合在@babel/preset-env和@babel/preset-react等预设里了,我们在开发的时候直接使用预设就可以。 目前比较常用的插件只有@babel/plugin-transform-runtime。
@babel/plugin-transform-runtime: 可以重用 Babel 注入代码,节省代码大小。
3. babel-polyfill
3.1 是什么
从广义上讲,polyfill是为环境提供不支持特性的一类文件或库,既有Babel官方提供的库,也有第三方提供的。babel-polyfill指的是Babel官方提供的polyfill,本书默认使用babel-polyfill。
3.2 如何使用
传统上的polyfill分为两类,一类是已构建成JS文件的polyfill.js,另一类是未构建的需要安装npm包的@babel/polyfill。
因为@babel/polyfill本质上是由两个npm包core-js与regenerator-runtime组合而成的,所以在使用层面上还可以再细分为是引入@babel/polyfill本身还是引入其组合子包。
总体来说,Babel官方提供的polyfill的使用方法主要有如下几种。
1)直接在HTML文件里引入Babel官方提供的polyfill.js文件。
2)在前端工程的入口文件里引入polyfill.js文件。
3)在前端工程的入口文件里引入@babel/polyfill。
4)在前端工程的入口文件里引入core-js/stable与regenerator-runtime/runtime。
5)在前端工程构建工具的配置文件入口项里引入polyfill.js文件。
6)在前端工程构建工具的配置文件入口项里引入@babel/polyfill。
7)在前端工程构建工具的配置文件入口项里引入core-js/stable与regenerator-runtime/runtime。
=> 从2019开始,推荐使core-js和regenerator-runtime这两个包,也就是方法4与方法7.
4. @babel/preset-env
@babel/preset-env是整个Babel大家族中最重要的一个预设。如果只能配置一个插件或预设,而且要求能完成现代JS工程所需的所有转码要求,那么一定非@babel/preset-env莫属
4.1 如何使用
@bebel/env是@babel/preset-env的简写
module.exports = {
presets: ["@babel/env"],
plugins: []
}
// 需要传参的时候,需要使用数组写法,数组的第二项是要传递的参数
module.exports = {
presets: [[“@babel/env",{}]]
}
4.2 @babel/preset-env与browserslist
browserslist叫作目标环境配置表,除了写在package.json文件里,也可以单独写在工程目录下的.browserslistrc文件里。我们用browserslist来指定代码最终要运行在哪些浏览器或Node.js环境里
"browserslist": [
">1%",
"not ie <= 8"
]
上面配置的含义是,该项目工程的目标环境是市场份额大于1%的浏览器并且不考虑IE 8及以下的IE浏览器。browserslist叫作目标环境配置表
4.3 @babel/preset-env的参数
重点要学习的参数有targets、useBuiltIns、corejs和modules。
4.3.1 targets
modules.exports = {
presets: [["@babel/env",{
targets: {
"chrome": "58",
"ie": "11"
}
}]]
}
如果我们对@babel/preset-env的targets参数进行了设置,那么Babel转码时就不会使用browserslist的配置,而是使用targets的配置。如果不设置targets,那么就会使用browserslist的配置。如果不设置targets,browserslist中也没有配置,那么@babel/preset-env就将所有ES6语法转换成ES5语法。正常情况下,我们推荐使用browserslist的配置而很少单独设置@babel/preset-env的targets参数。
4.3.2 useBuiltlns
PS: builtins的翻译是内嵌的
useBuiltIns参数的取值可以是usage、entry或false。默认值false。
false: 会把Polyfill全部引入 entry: 会根据配置的目标环境找出需要的Polyfill部分引入 usage: 会根据配置的目标环境、项目实际使用的api来按需部分引入
entry与usage这两个参数值的区别:entry这种方法不会根据我们实际用到的API针对性地引入polyfill,而usage可以做到这一点。另外,在使用的时候,entry需要我们在项目入口处手动引入polyfill,而usage不需要。需要注意的是,使用entry这种方法的时候,只能执行一次import polyfill,一般都是在入口文件中进行的。如果要执行多次import,则会发生错误。
4.3.3 core-js
取值 2/3。默认取值是2,这个参数只有在将useBuiltIns设置为usage或entry时才会生效。
core-js取默认值的时候,Babel转码时使用的是core-js@2版本(即core-js 2.x.x)。因为某些新API只有在core-js@3里才有,例如数组的flat方法。当我们需要使用core-js@3的API模块进行补齐时,我们就把该参数设置为3。
需要注意的是,core-js取值为2的时候,需要安装并引入core-js@2版本,或者直接安装并引入polyfill也可以。如果core-js取值为3,则必须安装并引入core-js@3版本才可以,否则Babel会转换失败并提示。
4.3.4 modules
这个参数的取值可以是amd、umd、system-js、commonjs、cjs、auto、false。在不设置的时候,取默认值auto。该参数用于设置是否把ES6的模块化语法转换成其他模块化语法。
常见的两种模块化语法:
- es6 import export
- commonjs require modules.exports
在该参数值是auto或不设置的时候,会发现我们转换后的代码里import都被转换成require了。如果我们将该参数改成false,那么就不会对ES6模块化进行转换,还是使用import引入模块。
使用ES6模块化语法有什么好处呢?在使用Webpack一类的构建工具时,可以更好地进行静态分析,从而可以做Tree Shaking等优化措施。
5 @babel/plugin-transform-runtime
5.1 @babel/runtime与辅佐函数
我们使用babel做转化的时候,babel会为补全我们的语法引入很多函数声明。这样做存在一个问题。在我们正常地进行前端工程开发的时候,少则有几十个JS文件,多则有上千个。如果每个文件里都使用相同的es6语法。那每个文件转化后都会注入这些相同的函数声明。这会导致我们用构建工具打包出来的包体积非常大。
优化:
我们把这些函数声明都放在一个npm包里,需要使用的时候直接从这个包里引入我们的文件。这样即使有上千个文件,也会从相同的包里引入这些函数。使用Webpack这一类的构建工具进行打包时,我们只需要引入一次npm包里的函数,这样就做到了复用,减小了包的体积。@babel/runtime就是上面说的这个npm包,@babel/runtime把所有语法转换会用到的辅助函数都集中在了一起。
6 babel转码过程
Babel转码主要包括三个阶段解析(parse)、转换(transform)和生成(generate)。
这三个阶段分别由@babel/parser、@babel/core和@babel/generator来完成。
解析: 转化成AST语法树
转化: 语法转化
生成: 把转化后的解构还原成JS代码
7 小结
@babel/preset-env (语法转化) @babel/polyfill (API补全)、 与@babel/plugin-transform-runtime是掌握Babel使用方法的非常重要的三个npm包,我们需要理解他们的用法,大概的原理。
后面的系列文章我也将继续展开讲解,和大家一起学习webpack,共勉!
转载自:https://juejin.cn/post/7222577873792843835