---
title: "静态部署 UmiJS 4"
date: 2023-02-20T00:49:03.000Z
author: Z.SHINCHVEN
tags: [UmiJS, React, SPA]
canonical: https://atlassc.net/2023/02/20/umijs-4-static-deployment
---
[UmiJS](https://umijs.org/) 4.0 之后，静态部署的配置发生了很多变化，这里记录一下。

```ts
import {defineConfig} from "umi";

const publicPathBase = '/news'

export default defineConfig({
  publicPath: publicPathBase + '/', // 静态资源路径的前缀
  base: publicPathBase + '/', // 路由前缀
  outputPath: './dist' + publicPathBase, // 打包输出路径
  mfsu: {}, // 开启 mfsu
  define: {
    BASE_URL: publicPathBase,
    PUBLIC_PATH: publicPathBase + '/',
  },
  routes: [
    {path: "/", component: "index"},
    {path: '/details', component: 'details'},
  ],
  npmClient: 'npm',
  exportStatic: {}, // 为每个 path 生成静态部署文件，不再支持 path-to-regexp 的参数
});
```

## 静态部署的路由原理

UmiJS 是一个基于 React 的 SPA 程序，程序加载完以后的页面切换都是在浏览器中进行的，不会再向服务器发送请求，具体的路由切换原理如下：

- 静态资源载入：当用户在浏览器中输入 URL 访问目标页面时，浏览器将会向服务器发送请求，服务器将返回对应的 HTML 文件以及 JS 和 CSS 文件。
- 加载程序：静态资源载入后，浏览器将运行 JS 代码中的 React App。
- SPA 路由：React App 启动后，用户再执行的页面切换默认都是通过 Browser Router 或者 Hash Router 来在浏览器地本程序中执行，而不再向服务器请求新的页面。

## exportStatic 与 path-to-regexp 参数

启用[exportStatic](https://umijs.org/docs/api/config#exportstatic)后将为每个`page`生成一个`html`文件，这样在浏览器输入地址直接打开指定`page`的`path`时，将通过访问`server`的`public`目录中对应的`html`文件来打开对应的`page`。

```bash
dist/news/index.html
dist/news/details/index.html
```

因为是静态文件部署，则不再支持对应实时数据的动态的`path-to-regexp`的参数，默认情况下只会输出`dist/news/details/:id/index.html`，而不会输出 `dist/news/details/1/index.html`、`dist/news/details/2/index.html`等。

如果一定要在静态文件部署模式下使用`path-to-regexp`的参数，可以通过配置`extraRoutePaths`来为 build 时已有的数据`预生成`html文件，对运行时的数据变更无效。

```ts
// .umirc.ts
export default {
  exportStatic: {
    // 配置固定值
    extraRoutePaths: ['/news/1', '/news/2'],
    // 也可以配置函数动态获取
    extraRoutePaths: async () => {
      const res = await fetch('https://api.example.com/news');
      const data = await res.json();
      return data.map((item) => `/news/${item.id}`);
    },
  },
}
```

如果一定要使用动态的`path-to-regexp`的参数，请考虑`hash history`或者`ssr`两种方案。而目前这两种方案在`UmiJS V4`中都还有bug。
