这是我参与更文挑战的第8天,活动详情查看:更文挑战
一、前言
完成项目初始化后,首先我们配置下项目打包的不同环境。
场景一:前端项目开发完毕后,要上线,往往测试环境接口和生产环境接口域名是不一样的,如果每次部署都手动修改需要调用的接口域名,那么很容易出错,也不利于工程化的实践,这里整理下在项目开发过程中,如果来配置不同的打包环境。
场景二:有时候项目对应的不是一个后端服务,如果你的前端项目需要接入多个域名的接口,应该怎么样配置,才能代码条理清晰,又不至于多个域名相互冲突。
由于一般配置环境变量最重要的原因就是,通过不同的环境,调用后端不同域名下的接口,如果没有配置就会导致项目代码混乱,不利于后期维护。这里我们来展示下如何通过配置来区分不同的环境构建。
准备工作:
- 几个用来测试的前端项目,都是通过CRA初始化的
- 本地安装Docker,通过Docker来测试打包后的文件访问的是哪个配置
二、原理说明
不管需要多少个环境,目的都是让预发环境读取预发环境的配置,让生产环境读取生产环境的配置,那么可以采用各种方式,只要能实现了这个目的就可以了。
项目中常见的操作有:
- 每次部署,手动修改打包配置(耗时,易错)
- 执行构建命令,传入对应的参数,存储在某个变量,需要时读取。
- 通过CI配置关联项目分支,构建时自动构建对应的环境。
- 其他
方法一,部署临时项目或小项目时会使用,修改成本比较低,稍大点的项目就不适用了,因为浪费时间,容易出错。
方法二,是我们最常使用的方式,执行构建命令,比如npm run build:pre
,npm run build:prod
就可以构建不同的环境,配置简单,实现的方式也多,同时可以读取当前分支,避免打错分支。
方法三,通过CI触发项目配置,不需要手动构建,但涉及知识较多,配置最复杂,超大项目的必选方案,一般项目可以使用,但没必要。
知道了原理和目的,那么其他实现方式也就不难了:
- 修改环境变量,通过环境变量区分不同的配置文件
- 通过
shell
,在项目下新建多个配置文件.env .env_pre .env_production .env_local
,在打包production
环境时,先备份.env
,通过cp
命令复制.env_production
文件为.env
,打包完成后再还原.env
文件,从而实现不同环境的配置 - 通过node、fs文件模块,强行写入环境变量来实现
- 甚至可以先构建项目完成,然后在项目外引入配置文件
下面我们选择几种常用的方式,具体配置和演示下,如何构建不同的打包环境。
下面使用的项目是上一篇文章,我们通过CRA构建的最基础的项目模版。具体项目demo,我们使用不同分支来演示。
二、cross-env
修改变量(推荐)
这个环节的演示使用environment/cross-env
分支,也会是项目的主要打包方式。
1、cross-env 说明
cross-env是一款可以跨平台设置,修改项目环境变量的脚本文件
cross-env的版本6仅支持Node.js 8和更高版本
2、安装修改环境变量的插件
yarn add cross-env -D
3、修改package.json启动脚本
"scripts": {
"start": "cross-env REACT_APP_ENV=development react-app-rewired start",
"build:pre": "cross-env REACT_APP_ENV=development react-app-rewired build",
"build:prod": "cross-env REACT_APP_ENV=production react-app-rewired build",
"test": "react-app-rewired test",
"eject": "react-scripts eject"
}
这里可以使用REACT_APP_
开头的任意变量
4、执行不同的命令,启动不同的环境
yarn start
启动的时候会设置REACR_APP_ENV为development,作为本地开发使用yarn build:pre
打包预发环境代码,设置REACR_APP_ENV为development,和本地执行的环境相同,当然你可以自行配置yarn build:prod
打包生产环境代码,设置REACR_APP_ENV为production 一般项目配置这些环境变量就可以了,你也可以增加其他的环境。
5、在项目中读取变量
console.log(process.env.REACT_APP_ENV)
在项目中直接使用就行了,接着我们配置下不同环境下的接口请求。
6、配置接口不同的访问地址
在src目录下新建config
文件夹,新建文件
const version = require("../../package.json") //获取当前版本
export const development = { // 配置预发和本地环境接口
env: "development",
version,
links: {
upm: "/api/test",
case: "/api/forward"
},
apis: {
api: "/api/test",
case: "/user"
}
}
export const production = { // 配置生产环境接口地址
env: "production",
version,
links: {
upm: "/production/api/test",
case: "/production/api/forward"
},
apis: {
api: "/production/api/test",
case: "/production/user"
}
}
看文件配置应该就知道是干啥的,项目中一般会有一些不同环境下使用的变量,比如
- 版本号
- 页面内的跳转链接
- 最重要的接口请求域名
这里在这个文件下统一引入,方便后续扩展更多的配置
接着是在相同路径下,新建另一个文件index.tsx
import * as config from "./environment"
class Config {
static DEV:string = "development";
static PRODUCTION:string = "production";
static allKeys:string[] = ["development", "pre", "production"];
static currentDev: string = process.env.REACT_APP_ENV || Config.PRODUCTION
static isDev(): boolean {
return Config.currentDev === Config.DEV;
}
static isProduction(): boolean {
return Config.currentDev === Config.PRODUCTION;
}
static getUrlLinks(key:string):string{
return config[Config.currentDev].links[key];
}
static getApiUrl(key: string):string {
return config[Config.currentDev].Apis[key];
}
static getVersion():string {
return config[Config.currentDev].version;
}
}
export default Config
7、通过该文件获取当前环境变量,封装函数获取不同的配置信息
(1)在src/index.tsx
中,
import Config from 'src/config'
console.log("获取环境", Config.env)
(2)然后执行yarn build:pre
,可以看到build
部署文件成功。
(3)启动本地docker服务(docker命令说明在结尾),然后运行
docker run -d -v /Users/user/Desktop/mine/fronted-demo/build:/usr/share/nginx/html -p 8000:80 --name nginx-fronted1 nginx
(4)在浏览器访问http://localhost:8000
(5)执行 yarn build:prod
,重启docker容器,访问http://localhost:8000
,会发现此时打印的是
我们可以看到,传入不同的变量就可以请求不同的地址。
同样的道理,修改build:pre 和 build:prod对应的环境,就可以保证生产环境和开发环境分离。
三、使用项目下的.env配置文件
方法一:只用项目自带的环境配置
1、CRA本身已经配置了不同的环境,我们只需要在项目下配置
.env
.env.production
文件就可以了,当执行yarn start
,项目会读取.env
配置,当执行yarn build
项目将会读取.env.production 文件,所以如果你的项目并不复杂,完全可以省去这一步的配置,直接使用项目自带的配置
.env
REACT_APP_ENV = environment
.env.production
REACT_APP_ENV = production
2、还原package.json
3、根目录添加文件config-overrides.js
,具体可自行配置
module.exports = function override(config, env) {
//do stuff with the webpack config...
return config;
}
4、打印内容
此时执行yarn build
, 部署docker,打开浏览器localhost:8000
方法二:结合dotenv-cli修改打包的环境
该方法使用environment/env-dotenv-cli分支下演示
1、安装dotenv-cli
yarn add dotenv-cli -D
dotenv-cli是个很简单的脚本,可以帮助项目读取不同的.env
文件。
2、在根目录下新建.env .env.pre .env.production文件
.env
REACT_APP_ENV = development
REACT_APP_API_REST = https://localhost:9000
REACT_APP_API_USER = https://localhost:9001
.env.pre
REACT_APP_ENV = pre
REACT_APP_API_REST = https://www-pre.baidu.com
REACT_APP_API_USER = https://www-pre.nihao.com
.env.production
REACT_APP_ENV = production
REACT_APP_API_REST = https://www.baidu.com
REACT_APP_API_USER = https://www.nihao.com
3、修改package.json
"scripts": {
"start": "react-app-rewired start",
"build:pre": "dotenv -e .env.pre react-app-rewired build",
"build:prod": "dotenv -e .env.production react-app-rewired build"
}
在build:pre
指令中加入,dotenv -e .env.pre
这里可以看到执行yarn build:pre
读取的是.env.pre的配置内容,这样就可以项目就可以读取不同的配置了,可以看到这个方法,是将配置文件放在了env中,上面一种方法是将文件放在js文件中,区别不大。
演示代码,分支environment/env-dotenv-cli
四、直接使用node包将变量写入
该分支使用environment/env-create-fs分支演示
通过插件我们写入变量,意思就是只要我们有一个配置,标识当前环境就可以了,所以我们可以在项目根目录下新建.env文件,并声明一个变量
REACT_APP_BUILD_ENV = development
此时读取该变量会是development
,只需要在打包之前修改这个变量就行了。
具体操作在根目录新建config-env.js
文件,这里需要注意的一点是commander
的高版本和低版本语法有变化,需要注意看看文档
const fs = require('fs');
const program = require('commander');
program.option('-e, --env <type>', 'set build env', 'pre');
program.parse(process.argv);
const params = program.opts()
const $1 = params.env;
if (['development', 'pre', 'production', 'proxy'].includes($1)) {
try {
fs.writeFileSync('.env', `REACT_APP_BUILD_ENV = '${$1}'`, 'utf-8');
} catch (error) {
console.error(error);
return;
}
} else {
console.error('参数不符合要求');
return;
}
修改package.json文件
"scripts": {
"start": "node ./config-env.js && react-app-rewired start",
"build:prod": "node ./config-env.js -e production && react-app-rewired build",
"build:pre": "node ./config-env.js -e pre && react-app-rewired build"
}
这里可以看到执行打包命令,然后运行config-env.js
文件,该文件引用node的fs模块和commander包,读取传入的环境变量,然后通过fs的方法修改文件的环境变量,直接运行
由于项目默认读取的是.env
文件,所以我们只需要执行node 。/config-env.js -e production
文件看到 .env
中环境变量修改成功就可以了。
具体配置的示例代码,见分支environment/env-create-fs
五、需要注意的点
1、ts通过变量获取对应的值,报错,解决办法?
static getUrlLinks(key:string):string{
return config[Config.currentDev].links[key];
}
这里ts语法会报错
解决办法这里暂时直接屏蔽掉,在tsconfig.json添加配置
{
"compilerOptions": {
"suppressImplicitAnyIndexErrors": true
}
}
2、.env* 文件需要以REACR_APP_
开头,才能在项目中读取
3、启动docker的镜像nginx
docker run -d -v /Users/user/Desktop/mine/fronted-demo2/build:/usr/share/nginx/html -p 8000:80 --name nginx-fronted2 nginx
- 其中-d 后面
/Users/user/Desktop/mine/fronted-demo/build:/usr/share/nginx/html
以冒号分割,前面是我本地项目的地址 - build是项目打包后文件所在的文件夹,后面是nginx容器访问的路径,通过挂载运行项目
- -p 8000:80 表示,本地通过8000端口访问,容器使用的80端口
- --name nginx-fronted 为启动的容器命名
- nginx是启动容器的镜像名称,本地没有会从远程docker仓库拉取。
4、其他可以使用的插件 www.npmjs.com/package/env…