国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

React 歷史項目維護與優化實踐

toddmark / 1006人閱讀

摘要:本文介紹了作者接手維護一個中型歷史項目時的一系列改進實踐,包括模塊結構拆分業務邏輯梳理打包優化等。代碼中如菜單名稱結構表單字段名等的各種硬編碼配置分散在各處。最后,在提升面向開發者的打包體驗方面,本次優化中主要實現的是與的解耦。

本文介紹了作者接手維護一個中型 React 歷史項目時的一系列改進實踐,包括模塊結構拆分、業務邏輯梳理、Webpack 打包優化等。

背景

這是一個 PC 的管理后臺類項目,沒有引入 react-router 和 redux。待維護的頁面所有模板和邏輯全部在一個千行級的 JSX 中實現,包括調用組件庫、發送 fetch 請求、切換子頁面狀態等。并且,該項目實際上并不是單頁應用,而是通過 Webpack 區分多個 entry 的方式實現了多入口頁面。

模塊拆分

在開始實現新增需求前,首先要做的是了解代碼,整理其結構并適當地以拆分模塊的形式逐步重構之。在這一步中,并不涉及最令人畏懼的【重構業務邏輯】,而更多地是【更高級的代碼美化】,在完整保留原有代碼邏輯和調用方式的前提下,利用一些 JS 的技巧,按照單一職責原則拆分不同的業務邏輯代碼到不同的模塊中,以提高【面條代碼】的模塊化程度。這一步處理要解決的主要問題是:

歷史代碼中混雜了 JSX 模板結構、數據處理、異步控制、狀態管理的各種邏輯。

代碼中如菜單名稱結構、表單字段名等的各種硬編碼配置分散在各處。

幾乎全部的業務邏輯均在一個扁平的組件中實現。

解決上述問題,并不涉及到具體業務邏輯的重寫,而是通過將同類功能提取為獨立模塊,通過一些簡單的語法糖來保證僅更改盡量少的業務代碼,就能實現初步的模塊拆分。

針對上述的幾個問題,初步的模塊拆分包括:

包含大多數 React 組件方法的主頁面組件。

包含異步請求的 action 模塊。

包含各種硬編碼配置的 consts 模塊。

包含調用組件庫中表單等組件的配置文件 model 模塊。

然后就可以一步步將代碼邏輯遷移到新模塊中,在保證頁面的功能不受影響的前提下逐步實現初步的模塊拆分了。這個過程中多次用到的技巧包括:

將執行異步請求的組件方法拆分至模塊中,再在構造器中 bind 回組件。如一個典型的查詢邏輯:

// main.js
class Demo extends Component {
  fetchData () {
    fetch("...").then(data => {
      // 此處通常有冗長的業務邏輯
      this.setState({ data })
    })
  }
}

可將其先拆分至 action.js 模塊中,形如:

// action.js
// 業務邏輯完全保留,只是添加了 export function 前綴
export function fetchData () {
  fetch("...").then(data => {
    this.setState({ data })
  })
}

然后在原組件中加載并 bind 該函數,從而實現模塊拆分:

import { fetchData } from "./actions"
 
class Demo extends Component {
  constructor() {
    // 在此 bind 即可
    this.fetchData = fetchData.bind(this)
  }
}

以及,將一些加載時引用了 this 的配置對象封裝至新模塊的工廠函數中:

render() {
  // 包含冗長表單配置的配置變量
  const demo = {
    // 直接將其提取至新模塊在此會報錯
    value: this.state.xxx
  }
}

新建一個返回 demo 的工廠函數:

// model.js
export const getDemo  = () => ({
  // 在此的業務代碼同樣可原封不動地移動
  value: this.state.xxx
})

修改原有位置的調用邏輯:

import { getDemo } from "./model"

render() {
  // 在調用工廠函數時綁定上下文,即可使模塊中 this 指向正確
  const demo = getDemo.call(this)
}

實踐中在這一步完成后,其實已經實現【將千行級代碼拆分至若干個百行級的模塊,每個模塊均僅包含類似的邏輯功能】了。

業務梳理

在初步整理模塊后,對代碼結構也有了初步的了解,此時可以開始添加一些新的業務需求了。這時,對于與新需求相關的原有代碼,可以在理解基礎上進行梳理與局部的重構,以實現新功能(注意這時重構是為了實現新功能,而非重寫原有代碼以實現相同功能)。

這一步主要需要解決的問題是:

原代碼中有較多晦澀的 if-else 控制流邏輯,包含對某些狀態的組合判斷,這對新加入業務代碼會有一定的障礙。

在 JSX 中大量【嵌套的三目表達式】長度很長且不易讀(這實際上是 JSX 相對模板天生的問題),這也造成了一定的困擾。

