4

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

 2 years ago
source link: https://segmentfault.com/a/1190000040890168
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

在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.tsx
export 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.tsx
export 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.js
const child_process = require('child_process')
const { cwd } =  require('process')
child_process.spawn('bash', ['./scripts/bash.sh'], {
  cwd: cwd(),
  shell: true,
});

// bash.sh
#!/bin/bash -x
sed -i "" "s/\$\$root/publicpath/g" dist/*

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK