乐趣区

关于javascript:从零开始构建企业级React项目一-umijs常用配置学习

文章开始前我想向大家一个问题用于更好的学习 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 渲染时的根组件并在外面包一个 Provider
export 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

退出移动版