写在前边
你还在为Webpack
中各种打包配置而烦恼吗?
今天我们来聊聊webpack
中注入环境变量的各种姿势,或者你会觉得注入环境变量通过命令行注入不就可以了吗?
如果你有这种想法,耐心看下去我相信你会有不一样的收获的~
毕竟所谓成长就是一点一滴积累的过程!让我们来聊聊Webpack 5
中使用环境变量的各种正确姿势。
文章中从三个方面来讲解Webpack
流程中的环境变量:
- 业务代码中注入使用
webpack
环境变量。 - 官方提供构建过程使用
webpack
环境变量。 - 传统环境变量方法使用
webpack
构建过程环境变量。
业务代码使用环境变量
使用webpack.DefinePlugin
插件在业务代码中注入环境变量
相信不少同学已经应用过这种场景,我们需要在打包过程中通过webpack
注入一些全局变量在业务代码中使用。
比如我们业务入口文件有这样一段代码:
代码语言:javascript复制// src/main.js
console.log('hello, Environment variable', __WEPBACK__ENV)
复制代码
我们希望的是业务代码中碰到这个__WEBPACK__ENV
这个变量时,代码中会认识这个变量并且输出正确字符串值pacakges
。
想一想我们应该怎么做?
熟悉webpack
的同学其实已经想到了,我们可以通过webpack
中的definePlugins
这个插件进行注入:
const wepback = require('webpack')
// webpack.config.js
...
new webpack.DefinePlugin({
__WEBPACK__ENV: JSON.stringify('packages'),
TWO: '1 1',
});
复制代码
我们通过在webpack
的plugins
中加入这段配置后当我们运行打包命令后,此时我们业务代码中如果出现__WEBPACK__ENV
这个变量的话他就会帮我们替换成为'packages'
这个字符串,从而达到类似环境变量注入的效果。
webpack.DefinePlugin
引发的思考
或许你已经很熟悉webpack.definePlugins
这个插件的使用了,别着急让我们耐心往下看看,由这段代码我们引发出一下的几个思考:
'packages'
已经是string
类型了,为什么我们还要使用JSON.stringify()
进行处理。- 此时的环境变量真的就是所谓的环境变量吗?
我们先来探讨一下这两个问题:
definePlugin
所谓的”环境变量“实现方式
webpack
官方文档中这样讲到
(Note that because the plugin does a direct text replacement, the value given to it must include actual quotes inside of the string itself. Typically, this is done either with alternate quotes, such as
'"production"'
, or by usingJSON.stringify('production')
.)
其实他也就是再说webpack.definePlugins
本质上是打包过程中的字符串替换,比如我们刚才定义的__WEBPACK__ENV:JSON.stringify('packages')
。
在打包过程中,如果我们代码中使用到了__WEPBACK__ENV
,webpack
会将它的值替换成为对应definePlugins
中定义的值,本质上就是匹配字符串替换,并不是传统意义上的环境变量process
注入。
这也就回答了我们第二个问题。
JSON.stringify()
处理环境变量
接下来我们来看看第一个问题,正所谓实践出真知。我们来试试对比配置两次不同的definePlugin
来看看结果:
// webpack.config.js
new webpack.DefinePlugin({
__WEBPACK__ENV: JSON.stringify('packages'),
TWO: '1 1',
});
// 打包后的代码 这里我们关闭了devtools 罗列出打包后打包后的代码
console.log('hello, Environment variable', 'packages')
复制代码
代码语言:javascript复制// webpack.config.js
new webpack.DefinePlugin({
__WEBPACK__ENV: 'packages',
TWO: '1 1',
});
// 打包后的代码 这里我们关闭了devtools 罗列出打包后打包后的代码
console.log('hello, Environment variable', packages)
复制代码
仔细对比这两段代码第一个问题的答案其实已经很明了了,针对definePlugin
这个插件我们使用它定义key:value
全局变量时,他会将value
进行会直接替换文本。所以我们通常使用JSON.stringify('pacakges')
或者"'packages'"
。
对于DefinePlugin
的流程以及需要额外注意的细节我们差不多已经说清除了,但是此时我们定义所谓的全局变量是在业务代码中进行使用的。但此时如果我们对于打包构建过程中想使用环境变量的话需要另一种方式来注入。
构建过程中使用环境变量
通常我们在使用webpack
过程中需要根据自己独特的需求去使用环境变量进行动态打包,比如一些通过动态读取项目中的文件夹从而在控制台动态和用户交互打包对应不同的bundle
。
此时在构建过程中使用环境变量就显得非常重要了,所谓构建过程中使用环境变量简单来说就是在非业务代码中,比如webpack.config.js
配置文件中注入环境变量。
我们来看看在项目中输入这行代码:
代码语言:javascript复制npx webpack --env goal=local --env production --progress --config ./webpack.config.js
复制代码
此时这行代码我们相当于运行webpack
读取当前目录中的webpack.config.js
配置文件进行打包,同时注入两个环境变量goal
和progress
他们的值分别为local
和true
。
这样我们就可以在配置文件中使用注入的环境变量了:
代码语言:javascript复制const path = require('path');
module.exports = (env) => {
// Use env.<YOUR VARIABLE> here:
console.log('Goal: ', env.goal); // 'local'
console.log('Production: ', env.production); // true
return {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
};
};
复制代码
细心的你可以已经发现了,这里我们的module.exports
导出的是一个包含env
的函数,而并不是传统的对象了。
通常,module.exports
指向配置对象。要使用 env
变量,你必须将 module.exports
转换成一个函数的方式进行使用。
我们来看看如果不使用函数的话:
代码语言:javascript复制const path = require('path');
// Use env.<YOUR VARIABLE> here:
console.log('Goal: ', process.env.goal); // undefined
console.log('Production: ', process.env.production); // undefined
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
};
复制代码
我们可以看到我们读取node
进程process
中的env.goal/production
发现两个分别都是undefined
。
也就是说通常我们使用--env
在命令行中为webpack
构建过程注入环境变量时,需要将配置文件的module.exports
导出一个函数的形式,从而在函数第一个参数中获取对应的key
拿到对应的环境变量value
。
那么问题又来了,诶?假如我就是想在node
的process
中获得对应的环境变量呢?我应该怎么办,我就是不想写一个函数。
传统环境变量方法使用webpack
构建过程环境变量。
应该怎么办呢?其实webpack
对应打包的原理就是通过shell
命令去执行我们的配置文件(nodejs
配置文件)。
假如我们在运行命令webpack
时注入真正传统意义上的环境变量而非通过--env
是不是就可以了呢?接下来我们来试一试~
这里我们借助了一个非常好用的环境变量插件cross-env
,它的使用方式很简单可以帮助我们在不同环境下linux/windows...
中以相同的方式去注入运行时环境变量,接下来我们来使用一下它:
代码语言:javascript复制不要忘记安装
npm install --save-dev cross-env
。
// package.json
"build": "cross-env NAME_W=aaa webpack --config ./webpack.config.js"
复制代码
我们通过cross-env NAME_W=aaa
注入了一个环境变量。
// webpack.config.js
console.log(process.env.NAME_W, 'env'); // 'aaa'
module.exports = {
entry: './src/a.js',
};
复制代码
在我们的尝试下,发现其实通过命令行传统方式注入环境变量的形式也是可以的!这样我们就逃离了导出必须是一个函数的限制可以"为所欲为了"。
总结
在webpack
构建以及业务代码中,环境变量的注入对于我们的帮助是非常大的。当需要一定体系的前端工程化代码时,环境变量无论是在构建过程还是业务代码中都起到了至关重要的作用。
看到这里我们想说到的其实都已经讲到了,我们来进行一个简单的总结吧:
在webpack
打包业务代码时,我们需要使用类似环境变量的方式使用一些全局变量时,可以通过webpack.DefinePlugin
去定义一些变量从而在业务代码中使用。(但是需要注意上边讲到的JSON.stringify()
)。
同时在构建过程中,我们可以通过webpack
官方提供的--env
参数以及在配置文件中通过module.exports
函数的方式使用--env
定义的环境变量。
同时也可以在构建过程中通过我们日常使用的方式注入环境变量而“逃脱”webpack
的限制,直接使用命令行中定义的环境变量然后通过process.env.xxx
去获取。