文章开始前我想向大家一个问题用于更好的学习Umijs,什么是Umijs?

Umi,中文可发音为乌米,是可扩大的企业级前端利用框架。Umi 以路由为根底的,同时反对配置式路由和约定式路由,保障路由的性能齐备,并以此进行性能扩大。而后配以生命周期欠缺的插件体系,笼罩从源码到构建产物的每个生命周期,反对各种性能扩大和业务需要。

Umi 是蚂蚁团体的底层前端框架,已间接或间接地服务了 3000+ 利用,包含 java、node、H5 无线、离线(Hybrid)利用、纯前端 assets 利用、CMS 利用等。他曾经很好地服务了咱们的外部用户,同时心愿他也能服务好内部用户。

以上是我摘抄自官网,说白了应用umijs能够使咱们更加便捷的实现创立-开发-公布整个我的项目生命周期,Umijs的性能有很多,以下我将列举几个开发中罕用的配置项;如果须要更加残缺的配置请参考官网文档《Umijs官网文档》

开始学习,首先咱们须要创立一个Umi我的项目

那么如何创立一个Umi我的项目呢?

咱们须要应用命令行在控制台输出

# 国内源$ npm i yarn tyarn -g# 前面文档里的 yarn 换成 tyarn$ tyarn -v# 阿里内网源$ tnpm i yarn @ali/yarn -g# 前面文档里的 yarn 换成 ayarn$ ayarn -v

以上步骤是Umijs用以装置依赖;

装置完依赖之后咱们须要创立一个空目录用来承载咱们的Umijs我的项目,
在此咱们能够手动创立一个空文件夹,也能够应用以下命令行创立

$ mkdir myapp && cd myapp

文件夹创立实现之后咱们须要开始创立Umijs我的项目了,咱们在命令行中输出以下命令

$ yarn create @umijs/umi-app

或者咱们能够抉择npx创立,如果应用npx则输出以下命令

$ npx @umijs/create-umi-app

这里须要留神的是执行创立umijs
我的项目时,会在你以后选中目录下间接退出依赖所以必须要创立一个文件夹进行承载,不然你创立实现之后会发现创立的umijs我的项目并没有包裹,所以并不是你想要的答卷;

实现以上步骤之后咱们须要装置umijs我的项目依赖,这个很简略,参考创立vue我的项目与react我的项目咱们只须要执行

$ npm install#或者$ npm i#或者$ yarn install

实现以上步骤则咱们的Umijs我的项目就构建实现了这时候咱们来剖析下umijs的目录构造
咱们以官网给出的目录构造为例子,接下来我为大家具体解读该目录构造中文件的作用

.├── package.json├── .umirc.ts├── .env├── dist├── mock├── public└── src    ├── .umi    ├── layouts/index.tsx    ├── pages        ├── index.less        └── index.tsx    └── app.ts

根目录
package.json
蕴含插件和插件集,以 @umijs/preset-、@umijs/plugin-、umi-preset- 和 umi-plugin- 结尾的依赖会被主动注册为插件或插件集。

.umirc.ts
配置文件,蕴含 umi 内置性能和插件的配置。

.env
环境变量。

比方:

PORT=8888
COMPRESS=none
dist 目录
执行 umi build 后,产物默认会寄存在这里。

mock 目录
存储 mock 文件,此目录下所有 js 和 ts 文件会被解析为 mock 文件。

public 目录
此目录下所有文件会被 copy 到输入门路。

/src 目录
.umi 目录
长期文件目录,比方入口文件、路由等,都会被长期生成到这里。不要提交 .umi 目录到 git 仓库,他们会在 umi dev 和 umi build 时被删除并从新生成。

layouts/index.tsx
约定式路由时的全局布局文件。

pages 目录
所有路由组件寄存在这里。

app.ts
运行时配置文件,能够在这里扩大运行时的能力,比方批改路由、批改 render 办法等。

以上摘抄自《Umijs官网文档》

如果你胜利构建我的项目你会发现目录中还有以下文件这些文件大多是一些我的项目代码格调的配置项,因为与我的项目过程没有太大关系,我简略解读一下

.editorconfig //编辑器代码格调配置,如首行缩进,编码方式等等;.gitignore//git提交疏忽项,在该文件中你能够设置疏忽提交的文件;.prettierignore//格式化代码时疏忽的文件;.prettierrc//格式化代码配置文件相比拟于.editorconfig该文件作用于文件,而.editorconfig作用于代码tsconfig.json//ts配置文件typings.d.ts//ts类型定义文件

以上就是我对umijs我的项目目录的解读,当然还有在目录中没有波及到的文件比方document.ejs;接下来我将为你具体解读;

