【JS】【react】前端读取环境变量的骚操作

【react】前端读取环境变量的骚操作

杨成功发布于 今天 02:00

背景

在经典的单页面应用中,以 react 为例,应用会区分开发环境和生产环境。开发环境是用 webpack-dev-server 编译并启动的前端项目,本质上启动的是一个 node 服务。生产环境也是需要 node 编译为纯静态页面,等待后续部署。

因为编译都用到了 node,所以就可以用 node 提供的 process.env 访问系统环境变量。同时 react 还提供了 process.env.NODE_ENV 来区分开发和生产环境

process.env.NODE_ENV == 'development' ## 开发环境

process.env.NODE_ENV == 'production' ## 生产环境

使用 NODE_ENV 最多的地方是 webpack 配置文件,用来判断当前环境是开发还是生产,然后使用不同的编译配置打包项目。

上面说的开发环境和生产环境只是用来区分 run startrun build。当项目 build 后生成静态文件准备部署时,我们还要区分是部署 staging 环境还是部署 release 环境。因为 staging 是正式部署生产前的测试阶段,所以这两个环境最大的区别就是接口的 baseURL 不同。

此时 process.env.NODE_ENV 的值都是 production,所以我们需要自定义一个新的环境变量来区分 staging 和 release。然后分别使用不同的 baseURL

假设新的环境变量是 REACT_APP_ENV,判断方式如下:

switch(process.env.REACT_APP_ENV) {

case 'staging':

// staging环境

baseURL = 'http://staging-url.com'

case 'release':

// release环境

baseURL = 'http://release-url.com'

}

那么,如何自定义 REACT_APP_ENV 呢?

编译时定义

上面说了,开发和生产环境打包文件时都是基于 node,所以在 process.env 上设置就可以。

推荐使用 cross-env 这个库,它的好处就是跨平台,window,Linux 或 Mac 都是相同的设置方式。

怎么用呢?比如你的 package.json 中的 build 命令是这样:

"scripts": {

"build": "node scripts/build.js

}

那么就可以基于 build 分别新增打包命令:

"scripts": {

"build": "node scripts/build.js,

"staging": "cross-env REACT_APP_ENV=staging node scripts/build.js",

"release": "cross-env REACT_APP_ENV=release node scripts/build.js",

}

现在 npm run stagingnpm run release 打包出来的文件唯一的区别就是 REACT_APP_ENV 的不同,这刚好满足了上面我们区分环境设置不同 baseURL 的需求。

但是要注意,也是后面我采坑的地方:这种环境变量的设置方式,只在编译的时候有效。本质上是在编译时根据 REACT_APP_ENV 判断出 baseURL 的值,然后写死在文件里。

也就是说,编译后,baseURL 的值已经是最终值,不会再执行 REACT_APP_ENV 的判断逻辑。

那么,有没有办法只 build 一次,打包一份文件,然后代码里直接读取系统环境变量,来判断使用哪个 baseURL 呢?

有,这是本文重点。

直接读取

首先说说为什么会有这个需求。我司要做前端项目容器化,打包成 docker 镜像部署。期望的是只打包一份镜像,然后 docker run 的时候传一个环境变量,然后前端项目里读这个环境变量,判断出 baseURL 是什么。

开始我的思路就是 process.env,后来发现不对,因为前端 js 是不能直接读取系统信息的。最后我们选定了方案,使用 node。

前端不能读取环境变量,但是node可以。我们的思路是用 node 读取到环境变量,然后用服务端渲染的方式传给前端,前端再将这个值保存在 window 全局对象里后续使用。

有了这个思路,我们来实践:

首先,项目目录下建 release 文件夹,包含两个文件:

1. package.json

{

"name": "release-server",

"version": "1.0.0",

"scripts": {

"start": "node server.js"

},

"dependencies": {

"express": "^4.13.3",

"path": "^0.12.7",

"ejs": "^2.3.4"

}

}

服务端渲染用 ejs 传值,所以要装 ejs

2. server.js

const path = require('path');

const express = require('express');

// 读取系统环境变量(docker设置)

const REACT_APP_ENV = process.env.REACT_APP_ENV;

const port = process.env.PORT || 8080;

const app = express();

app.use(express.static(__dirname + '/dist')); // dist 是打包后的目录

app.set('views', path.join(__dirname, '/dist/'));

app.set('view engine', 'ejs');

app.get('*', function response(req, res) {

res.render('index', { REACT_APP_ENV }); // 传递 REACT_APP_ENV

});

app.listen(port);

实际部署的时候,用 node 启动 server.js,然后 node 会读取到 REACT_APP_ENV,并通过 ejs 传给前端。

这一步完成,下一步就是将 html 模版换成 ejs 模版,并接受变量。

在 public 目录下将 index.html 改成 index.ejs,然后在 head 中增加一个接受变量的脚本块

<script>

var GLOBAL_ENV = {

"REACT_APP_ENV": "<%= REACT_APP_ENV %>", // 接收 node 传来到 REACT_APP_ENV

};

Object.freeze(GLOBAL_ENV);

</script>

然后将 webpack 的解析模版改为 ejs

new HtmlWebpackPlugin({

filename: "index.ejs",

template: path.resolve('public/index.ejs'),

})

最后修改 webpack 的 outputrelease/dist

大功告成!

配置完成后执行 run build,打包出来的文件是这样的

【JS】【react】前端读取环境变量的骚操作

然后将这份代码交给 node 运行起来就好了~

javascriptreact.js

阅读 47更新于 今天 02:44

本作品系原创,采用《署名-非商业性使用-禁止演绎 4.0 国际》许可协议


杨成功的全栈之路

决定花功夫做这件事情,那么有几个原则:绝对拒绝抄袭文章的智障行为,开这个专栏一方面记录自己的经验...

