一、框架介绍
umi是蚂蚁金服的前端开发框架,它内置了路由、web/移动端UI库、数据流、权限控制、常用hooks库、构建、部署、测试、等等一些工具,几乎涵盖了正常前端开发要用到的所有工具。
二、环境准备
-
pnpm
相比npm、yarn,pnpm更小+更快+扁平化+默认支持monorepo,有诸多有点。想要了解更多详细,可以参考这篇文章:pnpm实战教程
-
镜像管理工具
推荐使用镜像管理工具:
-
如果本地使用
npm/pnpm
管理nodejs包:则安装nrm
-
如果本地使用
yarn
管理nodejs包:则安装yrm
-
//这里使用yrm
npm i nrm -g
npm i yrm -g
查看镜像地址列表:yrm ls
测试每个镜像地址的响应时间:yrm test
,最快的镜像会被标绿色背景。
切换镜像地址:yrm use taobao
,切换到淘宝地址。
查看当前使用镜像地址:
yrm ls
yrm current
-
创建umi项目
mkdir umi-test && cd umi-test yarn create @umijs/umi-app #npx @umijs/create-umi-app yarn install #安装依赖 yarn start #启动项目
在浏览器里打开 http://localhost:8000/,能看到以下界面,
三、目录结构
一个基础的 Umi 项目大致是这样的:
.
├── package.json
├── .umirc.ts // umi配置,同config/config.js,二选一
├── .env // 环境变量
├── dist // 默认 build 输出目录
├── mock // mock 文件所在目录,基于express
├── public // 此目录下所有文件会被 copy 到输出路径。
└── src├── .umi // 临时文件目录,比如入口文件、路由等,都会被临时生成到这里。├── layouts/index.tsx // 全局布局├── models // 数据流├── wrappers // 权限管理├── global.js // 可以在这里加入polyfill├── global.css // 约定的全局样式文件,自动引入,也可以涌入global.less├── pages // 页面├── index.less└── index.tsx└── app.ts //运行时配置文件,可以在这里扩展运行时的能力
更多目录说明请参照 官网
四、构建时配置
umi在.umirc.ts
或config/config.ts
中配置项目和插件:
-
nodeModulesTransform:设置 node_modules 目录下依赖文件的编译方式。
nodeModulesTransform: {type: "none", //不变异node_modules中的文件exclude:"" //忽略的依赖库,包名,暂不支持绝对路径 },/* nodeModulesTransform: {type: "all", //全部编译exclude:"" //不需要编译的依赖库; }, */
-
fastRefresh:快速刷新
开发时可以保持组件状态,同时编辑提供即时反馈。
fastRefresh: {} //开启
开启前:
开启后:
-
devServer:配置开发服务器。
包含以下子配置项:
- port,端口号,默认
8000
- host,默认
0.0.0.0
- https,是否启用 https server,同时也会开启 HTTP/2
- writeToDisk,生成
assets
到文件系统
- port,端口号,默认
devServer: {port: 9999
}
配置开发服务的端口还有其他方式:
-
配置
.env
环境变量#根目录下创建 .env 文件 PORT=8888
-
脚本中设置端口
#全局安装cross-env
npm i -g cross-env# package.json
"scripts": {"start": "cross-env PORT=3999 umi dev",
},
这三种配置的优先级依次是:脚本中设置端口 > 配置 .env
环境变量 > devServer中设置port
- title:设置标题
-
favicon:icon图标
favicon: "/favicon.ico"
根目录新建
public/favicon.ico
图标,刷新页面,就可以看到图标已经变了。 -
dynamicImport:按需加载
umi打包时,默认是把所有js文件打包到同一个
umi.js
文件中,如下图所示:
这种打包方式当我们的项目不断扩展变庞大之后,umi.js将会变得非常臃肿,导致在首屏加载时很慢,所以我们可以使用dynamicImport
开启按需加载,即是否把构建产物进行拆分,在需要的时候下载额外的 JS 再执行。
dynamicImport: {}
再执行yarn build
打包后,我们可以看到dist
目录中文件就已经被分包,如图:
我们还可以借助dynamicImport.loading
属性,配置加载过程中的loading
提示组件。
dynamicImport: {loading: "@/pages/Loading"}
创建src/pages/Loading/index.tsx
,代码如下:
export default function IndexPage() {return (<div>loading...</div>);
}
然后我们再刷新页面时,可以看到loading...
提示。仔细的话可以看到,loading...
出现了两次:
- 根页面加载时
- 框架容器内页面加载时
如图:
-
根模版路径
如果需要自定义
html
默认文件,那么就创建src\pages\document.ejs
文件。 -
mountElementId:指定 react app 渲染到的 HTML 元素 id。
默认id是
root
,如果使用mountElementId
指定的id和document.ejs
中的不一致,那么会自动创建一个mountElementId
指定的id的div
节点。例如:
# config/config.ts mountElementId: "root2"# document.ejs <body><div id="app3"></div> </body>
运行时,我们打开页面显示源码,可以看到:
五、使用Web/移动端antd组件
import styles from './index.less';
import Header from '@/pages/header';
import { useState } from 'react';
import { Button } from "antd";
import { Button as MButton } from "antd-mobile";export default function IndexPage() {return (<div><Header /><h1 className={styles.title}>Page index-333</h1><Button>Web按钮</Button><MButton>Mobile按钮</MButton></div>);
}
效果如下:
需要注意的是:
umi中默认内置了
antd
移动端的v2
和v5
版本,那么在默认安装项目时安装了@umijs/preset-react": "1.x"
,这是一个比较老的版本,我们需要更新到最新,这样默认就是v5
版本,如果需要使用v2
则:import { Button as MButton } from "antd-mobile-v2";
我们在node_modules中可以看到默认安装了antd-mobile
和antd-mobile-v2
:
yarn remove @umijs/preset-react #先删除
yarn add @umijs/preset-react #再安装
import styles from './index.less';
import Header from '@/pages/header';
import { Button } from "antd";
import { Button as MButtonV5 } from "antd-mobile";//v5版本
import { Button as MButtonV2 } from "antd-mobile-v2";//v2版本export default function IndexPage() {return (<div><Header /><h1 className={styles.title}>Page index-333</h1><Button type='primary'>Web按钮</Button><MButtonV2 type='primary'>Mobile-v2按钮</MButtonV2><MButtonV5 color='primary'>Mobile-v5按钮</MButtonV5></div>);
}
六、theme:主题
1、web端主题
theme:{'@primary-color': '#1DA57A',
}
上述代码只是修改了web
的主题,并不影响移动端的主题配色,如上配置后,可以看到下图只是web端的Button
的颜色有了改变。
2、移动端主题
要修改移动端主题,我们可以通过src/global.less
全局样式中覆写。这里以修改主题色为例:
:root:root {--adm-color-primary: red;
}
可以看到移动端v5对应的主题色已经变更。
七、引入静态资源
1、引入图片
- 引入
src/assets
图片 - 引入
public
图片
//index.tsx
import user from "@/assets/images/user.png";
import "./index.less";
import styles from "./index.less";export default function IndexPage() {return (<div><p>1、调用 src/assets 中的图片</p><img src={user} /><img src={require("@/assets/images/user.png")} /><br /><br /><p>2、调用 public 中的图片</p><img src="img/bg.jpg" width="200" /><div className={styles.img1}>3、从 assets/images 中拿图片</div><div className="img2">4、从 public 中拿图片</div></div>);
}
//index.less
.img1,
.img2 {width: 200px;height: 80px;color: white;margin-top: 5px;
}.img1 {background: url("~@/assets/images/bg.jpg");
}.img2 {background: url("/img/bg.jpg");
}
2、引入css样式
上述在引入css中class时,使用了两种方式:
-
全局引入:
import "./index.less"; <div className="img2">4、从 public 中拿图片</div>
-
模块化引入:
import styles from "./index.less"; <div className={styles.img1}>3、从 assets/images 中拿图片</div>
全局引入的话,可能会造成全局污染;模块化引入,会给每个class加上随机序列号,避免全局污染;