从 Pro 到 umi.js

Table of Contents

1. Pro

Ant Design Pro 是一个前端的基于 React 脚手架(框架,开箱即用,提供了菜单和路由、数据处理等), 设计是用于企业级中后台解决方案(内部系统之类的)。

1.1. 技术栈

  • ES2015+,主要使用 JavaScript(废话)
  • React
  • UmiJS:可插拔的企业级 react 应用框架, 1.0 之前是使用 roadhog 的, umi = roadhog + 路由 。roadhog 封装了 webpack,简化 webpack 的配置
  • dva:数据流
  • antd:前端基于 React 的 UI 组件,类似 Bootstrap

所以,Pro 是什么?就是把这些组件全部封装起来,然后提供了一些范例。比较适合我这种不关心也不想深入学习前端技术,只想作为技术手段来实现前端开发的人。对于,一个专业的前端开发者,我不认为 Pro 是一个很好选择, 直接使用 React 原生的脚手架 create-react-app + webpack + antd 更好,或者使用 umi 也行。

Pro 没做什么太多额外的事情,而且臃肿的例子,删都要删除好久。目前还没有更好的解决方案。可以看我提的 issue

Pro 缺陷也是优势,对于我这样的伪前端(也不想深入)的人,只需要学习一下 ES6 和 React,然后照葫芦画瓢就可以开始写前端了。

随着版本的升级,这里说的技术栈已经不准确了,类似 V2 之后逐渐都用 TypeScript 来实现,而不是 JS

1.2. 如何评价 Pro 2.0

从 1.0 之前切换到 2.0,起初我是很抗拒的,因为 2.0 又加了很多乱七八糟的东西,改动比较大,菜单和路由合并了,这对于路由多的项目维护起来简直就是噩梦。

再加上鉴权系统变得更加的复杂了,我对 Pro 的鉴权系统一直都持否定的态度,鸡肋,需要的满足不了,不需要的剥离很费劲。

但是没办法啊,谁要自己前端菜呢,硬着头皮用了 2.0,砍无用的东西看了半天开才正式开始写(qwerty-client 就是这样)。用的时间长了,觉得 2.0 还是很不错的。直观上有几个地方值得夸赞:

  1. 配置更统一了,全部都在 config 文件下(用 umi 替代了 roadhog 之后)
  2. 默认支持按需加载,撒花
  3. model 支持 page model,即 page 私有的 model 只需要放在 page 自己的 models 文件夹下,无需像以前一样在 router 中注入,具体可以查看 umi 的文档
  4. 默认配置 alias,添加 @/ 别名到 src 目录,引用模块更加方便了

当然国际化这种功能我是不关心的。

1.3. 从 0.x 升级到 V2

2019-12-02 UPDATE

2018 刚开始使用 Pro 是 0.x 版本,后来不知道有没有使用 1.x 版本,忘记了;本身 Pro 就是由一堆的 package 组成的,所以具体的版本已经对应不上了。

随着内容的增多,打包的速度越来越慢,在刚开始使用的时候还经常会出现 webpack 打包卡到 91% 的经典问题(网上很多人也反馈,后来通过更换电脑解决)。 后来用 v2 写过一个博客系统,深感 v2 比 v1 无论从效率上还是代码组织上都略胜一筹,所以在今年的 11 月份准备长痛不如短痛,升级一下。

如上面所说,v2 和 v4 的区别仅在于重新进行了抽象:Pro 变成了一个 UI template,而脚手架的能力下沉到了 umi。所以升级到 V2 就可以了,升级文档: https://v2-pro.ant.design/docs/upgrade-v2-cn 文档只是写了迁移流程,而原理性的东西没说。因此,没遇到问题还好,只要遇到问题就很头大。

迁移的很快,但是测试起来之后,出现了很多小的问题(大部分是代码兼容性问题)。最麻烦的一个问题是,路由死循环。 当可变 URL 和 redirect 放到一起的时候,就很容易出现死循环;因为 V2 的路由方式跟 V1 不一样了,不再允许使用 <Switch> ,很多代码的写法要重新适配。 而且死循环问题在开发环境下很难复现,生产环境下基本上是必现的。后来逐渐的规避问题,也没能从根源上解决。

我之前提过一个 issue: https://github.com/ant-design/ant-design-pro/issues/5548 ,说是可能是 umi 的 bug,让我去 umi 再提 issue。 但是 ant 系的开源项目,为了减少 issue,提 issue 的流程都特别麻烦,我也就没提了。

今天再一次出现了路由死循环的问题,但是我打的包有问题,我同事打的包就没问题,做了很多尝试。后来通过删除 node_modules 和 package-lock.json 解决。

总之:前端这一套东西真是让人心力俱疲。

2. Umi

2.1. 作者(sorrycc)有关 umi 的文章

2.2. Pro 和 UmiJS

Pro 封装了 umi,umi 配置文件为 .umirc.jsconfig/config.js ,Pro 中使用 config/config.js ,但是进行了一定的改造。

相关配置需求可以查看这两篇文档:

Pro 0.x 版本和 1.x 版本 npm run start 进度卡到 91% 问题,可通过 HARD_SOURCE=none npm start 来解决,一些讨论见:https://github.com/ant-design/ant-design-pro/issues/1520

2.0 之后似乎没有这个问题了,但是有个另外一个问题,每次修改了 less 文件之后,编译速度特别慢(less 每次都要全量编译,cpu 不好的话速度会很慢),解决办法是删掉 /config/plugin.config.js 文件。 删掉之后影响的是换主题,但是换主题实际在使用中基本上没啥用。讨论见:https://github.com/ant-design/ant-design-pro/issues/2947

2.3. 如何评价 Pro 4.0

六月份发布了 v4 版本,一直比较忙也没时间去研究。从 0.x 版本用到 2.0 版本,我对 Pro 的发展一直不抱有很乐观的态度(甚至有些消极),以前在 issue 上有过一些争论,以至于对研发团队产品规划略有不满。

今天(2019-10-24)得空看了一下 v4 和 UmiJS,大有改观。涉及到我所关心的几个点列了一下:

  • v4 变成了 umi.js 的一个模板,安装也比较纯粹,选模板一样选择 ant design pro 即可;以前更像是 clone 下来完整的代码然后继续开发,不像是一个工具;
  • 抽象出 区块(Block) 的概念,把以前的组件全部单独出去,可插拔( umi block list ),框架不再臃肿,鉴权相关的也简单的许多, 早就该这么搞了,也是我以前感觉 Pro 定位不清晰的原因
  • layout 也抽象成了一个单独的组件: ant-design-pro-layout,这个有待商榷,这种是不是 antd 的责任?
  • 主打 Typescript,还好兼容 Javascript,一直没功夫学习 ts,学不动了

如果不是为了省事,直接使用 umi 创建一个 App 写模板也挺好的,成本也不高。这一次更新给研发团队点赞!

2.4. 再次评价 umi

以前写了断断续续的写了几年的前端(前后端一起写),从去年开始用 React,Pro 这一套东西也有近两年了,对前端的东西真的挺失望的。 从来没有一项技术让我有了从入门到放弃的感觉,即便是当年学 C++ 的时候,也是越学越有信心。

最新的项目用的是 V4,V4 有了比较大的提升,但是仍旧有一些基础的 Bug。前端的脚手架与前端的技术一样,更新实在太快了。 即便是 Release 版本,因为本地的环境差异很大(npm 版本,各种依赖包的版本),也有参差不齐的开源项目,发布的正式版也总是有很多的问题。 但如果不持续更新的话,隔几个版本就会出现不兼容的更新,再想升级就蛋疼了。

在我眼里,前端的东西,就是如此的不堪,从 Javascript 语言问世这个问题就已经存在了,后面做的事情无论是 node.js 还是 TypeScript 都是在修修补补。 都无法从根源上解决问题。但是没办法,我们需要他,他依旧是 Github 热度永远第一的语言。

那怎么办呢?

经过我自己躺过的坑,我建议对前端的核心技术还是需要深入了解一下,尽量用原生的框架,而不是像 Pro 这样的脚手架,他封装了太多的东西, 而且每一层都有可能是不稳定因素,虽然他对于二流前端,的确可以快速的搭建一套系统出来,但是一但出了问题就很致命了,你根本就不知道发生了什么。 我发现他竟然连 react-router 都封装了一层。

何为原生呢?

React 全家桶(react,react-router,redux 等)了解之后,使用官方的的 create-react-app 来创建应用,UI 库自己选型即可。这样的好处是遇到了问题 网上都有足够的资料帮你解决,社区也很好。坦白说,阿里开源的 antd 系列,社区都不怎么好。

2.5. 如何评价 Umi 3.x

时隔半年之后,它又升级了,升级到了 3.x,怎么想的,我也不知道。 3.x 把 2.x 的更多内容全部插件化了(包括但不仅限于 antd,dva,request 等)。 默认东西很少,需要自己手动开启,而且初始化时不在支持 TS/JS 选择,默认全部 TS(但是你又可以直接写 JS),这一点令人费解。

用 Umi3 写了一个小项目,不说设计上的,直观感受:

  1. 构建生成的文件很大
  2. 修改 less 文件之后,编译非常慢

3. FAQ

3.1. 部署时,文件名添加 hash 值

2.0 之后, npm run build 生成的 css 和 js 文件名不再包含 hash 值,这样会导致即便 nginx 设置了 index.html 不缓存,因为 css 和 js 每个版本的名字都是一样的,导致新版本更新之后,用户只有强制刷新浏览器才能生效。

解决办法是在 /config/config.js 中添加 hash:true ,这是 umi 的一个配置特性:

https://umijs.org/zh/config/#hash

3.2. npm run start 报错

npm run start 的时候,报错:

Module build failed: Error: The 'decorators' plugin requires a 'decoratorsBeforeExport' option, whose value must be a boolean. If you are migrating from Babylon/Babel 6 or want to use the old decorators proposal, you should use the 'decorators-legacy' plugin instead of 'decorators'.

解决的办法是用 npm install ,不要使用 cnpm 这种镜像。讨论在 ant-design-pro issues#2043 ,好像也没有看到具体的原因,应该是依赖问题。

之前用 npm 的时候也有类似的情况,一般是因为包依赖有问题,因为是镜像缘故,包的同步总会有先后顺序,卡到中间的时候就会出现依赖版本问题。

其实不光是 npm,其它的镜像也会出这种情况,比如 Emacs 的源引发的问题:swiper issue#2087

3.3. v1 升级 v2 之后报错:An immer producer returned a new value and modified its draft.

https://github.com/umijs/umi/issues/592

之前在 reducers 中使用了 state,但是升级之后不允许这么用了(好像是说简化写法,具体可以看 配置文件)。一种 hack 的解决办法是上面 issue 中提到的:

const stockList = [...state.stockList]

但是不知道这种方式的原理是什么。

2020-01-08 16:52:10 更新

https://github.com/umijs/umi/issues/816

上面说的这种办法不通用,想恢复以前的使用办法可以关闭 immer,

export default {
  plugins: [
    ['umi-plugin-dva', { immer: true }],
  ],
};

关闭之后又出现了 Reducer "index" returned undefined during initialization. 的报错,原因是 models 下面的 *.js 文件没有设置初始化 state, 查看代码发现,在 models 下有一些 utils.js 文件,移出 model 目录即可。应该是认为 models 下的 .js 文件都要符合 export { state: {} } 这样的格式。

3.4. 部署到非根路径报错:Uncaught SyntaxError: Unexpected token '<'

这个错误一般是因为 html 中 script src 引用的 js 文件有错(不是 js 格式的)。下面是 umi 部署到非根路径流程(假定路径为 /base ):

  1. umi 的 配置文件 中添加 basepublicPath/base/
  2. 构建的 dist 文件多加一层目录 base
  3. nginx

    location /base {
      # 用于配合 browserHistory使用
      try_files $uri $uri/ /index.html;
    }
    

First created: 2020-01-06 14:58:32
Last updated: 2022-12-11 Sun 12:49
Power by Emacs 29.0.91 (Org mode 9.6.6)