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 相关文章推荐
jQuery Ajax 仿AjaxPro.Utility.RegisterTypeForAjax辅助方法
Sep 27 Javascript
每天一篇javascript学习小结(面向对象编程)
Nov 20 Javascript
javascript实现的上下无缝滚动效果
Sep 19 Javascript
JavaScript观察者模式(publish/subscribe)原理与实现方法
Mar 30 Javascript
令按钮悬浮在(手机)页面底部的实现方法
May 02 Javascript
浅谈node中的exports与module.exports的关系
Aug 01 Javascript
[js高手之路]原型式继承与寄生式继承详解
Aug 28 Javascript
使用SVG基本操作API的实例讲解
Sep 14 Javascript
微信小程序实现保存图片到相册功能
Nov 30 Javascript
基于js实现抽红包并分配代码实例
Sep 19 Javascript
JavaScript实现HTML导航栏下拉菜单
Nov 25 Javascript
Vue CLI中模式与环境变量的深入详解
May 30 Vue.js
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版(2)
2006/10/09 PHP
php使用unset()删除数组中某个单元(键)的方法
2015/02/17 PHP
隐藏Nginx或Apache以及PHP的版本号的方法
2016/01/03 PHP
PHP共享内存用法实例分析
2016/02/12 PHP
PHP回调函数概念与用法实例分析
2017/11/03 PHP
Laravel框架实现修改登录和注册接口数据返回格式的方法
2018/08/17 PHP
php 的多进程操作实践案例分析
2020/02/28 PHP
Yii框架组件的事件机制原理与用法分析
2020/04/07 PHP
基于PHP实现堆排序原理及实例详解
2020/06/19 PHP
小型js框架veryide.librar源代码
2009/03/05 Javascript
使用js获取QueryString的方法小结
2010/02/28 Javascript
window.open 以post方式传递参数示例代码
2014/02/27 Javascript
javascript单引号和双引号的区别和处理
2014/05/14 Javascript
jQuery+html5+css3实现圆角无刷新表单带输入验证功能代码
2015/08/21 Javascript
解析jQueryEasyUI的使用
2016/11/22 Javascript
node.js版本管理工具n无效的原理和解决方法
2016/11/24 Javascript
jquery 追加元素append、prepend、before、after用法与区别分析
2016/12/02 Javascript
JS正则表达式修饰符中multiline(/m)用法分析
2016/12/27 Javascript
Linux系统中利用node.js提取Word(doc/docx)及PDF文本的内容
2017/06/17 Javascript
理解 javascript 中的函数表达式与函数声明
2017/07/07 Javascript
js最简单的双向绑定实例讲解
2018/01/02 Javascript
微信小程序中使用ECharts 异步加载数据实现图表功能
2018/07/13 Javascript
vue2.0 element-ui中el-select选择器无法显示选中的内容(解决方法)
2018/08/24 Javascript
通过Nodejs搭建网站简单实现注册登录流程
2019/06/14 NodeJs
Node.js学习之内置模块fs用法示例
2020/01/22 Javascript
详解Tensorflow数据读取有三种方式(next_batch)
2018/02/01 Python
Python3 pip3 list 出现 DEPRECATION 警告的解决方法
2019/02/16 Python
关于 Python opencv 使用中的 ValueError: too many values to unpack
2019/06/28 Python
Python代码使用 Pyftpdlib实现FTP服务器功能
2019/07/22 Python
使用Python脚本从文件读取数据代码实例
2020/01/19 Python
Python如何急速下载第三方库详解
2020/11/02 Python
台湾百利市购物中心:e-Payless
2017/08/16 全球购物
建筑工程自我鉴定
2013/10/18 职场文书
监察局领导班子四风问题整改措施思想汇报
2014/10/05 职场文书
Python中22个万用公式的小结
2021/07/21 Python
nginx配置指令之server_name的具体使用
2022/08/14 Servers