UmiJS開發技巧


UmiJS開發技巧

2020年06月23日 18:48  ·  閱讀 11807

UmiJS開發技巧

鑒於 UmiJS 是重度的封裝了很多工具和功能,對於剛接觸的人形成了一層技術壁壘(大佬請忽略這句話)。所以我總結了使用UmiJS 開發中遇到的坑和技巧。

本地開發 umi dev 時關閉 mock

參考: 希望本地開發 umi dev 時可以關閉 mock

方案一(推薦):在 npm scripts 中加入以下指令:

{
  "scripts": { "dev": "MOCK=none umi dev" } } 復制代碼

方案二:在 .env 文件里 設置 MOCK=none 也可以關閉

jsx無法轉到定義處

在 jsconfig.json 文件中進行如下配置:

{
  "compilerOptions": { "jsx": "react" } } 復制代碼

在umi中如何訪問靜態資源

在umi框架中,圖片等靜態資源主要放到三個地方:

  1. 在 /public 目錄下,一般放共享資源。
  2. 在 /src/assets/ 目錄下,一般放全局靜態資源。
  3. 在 /src/pages/ 里的各個頁面目錄下,放在這里的好處是更符合組件化開發的思想,便於拷貝復用。

由於靜態資源會受 context.config.publicPath 的影響,所以在 document.ejs 中應該這樣引入比較安全:

<script type="text/javascript" src="<%= context.config.publicPath %>ol.js" /> 復制代碼

如何訪問靜態圖片

1、如果在/public目錄下的靜態圖片,可以直接輸入絕對路徑,假設/public/yay.jpg,訪問方式如下:

<img src="/yay.jpg" />

注意:以上必須構建后在dist中才能看到。

2、在 /src/assets 和 /src/pages/ 目錄下的圖片,不能通過輸入絕對路徑訪問,必須先 import 導入,才能訪問。或者 require 導入。比如 /src/assets/yay.jpg 需:

import yayImg from '/src/assets/yay.jpg'; <img src={yayImg} /> <img src={require('/src/assets/yay.jpg')} 復制代碼

為什么會這樣呢?主要是因為構建時,/public 目錄下的文件會原樣復制到 /dist/ 目錄下,而 /src/assets/ 和 /src/pages/ 目錄下的文件會被改名並復制到 /dist/ 下。

react-router三種傳參方式

參考: react-router三種傳參方式

