# 环境变量的使用

现在我们区分 开发环境生产环境 的打包,是通过 webpack.dev.jswebpack.prod.js 这两个文件结合公共的配置文件来完成的。

  • 开发环境
"dev": "webpack-dev-server --config ./config/webpack.dev.js",
  • 生产环境
"build": "webpack --config ./config/webpack.prod.js",

我们还可以只跑通过一个配置文件 webpack.common.js,通过传参的方式来完成打包,这就是我们今天要讲的 环境变量。

# 修改配置文件

# 修改 webpack.dev.jswebpack.prod.js

我们直接导出开发环境和生产环境的配置,不去 merge 公共的配置了。

// webpack.dev.js

const path = require('path');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const webpack = require('webpack');

const devConfig = {
  mode: 'development',
  devtool: 'cheap-module-eval-source-map', // development
  module: {
    rules: [{
      test: /\.less$/,
      use: [
        {
          loader: MiniCssExtractPlugin.loader,
          options: {
            publicPath: '/public/path/to/',
            // 只在开发模式中启用热更新
            hmr: true,
            // 如果模块热更新不起作用,重新加载全部样式
            reloadAll: true,
          },
        },
        {
          loader: 'css-loader',
          options: {
            importLoaders: 2,
          }
        },
        'less-loader',
        'postcss-loader',
      ]
    }]
  },
  devServer: {
    contentBase: './dist',
    // open: true,
    port: 8080,
    hot: true
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new MiniCssExtractPlugin({
      filename: '[name].css', // 直接引用
      chunkFilename: '[name].chunk.css' // 间接引用
    }),
  ],
  output: {
    filename: "[name].bundle.js",
    chunkFilename: '[name].chunk.js', // 简介引入代码输出的名字
    path: path.resolve(__dirname, '../dist')
  },
  optimization: {
    minimizer: [new OptimizeCSSAssetsPlugin({})]
  },
}

module.exports = devConfig;

// webpack.prod.js

const path = require('path');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");

const prodConfig = {
  mode: 'production',
  devtool: 'cheap-module-source-map', // production
  module: {
    rules: [{
      test: /\.less$/,
      use: [
        {
          loader: MiniCssExtractPlugin.loader,
          options: {
            publicPath: '/public/path/to/',
            hmr: true,
          },
        },
        {
          loader: 'css-loader',
          options: {
            importLoaders: 2,
          }
        },
        'less-loader',
        'postcss-loader',
      ]
    }]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].css', // 直接引用
      chunkFilename: '[name].chunk.css' // 间接引用
    }),
  ],
  optimization: {
    minimizer: [new OptimizeCSSAssetsPlugin({})]
  },
  output: {
    filename: "[name].[contenthash].js",
    chunkFilename: '[name].[contenthash].js', // 简介引入代码输出的名字
    path: path.resolve(__dirname, '../dist')
  }
}

module.exports = prodConfig;

# 修改 webpack.common.js

接着我们引入两个环境的配置对象,将 module.exports 从导出一个对象变成了导出一个函数,当 webpack 配置对象 导出为一个函数 时,可以向起传入一个 "环境对象( environment)"

可以通过 env 判断之后的返回值,这个 env 是外部传过来的一个变量,我们会在打包的时候传进去。

const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

const devConfig = require('./webpack.dev.js');
const prodConfig = require('./webpack.prod.js');
const merge = require('webpack-merge');

const commonConfig = {
  entry: {
    main: "./src/index.js",
  },
  module: {
    rules: [{ 
      test: /\.js$/, 
      exclude: /node_modules/, 
      use: [
        'babel-loader',
        {
          loader: 'imports-loader?this=>window'
        }
      ]
    }, {
      test: /\.(png|jpg|gif)$/,
      use: {
        loader: 'file-loader',
        options: {
          name: '[name]_[hash].[ext]',
          outputPath: 'images/',
        }
      }
    }, {
      test: /\.(eot|ttf|svg|woff|woff2)$/,
      use: {
        loader: 'file-loader',
      }
    }]
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: 'src/index.html',
    }),
    new BundleAnalyzerPlugin({
      analyzerHost: '127.0.0.1',
      analyzerPort: 8889,
      openAnalyzer: false,
    }),
    new webpack.ProvidePlugin({
      $: 'jquery',
      _: 'lodash',
      _join: ['lodash', 'join']
    })
  ],
  optimization: {
    usedExports: true,
    runtimeChunk: {
      name: 'runtime',
    },
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          priority: -10,
          name: 'vendors',
        }
      }
    },
  },
  performance: false, // 关闭性能上的一些问题
}

module.exports = (env) => {
  if (env && env.production) {
    return merge(commonConfig, prodConfig);
  } else {
    return merge(commonConfig, devConfig);
  }
};

# 修改 package.json

我们修改 package.json 下的 script 字段,都改为使用 webpack.common.js,并在线上环境打包的时候传入一个全局参数 --dev.production

"scripts": {
    "bundle": "webpack --config ./config/webpack.common.js",
    "dev": "webpack-dev-server --config ./config/webpack.common.js",
    "build": "webpack --env.production --config ./config/webpack.common.js",
},

我们可以运行看一下函数的 env 参数是什么。

我们运行 npm run bundle,其 env 参数是 undefined

我们运行 npm run build,其 env 参数是 {production: true}

我们还可以这样穿全局参数:

"scripts": {
  "build": "webpack --env production --config ./config/webpack.common.js",
},

这个时候我们接受参数便需要写成:

module.exports = (production) => {
  if (production) {
    return merge(commonConfig, prodConfig);
  } else {
    return merge(commonConfig, devConfig);
  }
};

更多的传参方式大家可以参照下图:

由此我们便可以通过一个文件来完成区分环境打包的需求。

# 相关链接

# 示例代码

示例代码可以看这里: