从 Pro 到 umi.js
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 还是很不错的。直观上有几个地方值得夸赞:
- 配置更统一了,全部都在 config 文件下(用 umi 替代了 roadhog 之后)
- 默认支持按需加载,撒花
- model 支持 page model,即 page 私有的 model 只需要放在 page 自己的 models 文件夹下,无需像以前一样在 router 中注入,具体可以查看 umi 的文档
- 默认配置 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 的文章
- 2018-01-31 Hello! umi
- 2018-02-26 发布 umi 1.0
- 2018-09-03 发布 umi 2.0,可插拔的企业级 react 应用框架
- 2019-09-02 Hello! Umi UI 费精力搞这玩意干啥..
2.2. Pro 和 UmiJS
Pro 封装了 umi,umi 配置文件为 .umirc.js
或 config/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 写了一个小项目,不说设计上的,直观感受:
- 构建生成的文件很大
- 修改 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 的一个配置特性:
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
):
- umi 的 配置文件 中添加
base
和publicPath
为/base/
- 构建的 dist 文件多加一层目录 base
nginx
location /base { # 用于配合 browserHistory使用 try_files $uri $uri/ /index.html; }
3.5. Umi3 打包 OOM
设置 NODE_OPTIONS
,如 export NODE_OPTIONS=--max_old_space_size=4096