webpack配置文件

212 阅读2分钟

一、多环境配置,统一出口

your-project/
├── config/
│   ├── .env.dev         # 环境变量文件
│   ├── base.config.js   # 基础配置
│   ├── dev.config.js    # 开发环境配置
│   ├── prod.config.js   # 生产环境配置
│   └── test.config.js   # 测试环境配置
├── src/
│   └── index.html    
│   └── index.js
└── webpack.config.js    # 配置文件主入口
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

const temHtmlUrl = path.join(__dirname, '../src/index.html')
// 无效路径,注意在node中路径的使用
// const temHtmlUrl = '../src/index.html'

module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, '../dist'),
    filename: '[name].[contenthash].js',
  },
  module: {
    rules: [
      {
        test: /.js$/,
        exclude: /node_modules/,
        use: 'babel-loader'
      },
      {
        test: /.(sa|sc|c)ss$/,
        use: ['style-loader', 'css-loader', 'sass-loader']
      },
      {
        test: /.(png|jpe?g|gif|svg)$/i,
        type: 'asset/resource'
      }
    ]
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: temHtmlUrl
    })
  ]
};
const { merge } = require('webpack-merge');
const baseConfig = require('./base.config');
const path = require('path');

module.exports = merge(baseConfig, {
  mode: 'development',
  devtool: 'eval-cheap-module-source-map',
  devServer: {
    static: {
      directory: path.join(__dirname, '../dist'),
    },
    hot: true,
    compress: true,
    port: 9000,
    open: true
  }
});
const { merge } = require('webpack-merge');
const baseConfig = require('./base.config');
const TerserPlugin = require('terser-webpack-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');

module.exports = merge(baseConfig, {
  mode: 'production',
  devtool: 'none',
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin(),
      new CssMinimizerPlugin(),
    ],
    splitChunks: {
      chunks: 'all'
    }
  }
});
const path = require('path');
const { merge } = require('webpack-merge');

module.exports = (env) => {
  const environment = env.production ? 'prod' : env.test ? 'test' : 'dev';
  const configPath = path.resolve(__dirname, `config/${environment}.config.js`);
  const environmentConfig = require(configPath);
  return environmentConfig
};
{
  "scripts": {
    "start": "webpack serve --config webpack.config.js --env development",
    "build:prod": "webpack --config webpack.config.js --env production",
    "build:test": "webpack --config webpack.config.js --env test"
  }
}
npm install webpack webpack-cli webpack-dev-server webpack-merge --save-dev
npm install clean-webpack-plugin html-webpack-plugin --save-dev
npm install babel-loader @babel/core @babel/preset-env --save-dev
npm install style-loader css-loader sass-loader sass --save-dev
npm install terser-webpack-plugin css-minimizer-webpack-plugin --save-dev
# 开发环境
npm run start

# 生产环境打包
npm run build:prod

# 测试环境打包
npm run build:test

二、打包配置参数设置与读取

1、直接通过命令行

webpack --env key=value --env foo=bar

使用 --env 标志传递参数,参数会注入到 Webpack 配置函数的 env 对象中

# 传递环境标识
webpack --env production --env version=1.0.0

修改 webpack.config.js 以接收参数:

module.exports = (env) => {
  // env 对象包含命令行传递的参数
  console.log(env.production);    // true
  console.log(env.version);       // "1.0.0"
  
  return { /* 动态生成配置 */ };
};

2、结合 cross-env 传递系统环境变量

npm install cross-env --save-dev
{
  "scripts": {
    "build": "cross-env NODE_ENV=production webpack --env target=web"
  }
}

关于 process.env

  • process.env 是一个全局的对象,在node环境可以正常读取,但是在浏览器无法读取。
  • webpack内置支持读取配置文件中mode的值进行替换,在打包后的代码中,process.env.NODE_ENV 以静态字符串的形式存在,可以在浏览器中打印

当使用了cross-env 插件来传递参数后:

  • 在命令行中以键值对的形式设置参数
  • 传递的参数会被注入到全局对象process.env
"start": "cross-env hello=production webpack serve --config webpack.config.js --env development"

3、环境变量文件传参

安装插件

npm install dotenv-webpack --save-dev

创建环境文件

# .env.production
API_URL = 'https://api.example.com'
DEBUG_MODE = false

三、全局变量管理

针对不同的环境,设置不同的系统全局可用的常量,比如不同环境的文件上传地址等

1、webpack.DefinePlugin

构建时确定常量值,不同环境需要单独打包

const webpack = require('webpack');

module.exports = merge(baseConfig, {
  // ...
  plugins: [
    new webpack.DefinePlugin({
      // 注意:值需要 JSON.stringify 处理
      BASE_API: JSON.stringify('https://api.prod.com'),
      UPLOAD_URL: JSON.stringify('https://upload.prod.com')
    })
  ]
});
new webpack.DefinePlugin({
  BASE_API: JSON.stringify('https://api.dev.com'),
  UPLOAD_URL: JSON.stringify('https://upload.dev.com')
})

代码中直接访问:

// 直接访问全局常量
fetch(`${BASE_API}/users`);
uploadFile(UPLOAD_URL);

从维护的角度来说,这种方式不够明显,我们希望可以在专门的文件统一维护,因此不建议这种方式

2、dotenv-webpack + 环境文件

需要集中管理多环境变量,支持 .env 文件继承

安装依赖

npm install dotenv-webpack --save-dev

针对不同环境创建环境变量文件

BASE_API = 'https://api.dev.com'
UPLOAD_URL = 'https://upload.dev.com'

修改webpack配置

const path = require('path');
const { merge } = require('webpack-merge');
const Dotenv = require('dotenv-webpack');

module.exports = (env) => {
  console.log(env, 'env')
  const environment = env.production ? 'prod' : env.test ? 'test' : 'dev';
  const configPath = path.resolve(__dirname, `config/${environment}.config.js`);
  const globalEnvPath = path.resolve(__dirname, `config/.env.${environment}`);
  const environmentConfig = require(configPath);
  
  return merge(environmentConfig, {
    plugins: [
      new Dotenv({
        path: globalEnvPath
      })
    ]
  })
};

业务代码中使用

// 通过 process.env 访问
console.log(process.env.BASE_API);
console.log(process.env.UPLOAD_URL);