react+umi+dva+typescript创建及配置项目方案总结

仲皓君
2023-12-01

react+umi+dva+typescript创建及配置项目方案总结

背景描述:
  • Umi是蚂蚁金服开源的 react 应用框架,是可扩展的企业级应用框架。Umi 以路由为基础的,同时支持配置式路由和约定式路由,保证路由的功能完备,并以此进行功能扩展。然后配以生命周期完善的插件体系,覆盖从源码到构建产物的每个生命周期,支持各种功能扩展和业务需求。具有以下优势:
    • 可扩展,Umi 实现了完整的生命周期,并使其插件化,Umi 内部功能也全由插件完成。此外还支持插件和插件集,以满足功能和垂直域的分层需求。
    • 开箱即用,Umi 内置了路由、构建、部署、测试等,仅需一个依赖即可上手开发。并且还提供针对 React 的集成插件集,内涵丰富的功能,节省部分框架搭建及配置工作,可满足日常 80% 的开发需求。
    • 企业级,经蚂蚁、阿里、优酷、网易、飞猪、口碑等公司项目的验证,适合于大型企业级项目。
    • 大量自研,包含微前端、组件打包、文档工具、请求库、hooks 库、数据流等,满足日常项目的周边需求。
    • 完备路由,同时支持配置式路由和约定式路由,同时保持功能的完备性,比如动态路由、嵌套路由、权限路由等等。
    • 面向未来,在满足需求的同时,我们也不会停止对新技术的探索。比如 dll 提速、modern mode、webpack@5、自动化 external、bundler less 等等。 不适用于:IE8 或更低版本的浏览器、React 16.8.0 以下版本、Node 10 以下的环境。
  • 关于umi相对于其他应用级框架create-react-appnext.js的对比,这里引用官方:
    • create-react-app 是基于 webpack 的打包层方案,包含 build、dev、lint 等,他在打包层把体验做到了极致,但是不包含路由,不是框架,也不支持配置。所以,如果大家想基于他修改部分配置,或者希望在打包层之外也做技术收敛时,就会遇到困难。
    • next.js 是个很好的选择,Umi 很多功能是参考 next.js 做的。要说有哪些地方不如 Umi,我觉得可能是不够贴近业务,不够接地气。比如 antd、dva 的深度整合,比如国际化、权限、数据流、配置式路由、补丁方案、自动化 external 方面等等一线开发者才会遇到的问题。
  • dva是一个基于 reduxredux-saga 的数据流方案,然后为了简化开发体验,dva 还额外内置了 react-routerfetch,所以也可以理解为一个轻量级的、面向数据流处理的应用框架。具有以下优势:
    • 易学易用,仅有 6 个 api,对 redux 用户尤其友好,配合 umi 使用后更是降低为 0 API。
    • elm 概念,通过 reducers, effects 和 subscriptions 组织 model。
    • 插件机制,比如 dva-loading 可以自动处理 loading 状态,不用一遍遍地写 showLoading 和 hideLoading。
    • 支持 HMR,基于 babel-plugin-dva-hmr 实现 components、routes 和 models 的 HMR。
创建项目:
  • // 1.新建空白文件夹
    mkdir myapp && cd myapp
    // 2.创建umi项目(也可以:npm create umi // 或 yarn create umi)
    npx @umijs/create-umi-app // 或 yarn create @umijs/umi-app
    // 3.安装并运行
    npm install
    npm start
    