当咱们相熟Umijs的整个目录构造,咱们就要开始学习umijs在我的项目中的罕用配置项,以及一些重要知识点;我将分为以下几个模块来进行解读:

  1. 罕用配置 .umirc.ts;
  2. 承载文件与入口文件document.ejs;
  3. Umi Router与React Router的差别;
  4. 模仿数据 mock的根底应用;
  5. 运行时配置 app.ts;
罕用配置 .umirc.ts

我的项目创立之后你会发现目录中有一个名为.umirc.ts的ts文件,该文件为umijs的次要配置文件,蕴含 umi 内置性能和插件的配置;

关上文件后你会发现一些你可能相熟的配置

大抵选项如下:

import { defineConfig } from 'umi';export default defineConfig({  nodeModulesTransform: {    type: 'none',  },  routes: [    { path: '/', component: '@/pages/index' },  ]  fastRefresh: {},});

然而工作中咱们可能要用到更多配置因而咱们会在该文件中配置更多选项,以下我将介绍.umirc.ts的一些罕用配置选项,以下会局部借鉴《Umijs罕用配置》一文(因为我懒)

// config/config.js示例export default {  base: '/web/',  //部署到非根目录时才需配置  publicPath: '/web/', //部署到非根目录和base一起应用  mock:true,//是否开启mock  targets: { //配置浏览器最低版本,比方兼容ie11   ie: 11  },  history:{type:'hash'},//配置路由history模式  hash: true,  //开启打包文件的hash值后缀  treeShaking: true, //去除那些援用的但却没有应用的代码  plugins: [],//umijs插件配置项  //配置式路由时,路由文件由此援用(往下会讲到)  routes: routes,  //为解决跨域问题的反向代理以下为将http://xxx/代理为/api  proxy: {    "/api": {      "target": "http://xxx/",      "changeOrigin": true,      "pathRewrite": { "^/api" : "" }    }  },  alias: {'@': resolve(__dirname, '../src'),} //别名,umirc.js为'src'};

以上为我认为一些罕用的umijs配置项,如有脱漏欢送补充;

承载文件与入口文件document.ejs

如果你在创立我的项目之后认真的与react我的项目与vue我的项目做比对,你会发现你找不到index.html这个入口文件,请不要感觉奇怪,它只是用另一种模式展示给你,而你在scr目录下是看不到它的,那么它去了哪里呢?它存在与你的node_modules下的@umijs\core\lib\Html,关上Html文件夹你会发现上面有一个document.ejs文件,而当你关上document.ejs文件你会发现这个文件它外面其实是一段Html代码;代码如下:

<!doctype html><html><head>  <meta charset="utf-8" />  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" /></head><body><div id="<%= context.config.mountElementId || 'root' %>"></div></body></html>

入口文件index.html当初就是以document.ejs的模式存在于你的node_modules中,那么在此咱们就要有疑难了,如果咱们须要在入口文件中引入一些插件,比方高德地图,或者微信JSSDK,钉钉JSSDK等要怎么办呢?
别着急,你能够在你的src/pages目录下创立一个document.ejs文件,并复制粘贴node_modules\@umijs\core\lib\Html\document.ejs,里的代码进行改写;这样子你就领有了一个你想要的入口文件;当然如果你在它的html标签中进行文档流书写,则能够自定义你的模板文件,例如:

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta name="viewport" content="width=device-width,initial-scale=1.0">    <meta http-equiv="X-UA-Compatible" content="ie=edge">    <title>自定义模板文件</title></head><body>    <div>哈哈哈哈哈哈</div></body></html>

如果你这么做了,那么div中的【哈哈哈哈哈哈哈哈】会始终渲染在你的页面当中;

Umi Router与React Router的差别

UmiRouter是基于ReactRouter开发的,两者之间存在大量差别,如果你相熟vue那么你能很快上手该知识点

umijs应用的是约定式路由,这点与vue相似,你如果你看了以上的.umirc.ts你会发现其中有一个routes配置项,umi的路由协商配置就是在这里实现的;

配置路由
在配置文件中通过 routes 进行配置,格局为路由信息的数组。

比方:

export default {  routes: [    { exact: true, path: '/', component: 'index' },    { exact: true, path: '/user', component: 'user' },  ],}

path
Type: string
配置能够被 path-to-regexp@^1.7.0 了解的门路通配符。

component
Type: string
配置 location 和 path 匹配后用于渲染的 React 组件门路。能够是绝对路径,也能够是相对路径,如果是相对路径,会从 src/pages 开始找起。

如果指向 src 目录的文件,能够用 @,也能够用 ../。比方 component: '@/layouts/basic',或者 component: '../layouts/basic',举荐用前者。

