使用 Webpack 進(jìn)行代碼分片

在使用 React怯屉、Vue 等框架時蔚舀,我們可以使用其配套的路由庫如 react-router 和 vue-router 構(gòu)建單頁應(yīng)用饵沧,以發(fā)揮框架本身的最大威力。
單頁應(yīng)用使我們可以無刷新訪問頁面赌躺,擁有較好的性能和用戶體驗(yàn)狼牺,不再像過去那樣,每開一個頁面都要從服務(wù)器重新請求資源礼患,還可能會因?yàn)榫W(wǎng)絡(luò)的問題等待良久是钥。
單頁應(yīng)用在初次進(jìn)入頁面時就加載全部的資源,后續(xù)除了接口調(diào)用缅叠,幾乎不和服務(wù)器進(jìn)行交互了悄泥,頁面切換無煩惱。
但使用單頁應(yīng)用也有一個問題痪署,就是當(dāng)項(xiàng)目很大時码泞,我們常常打包后的文件常常很大,盡管我們可以嘗試使用 webpack 的 CommonsChunkPlugin 來提取公共代碼狼犯,但隨著項(xiàng)目體積的增大余寥,打包后的代碼還是不夠理想。
由于在訪問第一個頁面時需要加載所有的資源悯森,包括體積龐大的 bundle 文件宋舷,會造成首次加載速度變慢,首屏渲染時間增加等一些列的用戶體驗(yàn)問題瓢姻。為了解決這個問題祝蝠,我們希望有這么一種策略:是否可以在打包時不將所有的文件一起打包,而是只打包最必須的一部分(如首頁幻碱、登錄)绎狭,剩下的模塊進(jìn)行分片打包,每訪問到相應(yīng)的頁面時再按需請求呢褥傍?
答案就是 webpack 的分片機(jī)制儡嘶。

webpack 分片機(jī)制

webpack 分片機(jī)制就是將代碼進(jìn)行分片打包,實(shí)現(xiàn)按需加載恍风,使用分片機(jī)制前蹦狂,首先需要滿足兩個配置條件:
1.output 選項(xiàng)中需要有 chunkFileName:

chunkFilename: "static/js/[name].chunk.js",

2.plugins 選項(xiàng)中需要有 CommonsChunkPlugin:

new webpack.optimize.CommonsChunkPlugin({ name:'common', filename:'static/js/common.js'}),

雖然代碼分片打包主要用于生產(chǎn)環(huán)境,但建議在開發(fā)環(huán)境中也加上這樣的配置朋贬,就可以無需構(gòu)建而在開發(fā)環(huán)境(development)時就能看到和生產(chǎn)環(huán)境(production)一樣的效果了凯楔,還可以及早的發(fā)現(xiàn)問題。

幾種引入文件的方式

webpack 支持下面幾種文件的引用方式:

  • require
  • import
  • require.ensure

前兩個想必大家都不陌生锦募,最后一個可能不太常見摆屯,而這種方式正是使 webpack 進(jìn)行分片打包的關(guān)鍵。
使用 require 或 import 進(jìn)行打包時御滩,webpack 在執(zhí)行靜態(tài)編譯檢查時鸥拧,會將 require 或 import 后的代碼打包到同一文件中党远,而如果使用 require.ensure 引入文件,webpack 在檢查時發(fā)現(xiàn)這種引入方式富弦,就知道要對這部分文件進(jìn)行分片打包了沟娱,打包的文件名就是前面在 webpack 配置中定義的 chunkFilename。

使用 require.ensure

使用 require.ensure 較為簡單腕柜,這里以 Home 組件為例:

require.ensure([],(require) => {
    const User = require("./User").default
},"user");

下面說一下幾個相關(guān)參數(shù)的含義:
require.ensure 接受兩個參數(shù):

  • 第一個參數(shù)是數(shù)組济似,表示該模塊依賴的模塊,該模塊會在被依賴的模塊都被裝載后再引入盏缤,如果沒有依賴性砰蠢,使用空數(shù)組即可
  • 第二個參數(shù)是一個回調(diào)函數(shù),相關(guān)的異步模塊就是在這個函數(shù)中被引入的
  • 第三個參數(shù)是分片(chunk)文件的文件名唉铜,也就是 chunkFileName 配置中的 [name] 屬性台舱,如果不指定該參數(shù),將默認(rèn)為一個數(shù)字作為唯一的 ID潭流,建議總是定義 chunk 文件名竞惋,方便后期調(diào)試。

在 react-router 中使用代碼分片

同樣灰嫉,配合 require.ensure 也可以實(shí)現(xiàn)路由的按需加載拆宛。在使用路由按需加載時,我們只需將前面的函數(shù)進(jìn)行一下包裝讼撒,再將 component 換成 getComponent 即可浑厚。舉個例子:

