1.UmiJS #

UmiJS,中文发音为「乌米」,是可扩展的企业级前端应用框架。Umi 以路由为基础的,同时支持配置式路由和约定式路由,保证路由的功能完备,并以此进行功能扩展。然后配以生命周期完善的插件体系,覆盖从源码到构建产物的每个生命周期,支持各种功能扩展和业务需求。

umiJS

2.安装 #

npm install -g umi
umi -v

2.1 目录约定 #

.
├── config                              // 配置目录
│   └── config.ts                       // 主配置文件
├── dist                                // 构建输出目录
├── mock                                // 模拟数据目录
│   └── app.ts|tsx                      // 模拟的应用数据文件
├── src                                 // 源码目录
│   ├── .umi                            // Umi内部生成的临时目录
│   ├── .umi-production                 // Umi为生产环境生成的临时目录
│   ├── layouts                         // 布局组件目录
│   │   ├── BasicLayout.tsx             // 基础布局组件
│   │   ├── index.less                  // 布局样式文件
│   ├── models                          // 数据模型目录
│   │   ├── global.ts                   // 全局数据模型
│   │   └── index.ts                    // 模型索引文件
│   ├── pages                           // 页面组件目录
│   │   ├── index.less                  // 页面样式文件
│   │   └── index.tsx                   // 主页面组件
│   ├── utils                           // 工具函数目录
│   │   └── index.ts                    // 工具函数索引
│   ├── services                        // 服务请求相关目录
│   │   └── api.ts                      // API请求文件
│   ├── app.(ts|tsx)                    // 主应用配置文件
│   ├── global.ts                       // 全局文件
│   ├── global.(css|less|sass|scss)     // 全局样式文件
│   ├── overrides.(css|less|sass|scss)  // 覆盖样式文件
│   ├── favicon.(ico|gif|png|jpg|jpeg|svg|avif|webp)   // 网站图标文件
│   └── loading.(tsx|jsx)               // 加载组件
├── node_modules                        // npm依赖目录
│   └── .cache                          // 缓存目录
│       ├── bundler-webpack             // webpack打包器缓存
│       ├── mfsu                        // mfsu缓存
│       └── mfsu-deps                   // mfsu依赖缓存
├── .env                                // 环境变量文件
├── plugin.ts                           // 插件配置文件
├── .umirc.ts                           // Umi配置文件 (与 config/config 二选一)
├── package.json                        // npm包描述文件
├── tsconfig.json                       // TypeScript配置文件
└── typings.d.ts                        // TypeScript声明文件

3. 新建项目 #

3.1 新建项目目录 #

mkdir zhufeng-umi
cd zhufeng-umi
npm init -y

3.2 新建pages目录 #

commands#generate

mkdir src/pages

3.3 新建页面 #

3.3.1 pages\index.js #

src\pages\index.js

import React, { Component } from 'react'
import { Link } from 'umi';
import styles from './index.css';
export default class componentName extends Component {
  render() {
    return (
      <div>
        <h1 className={styles.title}>首页</h1>
        <Link to="/profile">个人中心</Link>
      </div>
    )
  }
}

src\pages\index.css

.title {
  background: rgb(121, 242, 214);
}

3.3.2 user.js #

src\pages\user.js

import React from 'react';
import styles from './user.css';
export default () => {
  return (
    <div>
      <h1 className={styles.title}>Page user</h1>
    </div>
  );
}

3.3.3 profile.js #

src\pages\profile.js

import React, { Component } from 'react'
import { history } from 'umi';
import styles from './profile.css';
export default class componentName extends Component {
  render() {
    return (
      <div>
        <h1 className={styles.title}>个人中心</h1>
        <button onClick={()=>history.back()}>返回</button>
      </div>
    )
  }
}

3.3.4 启动服务器 #

3.3.4.1 启动配置 #
  "scripts": {
    "dev": "umi dev",
    "build": "umi build"
  }
3.3.4.2 启动项目 #
npm run dev
3.3.4.3 部署发布 #

4. 全局 layout #

全局 layout

约定 src/layouts/index.js 为全局路由。返回一个 React 组件,并通过 <Outlet /> 渲染嵌套路由。

src/layouts/index.js

import React, { Component } from 'react';
import { Link,Outlet  } from 'umi';
export default class Layout extends Component {
    render() {
        return (
            <div>
                <ul>
                    <li><Link to="/" >首页</Link></li>
                    <li><Link to="/user">用户管理</Link></li>
                    <li><Link to="/profile">个人设置</Link></li>
                </ul>
                <div>
                <Outlet />
                </div>
            </div>
        )
    }
}

5.配置式路由 #

5.1 config.js #

config\config.js

import routes from "./routes";
export default {
    routes
}

5.2 routes.js #

config\routes.js

