优雅实现 React 项目多环境打包

知乎配图

在实际项目开发中,前端 er 常常会面对多个环境的接口:开发环境、测试环境、生产环境,所以项目中网络请求的 baseUrl也需要跟随这些环境来变化。

但是,我们一般会使用像 create-react-app或者 umi这样的脚手架来做项目的初始化,这些脚手架将 webpack 的配置黑盒化了,如何在不执行 eject 操作的前提下优雅地配置多个项目环境呢

在项目中最好不要一遇到问题就一键执行 eject 操作, eject 操作是不可逆的,执行之后会把所有细节都暴露在我们面前,让项目目录变得很庞大。

create-react-app 配置多环境接口

其实查看 create-react-app 的官方文档可以发现,create-react-app 默认是支持多个环境配置文件的:

  • .env:默认。

  • .env.local:本地覆盖。除 test 之外的所有环境都加载此文件

  • .env.development, .env.test, .env.production:设置特定环境。

  • .env.development.local, .env.test.local, .env.production.local:设置特定环境的本地覆盖。

左侧的文件比右侧的文件具有更高的优先级:

  • npm start: .env.development.local, .env.development, .env.local, .env

  • npm run build: .env.production.local, .env.production, .env.local, .env

  • npm test: .env.test.local, .env.test, .env (注意没有 .env.local )

例如我们部门目前开发流程中只有开发环境和测试环境两种接口(其中,本地开发和测试共用一个环境),

所以,我需要将测试环境下打包时使用的接口地址指定为 env.development中的接口地址,我分别写了两份配置文件 .env.development 以及 env.production,但是根据以上create-react-app 的官方文档,在执行 build 命令时,默认是加载 .env.production 文件中的变量,所以我在测试服务器上执行 npm run build 命令时就会使得接口地址被指定为生产环境的接口地址,这显然不是我想要的。

怎么办呢?

官方文档也给了我们答案——可以使用 dotenv 来做环境变量的管理(dotenv 可将环境变量从 .env 文件加载到 process.env中。)

因为我们要在命令行中使用,所以我们需要使用 dotenv-cli

话不多说,让我们开始吧~

写好各个环境的配置文件

首先,我们可以写好每个环境下的配置文件。

# .env.development
REACT_APP_BASE_URL='http://development.xxx.xxx' 
# env.production
REACT_APP_BASE_URL='http://production.xxx.xxx' 

修改 package.json 中的 scripts来指定环境

"scripts": {
    "start": "react-app-rewired start",
    "build:dev": "dotenv -e .env.development react-app-rewired build",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test",
    "eject": "react-scripts eject"
  }

这样,当我需要在测试服务器上打包前端代码时,我就可以执行npm run build:dev来指定使用 .env.development中的环境变量了~

umi 配置多环境接口

有了以上的经验我们就可以知道,其实多环境配置,不外乎就是将各个环境的配置文件分开,并使用额外的手段来在打包时指定对应环境的配置文件。

写好各个环境的配置文件

查看 UMI 文档 可知,环境变量被放在 config/config.js下的 define 这个配置中,

如果你使用 TypeScript 开发,那么配置文件是 config/config.ts。

所以同样的,我们可以将原来的 config/config.ts 做个分身,写两份配置文件,分别是 config/config.dev.tsconfig/config.prod.ts

修改 package.json 中的 scripts 来指定环境

查看 umi生成的模版项目中的package.json 可以发现: umi 默认是使用 cross-env来为 umi 打包指定配置文件。所以我们将package.json 中的 scripts 改写如下:

"scripts": {
  "start": "react-app-rewired start",
  "build-dev": "cross-env UMI_ENV=dev umi dev",
    "build-test": "cross-env UMI_ENV=test umi build",
    "build-prod": "cross-env UMI_ENV=prod umi build",
},

Tips:将配置和代码分开存储

将配置和代码分开存储

因为各个环境的部署版本之间,配置文件的差异程度可能很大,但是代码基本是不变的。

当然,上面所说的配置文件不包括内部应用程序的配置(例如,你可能将路由写成了配置文件)。

判断一个应用是否正确地将配置排除在代码之外,一个简单的方法是看该应用的基准代码是否可以立刻开源,而不用担心会暴露任何敏感的信息。——《The Twelve-Factor App》

反面教材

一个比较典型的反面教材就是在代码中再写一份类似 getBaseUrl.js这样的文件来做环境判断:

// getBaseUrl.js
const TEST_DOMAIN = process.env.REACT_APP_BASE_URL
const PRODUCTION_DOMAIN = process.env.REACT_APP_PRODUCTION_BASE_URL
let domain = TEST_DOMAIN

switch (process.env.NODE_ENV) {
  case 'development':
    domain = TEST_DOMAIN
    break
  case 'production':
    domain = PRODUCTION_DOMAIN
    break
  default:
    domain = TEST_DOMAIN
    break
}

export default domain

上面的变量是 .env 文件里面写好的变量:

# .env
REACT_APP_DEVELOPMENT_BASE_URL='http://xxxxxx' # 开发环境/测试环境的接口地址
REACT_APP_PRODUCTION_BASE_URL='http://xxxxxx'  # 生产环境的接口地址

其实我自己在刚开始用 React 写项目的时候就是这么干的😅,这样相当于将配置写在了代码里面,不仅可维护性比较差,而且别人看你代码的时候,可读性也比较差。

配置文件区分环境,相互独立

其实这种方式是 dotenv 所不推荐的,它的观点如下:

image-20191206213457315

dotenv 推荐直接在配置文件直接存储在不同的部署环境中,不做版本控制,所以你需要在各个环境配置好环境变量,它们都放在 .env 文件中。但是这个对于我们小作坊式开发来说,反而比较麻烦,所以我目前都是按照分配置文件的方式来实践的,如果正在阅读本篇文章的你有更好的方式,欢迎评论~

参考文件

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容