Node
这个和传统Java, C#应用程序基本一致,
- config
- default.yaml
- development.yaml
- production.yaml
- test.yaml
- src
- test
- .env
- .env.production
- .env.test
index.js
require('dotenv').config(); // 这句后续应交由dotenv-cli来实现
const config = require('config');
config是用来做常规设置,而dotenv区别config主要有2个因素:
- dotenv写到process的环境变量,比如说NODE_ENV, DEBUG的这些和process.env强绑定的设置
- 用户名密码之类不对外公开的信息,如果放在config则一并上传到了git repo,如果是公开的repo则公开了用户名密码,所以一般.env是不用来上传的
注:
- 整个加载过程是层叠覆盖式的,比如当NODE_ENV=production时,会先加载.env,然后再加载.env.production覆盖 (dotenv-cli -e则不会显式层叠加载)
对应的webpack.config.js
const path = require('path');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const _externals = require('externals-dependencies');
module.exports = {
mode: 'production',
target: 'node',
entry: './src/index.js',
module: {
rules: [
{
test: /\.js$/,
exclude: [
/test/,
/node_modules/
],
loader: 'babel-loader'
}
]
},
node: {
__filename: false,
__dirname: false
},
output: {
path: path.join(__dirname, 'build'),
filename: 'bundle.js'
},
optimization: {
minimizer: [new TerserPlugin()]
// minimizer: []
},
plugins: [
new CopyWebpackPlugin(['config', '.env*', 'package.json'])
],
externals: _externals()
};
在运行build的时候还是需要先制定NODE_ENV
NODE_ENV=production node bundle.js
再来看dotenv-cli, 这样可以去掉require(‘dotenv’).config(),然后在运行时选择NODE_ENV,
.env
NODE_ENV=development
DEBUG=app*
.env.production
NODE_ENV=production
ok, 然后配置运行指令,
dotenv -e .env node app
dotenv -e .env.prodcution node app
这样就比较有一致性了。
最后补充一下pm2的情况,
dotenv -e .env.production pm2 reload ecosystem.config.js
最终可以整理如下:
"scripts": {
"start": "node src/index",
"start:prod": "cross-env NODE_ENV=production node src/index",
"pm2": "dotenv -e .env.production pm2 reload ecosystem.config.js",
"build": "webpack --mode production --progress --display-modules --colors --display-reasons"
},
参考:
React
React的配置比Node会受限一些,主要是因为它运行在浏览器中,刚刚的config都是运行时,但React的配置则基本是编译时,因为.env的内容直接hard code到最终编译的js, 所以和Node是不同的,遵循create-react-app的要求,可以采用.env和.env.production等支持多环境,在加载.env.production时会先加载.env。
如果需要运行时,就比如build以后需要做配置,则需要在HTML中引入js,
<!DOCTYPE html>
<html lang="en">
<head>
<title>React App</title>
<script type="text/javascript">
window.RUNTIME = {
SERVICE: "http://xyz.api"
};
</script>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
然后在页面获取,
function App() {
return (
<div className="App">
{window.RUNTIM && window.RUNTIME.SERVICE &&
<h1>{window.RUNTIME.SERVICE}</h1>
}
<h1>{process.env.REACT_APP_MESSAGE}</h1>
</div>
);
}
此外,yarn start时NODE_ENV=development, yarn build后则NODE_ENV=production
现在需求来了,
- 在本地运行时,默认连接本地的服务,但可以手动设置采用其他服务地址
- 编译后, 则默认使用云端地址, 可手动修改服务地址
config.js
import Debug from 'debug';
const debug = Debug('app:config');
class Config {
constructor() {
debug(`NODE_ENV: ${process.env.NODE_ENV}`);
if (window.RUNTIME && window.RUNTIME.SERVICE) {
this.service = window.RUNTIME.SERVICE;
} else {
if (process.env.REACT_APP_SERVICE) {
this.service = process.env.REACT_APP_SERVICE;
} else {
throw new Error("Missing service configration");
}
}
}
}
export default new Config();
在index.js中直接可以import './config'
, 然后在app.js就可以消费了,
function App() {
return (
<div className="App">
<h1>{config.service}</h1>
</div>
);
}
最后补充一下env,
.env
REACT_APP_SERVICE=http://localhost:9007
.env
REACT_APP_SERVICE=https://api.space365.live
如果在HTML设置了service,则无视.env
<script type="text/javascript">
window.RUNTIME = { SERVICE: "http://xyz.api" };
</script>
上述代码可以在这里获取。