5

通过Webpack全局配置开发环境和多种生产环境的请求地址

 3 years ago
source link: https://zhuanlan.zhihu.com/p/147720556
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

通过Webpack全局配置开发环境和多种生产环境的请求地址

北京奇观技术有限责任公司 软件开发工程师

在线上项目的开发中,我们经常会有一个测试服务器一个正式服务器,当我们开发时我们会去使用测试服务器的接口地址,而发版时会把地址改为正式服务器的地址,因此我们可能会在两个地址来回切换(有可能还有更多环境,每个环境的请求地址都不同),甚至有时由于疏忽,会在发版时使用了测试服务器的地址。

这里,我通过webpack的definePlugin以三种方式来解决这个问题

官方文档时这么说的,我们可以通过配置这个插件,在[生产/开发]构建中使用不同的服务URL

v2-91c695971cc3441e379ccad4630f4d41_720w.jpg

具体使用:

第一种方式

直接在插件中写死,这样环境只能区分开发环境和生产环境 不能设置更多的环境

webpack.config.js

new webpack.DefinePlugin({
    //判断是生产环境的话 DEVELEPMENT为false开发环境为true
    DEVELEPMENT: isEnvProduction? JSON.stringify(false) : JSON.stringify(true),
    PRODUCTION:isEnvProduction? JSON.stringify(true) : JSON.stringify(false),
    //还可以添加一些别的全局变量
    USERNAME:JSON.stringify('zyx'),
}),

until.js

这样定义完我们就可以每次需要网络请求直接把host地址import进去

const host;
/* eslint-disable no-undef */
if(DEVELEPMENT){
    //如果是生产环境 设置请求链接
    host = 'http://xxx.xxx.xxx..xx/tp5/public/index.php/index/index/'
}else{
    //如果是开发环境 设置请求链接
    host = 'http://xxx.xxx.xxx..xx/tp5/public/index.php/index/index/'
}
export const host;

但是注意 一定要加/* eslint-disable no-undef */这句话

因为eslint认为这个全局变量是没有定义过的

我们直接使用可以拿到,但是eslint会让这里编辑失败

报错DEVELEPMENT is not defined

通过这句话,我们可以让eslint 对这段代码不做undefined判断

第二种方式

(这种方式实现是我早期使用的方法,第三种方式是第二种方式更优雅的实现,懒得看可以直接看第三种)

通过process.argv和配置文件.env.development的方式配置多种环境的请求地址

首先是.env.development配置开发环境的请求地址

其实这个的原理和第一种方法是一样的 只不过把开发环境的配置单独抽离出去了(根据webpack的文件系统,它会自动识别.env.development的配置)

wepack.config.js

 new webpack.DefinePlugin({
     ...env.stringified
}),

这句话的意思是DefinePlugin引入.env文件的配置信息

.env.development

REACT_APP_API=http://192.168.2.175:9292

然后我们任何文件都能通过process.env.REACT_APP_API访问到这个地址

console.log(process.env); 

控制台的输出:

这时其实我们已经拿到在.env.development 写入的全局变量,这时我们注意另外一个变量

console.log(process.defineEnv); 

这时控制台的输出是:

我们了解一下process.defineEnv是干什么的

node.js提供了process.argv来获取npm/yarn的命令参数

所以我们可以通过配置package.json来配置命令拿到我们全局变量

首先配置一个方法来解析参数

filterArg.js

module.exports = function(str){
  const argv = process.argv
  const result = argv.find(item => item.match(str))
  if (result) {
    return result.split('=')[1]
  }
  return null
}

修改wepack.config.js

new webpack.DefinePlugin({
    ...env.stringified,
    //定义process.defineEnv = 我们在命令中输入的参数
    'process.defineEnv': {
      REACT_APP_API: JSON.stringify(filterArgs('-api') || process.env.API_DEV)
    }
}),

然后配置package.json

