webpack4配置总结(四)

上一篇整理了loader的使用,这篇整理一下babelpostcss-loader的配置。

.babelrc

插件跟预设

其实,.babelrc配置文件是用来支持我们在使用babel解析编译代码时,使用一些插件来处理高版本语法或者提案语法。插件跟预设的区别在于,预设其实是一些插件的组合,它方便我们处理一类语法的打包编译问题,不需要我们手动配置一系列插件。.babelrc里只需要写成一个JSON格式。

预设@babel/preset-env

按照官网的说法,@babel/preset-env是一个智能的预设,它可以解析编译最新的js语法。它可以根据目标浏览器环境情况编译合适的插件列表,使编译打包后的项目能在目标浏览器环境中正常运行。

而目标浏览器的罗列,可以在package.json中使用browserslist属性设置,也可以设置预设属性targets,还可以在项目根目录上创建.browserslistrc来设置,如:

1
2
// .browserslistrc
cover 95%

@babel/preset-env除了上面提到的targets配置项外,还有两个配置项是在我的项目中使用到的。一个是useBuiltIns,另一个是corejs,两个配置项有关联。

useBuiltIns有三个值,其中默认值为false,意思是不引入babel编译的结果,把引入的位置,引入那些polyfill交给用户处理。之前的做法是安装@bable/polyfill,然后在入口文件中引入,但其实这样会引入很多用不着的polyfill。

这里说明一下,polyfill在MDN上有定义解释,我这里就摘一下:

Polyfill 是一块代码(通常是 Web 上的 JavaScript),用来为旧浏览器提供它没有原生支持的较新的功能。
比如说 polyfill 可以让 IE7 使用 Silverlight 插件来模拟 HTML Canvas 元素的功能,或模拟 CSS 实现 rem 单位的支持,或 text-shadow,或其他任何你想要的功能。

如果设置值为entry,则会将文件中import '@babel/polyfilll'语句结合targets,转换为一系列引入语句,去掉目标浏览器已支持的polyfilll模块,不管代码里有没有用到,只要目标浏览器不支持都会引入对应的polyfilll 模块。虽然要比全部引入要好,但是使用不到的polyfill还是会有。

而且现在babel也废弃了@bable/polyfill,所以需要我们自己选择使用哪个兼容库。那么这里的useBuiltIns也就最好设置为usage

设置usage,则不需要手动在代码中引入@babel/polyfill,而且打包的时候会根据实际代码的需要引入实际用上的polyfill模块。同时,因为@babel/polyfill已经不建议用,被废弃了,所以我们需要通过设置corejs来指明使用的那个版本的core-js

其实@babel/polyfill是对core-js(core-js/stable)做了封装,而且引用了regenerator-runtime/runtime
core-js其实是把所有新语法通过ES6之前的语法实现(现在已经支持到ES2019)。

这里可以设置为23,指定使用core-js哪个版本。关于core-js到底使用2还是3,怎么选择,原因是什么,我也还没有搞得很明白,网上关于这方面的说法不多,目前自己的项目中用的是2,而且版本是`core-js@2.6.11`,安装版本不同可能还会报错。所以这部分需要等以后了解了再整理出来。

所以最终预设的配置如下:

1
2
3
4
5
6
7
8
9
{
"presets": [ // 预设,从下到上执行
["@babel/preset-env", {
"useBuiltIns": "usage", // 使用的api 会自动转化 并且是按需加载
"corejs": 2 // 替换掉babel-polyfill,babel-polyfill已不建议使用
}]
],
// ...
}

插件

转回来我们来了解一下什么是插件。因为babel是一个编译器,虽然有解析,转换和打印输出三个步骤,但实际在转换上并不会做什么处理,也就是什么的不做就到打印输出了。但它支持插件,可以通过插件来进行代码转换。所以,所谓的插件,就是可以对babel解析的代码进行转换的编译工具(自己理解)。

配置插件,是通过plugins这个配置属性来配置的。plugins接受一个数组,这个数组用来列举插件。执行的顺序是从上到下。如果插件需要进一步配置,则写成数组。数组的第一项是插件名,第二项是配置json。

这里简单介绍一下我项目中使用到的插件:

@babel/plugin-proposal-decorators插件是用来解析支持装饰器草案语法的,按babel的举例演示,实际上是把装饰器语法转换为高级函数,用来返回类或者函数。这个插件有两个可选配置,一个是decoratorsBeforeExport,用来指定是否支持export语法前使用装饰器。值为truefalse。另一个是legacy,用来指定是否支持旧式装饰器的语法和行为,默认值为false

@babel/plugin-proposal-class-properties插件是用来解析支持class草案语法。这个插件有一个可选配置loose,这个配置默认为false,即

1
2
3
class A {
x = 1
}

x会使用Object.defineProperty来严格定义。如果loose设置为true,则为宽松处理,x将直接使用赋值表达式来处理。

上面两个插件如果同时使用时,官网有对配置上有明确的说明,@babel/plugin-proposal-decorators必须要在@babel/plugin-proposal-class-properties前面调用,而且如果@babel/plugin-proposal-decoratorslegacy设置了true,则要求@babel/plugin-proposal-class-propertiesloose设置为true

最后一个插件是@babel/plugin-transform-runtime。这个插件还需要安装@babel/runtime,是用例使用帮助函数来压缩代码。插件的功能是将编译后代码中把重复的代码块用过帮助函数来处理,使得代码量得以减少。

最后列一下配置:

1
2
3
4
5
6
7
{
"plugins": [ // 插件 从上到下执行
["@babel/plugin-proposal-decorators", {"legacy": true}], // 支持解析装饰器草案语法,legacy表示保留装饰器语法,需要@babel/plugin-proposal-class-properties的loose配置为true
["@babel/plugin-proposal-class-properties", {"loose": true}], // 支持解析class草案语法,loose表示宽松处理,即class A{a = 1}会转化为class A{this.a = 1}
"@babel/plugin-transform-runtime" // 需要安装@babel/runtime,使用帮助函数压缩代码
]
}

postcss.config.js

上篇说到,postcss是一个用来转化css代码的js工具,它支持配置插件来转化css代码,可以直接在webpack配置中配置option,也可以通过postcss.config.js来配置。

.babelrc的最外层写法不一样,postcss.config.js需要写成一个模块导出。里面的结构好像也不一样,只有一个plugins的配置项,这个配置项需要传入一个数组,这个数组的每一项就是需要使用的插件,通过require引入。

官方文档上列了很多插件,这里就不细细展开,只简单整理一下项目中使用的两个插件。

autoprefixer插件是用来添加浏览器前缀。这个插件方便我们在打包的时候生成不同浏览器不同前缀的样式。

postcss-pxtorem是用来把px单位转化为rem的插件。这个插件主要使用在移动端。移动端的屏幕尺寸有很多种,尺寸比例也各不相同。一般我们会使用rem的写法,只是一套经典的解决方案。这里使用postcss-pxtorem,配置的时候可以配置rootValue,用来指定一单位rem等于多少px。这样可以让你在开发时只要使用px,打包的时候会以375px视窗宽度换算宽度的rem值,然后项目上线后会以这个值来计算其他宽度的比例。比如rootValue设置37.5,则视窗宽度将固定为10rem,其他尺寸均以这个为标准。

这个插件让我们不需要关注怎么实现移动端屏幕适配问题。当然,如还有有些配置项还是需要注意的,如propList可以配置那些样式属性不需要转化,unitPrecision为转换成rem后保留的小数点位数,exclude为排除转化的目录。

还有一个问题,如果有需要不转化px,还可以写成PX

最后,附上配置:

1
2
3
4
5
6
7
8
9
10
11
module.exports = {
plugins: [
require('autoprefixer'),
require('postcss-pxtorem')({
rootValue: 30.1932367, // body宽折算为12.42rem。如果这里设置37.5,则宽折算为10rem
unitPrecision: 5,
propList: ['*'],
// exclude: /node_modules/i
})
]
}

接下来将整理webpack配置中的插件plugins