环境变量导致的 webpack 打包时不压缩 CSS 文件

项目上线的时候一般要把 JS 和 CSS 压缩一下,用 webpack 的 uglifyJSPlugin 和 css-loader 的 minimize 选项可以分别压缩 JS 和 CSS. 但是偶然发现一个项目里的 CSS 并没有被压缩。最后发现是一个环境变量在不同的系统下不统一的锅。

通过为 css-loader 指定参数,可以在打包的时候压缩 CSS 样式文件。例如:

{
  test: /(\.styl)$/,
  loaders: [
    'style-loader',
    {
      loader: 'css-loader',
      options: {
        minimize: process.env.NODE_ENV === 'production'
      }
    }
    'postcss-loader',
    'stylus-loader'
  ]
}

因为个人习惯,我一般不把 minimize 属性直接设置为 true,而是判断当前是否将要打包成生产环境用的文件,如果是才压缩 CSS. 然而就在这个地方出了锅,发现弄出来的 CSS 根本没压缩。一开始以为是 ExtractTextPlugin 的问题,后来发现如果直接把 minimize 的值设置为 true 的时候就会压缩,那么问题就在于 process.env.NODE_ENV === 'production' 表达式返回了不正确的值。

导致这个原因的问题在于没有设置 NODE_ENV 环境变量= =这个变量需要在运行 webpack 的时候设置,之前一直以为使用 webpack.DefinePlugin 定义 process.env.NODE_ENV 就可以的:

  new webpack.DefinePlugin({
    'process.env.NODE_ENV': JSON.stringify('production')
  })

猜测 webpack.DefinePlugin 插件定义的变量只对项目的代码有效(就是对要打包的目标生效),但是对打包工具 webpack 自身似乎是无效的,所以即便在项目中 process.env.NODE_ENV 能取到正常的值,但是对于其他情况下 process.env.NODE_ENV 就没有定义了。

解决方法就是手动在终端中定义 process.env.NODE_ENV 变量,但是这样太麻烦了,而且还有跨系统兼容性的问题。可以使用 cross-env 来定义环境变量,然后再通过其启动 webpack.

yarn add --dev cross-env

然后修改 package.json 中的 script 字段,在执行打包命令的时候先调用 cross-env 设置环境变量,然后再唤起 webpack. 例如:

"scripts": {
  "dist": "cross-env NODE_ENV=production webpack --config config/webpack.config.js --env=production",
  "serve": "cross-env NODE_ENV=dev webpack-dev-server --progress --config config/webpack.config.js --env=dev",
  "serve:dist": "cross-env NODE_ENV=dist wepack-dev-server --progress --config config/webpack.config.js --env=production",
  "watch": "cross-env NODE_ENV=dev webpack --progress --watch --config config/webpack.config.js --env=dev"
},

这样子再运行打包生产环境文件的命令的时候,webpack 就能获取到正确的 process.env.NODE_ENV 环境变量,就能正常压缩 CSS 了。