1、环境变量

想要消除 webpack.config.js 在 开发环境 和 生产环境 之间的差异,你可能需要 环境变量(environment variable)。
webpack 命令行 环境配置 的 --env 参数,可以允许你传入任意数量的环境变量。而 在 webpack.config.js 中可以访问到这些环境变量。例如, --env production 或 --env goal=local

webpack.config.js输出env为{ production : true, goal : local }

  1. npx webpack --env production --progress --env goal=local

对于我们的 webpack 配置,有一个必须要修改之处。通常, module.exports指向 配置对象。要使用 env 变量,你必须将 module.exports 转换成一个函数:
运行时输入 npx webpack --env production 则为生产环境

  1. //...
  2. module.exports = (env) => {
  3. return {
  4. //...
  5. // 根据命令行参数 env 来设置不同环境的 mode
  6. mode: env.production ? 'production' : 'development',
  7. //...
  8. }
  9. }

2、公共路径 publicPath

在 开发环境中,我们通常有一个 assets/ 文件夹,它与索引页面位于同一级别。这没太大问题,但是,如果我们将所有静态资源托管至 CDN,然后想在生 产环境中使用呢? 想要解决这个问题,可以直接使用一个 environment variable(环境变量)。

  1. npx webpack --env ASSET_PATH=http://localhost:8080/
  1. import webpack from 'webpack';
  2. // 尝试使用环境变量,否则使用根路径
  3. const ASSET_PATH = process.env.ASSET_PATH || '/';
  4. export default {
  5. output: {
  6. // 比如index.html中引入的 'build.js'会变成 'http://localhost:8080/build.js'
  7. //publicPath: 'http://localhost:8080/',
  8. publicPath: ASSET_PATH,
  9. },
  10. plugins: [
  11. // 这可以帮助我们在代码中安全地使用环境变量
  12. new webpack.DefinePlugin({
  13. 'process.env.ASSET_PATH': JSON.stringify(ASSET_PATH),
  14. }),
  15. ],
  16. };

有可能你事先不知道 publicPath是什么,webpack 会自动根据 import.meta.urldocument.currentScriptscript.src 或者 self.location变量设置 publicPath。你需要做的是将 output.publicPath 设为'auto'

  1. module.exports = {
  2. output: {
  3. publicPath: 'auto',
  4. },
  5. };

3、拆分配置文件

目前,生产环境和开发环境使用的是一个配置文件,我们需要将这两个文件单独放到 不同的配置文件中。如 webpack.config.dev.js (开发环境配置)和 webpack.config.prod.js (生产环境配置)。在项目根目录下创建一个配置文件 夹 config 来存放他们。
具体的拆分内容看第5点提取 **公共配置**
image.png
拆分成两个配置文件后,分别运行这两个文件:
-c--config 的缩写

  1. 开发环境: npx webpack serve -c ./config/webpack.config.dev.js
  2. 生产环境: npx webpack -c ./config/webpack.config.prod.js

由于放到cinfig文件下,输出时将./dist改为../dist

  1. output: {
  2. ...
  3. path: path.resolve(__dirname, '../dist'),
  4. ...
  5. },

4、npm脚本

每次打包或启动服务时,都需要在命令行里输入一长串的命令 配置 npm 脚本来简化命令行的输入
分成了两个config文件 执行不同命令时找到对应文件

  1. {
  2. "scripts": {
  3. "start": "npx webpack serve -c ./config/webpack.config.dev.js",
  4. "build": "npx webpack -c ./config/webpack.config.prod.js"
  5. }
  6. }

运行 : npm run start &npm run build

5、提取公共配置

这时,我们发现这两个配置文件里存在大量的重复代码,可以手动的将这些重复的代 码单独提取到一个文件里, 创建 webpack.config.common.js ,配置公共的内容:

webpack.config.common.js

  1. const path = require('path')
  2. const HtmlWebpackPlugin = require('html-webpack-plugin')
  3. const MiniCssExtractPlugin = require('mini-css-extract-plugin')
  4. const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
  5. const TerserPlugin = require('terser-webpack-plugin')
  6. module.exports = {
  7. entry: {
  8. index: './src/index.js',
  9. another: './src/another-module.js'
  10. },
  11. output: {
  12. //注意这个dist的路径设置成上一级
  13. path: path.resolve(__dirname, '../dist'),
  14. clean: true,
  15. assetModuleFilename: 'images/[contenthash][ext]'
  16. },
  17. plugins: [
  18. new HtmlWebpackPlugin({
  19. template: './index.html',
  20. filename: 'app.html',
  21. inject: 'body'
  22. }),
  23. new MiniCssExtractPlugin({
  24. filename: 'styles/[contenthash].css'
  25. })
  26. ],
  27. module: {
  28. rules: [
  29. {
  30. test: /\.png$/,
  31. type: 'asset/resource',
  32. generator: {
  33. filename: 'images/[contenthash][ext]'
  34. }
  35. },
  36. {
  37. test: /\.jpg$/,
  38. type: 'asset',
  39. parser: {
  40. dataUrlCondition: {
  41. maxSize: 4 * 1024 * 1024
  42. }
  43. }
  44. },
  45. {
  46. test: /\.(css|less)$/,
  47. use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader']
  48. },
  49. {
  50. test: /\.js$/,
  51. exclude: /node_modules/,
  52. use: {
  53. loader: 'babel-loader',
  54. options: {
  55. presets: ['@babel/preset-env'],
  56. plugins: [
  57. [
  58. '@babel/plugin-transform-runtime'
  59. ]
  60. ]
  61. }
  62. }
  63. }
  64. ]
  65. },
  66. optimization: {
  67. splitChunks: {
  68. cacheGroups: {
  69. vendor: {
  70. test: /[\\/]node_modules[\\/]/,
  71. name: 'vendors',
  72. chunks: 'all'
  73. }
  74. }
  75. }
  76. }
  77. }

webpack.config.dev.js 开发环境配置文件

module.exports = {
  output: {
    filename: 'scripts/[name].js'
  },

  mode: 'development',

  devtool: 'inline-source-map',

  devServer: {
    static: './dist'
  }
}

webpack.config.prod.js 生产环境配置文件

const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
const TerserPlugin = require('terser-webpack-plugin')

module.exports = {
  output: {
    filename: 'scripts/[name].[contenthash].js',
    publicPath: 'http://localhost:8080/'
  },

  mode: 'production',

  optimization: {
    minimizer: [
      new CssMinimizerPlugin(),
      new TerserPlugin()
    ]
  },

  performance: {
    hints: false
  }
}

6、合并配置文件

拆分好后,新的问题来了,如何保证配置合并没用问题呢?webpack-merge 这个工具可以完美解决这个问题。
npm install webpack-merge -D

webpack.config.js 总的配置文件

const { merge } = require('webpack-merge')

const commonConfig = require('./webpack.config.common')
const productionConfig = require('./webpack.config.prod')
const developmentConfig = require('./webpack.config.dev')

module.exports = (env) => {
  switch(true) {
    case env.development:
      return merge(commonConfig, developmentConfig)

    case env.production:
      return merge(commonConfig, productionConfig)

    defult:
      return new Error('No matching configuration was found')
  }
}

package.json 配置对应的env来merge对应环境下的json文件

  "scripts": {
    "start": "npx webpack serve -c ./config/webpack.config.js --env development",
    "build": "npx webpack -c ./config/webpack.config.js --env production",
  },