exact
Type: boolean
Default: true
示意是否严格匹配,即 location 是否和 path 齐全对应上。

比方:

export default {  routes: [    // url 为 /one/two 时匹配失败    { path: '/one', exact: true },        // url 为 /one/two 时匹配胜利    { path: '/one' },    { path: '/one', exact: false },  ],}

routes
配置子路由,通常在须要为多个门路减少 layout 组件时应用。

比方:

export default {  routes: [    { path: '/login', component: 'login' },    {      path: '/',      component: '@/layouts/index',      routes: [        { path: '/list', component: 'list' },        { path: '/admin', component: 'admin' },      ],    },   ],}

而后在 src/layouts/index 中通过 props.children 渲染子路由,

export default (props) => {  return <div style={{ padding: 20 }}>{ props.children }</div>;}

这样,拜访 /list 和 /admin 就会带上 src/layouts/index 这个 layout 组件。

redirect
Type: string
配置路由跳转。

比方:

export default {  routes: [    { exact: true, path: '/', redirect: '/list' },    { exact: true, path: '/list', component: 'list' },  ],}

拜访 / 会跳转到 /list,并由 src/pages/list 文件进行渲染。

wrappers
Type: string[]
配置路由的高阶组件封装。

比方,能够用于路由级别的权限校验:

export default {  routes: [    { path: '/user', component: 'user',      wrappers: [        '@/wrappers/auth',      ],    },    { path: '/login', component: 'login' },  ]}

而后在 src/wrappers/auth 中,

import { Redirect } from 'umi'援用export default (props) => {  const { isLogin } = useAuth();  if (isLogin) {    return <div>{ props.children }</div>;  } else {    return <Redirect to="/login" />;  }}

这样,拜访 /user,就通过 useAuth 做权限校验,如果通过,渲染 src/pages/user,否则跳转到 /login,由 src/pages/login 进行渲染。

title
Type: string
配置路由的题目。

页面跳转

import { history } from 'umi';// 跳转到指定路由history.push('/list');// 带参数跳转到指定路由history.push('/list?a=b');history.push({  pathname: '/list',  query: {    a: 'b',  },});// 跳转到上一个路由history.goBack();

hash 路由
详见 配置#history。

Link 组件
比方:

import { Link } from 'umi';export default () => (  <div>    <Link to="/users">Users Page</Link>  </div>);

而后点击 Users Page 就会跳转到 /users 地址。

留神:

Link 只用于单页利用的外部跳转,如果是内部地址跳转请应用 a 标签
路由组件参数
路由组件可通过 props 获取到以下属性,

match,以后路由和 url match 后的对象,蕴含 params、path、url 和 isExact 属性
location,示意利用以后处于哪个地位,蕴含 pathname、search、query 等属性
history,同 api#history 接口
route,以后路由配置,蕴含 path、exact、component、routes 等
routes,全副路由信息
比方:

export default function(props) {  console.log(props.route);  return <div>Home Page</div>;}

传递参数给子路由
通过 cloneElement,一次就好(Umi 2 时须要两次)。

import React from 'react';export default function Layout(props) {  return React.Children.map(props.children, child => {    return React.cloneElement(child, { foo: 'bar' });  });}

路由模块均为重要知识点所以以上路由模块我均借用文档《Umijs官网文档》

模仿数据 mock的根底应用

在工作中,咱们经常遇到后端接口提供不及时导致影响开发进度,因而咱们时常须要创立一些假数据来模仿提前开发,因而引入了mock的概念,umijs很好的交融了mock,那么咱们要怎么进行mock开发呢?
首先咱们须要在.umirc.ts中关上mock配置,咱们只需将mock配置设成true即可,该配置默认为false;
mock:true
当咱们开启了mock设置,那么咱们要怎么样来书写mock接口呢?也很简略;咱们在主目录中找到mock文件夹,在上面创立一个index.ts文件;umi会主动援用该ts文件为mock入口
上面我简略的为大家书写几个mock接口当作案例;

export default {  'GET /api/user':{    status:'success',    message:'申请胜利',    data:{      name:'王大锤',      sex:1,      age:18,    }  },  'PUT /api/user':{    status:'success',    message:'更新胜利',    data:{    }  },  'DELETE /api/money':{    status:'success',    message:'删除胜利',    data:{    }  },  'POST /api/money':{    status:'success',    message:'删除胜利',    data:{    }  }}

接口写好了,那咱们要怎么应用呢?也很简略,这里办法有很多,我就选用axios来进行申请
首先咱们当然要先装置axios
以下为装置命令

npm install axios或者npm i axios或者yarn add axios

装置完之后咱们在我的项目中援用

因为只做援用所以在此我不进行axios的封装,具体封装教程我在之后会讲

import axios from 'axios'export default function test(){    axios.get('/api/user').then(res=>{    /**res = {status:'success',    message:'申请胜利',    data:{      name:'王大锤',      sex:1,      age:18,    }}**/})}

至此咱们就大抵讲完了umijs的mock数据流程

运行时配置 app.ts

运行时配置须要在app.ts当中增加应用,然而你可能发现你刚刚创立的我的项目当中没有app.ts文件,那么就须要咱们手动增加了;

首先咱们须要在src目录下增加一个app.ts文件,而后咱们须要在外面重写几个办法;

运行时配置次要的配置办法有五个别离是:

  1. patchRoutes({ routes });
  2. render(oldRender: Function);
  3. onRouteChange({ routes, matchedRoutes, location, action });
  4. rootContainer(LastRootContainer, args);
  5. modifyClientRenderOpts(fn);

我将按程序一一介绍以上五个办法;

patchRoutes({ routes })
用于批改路由该路由不是以后路由而是你的整个约定式路由配置;也就是你在.umirc.ts种routes里的配置

当你启动该我的项目时该办法将会被调用,并且传入一个{routes}参数该参数的内容就是你的routes配置;

因为routes参数是一个数组,所以你能够用所有能够扭转数组内容的办法来批改你的路由配置例如unshift,push等等

因为该办法没有返回值,所以你须要在办法外部间接操作routes参数能力批改你的路由配置;

export function patchRoutes({ routes }) {  routes.unshift({    path: '/foo',    exact: true,    component: require('@/extraRoutes/foo').default,  });}

如果你抉择了增加一个新路由到你的路由配置项当中须要留神的是该路由的component必须是我的项目中存在的,否则将会报错;在我的项目中你可能用到该办法的场景有权限的校验返回不同的路由配置等等;

render(oldRender: Function)
覆写 render。

当调用该办法时会传入一个oldRender参数;该办法时全局性的,所以当你启动我的项目时便会被调用

如果你不运行oldRender办法责将阻止渲染你将失去一个空白页面;

export function render(oldRender) {  oldRender()  });}

