router-router 4 按需載入實踐
1. 前言
隨著前端項目的不斷擴大,一個原本簡單的網頁應用所引用的js文件可能變得越來越龐大。尤其在近期流行的單頁面應用中,越來越依賴一些打包工具(例如webpack),通過這些打包工具將需要處理、相互依賴的模塊直接打包成一個單獨的bundle文件,在頁面第一次載入時,就會將所有的js全部載入。但是,往往有許多的場景,我們並不需要在一次性將單頁應用的全部依賴都載下來。例如:我們現在有一個帶有許可權的"訂單後台管理"單頁應用,普通管理員只能進入"訂單管理"部分,而超級用戶則可以進行"系統管理";或者,我們有一個龐大的單頁應用,用戶在第一次打開頁面時,需要等待較長時間載入無關資源。這些時候,我們就可以考慮進行一定的代碼拆分(code splitting)。
2. 實現方式2.1 簡單的按需載入
代碼拆分的核心目的,就是實現資源的按需載入。考慮這麼一個場景,在我們的網站中,右下角有一個類似聊天框的組件,當我們點擊圓形按鈕時,頁面展示聊天組件。
從這個例子中我們可以看出,通過將載入chat.js的操作綁定在btn點擊事件上,可以實現點擊聊天按鈕後聊天組件的按需載入。而要動態載入js資源的方式也非常簡單(方式類似熟悉的jsonp)。通過動態在頁面中添加 標籤,並將 屬性指向該資源即可。
代碼拆分就是為了要實現按需載入所做的工作。想像一下,我們使用打包工具,將所有的js全部打包到了bundle.js這個文件,這種情況下是沒有辦法做到上面所述的按需載入的,因此,我們需要講按需載入的代碼在打包的過程中拆分出來,這就是代碼拆分。那麼,對於這些資源,我們需要手動拆分么?當然不是,還是要藉助打包工具。下面就來介紹webpack中的代碼拆分。
3. 代碼拆分
這裡回到應用場景,介紹如何在webpack中進行代碼拆分。在webpack有多種方式來實現構建是的代碼拆分。
3.1 import()
這裡的import不同於模塊引入時的import,可以理解為一個動態載入的模塊的函數(function-like),傳入其中的參數就是相應的模塊。例如對於原有的模塊引入 可以寫為 。但是需要注意的是, 會返回一個 對象。因此,可以通過如下方式使用:
可以看到,使用方式非常簡單,和平時我們使用的 並沒有區別。當然,也可以再加入一些異常處理:
當然,由於 會返回一個 對象,因此要注意一些兼容性問題。解決這個問題也不困難,可以使用一些 的polyfill來實現兼容。可以看到,動態 的方式不論在語意上還是語法使用上都是比較清晰簡潔的。
3.2 require.ensure()
在webpack 2的官網上寫了這麼一句話:
require.ensure()is specific to webpack and superseded byimport().
所以,在webpack 2裡面應該是不建議使用 這個方法的。但是目前該方法仍然有效,所以可以簡單介紹一下。包括在webpack 1中也是可以使用。下面是 的語法:
接受三個參數:
因此, 具體的用法如下:
3.3 Bundle Loader
除了使用上述兩種方法,還可以使用webpack的一些組件。例如使用Bundle Loader:
使用 來進行相應chunk的載入。該方法會返回一個 ,這個 接受一個回調函數作為參數。
和其他loader類似,Bundle Loader也需要在webpack的配置文件中進行相應配置。Bundle-Loader的代碼也很簡短,如果閱讀一下可以發現,其實際上也是使用 來實現的,通過給Bundle-Loader返回的函數中傳入相應的模塊處理回調函數即可在 的中處理,代碼最後也列出了相應的輸出格式:
4. react-router v4 中的代碼拆分
最後,回到實際的工作中,基於webpack,在react-router4中實現代碼拆分。react-router 4相較於react-router 3有了較大的變動。其中,在代碼拆分方面,react-router 4的使用方式也與react-router 3有了較大的差別。
在react-router 3中,可以使用 組件中 這個API來進行代碼拆分。 是非同步的,只有在路由匹配時才會調用。但是,在 中並沒有找到這個API,那麼如何來進行代碼拆分呢?
在react-router 4官網上有一個代碼拆分的例子。其中,應用了Bundle Loader來進行按需載入與動態引入
然而,在項目中使用類似的方式後,出現了這樣的警告:
Unexpected "!" in "bundle-loader?lazy!./component/chat". Do not use import syntax to configure webpack loadersimport/no-webpack-loader-syntax
Search for thekeywordsto learn more about each error.
在webpack 2中已經不能使用import這樣的方式來引入loader了(no-webpack-loader-syntax)
Webpack allows specifying the loaders to use in the import source string using a special syntax like this:
This syntax is non-standard, so it couples the code to Webpack. The recommended way to specify Webpack loader configuration is in aWebpack configuration file.
我的應用使用了create-react-app作為腳手架,屏蔽了webpack的一些配置。當然,也可以通過運行 使其暴露webpack等配置文件。然而,是否可以用其他方法呢?當然。
這裡就可以使用之前說到的兩種方式來處理: 或 。
和官方實例類似,我們首先需要一個非同步載入的包裝組件Bundle。Bundle的主要功能就是接收一個組件非同步載入的方法,並返回相應的react組件:
在原有的例子中,通過Bundle Loader來引入模塊:
注意:
由於不再使用Bundle Loader,我們可以使用 對該段代碼進行改寫:
需要注意的是,由於 會返回一個 對象,因此 組件中的代碼也需要相應進行調整
路由部分沒有變化
這時候,執行 ,可以看到在載入最初的頁面時載入的資源如下
而當點擊觸發到/post路徑時,可以看到
動態載入了 這個js文件,如果打開這個文件查看,就可以發現這個就是我們剛才動態 進來的模塊。
當然,除了使用 仍然可以使用 來進行模塊的非同步載入。相關示例代碼如下:
此外,如果是直接使用webpack config的話,也可以進行如下配置
5. 結束
代碼拆分在單頁應用中非常常見,對於提高單頁應用的性能與體驗具有一定的幫助。我們通過將第一次訪問應用時,並不需要的模塊拆分出來,通過 標籤動態載入的原理,可以實現有效的代碼拆分。在實際項目中,使用webpack中的 、 或者一些 (例如Bundle Loader)來做代碼拆分與組件按需載入。
後續打算弄一個腳手架出來
本項目地址: geekjc-antd-mobile
極客教程
分享編程知識
關注,每天推送好內容!
TAG:極客教程 |