由于業務邏輯的復用價值較低,這里較難通過代碼的形式給出【最佳實踐】的代碼,但通用的處理模式可總結如下:

通過一些簡單的 log 來判斷一個事件觸發流程中,基本的代碼調用和執行順序。

對執行過程中遇到的組件狀態,在 React 開發工具中確認 state / props 執行前后的變化,確定【某段業務邏輯所依賴的組件狀態,及其觸發前后的組件狀態】

以【編寫輸入新需求下輸入狀態,輸出新需求下輸出狀態】為目標,維護并編寫新業務邏輯代碼。

新邏輯完成后,逐步注釋并最終替換掉老代碼,漸進地實現業務需求。

在這一步達到較高的完善程度后,可以重新審視新增的代碼段做局部重構,或提取一些可復用的邏輯到上一步中的相應模塊中。到這一步為止,即可基本上將老項目像個人起手的項目一樣做到較為輕車熟路的開發維護了。

Webpack 優化

在業務需求按時完成的前提下,才有必要進行這一步的優化。對一個配置文件多達數百行的穩定期項目,切換當時的 Webpack 1 到 Webpack 2 難度較大,但相應的意義卻并不大。因此,在構建方向上的優化策略最后以這幾條為主:

分析多頁面的公共依賴配置,優化公共依賴提取,去除冗余依賴。

修復已知問題。

優化構建速度。

首先,在優化公共依賴方面,難點并不是【如何更改公共依賴】,而是如何獲知【有哪些依賴需要被提取為公共依賴】。在這方面,需要的是一個查看各 Bundle 內容及尺寸的可視化工具,可以使用 webpack-bundle-analyzer 這一 Webpack 插件來實現。使用該插件的方式也很簡單,直接將其添加在 Webpack 的 plugins 配置中,重新執行打包命令即可。打包成功后,會彈出瀏覽器窗口展示各 Bundle 的公共依賴,如下圖是優化前的公共依賴配置:

可以發現原始的依賴配置中,位于圖中角落的 common 包僅包括了原始的 React,而組件庫、lodash、moment 等依賴在每個頁面包中都重復出現了。因此,在 Webpack 的 entry 配置字段中,為 common 包添加 ["babel-polyfill", "lodash", "moment"] 等依賴名后,即可實現公共依賴的提取。

實際上,提取公共依賴并不能減少每個頁面最終的打包輸出體積。只有去除冗余依賴,才能直接影響頁面最終的包大小。那么這樣的冗余依賴是否存在呢?答案是肯定的。在排查過程中發現,導入 moment 這一非常常用的時間庫時,會默認導入其對應的多語言依賴 locale 包,而這對當前項目是完全無用的。對于這種【依賴本身依賴了冗余依賴】的情形,Webpack 同樣提供了優化方案。在 Plugins 中添加如下的一行即可:

new webpack.IgnorePlugin(/^./locale$/, /moment$/)

這一行代碼能夠直接減少開發環境 300K 的包大小!在進行了依賴優化后,得到的包體積可視化為下圖:

可以發現,common 的大小得到了大幅增加,而各個頁面的業務包體積則減少了 2/3 以上。不過,在這個優化方向上并沒有做到極致。由于 Webpack 1 不支持原生的 Tree Shaking 功能,導致了 UI 組件庫即便通過 import { xxx } 語法引入,最終還是會將整個組件庫導入公共依賴包中,沒有做到按需加載。而相應的 import 插件又存在配置上的不便,其結果是最終沒有在這個項目中實現 UI 組件庫的按需加載。當然,隨著 Webpack 2 的普及,新項目中這應當不會成為問題。

接下來,在修復已知問題方面,優化過程中修復了兩個較為常見的問題:common 包隨業務包變更而變更的問題;hash 值每次全量變更的問題。

在直接通過 CommonsChunkPlugin 拆分 common 包的配置方式下,每個頁面最終使用的包都是 common 包和業務包兩個。這時,在頁面 A 中修改業務邏輯,會造成 common 包的細微變動,導致新的打包文件中,common 包雖然沒有源碼變更,卻隨著業務包的變更而變更了。這會導致每次版本更新時包括 common 在內的所有包都會被全量更新,沒有實現按需的更新。

解決方案是,在 CommonsChunkPlugin 的配置中,將 name 字段改為 names 字段,提供 ["common", "manifest"] 兩個公共依賴入口。這樣,在業務包變動時,只有 manifest 會隨之變動,而 common 的內容不會受到影響,這也就實現了真正意義上的按需更新,更大限度地利用瀏覽器緩存。雖然這一實踐實際上是 Webpack 2 文檔中官方的推薦做法,但 Webpack 1 也完全支持。