...
const getHomeRoute = ( location,cb ) => {
    console.log(location)
    require.ensure([],(require) => {
        cb(null,require("./Home").default)
    },"home");
}

const getUserRoute = ( location,cb ) => {
    require.ensure([],(require) => {
        cb(null,require("./User").default)
    },"user");
}

ReactDOM.render(
    <Provider store = { store }>
        <Router history = {  hashHistory }>
            <Route path = "/" component = { App }>
                <IndexRoute getComponent = { getHomeRoute } />
                <Route path = "home" getComponent = { getHomeRoute }></Route>
                <Route path = "user" getComponent = { getUserRoute }></Route>
            </Route>
        </Router>
    </Provider>
, document.getElementById("root"));

如果不使用異步路由,Route 組件中使用 component 屬性根盒,如果需要使用異步路由钳幅,Route 組件中使用 getComponent 屬性,屬性值就是前面定義的相應(yīng)獲取函數(shù)炎滞。
關(guān)于獲取函數(shù)的兩個參數(shù):

  • 第一個參數(shù) location 是當(dāng)前的路由信息
  • 第二個參數(shù)是一個回調(diào)函數(shù)贡这,為 Node 的 Error First 風(fēng)格,該回調(diào)函數(shù)在異步組件被加載成功后再調(diào)用厂榛,然后將加載好的組件傳給 router。

總結(jié)

本文主要講了使用 require.ensure 配合 webpack 進(jìn)行異步加載丽惭,并講到了其和 react-router 的配合實(shí)現(xiàn)異步路由击奶,要實(shí)現(xiàn)異步路由加載,需要滿足以下兩個條件:

  • 使用 require.ensure 讓 webpack 對代碼進(jìn)行分片打包
  • 在 react-router 中使用 getComponent 而不是 component 加載異步分片文件

webpack 的看家本領(lǐng)就是文件打包责掏,對于異步文件分片的支持自然也不在話下柜砾,使用代碼分片打包可以顯著降低打包后的文件大小,并在生產(chǎn)場合下提高用戶體驗(yàn)换衬。

完痰驱。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末证芭,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子担映,更是在濱河造成了極大的恐慌废士,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,376評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蝇完,死亡現(xiàn)場離奇詭異官硝,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)短蜕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評論 2 385
  • 文/潘曉璐 我一進(jìn)店門氢架,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人朋魔,你說我怎么就攤上這事岖研。” “怎么了警检?”我有些...
    開封第一講書人閱讀 156,966評論 0 347
  • 文/不壞的土叔 我叫張陵孙援,是天一觀的道長。 經(jīng)常有香客問我解滓,道長赃磨,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,432評論 1 283
  • 正文 為了忘掉前任洼裤,我火速辦了婚禮邻辉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘腮鞍。我一直安慰自己值骇,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,519評論 6 385
  • 文/花漫 我一把揭開白布移国。 她就那樣靜靜地躺著吱瘩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪迹缀。 梳的紋絲不亂的頭發(fā)上使碾,一...
    開封第一講書人閱讀 49,792評論 1 290
  • 那天,我揣著相機(jī)與錄音祝懂,去河邊找鬼票摇。 笑死,一個胖子當(dāng)著我的面吹牛砚蓬,可吹牛的內(nèi)容都是我干的矢门。 我是一名探鬼主播,決...
    沈念sama閱讀 38,933評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼祟剔!你這毒婦竟也來了隔躲?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,701評論 0 266
  • 序言:老撾萬榮一對情侶失蹤物延,失蹤者是張志新(化名)和其女友劉穎宣旱,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體教届,經(jīng)...
    沈念sama閱讀 44,143評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡响鹃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,488評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了案训。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片买置。...
    茶點(diǎn)故事閱讀 38,626評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖强霎,靈堂內(nèi)的尸體忽然破棺而出忿项,到底是詐尸還是另有隱情,我是刑警寧澤城舞,帶...
    沈念sama閱讀 34,292評論 4 329
  • 正文 年R本政府宣布轩触,位于F島的核電站,受9級特大地震影響家夺,放射性物質(zhì)發(fā)生泄漏脱柱。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,896評論 3 313
  • 文/蒙蒙 一拉馋、第九天 我趴在偏房一處隱蔽的房頂上張望榨为。 院中可真熱鬧,春花似錦煌茴、人聲如沸随闺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽矩乐。三九已至,卻和暖如春回论,著一層夾襖步出監(jiān)牢的瞬間散罕,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工傀蓉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留笨使,地道東北人。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓僚害,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子萨蚕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,494評論 2 348

推薦閱讀更多精彩內(nèi)容