Webpack设置环境变量的一些误区详解


Posted in Javascript onDecember 19, 2019

一、前言

  • 日常的前端开发工作中,至少会有两套构建环境
    • 一套开发时使用,构建结果用于本地开发调试,不进行代码压缩、打印 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 上)

本文只是我个人的理解,如有错误还请告知,万分感谢

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

Javascript 相关文章推荐
JavaScript脚本语言在网页中的简单应用
May 13 Javascript
js 文件引入实现代码
Apr 23 Javascript
Wordpress ThickBox 添加“查看原图”效果代码
Dec 11 Javascript
jquery方法+js一般方法+js面向对象方法实现拖拽效果
Aug 30 Javascript
javascript数字时钟示例分享
Apr 23 Javascript
JavaScript如何调试有哪些建议和技巧附五款有用的调试工具
Oct 28 Javascript
js组件SlotMachine实现图片切换效果制作抽奖系统
Apr 17 Javascript
Vue.js组件tree实现无限级树形菜单
Dec 02 Javascript
js常用DOM方法详解
Feb 04 Javascript
使用Vue自定义数字键盘组件(体验度极好)
Dec 19 Javascript
利用Vue-draggable组件实现Vue项目中表格内容的拖拽排序
Jun 07 Javascript
vue遍历生成的输入框 绑定及修改值示例
Oct 30 Javascript
Echarts实现多条折线可拖拽效果
Dec 19 #Javascript
js判断一个对象是数组(函数)的方法实例
Dec 19 #Javascript
利用JS如何获取form表单数据
Dec 19 #Javascript
在Vue项目中使用Typescript的实现
Dec 19 #Javascript
JS数据类型STRING使用实例解析
Dec 18 #Javascript
JS精确判断数据类型代码实例
Dec 18 #Javascript
使用webpack/gulp构建TypeScript项目的方法示例
Dec 18 #Javascript
You might like
PHP缓存机制Output Control详解
2014/07/14 PHP
如何解决PHP获取不到SESSION信息之一般情况
2019/10/10 PHP
javascript读取xml
2006/11/04 Javascript
收藏一些不常用,但是有用的代码
2007/03/12 Javascript
window.dialogArguments 使用说明
2011/04/11 Javascript
读jQuery之十二 删除事件核心方法
2011/07/31 Javascript
ExtJs使用总结(非常详细)
2012/03/22 Javascript
JS实现淘宝幻灯片效果的实现方法
2013/03/22 Javascript
JS 获取select(多选下拉)中所选值的示例代码
2013/08/02 Javascript
js冒泡法和数组转换成字符串示例代码
2013/08/14 Javascript
textarea焦点的用法实现获取焦点清空失去焦点提示效果
2014/05/19 Javascript
javascript实现的网站访问量统计代码
2015/12/20 Javascript
jQuery validate插件submitHandler提交导致死循环解决方法
2016/01/21 Javascript
分享12个实用的jQuery代码片段
2016/03/09 Javascript
JavaScript中原型链存在的问题解析
2016/09/25 Javascript
jQuery基于ajax方式实现用户名存在性检查功能示例
2017/02/10 Javascript
webpack多页面开发实践
2017/12/18 Javascript
微信小程序实现YDUI的ScrollTab组件
2018/02/02 Javascript
Vue 理解之白话 getter/setter详解
2019/04/16 Javascript
maptalks+three.js+vue webpack实现二维地图上贴三维模型操作
2020/08/10 Javascript
swiperjs实现导航与tab页的联动
2020/12/13 Javascript
[03:23:49]2016.12.17日完美“圣”典全回顾
2016/12/19 DOTA
Python基础入门之seed()方法的使用
2015/05/15 Python
mac系统安装Python3初体验
2018/01/02 Python
对pandas将dataframe中某列按照条件赋值的实例讲解
2018/11/29 Python
Python实现京东秒杀功能代码
2019/05/16 Python
python使用minimax算法实现五子棋
2019/07/29 Python
python的等深分箱实例
2019/11/22 Python
简单了解django文件下载方式
2020/02/10 Python
python如何从键盘获取输入实例
2020/06/18 Python
员工薪酬激励方案
2014/06/13 职场文书
淘宝活动总结范文
2014/06/26 职场文书
2014年物流工作总结
2014/11/25 职场文书
道德模范事迹材料
2014/12/20 职场文书
初中作文评语集锦
2014/12/25 职场文书
Spring-cloud Config Server的3种配置方式
2021/09/25 Java/Android