export default [
    { path: '/', component: '@/pages/index.js' },
    {
        path: '/user',
        component: '@/pages/user/index',
        routes: [
            { path: 'list', component: '@/pages/user/list' },
            { path: 'add', component: '@/pages/user/add' },
            { path: 'detail/:id', component: '@/pages/user/detail/$id.js' },
        ],
    },
    {
        path: '/profile',
        component: '@/pages/profile.js',
        wrappers: [
            '@/wrappers/auth',
        ],
    },
    { path: '/login', component: '@/pages/login.js' }
]

5.3 routes.js #

mock\routes.js

export default {
    'GET /api/routes': [
        {
            path: '/foo',
            component: 'Foo'
        }
    ]
}

5.4 app.js #

src\app.js

import React from 'react';
//import Foo from '@/extraRoutes/Foo';
/**
//https://umijs.org/docs/api/runtime-config#patchclientroutes-routes-
export function patchClientRoutes({ routes }) {
    routes.unshift({
        path: '/foo',
        element: <Foo />,
    });
}
 */

let extraRoutes;
export function patchClientRoutes({ routes }) {
  routes.unshift(...extraRoutes);
}
export function render(oldRender) {
    fetch('/api/routes')
      .then((res) => {

        return res.json();
      })
      .then((res) => {
        console.log(res);
        extraRoutes = res.map(({path,component})=>{
            let Component = require(`@/extraRoutes/${component}`);
            console.log(Component.default);
            return {
                path,
                element: React.createElement(Component.default),
            }
        });
        oldRender();
      });
  }

5.5 auth.js #

src\wrappers\auth.js

import {Navigate,Outlet  } from 'umi';
export default () => {
    const isLogin = localStorage.getItem('isLogin');
    if (isLogin) {
        return <Outlet/>;
    } else {
        return <Navigate to={{ pathname: "/login"}} state={{ from: '/profile' }}/>;
    }
}

5.6 layouts\index.js #

src\layouts\index.js

import React, { Component } from 'react';
import { Link,Outlet  } from 'umi';
export default class Layout extends Component {
    render() {
        return (
            <div>
                <ul>
                    <li><Link to="/" >首页</Link></li>
                    <li><Link to="/user">用户管理</Link></li>
                    <li><Link to="/profile">个人设置</Link></li>
                </ul>
                <div>
                <Outlet />
                </div>
            </div>
        )
    }
}

5.7 Foo.js #

src\extraRoutes\Foo.js

import React, { Component } from 'react'
export default class componentName extends Component {
    render() {
        return (
            <div>
                Foo
            </div>
        )
    }
}

5.8 profile.js #

src\pages\profile.js

import React, { Component } from 'react'
import { history } from 'umi';
import styles from './profile.css';
export default class componentName extends Component {
  render() {
    return (
      <div>
        <h1 className={styles.title}>个人中心</h1>
        <button onClick={()=>history.back()}>返回</button>
      </div>
    )
  }
}

5.9 login.js #

src\pages\login.js

import React from 'react';
import { history,useLocation } from 'umi';
export default () => {
    const location = useLocation();
    return (
        <div>
            <h1 >Page login</h1>
            <button onClick={() => {
                localStorage.setItem('isLogin', 'true');
                debugger
                if (location.state && location.state.from) {
                    history.push(location.state.from);
                }
            }}>登录</button>
        </div>
    );
}

5.10 pages\index.js #

src\pages\index.js

import React, { Component } from 'react'
import { Link } from 'umi';
import styles from './index.css';
export default class componentName extends Component {
  render() {
    return (
      <div>
        <h1 className={styles.title}>首页</h1>
        <Link to="/profile">个人中心</Link>
      </div>
    )
  }
}

5.11 user\index.js #

src\pages\user\index.js

import React, { Component } from 'react';
import { Link } from 'umi';
export default class extends Component {
    render() {
        return (
            <ul>
                <li><Link to="/user/detail/1">张三</Link></li>
                <li><Link to="/user/detail/2">李四</Link></li>
            </ul>
        )
    }
}

5.12 list.js #

src\pages\user\list.js

import React, { Component } from 'react';
import { Link } from 'umi';
export default class extends Component {
    render() {
        return (
            <ul>
                <li><Link to="/user/detail/1">张三</Link></li>
                <li><Link to="/user/detail/2">李四</Link></li>
            </ul>
        )
    }
}

5.13 add.js #

src\pages\user\add.js

import React, { Component } from 'react';
export default class extends Component {
    render() {
        return (
            <form >
                <input />
                <input type="submit" />
            </form>
        )
    }
}

5.14 $id.js #

src\pages\user\detail\$id.js

import React, { Component } from 'react';
export default class extends Component {
    render() {
        return (
            <table>
                <thead>
                    <tr>
                        <td>字段</td>
                        <td></td>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td>1</td>
                        <td>张三</td>
                    </tr>
                </tbody>
            </table>
        )
    }
}