【webpack 黑魔法】问题: vue-loader.conf.js 配置的 postcss 对外置 less 文件无效

问题详述

按照官网文档在 vue-loader.conf.js 里面配置 postcss 为:

var utils = require('./utils');
var config = require('../config');
var isProduction = process.env.NODE_ENV === 'production';

module.exports = {
    loaders: utils.cssLoaders({
        sourceMap: isProduction
            ? config.build.common.productionSourceMap
            : config.dev.cssSourceMap,
        extract: isProduction
    }),
    preserveWhitespace: false,
    postcss: {
        plugins: [
            require('autoprefixer')({
                browsers: ['ie >= 9', 'last 2 versions']
            }),
            require('cssnano')({
                autoprefixer: false,
                safe: true
            })
        ]
    }
};

发现:在 vue 文件里面 import 外部 less 文件的时候,外部 less 文件的源码并没有经过 postcss ,而 vue 文件内部的 less 源码是经过的。

发现问题时的环境

  • Node.js v7.10.0, npm v5.3.0
  • webpack@2.7.0
  • vue-loader@11.3.4
  • postcss@6.0.10
  • autoprefixer@6.7.7
  • cssnano@3.10.0

问题排查与解决

打印一下最终传给 webpack 的 options 参数,发现有一个针对 .less 文件的 loader 配置(实际上我并没有在 webpack.base.conf.js 里面写针对 .less文件的 loader 配置),并且这个配置里面并没有 postcss-loader 配置,所以加载外部 less 文件没过 postcss 是说的过去的。

但是这个 less-loader 配置从哪里来的呢?经过分析,发现来自于 vue-loader.conf.js ,也就是说 vue-loader.conf.js 里面的 loaders 配置会被放置到 webpack 的 options 参数中去,所以我们要做只是在 vue-loader.conf.js 里面的 less loader 配置部分加上 postcss loader 配置就好了。

按照这个思路,先删掉 vue-loader.conf.js 里面的 postcss 配置,然后在 build/utils.js 里面改一下 less-loader 配置:

let lessLoaders = generateLoaders('less', {
    modifyVars: {
        '@veui-theme-color-nav': '#304ffe',
        '@veui-theme-color-primary': '#304ffe'
    }
});
lessLoaders.splice(2, 0, {loader: 'postcss-loader'});

return {
    css: generateLoaders(),
    // postcss: generateLoaders(),
    less: lessLoaders,
    sass: generateLoaders('sass', {
        indentedSyntax: true
    }),
    scss: generateLoaders('sass'),
    stylus: generateLoaders('stylus'),
    styl: generateLoaders('stylus')
};

然后在项目根目录下的 .postcssrc.js 文件中做如下配置:

// https://github.com/michael-ciniawsky/postcss-load-config

module.exports = {
    "plugins": {
        // to edit target browsers: use "browserlist" field in package.json
        "autoprefixer": {
            browsers: ['ie >= 9', 'last 2 versions']
        },
        "cssnano": {
            autoprefixer: false,
            safe: true
        }
    }
}

注意: 别在 utils.js 里面这样配置:

lessLoaders.splice(2, 0, {
    loader: 'postcss-loader'
    plugins: [
        require('autoprefixer')({
            browsers: ['ie >= 9', 'last 2 versions']
        }),
        require('cssnano')({
            autoprefixer: false,
            safe: true
        })
    ]
});

因为 plugins 参数会在 loader-runner 里面做一遍 stringify ,后果会很悲惨。

编辑于 2017-08-30