<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          UmiJS 中后臺(tái)項(xiàng)目實(shí)踐

          共 6697字,需瀏覽 14分鐘

           ·

          2020-10-27 20:00

          背景

          中后臺(tái)項(xiàng)目一般都有較強(qiáng)的頁(yè)面結(jié)構(gòu)或者邏輯一致性,頁(yè)面比如像搜索、表格、導(dǎo)航菜單、布局,邏輯方面比如像數(shù)據(jù)流,權(quán)限。如果基于 Webpack 封裝這些功能就需要比較大的前期工作,Umi 則以路由為基礎(chǔ),并以此進(jìn)行功能擴(kuò)展,包含微前端、組件打包、請(qǐng)求庫(kù)、hooks 庫(kù)、數(shù)據(jù)流等。基于此在公司內(nèi)落地 umi 的實(shí)踐。

          目錄結(jié)構(gòu)

          基于 umi 的項(xiàng)目整體目錄結(jié)構(gòu)說(shuō)明,對(duì)項(xiàng)目能有個(gè)大致的了解

          ├──?package.json
          ├──?config
          ??└──?config.js
          ├──?dist
          ├──?mock
          ├──?public
          └──?src
          ????├──?.umi
          ????├──?layouts/index.js
          ????├──?locales
          ????├──?models
          ????├──?pages
          ????????├──?index.less
          ????????└──?index.js
          ????├──?services
          ????├──?wrappers
          ????├──?global.js
          ????└──?app.js
          • config.js — 主要是路由配置,插件配置,webpack 配置
          • layouts — 布局相關(guān)
          • locales — 國(guó)際化
          • modelsdva 數(shù)據(jù)流方案或者 plugin-model
          • wrappers — 配置路由的高階組件封裝,比如路由級(jí)別的權(quán)限校驗(yàn)
          • app.js — 運(yùn)行時(shí)配置,比如需要?jiǎng)討B(tài)修改路由,覆蓋渲染 render,監(jiān)聽(tīng)路由變化
          • global.js — 全局執(zhí)行入口,比如可以放置 sentry

          路由

          路由可以說(shuō)是前端項(xiàng)目的基石,下面談?wù)劼酚上嚓P(guān)的配置

          //?config/route.js
          export?default?[{
          ??path:?'/merchant',
          ??name:?'商戶管理',
          ??routes:?[
          ????{
          ??????path:?'/merchant/list',
          ??????name:?'商戶列表'
          ??????component:?'./list'
          ????},
          ????{
          ??????path:?'/merchant/detail',
          ??????name:?'商戶詳情',
          ??????hideInMenu:?true,
          ??????component:?'./detail'
          ????}
          ??]
          }]

          路由配置除了常規(guī)的 namepathcomponent 也可以支持配置 umi 插件的配置選項(xiàng),比如pro-layout的 hideInMenu 來(lái)隱藏路由對(duì)應(yīng)導(dǎo)航菜單項(xiàng)

          路由組件按需加載可以在 config.js 中配置開(kāi)啟

          //?config/config.js
          export?default?{
          ??dynamicImport:?{}
          }

          路由也支持 hook 鉤子操作,比如登錄后再訪問(wèn)登錄頁(yè)面就重定向到首頁(yè)

          //?config/route.js
          {
          ??path:?'/login',
          ?wrappers:?[
          ????'@/wrappers/checkLogin',
          ??],
          ??component:?'./Login'
          }

          某些項(xiàng)目的路由可能是數(shù)據(jù)庫(kù)配置的,這個(gè)時(shí)候就需要?jiǎng)討B(tài)路由,從接口獲取數(shù)據(jù)創(chuàng)建路由

          //?src/app.js
          let?extraRoutes;

          export?function?patchRoutes({?routes?})?{
          ??merge(routes,?extraRoutes);
          }

          export?function?render()?{
          ??fetch('/api/routes').then((res)?=>?{?extraRoutes?=?res.routes?})
          }

          數(shù)據(jù)流方案選擇

          1. 使用 @umijs/plugin-dva,開(kāi)發(fā)方式類似 redux
          //?config/config.js
          export?default?{
          ??dva:?{
          ????immer:?true,
          ????hmr:?false,
          ??}
          }
          • 約定是到 model 組織方式,不用手動(dòng)注冊(cè) model
          • 文件名即 namespacemodel 內(nèi)如果沒(méi)有聲明 namespace,會(huì)以文件名作為 namespace
          • 內(nèi)置 dva-loading,直接 connect loading 字段使用即可
          1. 使用 @umijs/plugin-model

          一種基于 hooks 范式的簡(jiǎn)易數(shù)據(jù)管理方案(部分場(chǎng)景可以取代 dva),通常用于中臺(tái)項(xiàng)目的全局共享數(shù)據(jù)。

          //?src/models/useAuthModel.js
          import?{?useState,?useCallback?}?from?'react'

          export?default?function?useAuthModel()?{
          ??const?[user,?setUser]?=?useState(null)
          ??const?signin?=?useCallback((account,?password)?=>?{
          ????//?signin?implementation
          ????//?setUser(user?from?signin?API)
          ??},?[])
          ??const?signout?=?useCallback(()?=>?{
          ????//?signout?implementation
          ????//?setUser(null)
          ??},?[])
          ??return?{
          ????user,
          ????signin,
          ????signout
          ??}
          }

          使用 Model

          import?{?useModel?}?from?'umi';

          export?default?()?=>?{
          ??const?{?user,?fetchUser?}?=?useModel('user',?model?=>?({?user:?model.user,?fetchUser:?model.fetchUser?}));
          ??return?<>hello
          };

          從使用體驗(yàn)來(lái)講,中臺(tái)項(xiàng)目基本就是表單和表格,跨頁(yè)面共享數(shù)據(jù)場(chǎng)景并不是很多,使用 dva 有點(diǎn)過(guò)重,因此推薦使用第 2 種 plugin-model 這種輕量級(jí)的

          布局


          @umijs/plugin-layout 插件提供了更加方便的布局

          • 默認(rèn)為 Ant Design 的 Layout @ant-design/pro-layout[1],支持它全部配置項(xiàng)。
          • 側(cè)邊欄菜單數(shù)據(jù)根據(jù)路由中的配置自動(dòng)生成。
          • 默認(rèn)支持對(duì)路由的 403/404 處理和 Error Boundary。
          • 搭配 @umijs/plugin-access 插件一起使用,可以完成對(duì)路由權(quán)限的控制。
          //?src/app.js
          export?const?layout?=?{
          ??logout:?()?=>?{},?//?do?something
          ??rightRender:(initInfo)=>?{?return?'hahah';?},//?return?string?||?ReactNode;
          };

          權(quán)限

          一般項(xiàng)目離不開(kāi)權(quán)限的管理, umi 使用 @umijs/plugin-access 來(lái)提供權(quán)限設(shè)置

          //?src/access.js
          export?default?function(initialState)?{
          ??const?{?permissions?}?=?initialState;?//?getInitialState方法執(zhí)行后

          ??return?{
          ????canAccessMerchant:?true,
          ????...permissions
          ??}
          }
          1. 對(duì)路由頁(yè)面的權(quán)限控制,在路由配置中新增 access 屬性
          //?config/route.js
          export?default?[{
          ??path:?'/merchant',
          ??name:?'商戶管理',
          ??routes:?[
          ????{
          ??????path:?'/merchant/list',
          ??????name:?'商戶列表'
          ??????component:?'./list',
          ??????access:?'canAccessMerchant'
          ????}
          ??]
          }]
          1. 當(dāng)然也可以在頁(yè)面或組件內(nèi)用 useAccess 獲取到權(quán)限相關(guān)信息
          import?React?from?'react'
          import?{?useAccess?}?from?'umi'

          const?PageA?=?props?=>?{
          ??const?{?foo?}?=?props;
          ??const?access?=?useAccess();

          ??if?(access.canReadFoo)?{
          ????//?如果可以讀取?Foo,則...
          ??}

          ??return?<>TODO
          }

          export?default?PageA
          1. 實(shí)際業(yè)務(wù)開(kāi)發(fā)中,權(quán)限需要從接口動(dòng)態(tài)獲取,就需要使用 @umijs/plugin-initial-state@umijs/plugin-model
          //?src/app.js
          /**
          getInitialState會(huì)在整個(gè)應(yīng)用最開(kāi)始執(zhí)行,返回值會(huì)作為全局共享的數(shù)據(jù)。Layout 插件、Access 插件以及用戶都可以通過(guò) useModel('@@initialState')?直接獲取到這份數(shù)據(jù)
          */

          export?async?function?getInitialState()?{
          ??const?permissions?=?await?fetchUserPermissions()
          ??return?{?permissions?}
          }

          國(guó)際化

          @umijs/plugin-locale 國(guó)際化插件,用于解決 i18n 問(wèn)題

          使用 antd 開(kāi)發(fā),默認(rèn)是英文,顯示中文就需要開(kāi)啟國(guó)際化配置

          //?config/config.js
          export?default?{
          ??locale:?{
          ????default:?'zh-CN',
          ????antd:?true,
          ????baseNavigator:?true,
          ??}
          }

          在路由中的 title 或者 name 可直接使用國(guó)際化 key,自動(dòng)被轉(zhuǎn)成對(duì)應(yīng)語(yǔ)言的文案

          //?src/locales/zh-CN.js
          export?default?{
          ??'about.title':?'關(guān)于?-?標(biāo)題',
          }
          //?src/locales/en-US.js
          export?default?{
          ??'about.title':?'About?-?Title',
          }

          項(xiàng)目配置如下

          export?default?{
          ??routes:?[
          ????{
          ??????path:?'/about',
          ??????component:?'About',
          ??????title:?'about.title',
          ????}
          ??]
          }

          集成 redux 插件

          如果開(kāi)啟 dva,也就是使用 redux 來(lái)集中管理數(shù)據(jù)流,那么使用 redux-persist 插件持久化 redux 數(shù)據(jù)到 localStorage 里,大致使用如下

          //?src/app.js
          import?{?getDvaApp?}?from?'umi'
          import?{?persistStore,?persistReducer?}?from?'redux-persist'
          import?storage?from?'redux-persist/lib/storage'
          import?autoMergeLevel2?from?'redux-persist/lib/stateReconciler/autoMergeLevel2'
          import?createFilter?from?'redux-persist-transform-filter'

          export?const?dva?=?{
          ??config:?{
          ????onError(e)?{
          ??????e.preventDefault()
          ????},
          ????onReducer(reducer)?{
          ??????const?globalCollapsedFilter?=?createFilter('global',?['collapsed'])
          ??????const?persistConfig?=?{
          ????????key:?'root',
          ????????storage,
          ????????whitelist:?['global'],
          ????????transforms:?[globalCollapsedFilter],
          ????????stateReconciler:?autoMergeLevel2
          ??????}
          ??????return?persistReducer(persistConfig,?reducer)
          ????}
          ??}
          }

          window.addEventListener('DOMContentLoaded',?()?=>?{
          ??const?app?=?getDvaApp()
          ??persistStore(app._store)
          })

          插件開(kāi)發(fā)

          umi 實(shí)現(xiàn)了完整的生命周期,并使其插件化,這樣就為使用者提供了擴(kuò)展入口。比如設(shè)置默認(rèn)配置插件

          export?default?api?=>?{
          ??api.modifyDefaultConfig(config?=>?{
          ????return?Object.assign({},?config,?{
          ??????title:?false,
          ??????history:?{
          ????????type:?'hash'
          ??????},
          ??????hash:?true,
          ??????antd:?{},
          ??????dva:?{
          ????????hmr:?true
          ??????},
          ??????dynamicImport:?{
          ????????loading:?'@/components/PageLoading'
          ??????},
          ??????targets:?{
          ????????ie:?10
          ??????},
          ??????runtimePublicPath:?true,
          ??????terserOptions:?{
          ????????compress:?{
          ??????????drop_console:?true
          ????????}
          ??????}
          ????});
          ??});
          }

          Umi2 升級(jí)到 Umi3 的優(yōu)勢(shì)

          組內(nèi)電商項(xiàng)目在升級(jí)之前使用的是內(nèi)嵌 umi2antd-design-pro4, 雖然可以滿足業(yè)務(wù)開(kāi)發(fā),但是模板依然還是有較多不符合業(yè)務(wù)的部分,比如權(quán)限校驗(yàn)這塊。

          Umi3 的發(fā)布也帶來(lái)更好的架構(gòu)和開(kāi)發(fā)體驗(yàn)

          • 配置層做了大量精簡(jiǎn)
          • 最新的 Umi3 插件提供了 Layout, 數(shù)據(jù)流,權(quán)限等新方案
          • 終于把模板內(nèi)的權(quán)限相關(guān)代碼內(nèi)置化了

          基于 Umi 搭建腳手架模板

          基于 Umi 搭建內(nèi)部中臺(tái)腳手架模板如下圖顯示

          基于 Umi 此腳手架模板擴(kuò)展了如下能力

          • 編譯打包符合公司 beetle(內(nèi)部 CI/CD 平臺(tái))部署規(guī)范的 dist 目錄
          • 自定義默認(rèn)配置插件,減少配置項(xiàng)配置
          • eslint 校驗(yàn)
          • prettier 格式化代碼
          • git 提交規(guī)范
          • 結(jié)合 pro-layout 實(shí)現(xiàn)更加方便的布局
          • 利用運(yùn)行時(shí)配置 app.js 動(dòng)態(tài)生成本地和遠(yuǎn)程相結(jié)合的配置式導(dǎo)航菜單
          • 結(jié)合 plugin-access 插件和內(nèi)部權(quán)限系統(tǒng)實(shí)現(xiàn)頁(yè)面或按鈕級(jí)別權(quán)限控制

          新建項(xiàng)目根據(jù)公司內(nèi)的腳手架工具選擇中臺(tái)模板可快速創(chuàng)建帶有權(quán)限、布局、代碼規(guī)范、通用頁(yè)面等功能的初始項(xiàng)目,可以很大的避免重復(fù)工作。

          總結(jié)

          Umi 提供了開(kāi)箱即用能力, 你不需要配置 webpack,babel 這些,最佳實(shí)踐配置已內(nèi)置化。當(dāng)然也可以自定義開(kāi)發(fā)插件擴(kuò)展。Umi 在性能上做了很多努力,這些對(duì)于開(kāi)發(fā)者是無(wú)感知的。

          稍有不足的是 Umi 對(duì) webpack-dev-server 配置開(kāi)放較少,如果有對(duì) webpack-dev-server 有比較大配置需求則需要考量一下~~


          ●?你不知道的 Animation 動(dòng)畫技巧

          ●?前端入門機(jī)器學(xué)習(xí) Tensorflow.js 簡(jiǎn)明教程

          ●?Taro 支持使用 Vue3 開(kāi)發(fā)小程序



          ·END·

          圖雀社區(qū)

          匯聚精彩的免費(fèi)實(shí)戰(zhàn)教程



          關(guān)注公眾號(hào)回復(fù) z 拉學(xué)習(xí)交流群


          喜歡本文,點(diǎn)個(gè)“在看”告訴我

          瀏覽 56
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日韩特黄 | A黄色视频网站 | 操逼动视频 | 麻豆久久爱 | 夜色视频在线播放 |