所以你能够在页面加载前判断一些必要加载条件,比方权限校验;参数传入等等;
因为该办法在patchRoutes之前运行你能够配合patchRoutes打出一套组合拳;比方在render当中判断权限,而后在patchRoutes当中进行路由配置初始化;
例如官网案例

let extraRoutes;export function patchRoutes({ routes }) {  merge(routes, extraRoutes);}export function render(oldRender) {  fetch('/api/routes').then(res=>res.json()).then((res) => {     extraRoutes = res.routes;    oldRender();  })}

onRouteChange({ routes, matchedRoutes, location, action })
只有路由切换或者加载该办法都会被执行相似于vue router当中的routerEach;你能够在路由切换的同时记录埋点,因为该办法返回四个参数包含具体的路由参数,你能够在此判断是否执行向下操作

export function onRouteChange({ routes,matchedRoutes,location, action }) {        console.log(routes);  路由汇合        console.log(matchedRoutes);  以后匹配的路由及其子路由        console.log(location);   location及其参数        console.log(action);   以后跳转执行的操作        }

rootContainer(LastRootContainer, args)

批改交给 react-dom 渲染时的根组件。

因为该办法应用场景较少在此我间接援用官网案例

//批改react-dom渲染时的根组件并在外面包一个Providerexport function rootContainer(container) {  return React.createElement(ThemeProvider, null, container);}

modifyClientRenderOpts(fn)

批改 clientRender 参数
该办法在个别我的项目中极少用到,我惟一能想到的也就是官网文档中给出的在批改微前端节点,具体还须要依据应用场景来讲,所以我会简略给出一个案例,余下的我会在之后的微前端章节当中演示;

let isSubApp = false;export function modifyClientRenderOpts(memo) {  return {    ...memo,    rootElement: isSubApp ? 'sub-root' : memo.rootElement,      };}
其余

讲点其余的,Umijs是阿里开发的企业级框架,所以该框架中自带阿里引以为傲的antd你能够在umijs我的项目中间接援用antd的组件而不须要npm装置;Umijs给我最大的感触就是让我想起了当年写vue2的日子,umijs做了很多整合,简化了很多操作,提供了弱小的插件;然而我却并不是特地喜爱该框架,感觉应用umijs你将会少了很多摸索,因而你可能失去很多知识点,如果你没用过react第一个我的项目就是umijs我的项目我并不倡议你间接应用,umijs扭转了很多react的语法,尽管便捷了然而并不能让你很好把握react;当然如果你想要便捷迅速的来进行开发大可应用umijs。

没了,下一篇我讲讲搭建长久化数据层以及immer