webpack 对 css 压缩中对前缀的处理

在 vue-cli 创建的项目中,用默认的 webpack 配置对项目打包后,发现 css 文件中样式的前缀有所缺失,例如:flex 这个应该有前缀的属性却没有(display:-webkit-flex; && -webkit-flex:1),导致样式在 iphone 6s plus 上出现了兼容问题。

postcss 对 css 的前缀是有处理功能的,在项目的默认配置中,会根据各个浏览器最新两个版本的支持情况去添加前缀的,而现在浏览器都应该能很好地支持 flex 了,于是,便不再加前缀。对此,我们可以做如下处理:

//vue-loader.config.js

......
module.exports = {
 ......
  postcss: [
    require('autoprefixer')({ browsers: ['last 10 Chrome versions', 'last 5 Firefox versions', 'Safari >= 6', 'ie > 8'] })
  ]
}

 

经过以上处理,打包后的 css 应该就拥有合适的前缀了,但并不如此,原因是在打包过程中,css 有个压缩动作,在这个动作中,压缩插件(用的是 optimize-css-assets-webpack-plugin 这个插件)会再一次对 css 的前缀做处理,会将它认为不需要的代码(如不需要的 css 前缀)去掉。因为前面已经用 postcss 对 css 的前缀做过处理,所以在这里对 css 前缀的处理是多余的,我们可以做如下处理:

// webpack.prod.config.js

......
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')

......

new OptimizeCSSPlugin({
    cssProcessor: require('cssnano'),
    cssProcessorOptions: {
    discardComments: { removeAll: true },
    // 避免 cssnano 重新计算 z-index
    safe: true,
    //cssnano通过移除注释、空白、重复规则、过时的浏览器前缀以及做出其他的优化来工作,一般能减少至少 50% 的大小
    //cssnano 集成了autoprefixer的功能。会使用到autoprefixer进行无关前缀的清理。默认不兼容ios8,会去掉部分webkit前缀,比如flex
    //所以这里选择关闭,使用postcss的autoprefixer功能
    autoprefixer: false
    },
    canPrint: true
    //cssProcessorOptions: config.build.productionSourceMap ? { safe: true, map: { inline: false } } : { safe: true }
}),

......

 

再次打包后,你会发现你想要的前缀出现了。

 

即便如此做了,你发现 -webkit-flex:1 这个还是没有出现,于是有了下面这个文件

const fs = require('fs');
const path = require('path');
const config = require('../config/index.js');


function resolve(dir) {
    return path.join(__dirname, '..', dir)
}

function changeFile(obj) {
    fs.readFile(obj.changeFile, function(err, data) {
        if (err) {
            throw err;
        } else {
            var dataStr = data.toString();
            // dataStr = dataStr.replace(obj.olddisplayflex, ';display:-webkit-flex;display:flex');
            dataStr = dataStr.replace(obj.oldflxe, function() {
                var source = arguments[0];
                var flexNum = source.match(/\d+/)[0];
                var str = ';-webkit-flex:' + flexNum + ';flex:' + flexNum;
                return str;
            });
            fs.unlink(obj.changeFile, function(err) {
                if (err) {
                    throw err
                } else {
                    fs.writeFile(obj.changeFile, dataStr, function(errs) {
                        if (errs) {
                            throw errs
                        } else {
                            var cssNam = obj.changeFile.split('/');
                            console.log('\x1B[32m%s\x1B[39m', '样式 flex 修改成功--------' + cssNam[cssNam.length - 1]);
                        }
                    });
                }
            })
        }
    });
}

// 因为每次打包,css 的文件名都不一样,所以通过遍历文件夹来找到 css 文件 function getFile(obj) { fs.readdir(obj.changeFile, function(err, files) {
if (err) { throw err; } else { files.forEach(function(item) { if (/(css)$/.test(item)) { obj.changeFile = obj.changeFile + item; changeFile(obj); } }); } }); } var webkit = { changeFile: config.build.assetsRoot + '/' + config.build.assetsSubDirectory + '/css/', //resolve('/farm/static/css/'), oldflxe: /;+\s*flex\:\s*\d+/g, olddisplayflex: /;+\s*display\:\s*flex/g } var webkitHtml = { changeFile: config.build.assetsRoot + '/index.html', //resolve('/farm/index.html'), oldflxe: /;+\s*flex\:\s*\d+/g, olddisplayflex: /;+\s*display\:\s*flex/g } function cssFix() { getFile(webkit); changeFile(webkitHtml); } module.exports = cssFix;

这个代码是在 npm run build 之后运行的,其作用就是给需要添加 -webkit-flex:x 的地方加上这个。

这个也是无奈之下不得已而为之,我会继续寻找别的更好的方法,之后再更新了。

 

2018.10.22 更新:使用 vue-cli 3.0 创建项目,这个问题解决了。

posted @ 2018-05-29 12:03  青风无痕  阅读(390)  评论(1编辑  收藏  举报