import { Component } from 'react' import router from 'umi/router' const RouterDemo = () => { const onOk = () => { router.push({ pathname: 'test/router', // 點擊之后,頁面會跳轉且地址上會跟上query的參數,?id=1&code=123 // 獲取方式傳值內容的方式: this.props.location.query query: { id: '1', code: '123', }, // 點擊之后,頁面會跳轉 // 通過this.props.location.params可以獲得params的值 // params可以為其他名字,如text、nihao等,不一定是params // 刷新頁面后,params的值會丟失。 params: { d: '1', code: '123', }, // 使用state傳值和params傳值一樣,都不會再url中顯示出來 // state傳值與params傳值的區別是state傳值刷新頁面值還在,而使用params傳值刷新后值不沒有了。 state: { d: '1', code: '123', }, }) } return <div onClick={this.onOk}>點擊測試</div> } 復制代碼

修改瀏覽器上方圖標

參考: HTML 配置模板

<!-- 圖片在 /public 下 --> <link rel="icon" type="image/x-icon" href="<%= context.publicPath %>favicon.png" /> <!-- 圖片在 /src/assets/ 下--> <link rel="icon" type="image/x-icon" href="<%= context.publicPath %>static/favicon.png" /> 復制代碼

支持 ie11

參考: ie11兼容問題

配置瀏覽器最低版本,會自動引入 polyfill 和做語法轉換,配置的 targets 會和合並到默認值,所以不需要重復配置:

// umi默認兼容最低瀏覽器版本 // Default: { chrome: 49, firefox: 45, safari: 10, edge: 13, ios: 10 } export default { targets: { ie: 11, }, }; 復制代碼

編譯 node_modules 下的包

UmiJS 2.x

參考: How to configure extraBabelIncludes

const path = require('path'); { extraBabelIncludes: [path.resolve(__dirname, 'node_modules/<package_name>')], } 復制代碼

UmiJS 3.1+

參考: nodeModulesTransform如何做編譯提速

UmiJS 3 刪除了 extraBabelIncludes 和 es5ImcompatibleVersionsnode_modules 也走 babel 編譯后就沒有意義了,無需配置

UmiJS 3 默認編譯 node_modules 下的文件,帶來一些收益的同時,也增加了額外的編譯時間。如果不希望 node_modules 下的文件走 babel 編譯,可通過以下配置減少 40% 到 60% 的編譯時間。

export default { nodeModulesTransform: { type: 'none', exclude: [], // 忽略的依賴庫,包名,暫不支持絕對路徑;可通過 exclude 配置添加額外需要編譯的 }, } 復制代碼

並行運行任務

call

參考: 求教多個異步的請求問題?同時執行多個任務

yield 指令可以很簡單的將異步控制流以同步的寫法表現出來,但與此同時我們將也會需要同時執行多個任務,我們不能直接這樣寫:

// 錯誤寫法,effects 將按照順序執行 const users = yield call(fetch, '/users') const repos = yield call(fetch, '/repos') 復制代碼

由於第二個 effect 將會在第一個 call 執行完畢才開始。所以我們需要這樣寫:

// 正確寫法, effects 將會同步執行 *effects({}, { all, call }) { const [users, repos] = yield all([ call(fetch, '/users'), call(fetch, '/repos') ]) } 復制代碼

當我們需要 yield 一個包含 effects 的數組, generator 會被阻塞直到所有的 effects 都執行完畢,或者當一個 effect 被拒絕 (就像 Promise.all 的行為)。

put

參考: yield all中放put而出現的問題

*effects({}, { all, call }) { const [users, repos] = yield all([ yield put({ type: 'getUsers' }), yield put({ type: 'getRepos' }) ]) } 復制代碼

或者使用 put.resolve:

*effects({}, { all, call }) { const [users, repos] = yield all([ put.resolve({ type: 'getUsers' }), put.resolve({ type: 'getRepos' }) ]) } 復制代碼

局部覆蓋antd 樣式

由於業務的個性化需求,我們經常會遇到需要覆蓋組件樣式的情況,這里舉個簡單的例子。

antd Select 在多選狀態下,默認會展示所有選中項,這里我們給它加一個限制高度,超過此高度就出滾動條。

<Select
  mode="multiple" style={{ width: 300 }} placeholder="Please select" className={styles.customSelect} > {children} </Select> 復制代碼
.customSelect { :global { .ant-select-selection { max-height: 51px; overflow: auto; } } } 復制代碼

方法很簡單,有兩點需要注意:

  • 引入的 antd 組件類名沒有被 CSS Modules 轉化,所以被覆蓋的類名 .ant-select-selection 必須放到 :global 中。
  • 因為覆蓋是全局性的。為了防止對其他 Select 組件造成影響,所以需要包裹額外的 className 限制樣式的生效范圍。

優化包大小

參考: H5 分包實現首屏加載時間優化webapck4 玄妙的 SplitChunks Plugin請問如何單獨打包組件

UmiJS 2.x

{
  // 忽略 moment 的 locale 文件,用於減少尺寸。 // https://v2.umijs.org/zh/config/#ignoremomentlocale ignoreMomentLocale: true, // 配置是否開啟 treeShaking,默認關閉。 // https://v2.umijs.org/zh/config/#treeshaking treeShaking: true, // 通過 [webpack-chain](https://github.com/mozilla-neutrino/webpack-chain) 的 API 擴展或修改 webpack 配置。 // https://v2.umijs.org/zh/config/#chainwebpack chainWebpack(config) { config.optimization.splitChunks({ chunks: 'all', automaticNameDelimiter: '~', name: true, minSize: 30000, minChunks: 1, cacheGroups: { echarts: { name: 'echarts', test: /[\\/]node_modules[\\/](echarts)[\\/]/, priority: -9, enforce: true, }, antd: { name: 'antd', test: /[\\/]node_modules[\\/](@ant-design|antd|antd-mobile)[\\/]/, priority: -10, enforce: true, }, vendors: { name: 'vendors', test: /[\\/]node_modules[\\/]/, priority: -11, enforce: true, }, }, }); }, plugins: [ [ // 這是官方封裝的一個插件集,包含 18 個常用的進階功能。 // https://v2.umijs.org/zh/plugin/umi-plugin-react.html#%E5%AE%89%E8%A3%85 'umi-plugin-react', { // 默認是 ['umi'],可修改,比如做了 vendors 依賴提取之后,會需要在 umi.js 之前加載 vendors.js // https://v2.umijs.org/zh/plugin/umi-plugin-react.html#chunks chunks: ['vendors', 'antd', 'echarts', 'umi'], }, ], ], } 復制代碼

UmiJS 3.x

參考 升級 umi-plugin-react 為 @umijs/preset-react

由於 Umi 3 的配置方式是拍平的方式,還需要修改配置:

{
  // 忽略 moment 的 locale 文件,用於減少尺寸。 // https://v2.umijs.org/zh/config/#ignoremomentlocale ignoreMomentLocale: true, // 配置是否開啟 treeShaking,默認關閉。 // https://v2.umijs.org/zh/config/#treeshaking treeShaking: true, // 通過 [webpack-chain](https://github.com/mozilla-neutrino/webpack-chain) 的 API 擴展或修改 webpack 配置。 // https://v2.umijs.org/zh/config/#chainwebpack chainWebpack(config) { config.optimization.splitChunks({ chunks: 'all', automaticNameDelimiter: '~', name: true, minSize: 30000, minChunks: 1, cacheGroups: { echarts: { name: 'echarts', test: /[\\/]node_modules[\\/](echarts)[\\/]/, priority: -9, enforce: true, }, antd: { name: 'antd', test: /[\\/]node_modules[\\/](@ant-design|antd|antd-mobile)[\\/]/, priority: -10, enforce: true, }, vendors: { name: 'vendors', test: /[\\/]node_modules[\\/]/, priority: -11, enforce: true, }, }, }); }, // https://umijs.org/zh-CN/config#chunks chunks: ['vendors', 'antd', 'echarts', 'umi'], } 復制代碼

momentjs

使用中文配置

參考: antd design國際化配置為中文時,日期組件中月與星期顯示為英文,其他顯示為中文

import { LocaleProvider } from 'antd'; import zh_CN from 'antd/lib/locale-provider/zh_CN'; import moment from 'moment'; import 'moment/locale/zh-cn'; moment.locale('zh-cn'); ... return <LocaleProvider locale={zh_CN}><App /></LocaleProvider>; 復制代碼

替換 momentjs

參考: antd-dayjs-webpack-plugin替換 Moment.js基於umi、antd的前端工程優化實踐

請先刪除 ignoreMomentLocale: true 配置再進行以下操作:

yarn add antd-dayjs-webpack-plugin -D
復制代碼
export default { chainWebpack(config) { // antd moment -> dayjs // 如果在 Ant Design 3.x 的項目中使用本插件,需要傳入以下配置,指定 preset。 config.plugin('moment2dayjs').use('antd-dayjs-webpack-plugin', [ { preset: 'antdv3' } ]) } } 復制代碼

如果項目中需要使用中文語言,還要引入dayjs的中文語言包並與antd的ConfigProvider配合服用。

// 設置dayjs中文 import dayjs from 'dayjs' import 'dayjs/locale/zh-cn' dayjs.locale('zh-cn') import { ConfigProvider } from 'antd' import zhCN from 'antd/lib/locale-provider/zh_CN' export default ({children}) => <ConfigProvider locale={zhCN}>{children}</ConfigProvider> 復制代碼

通過上述配置后,使用DatePicker組件拿到的日期與之前一致,但可以直接使用dayjs的API操作日期,moment不復存在。最終dayjs打包體積為14.64KB,減小了330KB之多。

注:目前dayjs@1.8.20后有個bug會導致替換后WeekPicker顯示不正常,1.8.21版本之后已修復。

dva-loading 使用

參考: dva-loading 實踐用法

loading 分為四種使用情況,下面依次用代碼展示:

1、全局

監聽的是應用中所有 effect 是否執行完畢,若執行完畢。loading 的值就變為 false

import React from 'react' const {useSelector,useDispatch} = 'dva' import {Spin} from 'antd' const DemoPage = () => { const {loading} = useSelector(stores => ({ loading: stores.loading })) return ( <Spin spinning={loading.global}/> ) } 復制代碼

2、model

監聽某個模塊的所有 effect 是否執行完畢,若執行完畢。loading 的值就變為 false

import React from 'react' const {useSelector,useDispatch} = 'dva' import {Spin} from 'antd' const DemoPage = () => { const {loading,demoModel} = useSelector(stores => ({ loading: stores.loading, demoModel: stores.loading, })) return ( <Spin spinning={loading.models.demoModel}/> ) } 復制代碼

3、effect:

監聽某個 effect 是否執行完畢,若執行完畢。loading 的值就變為 false

import React from 'react' const {useSelector,useDispatch} = 'dva' import {Spin} from 'antd' const DemoPage = () => { const {loading,demoModel} = useSelector(stores => ({ loading: stores.loading, demoModel: stores.loading, })) return ( <Spin spinning={loading.effects['demoModel/effect1']/> ) } 復制代碼

4、effects

如果想監聽某個 model 中的某幾個 effect,可以使用 || 連接,當全部執行完畢時,返回的是 undefined,所以必須在末尾拼接 || false

import React from 'react' const {useSelector,useDispatch} = 'dva' import {Spin} from 'antd' const DemoPage = () => { const {loading,demoModel} = useSelector(stores => ({ loading: stores.loading, demoModel: stores.loading, })) return ( <Spin spinning={ loading.effects['demoModel/effect1'] || loading.effects['demoModel/effect3'] || loading.effects['demoModel/effect4'] || false } /> ) } 復制代碼

關閉 Umi UI

umi 項目默認啟動 umi ui,會出現一個mini圖標氣泡浮在右下角,關閉有兩種方式,一種是直接用樣式 display none。另一種是在啟動時加上 UMI_UI=none 環境變量。

{
  "scripts": { "start": "UMI_UI=none umi dev", "dev": "MOCK=none UMI_UI=none umi dev", } } 復制代碼

配置多環境

參考: umi如何配置多環境umi define config

1、安裝 cross-env 插件: yarn add cross-env -D

2、在 .umirc.js 文件中添加 define

export default { define: { // 添加這個自定義的環境變量 // 本地開發環境:dev,test環境:test,生產環境:prod "process.env.PRO_ENV": process.env.PRO_ENV }, } 復制代碼

3、package.json 添加 npm scripts

{
  "scripts": { "start": "cross-env PRO_ENV=dev umi dev", "test": "cross-env PRO_ENV=test umi dev", "build": "cross-env PRO_ENV=prod umi build", } } 復制代碼

本文首發於楊俊寧的博客,創作不易,您的點贊👍是我堅持的動力


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM