waterv 2018-08-24
乱还
最近基于vue-cli2 学习webpack,将vue-cli2的webpack配置强撸了一遍,感觉身体已被掏空。。。但还是收获不少的,起码掌握了webpack的一些基本套路、开发环境和生产环境的概念、根据不同的环境写不同的webpack配置、和一些常用插件的用法等。
问题来了
基于vue-cli不用自己配置webpack开撸项目是十分爽的,但当我在撸得正爽的时候发现一个问题,就是项目打包前和打包后的css前缀不一致的,如下(浏览器:Chrome):
--给app.vue下的img添加样式
img{ display: flex; transform: translateX(200px) }
--打包前(即开发环境)img的样式
--打包后(即生产环境)img的样式
根据上面可看出打包前和打包后元素所带的css前缀不一致了。当我们给一个元素设置css3属性时,是希望它带有浏览器前缀来兼容的。vue-cli也给我们搭建这样的功能(是通过配置postcss的autoprefixer实现的)
--postcss配置写在.postcssrc.js,
module.exports = { "plugins": { "postcss-import": {}, "postcss-url": {}, // to edit target browsers: use "browserslist" field in package.json "autoprefixer": {} } }
--浏览器规则则写在package.json上,
"browserslist": [ "> 1%", "last 2 versions", "not ie <= 8" ]
--开发环境(build/webpack.dev.conf.js)样式相关的loader
module: { rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true }) },
--生产环境(build/webpack.prod.conf.js)样式相关的loader
module: { rules: utils.styleLoaders({ sourceMap: config.build.productionSourceMap, extract: true, usePostCSS: true }) },
从上面可以看出,vue-cli的开发环境和生产环境都是使用了postcss的,并且配置是一样的,那么为什么打包前和打包后元素所带的css前缀不一致呢,
锁定问题
我们可以分析对比下build/webpack.dev.conf.js和build/webpack.prod.conf.js这两个文件,影响css的无非就module里处理样式的loader和处理css的插件plugin,从上面可以看出影响前缀的postcss的loader在两个环节中是一致的,那么就可以知道问题出在处理css的插件上了。
经过排查发现,webpack.prod.conf.js配置里是多了两个css处理插件的,如下
ExtractTextPlugin这是提取分离css文件,不会影响css前缀,排除,那么问题就锁定到OptimizeCSSPlugin插件身上。再进一步,当我们把OptimizeCSSPlugin插件注释掉,然后打包测试,居然发现这时开发环境和生产环境的css前缀一致了,就是它了!!!
我们打开到npm官网搜一下这家伙https://www.npmjs.com/package/optimize-css-assets-webpack-plugin,这是一个优化压缩css代码的插件,但很失望,文档说明很少
但我们注意到有一句话很关键:
什么鬼,这货里面依赖了cssnano,这插件也是用来优化处理css格式、前缀什么的。同时也有个autoprefixer配置参数,直接到它官网(这个好像需要番墙) https://cssnano.co/ 找到autoprefixer(比较难找得借助翻译):
这里的翻译是:根据browsers选项删除不必要的前缀。请注意,默认情况下,它不会向CSS文件添加新前缀,这就可以解析清除我们的问题了,原来这插件的autoprefixer(默认应该是为true)把它认为不必要的前缀删掉了,而postcss的autoprefixer是将我们设定的浏览器范围的前缀加上,因此完美冲突了
解决问题
最后在github上找到解决方案(忘了复制找不回那地址了,具体为啥这样设置没说,这得深入这个插件的源码了),在build/webpack.prod.conf.js文件中OptimizeCSSPlugin插件的属性cssProcessorOptions加上autoprefixer:false来禁用它,避免冲突
上代码:
new OptimizeCSSPlugin({ cssProcessorOptions: config.build.productionSourceMap ? { safe: true, map: false,autoprefixer:false } : { safe: true, autoprefixer: false} }),
结论
最后,看看我们dev和build出来的css前缀,应该就一致的了:
问题原因就是:OptimizeCSSPlugin里面依赖了cssnano,而cssnano里面也有一个autoprefixer配置参数,它的作用是删除不必要的前缀(会误删在某些浏览器必要的前缀),这与postcss的autoprefixer效果冲突了,因此禁用它。
现在打包出来的与我们设定的浏览器范围对应的前缀一致,感觉整篇文章有点铝耍馐俏医饩稣馕适碧獾难罚锹家幌掳桑缬蟹治霾欢缘穆榉持赋觯恍唬
background-color: blue;background-color: yellow;<input type="button" value="变蓝" @click="changeColorT