"scripts": {
    "start": "node scripts/start.js",
    "build:dev": "node scripts/build.js -api=http:192.168.1.1",
    "build:test": "node scripts/build.js -api=http:192.168.1.2",
    "build:pro": "node scripts/build.js -api=http:192.168.1.3",
    "test": "node scripts/test.js"
  },

我们测试一下npm run build:dev

输出process.defineEnv

console.log(process.defineEnv); 

控制台结果:

我们拿到了命令参数-api的值http:192.168.1.1

这样其实我们就达到了我们的效果

如果在开发环境我们就直接使用process.env.REACT_APP_API 的请求地址

当我们要运行在不同的生产环境时

我们就配置不同的build:xx 的 脚本 然后运行

在项目中使用process.defineEnv.REACT_APP_API

until.js

const host;
/* eslint-disable no-undef */
if(process.env.REACT_APP_API){
    //如果是生产环境 拿到process.env.REACT_APP_API的值
    host = process.env.REACT_APP_API
}else{
    //如果是生产环境 拿到对应的生产环境的请求地址
    host = process.defineEnv.REACT_APP_API
}
export const host;

第三种方式(通过文件的方式优雅的实现第二种逻辑)

这里我们定义三种环境devprotest(跟以前的开发环境、生产环境没有任何关系,是我们自己定义的三种环境)

首先我们先引入一个yargs

其实这个东西跟process.argv功能上并没有什么区别,但是process.argv的可配置性不高,所以这里使用yargs

$ npm install yargs --dev --save

这里我们同样定义一个文件来解析我们脚本里的参数

webpack.env.conf.js

// 定义参数配置
const argv = require('yargs').argv;

// 获取脚本种的参数e
const env = argv.e;

// require指定的环境配置文件  这个是一个文件名 看到下面你就理解了
const envConfigFile = "../config/env/" + env + ".env.js";

// 将require的配置文件原封不动export回出去
module.exports = require(envConfigFile);

为了方面你们理解envConfigFile这个参数是干什么用的 我先把文件目录给你们展示出来

其实envConfigFile就是env 文件夹下面三个文件的名称

然后配置webpack

webpack.config.js

const envConfig = require('./webpack.env.conf')
//设置全部变量等于envConfigFile这个文件暴露出来的值
new webpack.DefinePlugin({
    'HOST': envConfig
 }),

dev.env.js

'use strict'
//暴露出来我们要使用的全部全局变量
module.exports = {
  NODE_ENV: '"dev"',
  API_HOST: '"http://dev.xx.com:8080"'
}

pro.env.js

'use strict'
//暴露出来我们要使用的全部全局变量
module.exports = {
  NODE_ENV: '"pro"',
  API_HOST: '"http://pro.xx.com:8080"'
}

test.env.js

'use strict'
//暴露出来我们要使用的全部全局变量
module.exports = {
  NODE_ENV: '"test"',
  API_HOST: '"http://test.xx.com:8080"'
}

package.json

 "scripts": {
    "start": "node scripts/start.js --e dev",
    "start:dev": "node scripts/start.js --e dev",
    "start:pro": "node scripts/start.js --e pro",
    "start:test": "node scripts/start.js --e test",
    "build:dev": "node scripts/build.js --e dev",
    "build:test": "node scripts/build.js --e pro",
    "build:pro": "node scripts/build.js --e test",
    "test": "node scripts/test.js"
  },

运行 npm run start:dev

useEffect(()=>{
        //测试全局变量
        /* eslint-disable no-undef */
        console.log('测试全局变量');
        console.log(HOST);
        /* eslint-disable no-new */
    },[])

这个方式配置是不区分webpack自己定义的开发环境和生产环境,是我们自己定义的devprotest三种环境,所以npm start和npm run build是一样的

具体原理上的,方法1和方法2看明白了,其实这个很好理解 所以我写的解释可能少了些

如果我们的项目只有一个生产环境和开发环境时我推荐使用第一种配置方式,因为它非常简单快捷。

当我们有多个生产环境时,建议使用第三种或是第二种方式,千万不要直接在项目中写入多个host,然后在对环境中把其他host注释掉,这样写的话非常繁琐,还容易出错。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK