什么是Umi
是可扩展的企业级前端应用框架。Umi 以路由为基础的,同时支持配置式路由和约定式路由,保证路由的功能完备,并以此进行功能扩展。然后配以生命周期完善的插件体系,覆盖从源码到构建产物的每个生命周期,支持各种功能扩展和业务需求。
- 🎉 可扩展,Umi 实现了完整的生命周期,并使其插件化,Umi 内部功能也全由插件完成。此外还支持插件和插件集,以满足功能和垂直域的分层需求。
- 📦 开箱即用,Umi 内置了路由、构建、部署、测试等,仅需一个依赖即可上手开发。并且还提供针对 React 的集成插件集,内涵丰富的功能,可满足日常 80% 的开发需求。
- 🐠 企业级,经蚂蚁内部 3000+ 项目以及阿里、优酷、网易、飞猪、口碑等公司项目的验证,值得信赖。
- 🚀 大量自研,包含微前端、组件打包、文档工具、请求库、hooks 库、数据流等,满足日常项目的周边需求。
- 🌴 完备路由,同时支持配置式路由和约定式路由,同时保持功能的完备性,比如动态路由、嵌套路由、权限路由等等。
- 🚄 面向未来,在满足需求的同时,我们也不会停止对新技术的探索。比如 dll 提速、modern mode、webpack@5、自动化 external、bundler less 等等。
官网这张图挺不错的
开始使用
安装
# 新建文件夹 mkdir dirname && cd dirname # 拉取初始文件 yarn create @umijs/umi-app # 安装依赖 yanr # 运行 yarn start
打开浏览器,访问localhost:8000端口(默认8000,如果被占用会依次往后寻找)
目录结构
├── package.json # 包管理文件 ├── .umirc.ts # umi配置文件 ├── .env # 环境变量设置 ├── dist # 打包产物目录 ├── mock # mock数据目录 ├── public # 静态资源目录 └── src # 代码主目录 ├── .umi # 临时文件,每次打包后会重新生成 ├── layouts/index.tsx # 布局 ├── pages # 页面 ├── index.less └── index.tsx └── app.ts # 运行时配置文件
除了.umirc.ts可作为配置文件之外,可以新建.umirc.local.ts配置文件,local只有在dev环境下才会生效,并且会和.umirc.ts进行合并
app.ts是运行时配置文件,主要的作用时在运行时修改一些既有的配置
例如:使用patchRoutes
来修改在路由配置中约定的路由
// 在路由配置最前面加一个foo路由 export function patchRoutes({ routes }) { routes.unshift({ path: '/foo', exact: true, component: require('@/extraRoutes/foo').default, }); }
使用render
来覆盖默认的渲染方法,可以用于权限检测等
import { history } from 'umi'; export function render(oldRender) { fetch('/api/auth').then(auth => { if (auth.isLogin) { oldRender() } else { history.push('/login'); oldRender() } }); }
使用onRouteChange
可以在初始加载或路由变化时进行操作,如埋点、设置标题等
export function onRouteChange({ location, routes, action }) { bacon(location.pathname); } export function onRouteChange({ matchedRoutes }) { if (matchedRoutes.length) { document.title = matchedRoutes[matchedRoutes.length - 1].route.title || ''; } }
路由
现代前段开发大部分都是单页应用了,单页应用的基础就在于前端路由,页面的跳转都在浏览器完成,不会再次请求HTML,后续所有的HTML都是JS生成的
在Umi中有两种模式的路由,一种是基于约定、一种是基于配置,所谓约定就是根据事先规定好的文件位置自动生成路由文件,配置就是实现在配置文件中声明路由及对应的页面位置。
路由配置如下
const routes: IRoute[] = [ { path: '/', exact: true, // redirect: '/workspace', // 跳转之后就无法命中当前声明的组件 title: '首页', component: '@/pages/home/index', wappers: [], // 高阶路由组件 },{ path: '/device/detail/:name', // :name,动态路由,可以在props.match.params中获取匹配的参数 component: '@/pages/device/detail' },{ path: '/user', redirect: '/user/list' routes: [ {path: '/user/list', component: '@/pages/user/list'}, {path: '/user/detail/:name', component: '@/pages/user/detail'}, ] } ]
wappers使用方法可以看一下文档,传送门
如果没有配置路由,Umi会进入约定路由模式,根据pages目录下的文件自动生成路由,例如下面的文件目录
└── pages ├── index.tsx └── users.tsx
就等效于这样的配置路由
[ { exact: true, path: '/', component: '@/pages/index' }, { exact: true, path: '/users', component: '@/pages/users' }, ]
以下情况不会被注册为路由
- 以
.
或_
开头的文件或目录 - 以
d.ts
结尾的类型定义文件 - 以
test.ts
、spec.ts
、e2e.ts
结尾的测试文件(适用于.js
、.jsx
和.tsx
文件) components
和component
目录utils
和util
目录- 不是
.js
、.jsx
、.ts
或.tsx
文件 - 文件内容不包含 JSX 元素
使用[]
包裹的文件可以被判定为动态路由,比如
└── pages └── users └── [id].tsx └── index.tsx
等价于配置中的
[ { exact: true, path: '/', component: '@/pages/index' }, { exact: true, path: '/users/:id', component: '@/pages/users/[id]' }, ]
创建_layout.tsx
文件可以声明嵌套路由,例如
└── pages └── users ├── _layout.tsx ├── index.tsx └── list.tsx
会生成
[ { exact: false, path: '/users', component: '@/pages/users/_layout', routes: [ { exact: true, path: '/users', component: '@/pages/users/index' }, { exact: true, path: '/users/list', component: '@/pages/users/list' }, ] } ]
约定路由中要使用wrappers需要在组件中添加wrappers属性,例如
import React from 'react' function User() { return <>user profile</> } User.wrappers = ['@/wrappers/auth'] // User.title = '用户中心' // 其他路由拓展属性都可以在这里添加 export default User
页面跳转
页面跳转有声明式和命令式两种,声明式就是使用XML格式的标签来进行跳转,如
<Link to="/list">Go to list page</Link>
命令式的主要是通过history进行跳转
import { history } from 'umi'; function goToListPage() { // 带参跳转,两种方式等价 history.push('/list?a=b'); history.push({ pathname: '/list', query: { a: 'b', }, }); } // 或者使用props中的history模块跳转 export default (props) => ( <Button onClick={()=>props.history.push('/list');} >Go to list page </Button> );