avatar

杨成功

前端为基,深耕js

1.3k 声望

23 粉丝

0 条评论

得票时间

avatar

杨成功

前端为基,深耕js

1.3k 声望

23 粉丝

宣传栏

背景

在经典的单页面应用中,以 react 为例,应用会区分开发环境和生产环境。开发环境是用 webpack-dev-server 编译并启动的前端项目,本质上启动的是一个 node 服务。生产环境也是需要 node 编译为纯静态页面,等待后续部署。

因为编译都用到了 node,所以就可以用 node 提供的 process.env 访问系统环境变量。同时 react 还提供了 process.env.NODE_ENV 来区分开发和生产环境

process.env.NODE_ENV == 'development' ## 开发环境

process.env.NODE_ENV == 'production' ## 生产环境

使用 NODE_ENV 最多的地方是 webpack 配置文件,用来判断当前环境是开发还是生产,然后使用不同的编译配置打包项目。

上面说的开发环境和生产环境只是用来区分 run startrun build。当项目 build 后生成静态文件准备部署时,我们还要区分是部署 staging 环境还是部署 release 环境。因为 staging 是正式部署生产前的测试阶段,所以这两个环境最大的区别就是接口的 baseURL 不同。

此时 process.env.NODE_ENV 的值都是 production,所以我们需要自定义一个新的环境变量来区分 staging 和 release。然后分别使用不同的 baseURL

假设新的环境变量是 REACT_APP_ENV,判断方式如下:

switch(process.env.REACT_APP_ENV) {

case 'staging':

// staging环境

baseURL = 'http://staging-url.com'

case 'release':

// release环境

baseURL = 'http://release-url.com'

}

那么,如何自定义 REACT_APP_ENV 呢?

编译时定义

上面说了,开发和生产环境打包文件时都是基于 node,所以在 process.env 上设置就可以。

推荐使用 cross-env 这个库,它的好处就是跨平台,window,Linux 或 Mac 都是相同的设置方式。

怎么用呢?比如你的 package.json 中的 build 命令是这样:

"scripts": {

"build": "node scripts/build.js

}

那么就可以基于 build 分别新增打包命令:

"scripts": {

"build": "node scripts/build.js,

"staging": "cross-env REACT_APP_ENV=staging node scripts/build.js",

"release": "cross-env REACT_APP_ENV=release node scripts/build.js",

}

现在 npm run stagingnpm run release 打包出来的文件唯一的区别就是 REACT_APP_ENV 的不同,这刚好满足了上面我们区分环境设置不同 baseURL 的需求。

但是要注意,也是后面我采坑的地方:这种环境变量的设置方式,只在编译的时候有效。本质上是在编译时根据 REACT_APP_ENV 判断出 baseURL 的值,然后写死在文件里。

也就是说,编译后,baseURL 的值已经是最终值,不会再执行 REACT_APP_ENV 的判断逻辑。

那么,有没有办法只 build 一次,打包一份文件,然后代码里直接读取系统环境变量,来判断使用哪个 baseURL 呢?

有,这是本文重点。

直接读取

首先说说为什么会有这个需求。我司要做前端项目容器化,打包成 docker 镜像部署。期望的是只打包一份镜像,然后 docker run 的时候传一个环境变量,然后前端项目里读这个环境变量,判断出 baseURL 是什么。

开始我的思路就是 process.env,后来发现不对,因为前端 js 是不能直接读取系统信息的。最后我们选定了方案,使用 node。

前端不能读取环境变量,但是node可以。我们的思路是用 node 读取到环境变量,然后用服务端渲染的方式传给前端,前端再将这个值保存在 window 全局对象里后续使用。

有了这个思路,我们来实践:

首先,项目目录下建 release 文件夹,包含两个文件:

1. package.json

{

"name": "release-server",

"version": "1.0.0",

"scripts": {

"start": "node server.js"

},

"dependencies": {

"express": "^4.13.3",

"path": "^0.12.7",

"ejs": "^2.3.4"

}

}

服务端渲染用 ejs 传值,所以要装 ejs

2. server.js

const path = require('path');

const express = require('express');

// 读取系统环境变量(docker设置)

const REACT_APP_ENV = process.env.REACT_APP_ENV;

const port = process.env.PORT || 8080;

const app = express();

app.use(express.static(__dirname + '/dist')); // dist 是打包后的目录

app.set('views', path.join(__dirname, '/dist/'));

app.set('view engine', 'ejs');

app.get('*', function response(req, res) {

res.render('index', { REACT_APP_ENV }); // 传递 REACT_APP_ENV

});

app.listen(port);

实际部署的时候,用 node 启动 server.js,然后 node 会读取到 REACT_APP_ENV,并通过 ejs 传给前端。

这一步完成,下一步就是将 html 模版换成 ejs 模版,并接受变量。

在 public 目录下将 index.html 改成 index.ejs,然后在 head 中增加一个接受变量的脚本块

<script>

var GLOBAL_ENV = {

"REACT_APP_ENV": "<%= REACT_APP_ENV %>", // 接收 node 传来到 REACT_APP_ENV

};

Object.freeze(GLOBAL_ENV);

</script>

然后将 webpack 的解析模版改为 ejs

new HtmlWebpackPlugin({

filename: "index.ejs",

template: path.resolve('public/index.ejs'),

})

最后修改 webpack 的 outputrelease/dist

大功告成!

配置完成后执行 run build,打包出来的文件是这样的

【JS】【react】前端读取环境变量的骚操作

然后将这份代码交给 node 运行起来就好了~

以上是 【JS】【react】前端读取环境变量的骚操作 的全部内容, 来源链接: utcz.com/a/108819.html

回到顶部