umi项目常用配置总结

真的老喜欢用umi了,最近独立从0负责了好几个项目,技术栈都是umi + ant design,正好写一个小总结聊一聊umi项目的常见配置吧~

本篇文档由官方文档总结而来,如果参照以下步骤遇到问题,以官方文档为准,查看是否有版本更新,本篇文档的使用版本为umi4 + React18 + Ant design 5.x

创建umi项目

umi官方推荐使用pnpm,笔者在这里也使用了pnpm

bash 复制代码
npm install -g umi pnpm # 首先全局安装umi和pnpm
mkdir umi-test
cd umi-test
pnpm dlx create-umi@latest # 初始化umi仓库(官方推荐使用pnpm,镜像源可以选择taobao,国内访问速度较快)

启用eslint、prettier、husky

如果我们初始化项目使用的是umi max,则无需安装,因为max已经包含了eslint;如果使用的是umi,则有如下两种方法安装

第一种方法:官网上的方法

比较特别的一点是:保存时会按照字母顺序对导入的包进行排序

1. 安装eslint

安装

ruby 复制代码
 pnpm add @umijs/lint -D # 需要先安装@umijs/lint
 pnpm add -D eslint "stylelint@^14" # 目前 @umijs/lint 使用的 stylelint 版本是 v14

配置

php 复制代码
// .eslintrc.js
module.exports = {
  // Umi 项目
  extends: require.resolve('umi/eslint'),

  // Umi Max 项目
  extends: require.resolve('@umijs/max/eslint'),
}

// .stylelintrc.js
module.exports = {
  // Umi 项目
  extends: require.resolve('umi/stylelint'),

  // Umi Max 项目
  extends: require.resolve('@umijs/max/stylelint'),
}

umi lint说明:

  • --quiet: 可选,禁用 warn 规则的报告,仅输出 error
  • --fix: 可选,自动修复 lint 错误

关于版本问题,可以先查看下官网有没有更新:umijs.org/docs/guides...

2. 安装prettier

直接执行 pnpm umi g即可自动化安装及配置

3. 安装lint-staged与husky

介绍:

lint-staged用来驱动 umi lint命令,每次仅检查变更的文件;husky 用来绑定Git Hooks,比如pre-commit、commit-msg(对提交内容的格式规范进行检查)

  • 第一种方式:基于umi的微生成器直接安装(自动安装umi内置的版本,不会出现版本错误)

    umi g precommit

  • 第二种方式:手动增加

安装

csharp 复制代码
pnpm add lint-staged husky -D
pnpm exec husky init # 初始化husky

初始化完成后,需要手动修改 .husky/pre-commit文件的内容:

bash 复制代码
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

- npm test
+ npx lint-staged

在package.json中增加如下配置:(切记,调用pre-commit时应该先eslint后prettier)

json 复制代码
{
   "lint-staged": {
     "*.{js,jsx,ts,tsx,css,less}": [
       "umi lint"
     ],
     "**/*": "prettier --write --ignore-unknown"
   }
}

第二种方法:@umijs/fabric

这种方法的便捷性在于 @umijs/fabric集eslint、prettier、stylelint为一体,不需要再单独配置

安装

css 复制代码
pnpm i @umijs/fabric

配置

java 复制代码
// .prettierrc.js
const fabric = require('@umijs/fabric');

module.exports = {
  ...fabric.prettier,
};

// .stylelintrc.js
const fabric = require('@umijs/fabric');
module.exports = {
  ...fabric.stylelint,
};

// .eslintrc.js
module.exports = {
  extends: [require.resolve('@umijs/fabric/dist/eslint')],
  plugins: ['react'],

  // 自定义全局变量
  globals: {
    REACT_APP_ENV: true,
    REACT_APP_API_URL: true,
  },
  // 根据个人习惯自定义rule
  rules: {
    'no-console': 'off',
    'react-hooks/exhaustive-deps': 'off', // react-hooks 依赖检查
    'no-empty': 'off', // catch{} 允许为空
    '@typescript-eslint/no-shadow': ['off'], // 当前作用域变量名不能与父级作用域变量同名
  },
};

后续安装 lint-stagedhusky的方法与第一种相同,如果配置此项,需要手动安装一下eslint(因为在pre-commit的时候需要执行eslint对应的命令~)

启用plugin

umi内置了很多方便的插件,如果需要使用,首先需要安装 @umijs/plugins,并且需要在.umirc.ts中进行相关配置(如果没有正确配置,会报错!!)

css 复制代码
pnpm i -D @umijs/plugins

一般来说,我会使用initialState、useModel、request、antd这些插件,那么我们需要在.umirc.ts中配置

css 复制代码
// .umirc.ts
export default {
  plugins: [
    '@umijs/plugins/dist/initial-state', // 定义项目的初始状态
    '@umijs/plugins/dist/model',
    '@umijs/plugins/dist/request',
    '@umijs/plugins/dist/antd',
  ],
  antd: {},
  initialState: {},
  model: {},
  request: {
    dataField: '',
  },
};

getInitialState

大多数的前端项目现在都已经开始设置 initState,前台项目可以存储用户的登录信息,后台管理系统可以存储用户的权限信息,从而进行权限管理,不仅仅局限于 umi 中,还包括 ice 等基于 React 封装的前端框架

我们除在上述.umirc.ts中配置的内容之外,还需要在app.ts中加入如下函数,当页面初次加载时,会先调用 getInitialState函数,等该函数获取到结果之后,才会进行其它组件的渲染(所以后台管理系统经常用它做权限管理喽)

javascript 复制代码
// app.ts
export const getInitialState = async () => {
  const initialData = await requestGetUserProfile();
  return initialData?.data;
};

下面是调用的例子

javascript 复制代码
// index.tsx
import { useModel } from 'umi';

const Home = () => {
  // refresh用于重新执行 getInitialState 函数,而 setInitialState 是手动设置 initialState 值
  const { initialState, loading, refresh, error, setInitialState } = useModel('@@initialState');
  return <>Home</>
};

export default Home;

官方文档:umijs.org/docs/api/ru...

useModel

useModel是umi项目里超棒的一个语法糖,极大的简化了状态管理的操作

先在src下创建models文件夹,根据需求创建指定名称的ts文件,这里的示例是user.ts

typescript 复制代码
// user.ts
import { useState } from 'react';

interface IPersonalInfo {
  username?: string;
  email?: string;
}
const UserState = () => {
  const [personalInfo, setPersonalInfo] = useState<IPersonalInfo>({});

  return { personalInfo, setPersonalInfo };
};

export default UserState;

调用如下

javascript 复制代码
// index.tsx
import { useModel } from 'umi';

const Home = () => {
  const { personalInfo } = useModel('user'); // 文件名的前缀
  return <></>;
};

export default Home;

request

umi 内置了request插件,并且内置了ahooks2中的useRequest,不需要额外安装axios,并且 umi 内置了 ahooks2中的useRequest,简化了请求的代码

ahooks2中useRequest的官方文档:ahooks-v2.js.org/zh-CN/hooks...

typescript 复制代码
// /service/user.ts
import { request } from 'umi';
import { BASE_URL } from './config';

export const requestLogin = async (data: any) => {
  return await request(`${BASE_URL}/api/Auth/Login`, {
    method: 'post',
    data,
  });
};

antd

内置antd组件,目前为4.x版本,并且可按需导入你需要的组件库,如果需要安装其它的版本的antd,则需要手动安装了

具体配置项参照官方文档:umijs.org/docs/max/an...

关于跨域

跨域本身是因为浏览器自己的限制,需要后端来配置白名单。如果使用umi的话,我们在前端可以使用本地代理,同样可以解决跨域问题。类比nginx服务器代理,如果匹配/api路径,则转发到后端服务器。在umi项目中,我们只需要在 .umirc.ts中添加如下代码即可实现

javascript 复制代码
export default {
  proxy: {
    '/api': {
      'target': 'http://jsonplaceholder.typicode.com/',
      'changeOrigin': true,
      'pathRewrite': { '^/api' : '' },
    },
  },
}

全局请求拦截

在app.ts中配置即可

typescript 复制代码
// app.ts
// TODO: 后端接口的报错类型
enum ErrorShowType {
  SILENT = 0,
  WARN_MESSAGE = 1,
  ERROR_MESSAGE = 2,
  NOTIFICATION = 3,
  REDIRECT = 9,
}

// TODO:后端接口响应数据的类型
interface ResponseStructure {
  success: boolean;
  data: any;
  errorCode?: number;
  errorMessage?: string;
  showType?: ErrorShowType;
  response?: any;
}

export const request: RequestConfig = {
  // 超时时间
  timeout: 1000 * 10,
  // 请求头
  headers: { 'X-Requested-With': 'XMLHttpRequest' },
  errorConfig: {
    errorThrower: (res: ResponseStructure) => {
      const { success, data, errorCode, errorMessage, showType } = res;
      if (!success) {
        const error: any = new Error(errorMessage);
        error.name = 'BizError';
        error.info = { errorCode, errorMessage, showType, data };
        throw error; // 抛出自制的错误
      }
    },
    errorHandler: (error: any) => {
      console.log('error', error);
      // TODO:配置后端接口的code
      if (error.response.data?.code) {
        // 请求成功发出且服务器也响应了状态码,但状态代码超出了 2xx 的范围
        switch (error.response.data.code) {
          case 200: {
            return;
          }
          case 401: {
            if (localStorage.getItem('token')) {
              localStorage.removeItem('token');
            }
            if (
              location.pathname !== 'login' &&
              location.pathname !== '/register'
            ) {
              history.replace('/login');
              message.error('请先登录');
            }
            return;
          }
          default: {
            message.error(error.response.data?.data);
            return;
          }
        }
      } else if (error.request) {
        // 请求已经成功发起,但没有收到响应
        message.error('服务器错误,请稍后重试!');
      } else {
        // 发送请求时出了点问题
        message.error('请求错误,请重试!');
      }
    },
  },
  requestInterceptors: [
    (url: any, options: any): any => {
      if (
        options.method === 'post' ||
        options.method === 'put' ||
        options.method === 'delete' ||
        options.method === 'get'
      ) {
        const headers = !!localStorage.getItem('token') && {
          Authorization: 'Bearer ' + localStorage.getItem('token'),
        };
        return {
          url,
          options: { ...options, headers },
        };
      }
    },
  ],
  responseInterceptors: [
    (res: any) => {
      return res;
    },
  ],
};

mock

在开发中由于某些原因,后端接口有时候不是可以及时给到,我们就需要使用mock接口了,umi 提供了开箱即用的 mock

参见官方文档:umijs.org/docs/guides...

router

参见官方文档:umijs.org/docs/guides...

指定端口运行

推荐在环境变量文件 .env中设置 PORT=3000,这里输入你想运行的端口即可

其它环境变量的配置参见官网:umijs.org/docs/guides...

样式

umi 支持 less,scss 等css预处理器,通常我一般定义 index.module.less,然后在主文件中按照CSS Modules的方式去调用,如: import styles from 'index.module.less'

小知识:index.less 和 index.module.less 有什么区别?

答:index.module.less 在引入时编译器会对其进行特殊处理,每个类名都会被转换为一个独特的哈希值,来保证他的局部性,例如我们在 F12 打开控制台之后就会看到显示的类是在原有的基础上后面跟了一串哈希字符串

使用微生成器

常见的当然是生成页面和组件了,可以减少我们的代码量

生成页面:可以批量生成,指定路径生成,或者执行命令后再进行选择

bash 复制代码
umi g page page1 page2 a/nested/page3
umi g page a/nested/page3
umi g page

生成组件:umi g component

基于上述两个命令,umi 也可以提前设置他们的模板,这样就更方便了

更多微生成器参见官方文档:umijs.org/docs/guides...

相关推荐
FinGet3 小时前
那总结下来,react就是落后了
前端·react.js
王解6 小时前
Jest项目实战(2): 项目开发与测试
前端·javascript·react.js·arcgis·typescript·单元测试
AIoT科技物语1 天前
免费,基于React + ECharts 国产开源 IoT 物联网 Web 可视化数据大屏
前端·物联网·react.js·开源·echarts
初遇你时动了情1 天前
react 18 react-router-dom V6 路由传参的几种方式
react.js·typescript·react-router
番茄小酱0011 天前
ReactNative中实现图片保存到手机相册
react native·react.js·智能手机
王解1 天前
Jest进阶知识:深入测试 React Hooks-确保自定义逻辑的可靠性
前端·javascript·react.js·typescript·单元测试·前端框架
小牛itbull1 天前
ReactPress—基于React的免费开源博客&CMS内容管理系统
前端·react.js·开源·reactpress
~甲壳虫1 天前
react中得类组件和函数组件有啥区别,怎么理解这两个函数
前端·react.js·前端框架
用户8185216881171 天前
react项目搭建create-router-dom,redux详细解说
react.js
new Vue()1 天前
Vue vs React:两大前端框架的区别解析
vue.js·react.js·前端框架