「这是我参与11月更文挑战的第7天,活动详情查看:2021最后一次更文挑战
前言
在前端项目的开发、测试、上线等过程中,项目势必会运行在多种环境中,最少也有如: dev(开发)、pre(测试)、prod(正式)几种环境。也经常会遇到请求的接口也根据环境不同,提供了不同的url,如 pre 环境下使用 https://server-pre.com/api,prod 环境下使用 https://server.com/api。
如果通过人力去对这些变量进行维护,那么不可避免的会有一些不方便的情况。那么我们需要一个 API_URL 的环境变量来进行一个判断,在对应环境下使用对应的接口连接。
对于 React 项目来说,实测并不能在 process.dev 获取到定义的 API_URL 内容。哪怕使用了 REACT_APP_API_ENV 的方式,也无法在项目中获取到这个环境变量。那么接下来,就需要升级一下我们的 webpack 配置了
webpack 配置可以参考:
我是这样搭建React+TS的通用webpack脚手架的(阶段一)
我是这样搭建React+TS的通用webpack脚手架的(阶段二)
定义 NDOE_ENV
刚开始我想到了通过定义 NODE_ENV 的形式来给 API_ENV 赋值,因此使用了 cross-env 的包来对环境变量进行定义
// 这是之前 package.json的 scripts
"scripts": {
start: "webpack serve --config build/webpack.dev.config.js --open",
build: "yarn build:css && yarn build:prod",
build:prod: "npx webpack --config build/webpack.prod.config.js",
build:css: "postcss src/css/styles.css -o src/css/output.css",
watch:css: "postcss src/css/styles.css -o src/css/output.css -w",
dev: "concurrently "yarn watch:css " "yarn start "",
lint: "eslint src --fix --ext .ts,.tsx "
}
//新的 package.json 的 scripts
"scripts": {
"watch:css": "postcss src/css/styles.scss -o src/css/output.css -w",
"build:css": "postcss src/css/styles.scss -o src/css/output.css",
"start": "cross-env NODE_ENV=development webpack serve --config build/webpack.dev.config.js --open",
"build:prod": "cross-env NODE_ENV=production npx webpack --config build/webpack.prod.config.js",
"build:pre": "cross-env NODE_ENV=pre npx webpack --config build/webpack.prod.config.js",
"dev": "concurrently "yarn watch:css " "yarn start "",
"pre": "yarn build:css && yarn build:pre",
"build": "yarn build:css && yarn build:prod",
"lint": "eslint --fix src --ext .ts,.tsx "
},
此时,使用 yarn pre 命令进行打包,会发现一个报错:
在看了 webpack 的文档后
NODE_ENV,也就是 webpack 的 mode,只支持 none、development、production 这三种选项,如果需要自定义 mode,需要把配置从
module.exports = {
mode: 'none',
};
修改到 function 的形式
const config = {
entry: './app.js',
//...
};
module.exports = (env, argv) => {
if (argv.mode === 'development') {
config.devtool = 'source-map';
}
if (argv.mode === 'production') {
//...
}
return config;
};
那这就与我们之前在项目中根据 mode 拆分成 webpack.base.config.js、webpack.dev.config.js、webpack.prod.config.js 这些文件的初衷产生了冲突。
定义 API_ENV
既然设置 NODE_ENV 这种方式走不通,那就尝试在前端定义一个 API_ENV
更改一下 package.json 的 scripts
"scripts": {
"start": "cross-env API_ENV=dev webpack serve --config build/webpack.dev.config.js --open",
"build:prod": "cross-env API_ENV=prod npx webpack --config build/webpack.prod.config.js",
"build:pre": "cross-env API_ENV=pre npx webpack --config build/webpack.prod.config.js",
"build:css": "postcss src/css/styles.css -o src/css/output.css",
"watch:css": "postcss src/css/styles.css -o src/css/output.css -w",
"pre": "yarn build:css && yarn build:pre",
"build": "yarn build:css && yarn build:prod",
"dev": "concurrently "yarn watch:css " "yarn start "",
"lint": "eslint src --fix --ext .ts,.tsx "
},
这里用 webpack 的 DefinePlugin 插件来修改一下 webpack.base.config
module.exports = {
//...
plugins: [
//...
new webpack.DefinePlugin({
"process.env.API_ENV": JSON.stringify(process.env.API_ENV),
API_ENV: JSON.stringify(process.env.API_ENV)
})
]
}
然后在我们的 config.ts 文件中,修改我们的 apiUrl
let apiUrl: string;
const apiUrlMap: {[key: string]: string} = {
dev: 'https://server-pre.com/api',
pre: 'https://server-pre.com/api',
prod: 'https://server.com/api',
}
apiUrl = apiUrlMap[process.env.API_ENV]
export default apiUrl;
结果
通过这种方式定义 API_ENV,我们就可以看到,部署在 pre 环境下的项目,使用的 apiUrl 是 https://server-pre.com/api,production 环境下使用的是 https://server.com/api。这样,我们在每次合并 pre 分支的代码到主分支,就不用担心 apiUrl 被覆盖啦!