配置项目:
  • 当按照第一步创建完项目后,对于typescript而言已经在项目里有了默认的配置,此时查看umi版本,确认是否是v3及以上版本,因为v3在细节上做了优化,参考升级到v3版本(注意:Node版本在 10.13 或以上)。

  • 1.umi本身默认了less,其实完全够用,但也可以配置sass预编译(**注意:**由于 node-sass 插件本生与node之间存在一定的兼容问题,可以不安装此插件,默认使用dart-sass)。

    • npm install sass sass-loader --save -dev
      
  • 2.安装antd。

    • npm install antd --save
      
  • 3.配置axios请求:

    • // 1.安装
      npm install axios --save
      
      // 2.请求封装
      import axios from 'axios'
      
      const service = axios.create({
        baseURL: import.meta.env.VITE_API_URL as any,
        timeout: 50000,
        headers: { 'Content-Type': 'application/json' }
      })
      
      service.interceptors.request.use(
        (config) => {
          config.headers.common['Authorization'] = 'Authorization'
          return config
        },
        (error) => {
          return Promise.reject(error)
        }
      )
      
      service.interceptors.response.use(
        (response) => {
          const res = response.data
          if (res.code !== 200) {
            return Promise.reject(service.interceptors.response)
          } else {
            return response.data
          }
        },
        (error) => {
          return Promise.reject(error)
        }
      )
      
      export default service
      
      
  • 4.配置 ESlint 代码审查(**注意:**如果配置完eslint后,格式化没有效果,此时需要注意编辑器是否开启eslint):

    • // 1.安装
      npm i eslint eslint-config-prettier eslint-plugin-typescript eslint-plugin-vue typescript-eslint-parser vue-eslint-parser @typescript-eslint/eslint-plugin @typescript-eslint/parser -S -D
      
      // 2.配置 .eslintignore
      *.sh
      node_modules
      lib
      *.md
      *.scss
      *.woff
      *.ttf
      .vscode
      .idea
      dist
      mock
      public
      bin
      build
      config
      index.html
      src/assets
      
      // 3.配置 .eslintrc.js
      module.exports = {
      	root: true,
      	env: {
      		browser: true,
      		es2021: true,
      		node: true,
      	},
      	parser: 'vue-eslint-parser',
      	parserOptions: {
      		ecmaVersion: 12,
      		parser: '@typescript-eslint/parser',
      		sourceType: 'module',
      	},
      	extends: ['plugin:vue/vue3-essential', 'plugin:vue/essential', 'eslint:recommended'],
      	plugins: ['vue', 'typescript', '@typescript-eslint'],
      	    rules: {
            "vue/max-attributes-per-line": [2, {
              "singleline": 10,
              "multiline": {
                "max": 1,
                "allowFirstLine": false
              }
            }],
            "vue/singleline-html-element-content-newline": "off",
            "vue/multiline-html-element-content-newline":"off",
            "vue/name-property-casing": ["error", "PascalCase"],
            "vue/no-v-html": "off",
            'accessor-pairs': 2,
            'arrow-spacing': [2, {
              'before': true,
              'after': true
            }],
            'block-spacing': [2, 'always'],
            'brace-style': [2, '1tbs', {
              'allowSingleLine': true
            }],
            'camelcase': [0, {
              'properties': 'always'
            }],
            'comma-dangle': [2, 'never'],
            'comma-spacing': [2, {
              'before': false,
              'after': true
            }],
            'comma-style': [2, 'last'],
            'constructor-super': 2,
            'curly': [2, 'multi-line'],
            'dot-location': [2, 'property'],
            'eol-last': 2,
            'eqeqeq': ["error", "always", {"null": "ignore"}],
            'generator-star-spacing': [2, {
              'before': true,
              'after': true
            }],
            'handle-callback-err': [2, '^(err|error)$'],
            'indent': [2, 2, {
              'SwitchCase': 1
            }],
            'jsx-quotes': [2, 'prefer-single'],
            'key-spacing': [2, {
              'beforeColon': false,
              'afterColon': true
            }],
            'keyword-spacing': [2, {
              'before': true,
              'after': true
            }],
            'new-cap': [2, {
              'newIsCap': true,
              'capIsNew': false
            }],
            'new-parens': 2,
            'no-array-constructor': 2,
            'no-caller': 2,
            'no-console': 'off',
            'no-class-assign': 2,
            'no-cond-assign': 2,
            'no-const-assign': 2,
            'no-control-regex': 0,
            'no-delete-var': 2,
            'no-dupe-args': 2,
            'no-dupe-class-members': 2,
            'no-dupe-keys': 2,
            'no-duplicate-case': 2,
            'no-empty-character-class': 2,
            'no-empty-pattern': 2,
            'no-eval': 2,
            'no-ex-assign': 2,
            'no-extend-native': 2,
            'no-extra-bind': 2,
            'no-extra-boolean-cast': 2,
            'no-extra-parens': [2, 'functions'],
            'no-fallthrough': 2,
            'no-floating-decimal': 2,
            'no-func-assign': 2,
            'no-implied-eval': 2,
            'no-inner-declarations': [2, 'functions'],
            'no-invalid-regexp': 2,
            'no-irregular-whitespace': 2,
            'no-iterator': 2,
            'no-label-var': 2,
            'no-labels': [2, {
              'allowLoop': false,
              'allowSwitch': false
            }],
            'no-lone-blocks': 2,
            'no-mixed-spaces-and-tabs': 2,
            'no-multi-spaces': 2,
            'no-multi-str': 2,
            'no-multiple-empty-lines': [2, {
              'max': 1
            }],
            'no-native-reassign': 2,
            'no-negated-in-lhs': 2,
            'no-new-object': 2,
            'no-new-require': 2,
            'no-new-symbol': 2,
            'no-new-wrappers': 2,
            'no-obj-calls': 2,
            'no-octal': 2,
            'no-octal-escape': 2,
            'no-path-concat': 2,
            'no-proto': 2,
            'no-redeclare': 2,
            'no-regex-spaces': 2,
            'no-return-assign': [2, 'except-parens'],
            'no-self-assign': 2,
            'no-self-compare': 2,
            'no-sequences': 2,
            'no-shadow-restricted-names': 2,
            'no-spaced-func': 2,
            'no-sparse-arrays': 2,
            'no-this-before-super': 2,
            'no-throw-literal': 2,
            'no-trailing-spaces': 2,
            'no-undef': 2,
            'no-undef-init': 2,
            'no-unexpected-multiline': 2,
            'no-unmodified-loop-condition': 2,
            'no-unneeded-ternary': [2, {
              'defaultAssignment': false
            }],
            'no-unreachable': 2,
            'no-unsafe-finally': 2,
            'no-unused-vars': [2, {
              'vars': 'all',
              'args': 'none'
            }],
            'no-useless-call': 2,
            'no-useless-computed-key': 2,
            'no-useless-constructor': 2,
            'no-useless-escape': 0,
            'no-whitespace-before-property': 2,
            'no-with': 2,
            'one-var': [2, {
              'initialized': 'never'
            }],
            'operator-linebreak': [2, 'after', {
              'overrides': {
                '?': 'before',
                ':': 'before'
              }
            }],
            'padded-blocks': [2, 'never'],
            'quotes': [2, 'single', {
              'avoidEscape': true,
              'allowTemplateLiterals': true
            }],
            'semi': [2, 'never'],
            'semi-spacing': [2, {
              'before': false,
              'after': true
            }],
            'space-before-blocks': [2, 'always'],
            'space-before-function-paren': [2, 'never'],
            'space-in-parens': [2, 'never'],
            'space-infix-ops': 2,
            'space-unary-ops': [2, {
              'words': true,
              'nonwords': false
            }],
            'spaced-comment': [2, 'always', {
              'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
            }],
            'template-curly-spacing': [2, 'never'],
            'use-isnan': 2,
            'valid-typeof': 2,
            'wrap-iife': [2, 'any'],
            'yield-star-spacing': [2, 'both'],
            'yoda': [2, 'never'],
            'prefer-const': 2,
            'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
            'object-curly-spacing': [2, 'always', {
              objectsInObjects: false
            }],
            'array-bracket-spacing': [2, 'never']
          }
      };
      
 类似资料: