在umi中实现一次构建多环境部署

最近在工作中,听闻共事埋怨在外部平台上构建我的项目很慢。初步剖析了一下,起因无非两个:1. 我的项目自身较大,导致构建工夫较长 2. 咱们的构建部署流程是:一次build qa和prod环境2个包,而后再别离部署不同环境的构建产物,无疑这样会导致整体构建工夫变长。
前者不是本文的重点,本文只探讨第二点:即如何 一次构建多环境部署。

问题

build once deploy anywhere 在后端曾经是比拟常见了,然而对于前端来说,会有几点问题

1.环境变量

即 process.env.XXX 会在build阶段间接被编译成以后值
举例: process.env.RUNTIME 在被编译之后,就曾经在代码中固定为 ‘this is qa runtime’,这意味着咱们不能及时更改它。如果想要针对不同环境,更改为不同的值,那就须要从新构建

export default function IndexPage() {  return (    <div>      <p> `{process.env.RUNTIME}` </p>    </div>  );}// 在通过yarn build之后这段代码就成了function o() {      return Object(r["jsx"])("div", {        children: Object(r["jsxs"])("p", {          children: [" `", "this is qa runtime", "` "]        })      }) }

要解决这个问题,最简略的方法就是将所有配置写到一个config.json中,应用fetch将其在代码中引入。
public/config.json

{  "dev":{    "RUNTIME": "this is dev runtime"  },  "qa":{    "RUNTIME": "this is qa runtime"  },  "prod":{    "RUNTIME": "this is prod runtime"  }}

在 umi app.tsx中引入(我的项目部署时,会将部署信息 delopyEnv注入进来,用于我的项目判断是处于dev,qa,prod中的哪个环境)

 // app.tsxexport function render(oldRender: any) {  fetch('./config.json')  .then((res) => res.json())  .then((config) => {    window.config = config[window?.APP_METADATA?.deployEnv|| 'dev'];    oldRender()  })}// pages/home/index.tsxexport default function IndexPage() {  return (    <div>      <h1 className={styles.title}>Page index</h1>      <p> `{window.config.RUNTIME}` </p>    </div>  );}

至此 咱们能够看到,咱们就能够应用window.config.RUNTIME 来代替 process.env.RUNTIME

2.publicPath

咱们在本地运行的时候,publicpath个别就为根目录地址。然而在线上环境的话,个别 会将css js img等资源文件托管到CDN上。
即咱们在qa环境构建进去的资源文件 会以相似<script src="https://static.qa.fiture.com/h1t86b7fg6c7k17v78ofck5d/umi.f6afc434.js"></script>的模式存在于我的项目中。
若要动静的去依据环境扭转拜访img script link 地址的话,
目前我的思路是:在打包的时候应用占位符作为publicpath。等到启动我的项目的时候,运行一个脚本,将占位符替换掉即可。
咱们设置非本地环境时的publicpath 为$$root/作为占位符

const publicPath = development ? './' : '$$root/';

那么对应的构建产物index.html就会是

 <head>    <link rel="stylesheet" href="$$root/umi.css" />    <script>      //! umi version: 3.5.20    </script>  </head>  <body class="body">    <div id="root"></div>    <script src="$$root/umi.js"></script>  </body>

故咱们能够在部署前执行命令
sed -i "" "s/\$\$root/publicpath/g" dist/*
将$$root 替换成真正的public path门路(部署时由环境变量注入).
最初咱们将其写成一个脚本 在scripts/replacePath.js中 并增加到package.json中

//package.json  "scripts": {      "replacePath": "node scripts/replacePath"  },// replacePath.jsconst child_process = require('child_process')const { cwd } =  require('process')child_process.spawn('bash', ['./scripts/bash.sh'], {  cwd: cwd(),  shell: true,});// bash.sh#!/bin/bash -xsed -i "" "s/\$\$root/publicpath/g" dist/*

最初附上对应的代码 demo地址