Webpack 设置环境变量的误区
一、前言
- 日常的前端开发工作中,至少会有两套构建环境
- 一套开发时使用,构建结果用于本地开发调试,不进行代码压缩、打印 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 环境(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 环境(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 环境(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 环境(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 环境(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
来获取到设置的环境变量,需要通过webpack.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
上)- 本文只是我个人的理解,如有错误还请告知,万分感谢
五、推荐阅读
转载自:https://juejin.cn/post/6844904023791796237