Webpack中各种环境变量的正确姿势

2021-11-15 14:25:02 浏览数 (1)

写在前边

你还在为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这个插件进行注入:

代码语言:javascript复制
const wepback = require('webpack')
// webpack.config.js
...
new webpack.DefinePlugin({
  __WEBPACK__ENV: JSON.stringify('packages'),
  TWO: '1 1',
});
复制代码

我们通过在webpackplugins中加入这段配置后当我们运行打包命令后,此时我们业务代码中如果出现__WEBPACK__ENV这个变量的话他就会帮我们替换成为'packages'这个字符串,从而达到类似环境变量注入的效果。

webpack.DefinePlugin引发的思考

或许你已经很熟悉webpack.definePlugins这个插件的使用了,别着急让我们耐心往下看看,由这段代码我们引发出一下的几个思考:

  1. 'packages'已经是string类型了,为什么我们还要使用JSON.stringify()进行处理。
  2. 此时的环境变量真的就是所谓的环境变量吗?

我们先来探讨一下这两个问题:

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 using JSON.stringify('production').)

其实他也就是再说webpack.definePlugins本质上是打包过程中的字符串替换,比如我们刚才定义的__WEBPACK__ENV:JSON.stringify('packages')

在打包过程中,如果我们代码中使用到了__WEPBACK__ENVwebpack会将它的值替换成为对应definePlugins中定义的值,本质上就是匹配字符串替换,并不是传统意义上的环境变量process注入。

这也就回答了我们第二个问题。

JSON.stringify()处理环境变量

接下来我们来看看第一个问题,正所谓实践出真知。我们来试试对比配置两次不同的definePlugin来看看结果:

代码语言:javascript复制
// 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配置文件进行打包,同时注入两个环境变量goalprogress他们的值分别为localtrue

这样我们就可以在配置文件中使用注入的环境变量了:

代码语言: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

那么问题又来了,诶?假如我就是想在nodeprocess中获得对应的环境变量呢?我应该怎么办,我就是不想写一个函数。

传统环境变量方法使用webpack构建过程环境变量。

应该怎么办呢?其实webpack对应打包的原理就是通过shell命令去执行我们的配置文件(nodejs配置文件)。

假如我们在运行命令webpack时注入真正传统意义上的环境变量而非通过--env是不是就可以了呢?接下来我们来试一试~

这里我们借助了一个非常好用的环境变量插件cross-env,它的使用方式很简单可以帮助我们在不同环境下linux/windows...中以相同的方式去注入运行时环境变量,接下来我们来使用一下它:

不要忘记安装npm install --save-dev cross-env

代码语言:javascript复制
// package.json
 "build": "cross-env NAME_W=aaa webpack --config ./webpack.config.js"
复制代码

我们通过cross-env NAME_W=aaa注入了一个环境变量。

代码语言:javascript复制
// 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去获取。

0 人点赞