Webpack 环境变量设置误区:DefinePlugin 与 cross-env 的正确用法

作者:知秋时间:2026-10-23 13:57:06浏览:623

本文深入解析 Webpack 中环境变量的设置机制,重点区分 webpack.DefinePlugin 与 cross-env 插件的作用范围。DefinePlugin 用于在浏览器端注入全局变量,而 cross-env 仅用于 Node.js 构建环境。文章指出将两者混用可能导致变量覆盖或获取失败,并提供了正确的配置建议,帮助开发者避免常见的配置误区。

Webpack 环境变量配置基础

前言

  • 日常的前端开发工作中,至少会有两套构建环境
    • 在日常前端开发中,通常至少需要维护两套构建环境。一套用于本地开发调试,其构建结果不进行代码压缩,会打印 debug 信息并包含 sourcemap 文件;另一套用于线上发布,构建结果经过压缩,运行时不打印 debug 信息,且静态文件不包含 sourcemap。
    • 一套发布时使用,构建结果用于线上,即代码都是压缩过的、运行时不打印 debug 信息、静态文件不包括 sourcemap 等
  • 从 webpack 4.0 版本开始,官方引入了 mode 概念来简化环境区分。
选项 描述
development 会将 process.env.NODE_ENV 的值设为 development。启用 NamedChunksPlugin 和 NamedModulesPlugin
production 会将 process.env.NODE_ENV 的值设为 production。启用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin 和 UglifyJsPlugin

区分开发/生产环境的方法

二、区分开发环境/生产环境的多种方式

2.1 使用命令行

2.1.1 写法一


"scripts": {
 // 默认 mode 为 development
 "dev1": "webpack-dev-server",
 // 默认 mode 为 production,不过这样写,打包的时候会有警告
 "build1": "webpack",
}

通过上述 script 脚本配置,可以在项目中的任意模块内通过 process.env.NODE_ENV 获取到当前的环境变量值。

然而,这种写法无法在 Node.js 环境(即 webpack 配置文件本身)中获取到当前的环境变量。


// index.js 
function getEnv() {
 console.log(process.env.NODE_ENV);// development | production
}

// webpack.config.js
const path = require('path');
const webpack = require('webpack');

console.log('NODE_ENV',process.env.NODE_ENV);// undefined

module.exports = {
 	entry:'./src/index.js',
  output: {
   filename: 'js/[name].js'
  },
 		...
};

2.1.2 写法二


"scripts": {
 "dev2": "webpack --mode=development",
 "build2": "webpack --mode=production",
}

该写法与写法一产生的结果完全一致。

2.1.3 写法三


"scripts": {
 "dev3": "webpack-dev-server --env=development",
 "build3": "webpack --env=production",
}

使用上述 script 脚本时,无法在任意模块内通过 process.env.NODE_ENV 获取当前的环境变量。

但是,可以在 Node.js 环境(webpack 配置文件)中,通过接收参数的函数来获取当前的环境变量。


// index.js 
function getEnv() {
 console.log(process.env.NODE_ENV);// undefined
}

// webpack.config.js
const path = require('path');
const webpack = require('webpack');

console.log('NODE_ENV',process.env.NODE_ENV);// undefined

// 通过函数获取当前环境变量
module.exports = (env,argv) => {
 console.log('env',env);// development | production
 return {
 	entry:'./src/index.js',
  output: {
   filename: 'js/[name].js'
  },
 		...
 }
};

2.2 使用 mode


// index.js 
function getEnv() {
  console.log(process.env.NODE_ENV);// development | production
}

// webpack.config.js
const path = require('path');
const webpack = require('webpack');

console.log('NODE_ENV',process.env.NODE_ENV);// undefined

module.exports = {
 	mode:'development',// development | production
 	entry:'./src/index.js',
    output: {
      filename: 'js/[name].js'
    },
  		...
};

其结果与 2.1 中的写法二相同。

两者的主要区别在于:前者是在命令行中设置,后者是在 webpack 配置文件中设置。

2.3 使用 webpack.DefinePlugin

首先需要明确该插件的作用:它用于设置全局变量(注意,并非挂载到 window 对象上),使得所有模块都能读取到该变量的值。


// index.js 
function getEnv() {
  console.log(process.env.NODE_ENV);// development
  console.log(NODE_ENV);// production
}

// webpack.config.js
const path = require('path');
const webpack = require('webpack');

// 这里只是凑巧和环境变量同名了,所以才不会报错
console.log('process.env.NODE_ENV',process.env.NODE_ENV);// undefined
console.log('NODE_ENV',NODE_ENV);// error !!!

module.exports = {
 	mode:'development',// development | production
 	entry:'./src/index.js',
    output: {
      filename: 'js/[name].js'
    },
 	plugins:[
      new webpack.DefinePlugin({
      	'process.env.NODE_ENV':JSON.stringify('development'),
        'NODE_ENV':JSON.stringify('production'),
    }),
  ],
  		...
};

在任意模块内,可以通过 process.env.NODE_ENV 获取到当前设置的环境变量。

同样,这种方式无法在 Node.js 环境(webpack 配置文件)下获取到当前的环境变量。

2.4 使用 cross-env 插件

此前我误以为该插件可以同时设置所有环境(包括浏览器环境和 Node 环境)下的变量。经过实际测试发现,它只能设置 Node 环境下的变量,即 NODE_ENV。

2.4.1 写法一


"scripts": {
 	"dev1": "cross-env NODE_ENV='production' webpack-dev-server",
    "build1": "cross-env NODE_ENV='development' webpack",
}

通过上述 script 脚本,可以在任意模块内通过 process.env.NODE_ENV 获取到当前的环境变量。

同时,也可以在 Node.js 环境(webpack 配置文件)中获取到当前的环境变量。

但这里存在一个问题:在浏览器环境和 Node 环境下获取到的变量值可能不一致。


// !!!!!!
// npm run build1 
// !!!!!!

// index.js 
function getEnv() {
  console.log(process.env.NODE_ENV);// production
}

// webpack.config.js
const path = require('path');
const webpack = require('webpack');

console.log('process.env.NODE_ENV',process.env.NODE_ENV);// development

module.exports = {
 	entry:'./src/index.js',
    output: {
      filename: 'js/[name].js'
    },
  		...
};

2.4.2 写法二


"scripts": {
 "dev2": "cross-env NODE_ENV='development' --mode development",
 "build2": "cross-env NODE_ENV='production' --mode production",
}

通过上述 script 脚本,可以在任意模块内通过 process.env.NODE_ENV 获取到当前的环境变量。

也可以在 Node.js 环境(webpack 配置文件)中,获取到当前的环境变量。

因此,在浏览器环境下读取到环境变量值主要依靠 mode 配置,而在 Node 环境下读取到环境变量值则依靠 cross-env。


// !!!!!!
// npm run build2 
// !!!!!!

// index.js 
function getEnv() {
  console.log(process.env.NODE_ENV);// production
}

// webpack.config.js
const path = require('path');
const webpack = require('webpack');

console.log('process.env.NODE_ENV',process.env.NODE_ENV);// production

module.exports = {
 	entry:'./src/index.js',
    output: {
      filename: 'js/[name].js'
    },
  		...
};

常见配置误区解析

三、误区

经常在一些技术交流群中看到这样的疑问:当 cross-env 和 webpack.DefinePlugin 配合使用时,无法通过 process.env.xxx 来获取设置的环境变量,而必须通过 DefinePlugin 中设置的 key 来获取。

引发这个问题的可能原因是:先通过 cross-env 设置了 NODE_ENV 变量,随后又在 DefinePlugin 中重复设置了一遍环境变量。


"scripts": {
 "dev": "cross-env NODE_ENV='development' --mode development"
}

// index.js 
function getEnv() {
  console.log(process.env.NODE_ENV);// development
}

// webpack.config.js
const path = require('path');
const webpack = require('webpack');

console.log('process.env.NODE_ENV',process.env.NODE_ENV);// development

module.exports = {
 	entry:'./src/index.js',
    output: {
      filename: 'js/[name].js'
    },
 	plugins:[
      new webpack.DefinePlugin({
       	// 设置环境变量
        	'process.env.NODE_ENV':JSON.stringify('development'),
      }),
    ],
  		...
};

此时会发现,浏览器环境和 Node 环境都能获取到设置的变量了,于是误以为之后设置其他全局变量时,只需照此写法即可。

认为 cross-env 和 DefinePlugin 是配套使用的,这种看法本身存在偏差,因为两者的作用点完全不同。

  • DefinePlugin 的作用:是设置浏览器环境下能读取到的“全局变量”,直接通过 key 读取,在 Node 环境下是无法读取到的。
  • cross-env 的作用:是通过命令行设置环境变量 NODE_ENV,使 Node 环境下能读取到,通过 process.env.NODE_ENV 读取。
  • 如果在 DefinePlugin 里设置的 key 是 process.env.NODE_ENV,这会覆盖 webpack 通过 mode 模式设置的环境变量的值。

"scripts": {
 "dev": "cross-env NODE_ENV='development' --mode development"
}

// index.js 
function getEnv() {
  console.log(process.env.NODE_ENV);// 666666
}

// webpack.config.js
const path = require('path');
const webpack = require('webpack');

console.log('process.env.NODE_ENV',process.env.NODE_ENV);// development

module.exports = {
 	entry:'./src/index.js',
    output: {
      filename: 'js/[name].js'
    },
 	plugins:[
      new webpack.DefinePlugin({
        // 注意:因为同名的 key,这里的值会覆盖默认的值 !!!!!!
        	'process.env.NODE_ENV':JSON.stringify('666666'),
      }),
    ],
  		...
};

总结与建议

四、总结

cross-env 是专门用来设置 Node 环境变量的工具。

webpack.DefinePlugin 是专门用来设置浏览器环境下的全局变量(不会挂载到 window 上)的工具。

本文仅为个人理解,如有错误还请告知,万分感谢。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对本站的支持。

作者最新文章