使用react-router做延遲加載路由配置

情景描述

  • 客戶要求我們首次打開頁面的時候必須在1s之內(nèi)
  • 可是項目很大,首頁加載模塊體積大首屏加載時間長
  • 為了解決這個問題項目中使用按需加載路由配置這種方式
  • 將router寫成了如下的樣子
import {AppContainer} from 'containers'

export const routes = {
const errorLoading = _ => _ // console.error('Dynamic loading failed' + err)

const loadRoute = cb =>
  module => cb(null, module.default)


export const routes = {
  component: AppContainer,
  path: '/',
  indexRoute: {
    getComponent(location, callback) {
      import('./containers/User/LandingPageContainer')
        .then((module) => {
          callback(null, module.default)
        })
        .catch(err => errorLoading(err))
    }
  },
  childRoutes: [
    {
      path: '/admin',
      getChildRoutes(partialNextState, callback) {
        import('./containers/Admin/routes')
          .then(loadRoute(callback))
          .catch(err => errorLoading(err))
      },
      onEnter: checkInvalidRoleAndRedirect
    },
    {
      path: '/wms/create',
      getComponent(nextState, callback) {
        import('./containers/WMS/CreateOrderContainer')
          .then(loadRoute(callback))
          .catch(err => errorLoading(err))
      }
    }
  ]
}
  • 導(dǎo)致我完全不能明白。。。。

解釋

  • Q1:這種寫法和以前的使用標簽區(qū)別是啥呢?
<BrowserRouter>
      <Route path="/tacos" component={Tacos}/>
    </div>
</BrowserRouter>
  • A1:區(qū)別:

    • 使用標簽的寫法webpack會把所有的文件全部打包在一個main.*****.js文件,也就是說這時候龐大的項目中所有js代碼全部都被打包到一個js文件中。會造成的問題
      • 當用戶請求首頁,首頁的代碼以及項目中所有的代碼全部都在main.****.js文件中。
      • 為了將首頁render出來,必須將這個非常大的js文件請求回來
      • 因此非常耗時
    • 使用項目中的寫法
      • webpack會通過import()這個方法作為code spliting的分割點,然后將龐大的項目根據(jù)分割點分成若干的chunk.js文件。
      • 然后當你訪問首頁的時候
      • 我們只需要請求首頁的chunk.js文件即可
      • 這時候每次請求的內(nèi)容大大減少,時間就會減小
  • Q2: 按需加載又是什么樣的概念呢?

  • A2: 按需加載很好理解,需要什么加載什么,問題在于如何保證你需要的都能加載進來,你不需要的都不加載進來呢?重點在于我們通過webpack將文件打包成靜態(tài)文件,部署到服務(wù)器,要做到按需加載(按需請求),就必須要求webpack做到合適的分隔項目并且將他們打包到不同的文件(chunk文件中)所以要實現(xiàn)好的按需加載必須要要求webpack能夠做好將不同的代碼打包到不同的文件。


  • Q3:那么webpack又是如何分割項目并打包到不同的文件中呢?
  • A3:webpack提供了code splitting特性,此特性能夠把代碼分離到不同的bundle文件實現(xiàn)按需加載。在webpack的官網(wǎng)介紹了三種實現(xiàn)code splitting,采用動態(tài)導(dǎo)入的方式,結(jié)合es6提出的import(和promise)作為code splitting分割點,將不同本部分分別打包在不同的chunk文件中。
    • ps:webpack主要有兩種代碼分割的分割點選擇方式:
      • 1.import
      • 2.require.ensure

  • Q4:import是什么和我們之前的模塊引入使用import不是一個東西嗎?
  • A4:兩種import分別是同步和異步加載模塊(也可以看做靜態(tài)和動態(tài)的引入模塊),兩種引入方式的最大區(qū)別在:
    • import App from './component/app':編譯時加載模塊,因此必須寫在每個模塊的最上方,寫在編譯時候不會執(zhí)行的地方就會失效(比如寫在if里面),只能做靜態(tài)引入不能做動態(tài)引入
    • import('./component/app').then((module)=>{console.log('this is dynamic import module',module.default)}).catch(err=> 'dynamic import failed'):是運行時加載模塊(和require一樣),所以只有import()和require能夠做到動態(tài)引入
      • require和import之間的區(qū)別又是什么呢?
        • require:是同步的
        • import:返回的是promise是異步的

  • Q5:那么使用webpack做按需加載需要配置什么嗎? 代碼中又要做什么樣的改變呢?
  • A5:改變需要分成兩個部分:
    • webpack配置上的改變:配置需要做的改變基本沒有,頂多就是配置一下chunk文件的名字
    ```js
    entry: {
        chunkFilename: '[name].[chunkhash:5].chunk.js',
        //給生成的chunk文件確定命名規(guī)范,name在沒有設(shè)置的時候默認使用id
        //chunkhash:5 5位hash碼
    
    }
    - 代碼上的改變:這里主要針對react實現(xiàn)按需加載,如果想要對react實現(xiàn)按需加載,那么就需要webpack和react-router之間的配合。so react-router實現(xiàn)按需加載該怎么配置(主要分成兩個部分):
    - 實現(xiàn)組件的按需引入:react-router提供了方法代替相應(yīng)屬性實現(xiàn)對相應(yīng)路由組件的異步掛載
      - getComponent: 代替Route標簽的component實現(xiàn)當訪問到當前路徑的時候再執(zhí)行該方法加載組件
        - 參數(shù)有兩個
          - location:是一個對象包含當前的所有路由中能獲取的信息
          - callback:回調(diào)函數(shù),用于異步引入組件成功后調(diào)用
            - 參數(shù)有兩個: 
              - error(如果沒有error這個參數(shù)在調(diào)用的時候?qū)懗蒼ull,如果不寫成null,那么在當前路由下就會報出Require.ensure error的錯誤)
              - 組件:請注意如果你是用的是import引入組件那么promise返回的數(shù)據(jù)應(yīng)該是整個module對象,而不是你的組件
                - 如果在module使用default暴露:那么callback的第二參數(shù)必須是module.default
                - 如果在module中使用export const a、export const那么第二個參數(shù)必須是module.a或者module.b
      - getChildRoutes:代替某個Route的子組件實現(xiàn)異步加載child組件(大有作用??! 下一篇簡書介紹)
      - getIndexRoute: 但是實踐過后發(fā)現(xiàn)使用失敗不知道為什么,所以換成了`indexRoute: { getComponent()}`
    - 寫明code splitting的分割點:之前提到過有兩種分割方式
      - 使用webpack 提供的require.ensure實現(xiàn):用這個方法定義分割點獨立打包chunk
      - 使用es6的動態(tài)import實現(xiàn):參數(shù)是引入module的地址   方法返回promise 回調(diào)函數(shù)的參數(shù)中包含module
    ```js
      import AppContainer from './components/AppContainer'
      import LandingPageContainer from './containers/User/LandingPageContainer'
      import CreateOrderContainer from './containers/WMS/CreateOrderContainer'
      <Router>
         <Route path='/' component={AppContainer}>
           <IndexRoute component={LandingPageContainer} />
           <Route path='/wms/creat' component={CreateOrderContainer} />
         </Route>
      </Router>
      //原來的寫法  所有的組件都是靜態(tài)引入,也就意味這在編譯的時候就必須將所有引入的文件(也就是項目中所有的組件)打包在一個js文件中,當瀏覽器沒有緩存的時候,第一次請求就要把一個很大的js文件請求回來
      
    

  • Q6:那么對于第三方模塊如何實現(xiàn)性能的提升呢?
  • A6: 采用將所有的第三方庫的全部都打包到一個js文件,原因:
    - 由于這一部分內(nèi)容不怎么需要變化,所以打包好之后就放在一個js文件中不動了
    - 這樣既有利于緩存而且不需要重復(fù)打包。
    - 但是剝離第三方庫主要對于開發(fā)的時候會加快打包速度
    - 可以使用commonChunkPlugin來實現(xiàn)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • GitChat技術(shù)雜談 前言 本文較長,為了節(jié)省你的閱讀時間,在文前列寫作思路如下: 什么是 webpack,它要...
    蕭玄辭閱讀 12,918評論 7 110
  • 版權(quán)聲明:本文為博主原創(chuàng)文章,未經(jīng)博主允許不得轉(zhuǎn)載。 webpack介紹和使用 一、webpack介紹 1、由來 ...
    it筱竹閱讀 11,487評論 0 21
  • 目錄第1章 webpack簡介 11.1 webpack是什么? 11.2 官網(wǎng)地址 21.3 為什么使用 web...
    lemonzoey閱讀 1,839評論 0 1
  • 工作能力實質(zhì)上就是能夠不斷解決問題的能力,但是很多人在這方面都存在或這或那的問題。那么出現(xiàn)這些問題的原因在哪呢?我...
    登浩閱讀 1,221評論 0 12
  • 1上午參加當?shù)匦聫V告法的學(xué)習(xí),深深理解公司為什么一再規(guī)范我們的分享內(nèi)容。 2學(xué)習(xí)亓克版的邁向富足對于如何更好講解邁...
    環(huán)保天使尹宏閱讀 344評論 0 0

友情鏈接更多精彩內(nèi)容