另一個問題是,每次打包的產物文件中雖然都附帶了一個 hash 值,但對所有打包文件,該值都是一樣的。這同樣會導致僅有某個 bundle 變更時,全量的生產包名稱變更,造成緩存的失效。相應的解決方案也很簡單:將 output 配置字段中的 [hash] 改為 [chunkhash],即可為每個包添加不同的 hash 值。

最后,在提升面向開發者的打包體驗方面,本次優化中主要實現的是 lint 與 Webpack 的解耦。在使用 IDE 開發時,lint 的引入較為繁瑣,因此當時采用的是將 lint 作為 Webpack 的 loader 形式引入,在每次增量打包后執行 lint,對存在不符合風格指南的代碼在終端報錯并不予編譯通過的策略。這個模式兼容性繞過了編輯器和 IDE 的配置,因而更加通用,但問題在于:

每次打包都需要重復的 lint 過程,降低了打包速度。

lint 規則較嚴格時,調試過程受到了較大的限制。如 class 方法必須存在對 this 的引用、函數參數必須全部被使用、不允許 return 后存在業務邏輯等 lint 策略,它們雖然確實能提高代碼質量,但在調試過程中局部存在這樣的代碼非常常見,禁止編譯這些不存在語法問題的代碼,對開發效率存在較大的影響。

因而,在優化中果斷去除了 Webpack 的 lint 配置,轉而通過 VSCode 等編輯器的 lint 插件實現開發過程中的動態 lint 提示和自動美化。另外,對 Webpack 每次打包的輸出格式也進行了優化,去除了較多冗余的包信息 log 內容,僅保留每次打包的 hash 信息即可。最后的開發體驗與新 Webpack 2 項目相近,實現了一定的開發效率提升。

總結

在維護過程中,首先還是理解已有業務代碼,然后循序漸進地走改良路線,而不應以【老代碼好亂】為理由貿然重寫,這會存在很大的風險。雖然 React 本身設計較為松散,使得開發者更容易產出較無序的代碼,但 JS 目前的模塊和 OO 機制為無需重寫的填坑提供了很大的幫助,實踐中最后本質上重寫的也只有新需求相關的部分,已有的邏輯得到了盡可能的保留和復用。而性能優化則屬于錦上添花的【折騰向】內容,優先級較低,可以在時間相對寬松的時候處理,優化方式上也有較多的工具和插件支持,相對需要實際編碼的業務而言,難度較低。

希望以上實踐經驗對于更多開發者的踩坑 / 填坑路能夠有所幫助。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/83198.html

相關文章

  • 前端每周清單第 49 期:Webpack 4 Beta 嘗鮮,React Windowing s

    摘要:盡管等待了多年,但是最終還是發布了正式版本與上一個版本相比未有重大變化,主要著眼于部分錯誤修復與提升。能夠將異步函數移入獨立線程中,可以看做函數的單函數簡化版。不過需要注意的是,僅支持純函數,其會在獨立的作用域中運行這些函數。 showImg(https://segmentfault.com/img/remote/1460000013038757); 前端每周清單專注前端領域內容,以對...

    muzhuyu 評論0 收藏0
  • android知識大總結 - 收藏集 - 掘金

    摘要:中簡單搞定接口訪問,以及簡析掘金最近總結的一些經驗,對于或中使用接口的一些心得。這里,本文將數據結構之學習總結掘金前言前面介紹了的數據結構,今天抽空學習總結一下另一種數據結構。淺析事件傳遞掘金中的事件傳遞主要涉及三個方法和。 Android 系統中,那些能大幅提高工作效率的 API 匯總(持續更新中...) - 掘金前言 條條大路通羅馬。工作中,實現某個需求的方式往往不是唯一的,這些不...

    luodongseu 評論0 收藏0
  • 前端每周清單第 50 期: AngularJS and Long Term Support, Web

    摘要:在該版本發布之后,開發團隊并不會繼續發布新的特性,而會著眼于進行重大的錯誤修復。發布每六個星期,團隊就會創建新的分支作為發布通道,本文即是對新近發布的版本進行簡要介紹。 showImg(https://segmentfault.com/img/remote/1460000013229009); 前端每周清單專注前端領域內容,以對外文資料的搜集為主,幫助開發者了解一周前端熱點;分為新聞熱...

    DobbyKim 評論0 收藏0
  • 方案設計--如何看待前端框架選型 ?

    摘要:純前端開發主要是針對靜態頁面。自主權最大,正常是使用進行輔助開發,上線等。大致原因使用是為了和端的保持同步。四總結對于比較正式的項目,前端技術選型策略一定是產品收益最大化,用戶在首位。 對于前端團隊,可以實現企業受益最大化要點。 一、技術選型的策略 1、保證產品質量 (1)功能穩健:網頁不白屏,不錯位,不卡死;操作正常;數據精準。 (2)體驗優秀:加載體驗,交互體驗,視覺體驗,無障礙訪...

    gnehc 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<