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 相关文章推荐
Js获取数组最大和最小值示例代码
Oct 29 Javascript
JS与C#编码解码
Dec 03 Javascript
js中opener与parent的区别详细解析
Jan 14 Javascript
form.submit()不能提交表单的原因分析
Oct 23 Javascript
jQuery实现鼠标划过修改样式的方法
Apr 14 Javascript
JQuery标签页效果实例详解
Dec 24 Javascript
基于Javascript实现二级联动菜单效果
Mar 04 Javascript
基于BootStrap Metronic开发框架经验小结【七】数据的导入、导出及附件的查看处理
May 12 Javascript
AngularJS入门教程之数据绑定用法示例
Nov 01 Javascript
JS路由跳转的简单实现代码
Sep 21 Javascript
3种vue组件的书写形式
Nov 29 Javascript
es6函数之尾递归用法实例分析
Apr 25 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
Mysql的常用命令
2006/10/09 PHP
PHP GD 图像处理组件的常用函数总结
2010/04/28 PHP
php实现利用phpexcel导出数据
2013/08/24 PHP
33道php常见面试题及答案
2015/07/06 PHP
关于PHP虚拟主机概念及如何选择稳定的PHP虚拟主机
2018/11/20 PHP
共享自己写一个框架DreamScript
2007/01/20 Javascript
建议大家看下JavaScript重要知识更新
2007/07/08 Javascript
jQuery 源代码显示控件 (Ajax加载方式).
2009/05/18 Javascript
JavaScript中的对象的extensible属性介绍
2014/12/30 Javascript
js实现鼠标悬浮给图片加边框的方法
2015/01/30 Javascript
javascript实现百度地图鼠标滑动事件显示、隐藏
2015/04/02 Javascript
js获取微信版本号的方法
2015/05/12 Javascript
javascript实现五星评分功能
2015/11/10 Javascript
快速解决Canvas.toDataURL 图片跨域的问题
2016/05/10 Javascript
Angularjs---项目搭建图文教程
2016/07/08 Javascript
Angularjs实现mvvm式的选项卡示例代码
2016/09/08 Javascript
JavaScript中splice与slice的区别
2017/05/09 Javascript
nodejs调取微信收货地址的方法
2017/12/20 NodeJs
webpack热模块替换(HMR)/热更新的方法
2018/04/05 Javascript
vue+高德地图写地图选址组件的方法
2019/05/18 Javascript
JSON stringify方法原理及实例解析
2020/10/23 Javascript
Django原生sql也能使用Paginator分页的示例代码
2017/11/15 Python
django ModelForm修改显示缩略图 imagefield类型的实例
2019/07/28 Python
学python安装的软件总结
2019/10/12 Python
postman和python mock测试过程图解
2020/02/22 Python
python对指定字符串逆序的6种方法(小结)
2020/04/02 Python
python爬取网易云音乐热歌榜实例代码
2020/08/07 Python
Conforama西班牙:您的家具、装饰和电器商店
2020/02/21 全球购物
Java语言的优势
2015/01/10 面试题
工厂门卫岗位职责范本
2014/04/04 职场文书
新学期国旗下演讲稿
2014/05/08 职场文书
医学专业大学生求职信
2014/07/12 职场文书
学校总务处领导班子民主生活会对照检查材料思想汇报
2014/09/27 职场文书
秋季运动会开幕词
2015/01/28 职场文书
党员个人年度总结
2015/02/14 职场文书
《家》读后感:万惜拯救,冷暖自知
2019/09/25 职场文书