Ant Design Pro 常见问题

antd pro 官方文档介绍了动态切换主题的方法。但是并没有讲的特别清楚,而且编译主题的时间比较长,非常影响开发效率。下面介绍下我的解决办法。

# 自定义主题样式

# 动态主题切换原理

主题切换主要是通过 unm-plugin-antd-theme 插件实现的,unm-plugin-antd-theme 插件通过 antd-pro-merge-less 将 less 文件编译为一个主题 css 文件。
所以 unm-plugin-antd-theme 的配置文件就是定义的 antd-pro-merge-less (https://github.com/chenshuai2144/antd-pro-merge-less) 的参数,如下所示,要求是 json 文件,文件名 theme.config.json:

‘’ ‘’
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
{
"theme": [{
"key": "dark",
"theme": "dark",
"fileName": "dark.css",
"modifyVars": {
"@font-size-base": "12px",
"@table-padding-vertical": "10px",
"@link-color": "#0070cc"
}
},
{
"key": "volcano",
"fileName": "volcano.css",
"modifyVars": {
"@primary-color": "#FA541C",
"@font-size-base": "12px",
"@table-padding-vertical": "10px",
"@link-color": "#0070cc"
}
},
{
"key": "volcano",
"theme": "dark",
"fileName": "dark-volcano.css",
"modifyVars": {
"@primary-color": "#FA541C",
"@font-size-base": "12px",
"@table-padding-vertical": "10px",
"@link-color": "#0070cc"
}
}
],
"min": true,
"isModule": true,
"ignoreAntd": false,
"ignoreProLayout": false,
"cache": true
}

每种主题一个不同的文件,fileName 定义了文件名,theme 为 dark 表示暗黑主题(对应 antdpro 主题设置里面的 realDark),不写就是亮色主题(对应 antdpro 主题设置里面的 light 或 dark)。modifyVars 就是对 antd 默认变量的定制。

如果发现上面没有默认的亮色主题,因为这时不用单独的主题 css 文件,直接用默认的就好。
每次编译的时候 unm-plugin-antd-theme 插件会遍历上面定义的每个主题,编译为一个 css 文件,开发时位于 node_modules/.plugin-theme/theme 目录下,发布时位于 theme 目录下,每个主题文件编译都需要几秒钟,所以主题多了编译时间会比较慢,后面会讲怎么解决这个问题。
关于插件的使用,umi3 对于 umi-plugin 开头的插件是自动加载的,不需定义在 config 文件的 plugins 中,如果看到一些老的教程不要感到困惑。

好了,有了主题文件,接下来要解决怎么应用主题,其实很简单,就是重新加载新的 css 文件。antd pro 官方给了参考例子,也可以参考 SettingDrawer 源代码

# 解决主题编译慢问题

开发期每次都编译主题是难以忍受的,所以我的办法是开发器能够配置是否编译主题,而发布时总是编译主题。可惜 unm-plugin-antd-theme 插件本身并没有提供这种配置能力。好在 umi 的扩展能力非常强,我写了一个插件来解决这个问题,其实非常简单,代码只有几行,插件名 umi-plugin-config

也可以使用 umi 禁用插件的方法, unm-plugin-antd-theme 插件插件的 key 为 antdTheme,修改 config 文件如下:

‘’ ‘’
1
2
3
4
5
6
7
import { defineConfig } from 'umi';
const { REACT_APP_ENV } = process.env;
export default defineConfig({
...
antdTheme: REACT_APP_ENV !== 'dev',
...
});

# 主题配件文件优化

unm-plugin-antd-theme 插件的配置文件为 json 格式,很不方便,一来不好加入注释,二来不好共享一些变量,毕竟多个主题有一些一样的成分。为了解决这个问题,还是用到 umi 插件的扩展能力,在插件中将 js 定义转换为 json 定义,详见上述 umi-plugin-config 插件。

通过例子说明这样做的好处。你是否还记得默认的亮色主题没有编译为单独的主题 css,那么所有主题统一修改的变量如果做呢。

默认的主题还是可以通过 umi 的配置文件的 theme 配置:

theme.js theme.js
1
2
3
4
5
6
7
export default {
...
"@font-size-base": "12px",
"@table-padding-vertical": "10px",
"@link-color": "#0070cc",
...
};

config.ts config.ts
1
2
3
4
5
6
7
8
import { defineConfig } from 'umi';
import theme from './theme';
const { REACT_APP_ENV } = process.env;
export default defineConfig({
...
theme,
...
});

然后其他主题就需要在 unm-plugin-antd-theme 插件的 json 配置文件中,每个主题的 modifyVars 中都要加入,本文一开始已经给出了例子。

显而易见上面的统一变量修改需要烦人的重复,将 json 改成 js 后就能完美解决这个问题,theme.config.json 会变成如下,需要使用 CommonJS 规范定义模块:

‘’ ‘’
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
const theme = require('./theme').default;
module.exports = {
"theme": [
{
"key": "dark",
"theme": "dark",
"fileName": "dark.css",
"modifyVars": {
...theme
}
},
{
"key": "volcano",
"fileName": "volcano.css",
"modifyVars": {
"@primary-color": "#FA541C",
...theme
}
},
{
"key": "volcano",
"theme": "dark",
"fileName": "dark-volcano.css",
"modifyVars": {
"@primary-color": "#FA541C",
...theme
}
}
],
"min": true,
"isModule": true,
"ignoreAntd": false,
"ignoreProLayout": false,
"cache": true
};

这样就可以将统一的变量修改复用起来。umi-plugin-config 插件检测到 theme.config.js 文件就会自动转换为 theme.config.json 文件。

# 自定义主题注意事项

要支持动态切换主题,需要严格规范样式的定义方式。

  1. 不要使用固定的颜色,尽量使用 antd 已有变量,例如 @text-color,表示文字颜色,在亮色和暗黑模式下值是不一样的,antd-pro-merge-less 已经为我们自动处理了,我们只需要使用 @text-color
  2. 所有主题统一修改的变量定义在上述 theme.js 中,所有主题复用
  3. 主题不一样的变量修改在各自的配置中定义
  4. 所有主题统一修改的样式定义在 global.less 文件中,需要设置最高优先级
  5. 所有主题用的同一个变量但是值不一样(亮色和暗黑不一样),定义在组件 less 中,需要使用:global
  6. 如果无法通过 less 定义样式,可以通过 settings 获取主题后动态设置行内样式

# 启动项目失败

# Node 版本问题

这是因为 安装 node 的版本过高导致项目无法正常启动
在 项目中的 package.json 中,修改 dev 启动命令:

''
1
2
3
4
5
6
"scripts": {
"analyze": "cross-env ANALYZE=1 umi build",
"build": "umi build",
"deploy": "npm run build && npm run gh-pages",
"dev": "set NODE_OPTIONS=--openssl-legacy-provider && npm run start:dev",
...

如果遇到这种问题,推荐使用:

''
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
* Webpack █████████████████████████ building (10%)


node:internal/crypto/hash:71
this[kHandle] = new _Hash(algorithm, xofLen);
^

Error: error:0308010C:digital envelope routines::unsupported
at new Hash (node:internal/crypto/hash:71:19)
at Object.createHash (node:crypto:133:10)
at BulkUpdateDecorator.hashFactory (C:\Users\litianhao\Desktop\公司项目\fte_manage_antd\node_modules\@umijs\deps\compiled\webpack\5\bundle5.js:184161:18)
at BulkUpdateDecorator.update (C:\Users\litianhao\Desktop\公司项目\fte_manage_antd\node_modules\@umijs\deps\compiled\webpack\5\bundle5.js:184062:50)
at C:\Users\litianhao\Desktop\公司项目\fte_manage_antd\node_modules\@umijs\deps\compiled\webpack\5\bundle5.js:107101:9
at C:\Users\litianhao\Desktop\公司项目\fte_manage_antd\node_modules\@umijs\deps\compiled\webpack\5\bundle5.js:33829:16
at FSReqCallback.readFileAfterClose [as oncomplete] (node:internal/fs/read_file_context:68:3) {
opensslErrorStack: [ 'error:03000086:digital envelope routines::initialization error' ],
library: 'digital envelope routines',
reason: 'unsupported',
code: 'ERR_OSSL_EVP_UNSUPPORTED'
}

Node.js v18.14.1
Done in 7.59s.

# Cannot find module ‘umi-build-dev/lib/routes

  1. 确认安装的 Umi 版本是否正确:首先,检查项目中 package.json 文件中的 umi 的版本号是否正确,确保版本号与项目所需的版本一致。
  2. 清除缓存并重新安装依赖:可以尝试使用以下命令清除 npm 缓存并重新安装依赖:
    ''
    1
    2
    npm cache clean --force
    npm install
  3. 确认 umi-build-dev 模块是否存在:在项目目录中,检查 node_modules 目录下是否存在 umi-build-dev 模块。如果不存在,可能是安装过程中出现了问题,可以尝试重新安装依赖。
  4. 更新 umi-build-dev 模块:如果 umi-build-dev 模块已经存在,但仍然出现错误,可以尝试更新该模块。使用以下命令更新 umi-build-dev 模块:

''
1
npm update umi-build-dev

或者使用 yarn 的命令:
''
1
yarn upgrade umi-build-dev

5. 如果以上方法仍然无法解决问题,可以尝试删除整个 node_modules 目录,并重新安装依赖。
如果问题仍然存在,可以查看 Umi 的官方文档、搜索相关问题的解决方案,或者在开发社区进行提问,以获取更准确的解决方法。