移動spa商城優化記(二)--- 減少70%的打包等待時間

JAVASCRIPT發表於2018-04-02

背景

上篇講了首屏優化,具體文章詳見移動spa商城優化記(一)---首屏優化篇,這次來分享一下打包速度的一些優化經驗,因為在實際專案開發中,隨著專案的不斷增大,依賴項不斷增多,我們會發現webpack打包速度會越來越慢,有時候npm run一下可能出去上個廁所的時間都夠了,在這快速發展的時代,這麼拖節奏的事情絕不允許,本篇還是以公司spa商城為例,詳細介紹一下優化打包速度方面的經驗。

開始

公司這個專案的起手模板是vue-cli的webpack模板,專案完成大概有將30個頁面,未經優化前打包時間如圖:

優化前的時間
大概兩分鐘左右,是不是出去上個廁所的時間都夠了。

接下來開始優化,優化主要分四方面:減少打包檔案數量,減少不必要的功能開銷,優化打包方式,升級打包工具。

1.減少打包檔案數量

指導思想:要打包的東西少了速度自然就快了。

1.dll

webpack.DllPlugin + webpack.DllReferencePlugin這組外掛應該是借鑑了dll的思想所以叫dllplugin這個名字,目的就是將vue,vue-router,react,jquery等等這些體積較大,專案中不常更新的第三方包抽離出來單獨打包,然後告訴webpack這些包我之前已經打包過了,你每次打包直接用就行了,不用每次再去重新打包一次了。

使用方法:

  1. build資料夾下新建一個webpack.dll.conf.js,內容可以這樣寫:
const path = require('path')
const webpack = require('webpack')

module.exports = {
    entry:{
        //這地方寫你想抽離的包,可以參考你的package.json檔案下的dependencies
        vue:['vue','vue-router'] 
    },
    output:{
        //這地方寫你打包後生成檔案的路徑
        path:path.join(__dirname,"../src/dll"),
        filename:'[name].dll.js',
        library:'[name]'
    },
    plugins:[
        //這個外掛是重點,用於打包上面entry裡配置的包
        new webpack.DllPlugin({
            path:path.join(__dirname,"../src/dll",'[name]-manifest.json'),
            name:'[name]',
        }),
        new webpack.optimize.UglifyJsPlugin()
    ]
}

複製程式碼
  1. 執行 webpack --config build/webpack.dll.conf.js打包生成抽離的公共包。
    此時src下應該能看到dll目錄及生成的公共包js及json。
    公共包js及json
  2. 正常webpack配置檔案裡配置DllReferencePlugin進行關聯
 plugins: [
        new webpack.DllReferencePlugin({
            //這裡寫上一步打包出的json路徑
            manifest:require('../src/dll/vue-manifest.json')
        })
        ......
    ]
複製程式碼

現在,再次打包就可以了,你提取出的第三方包越多,打包速度優化的越明顯。如果想讓打包出的html可以自動引入第二步打包出的dll.js檔案,可以使用add-asset-html-webpack-plugin或者自己修改HtmlWebpackPlugin的配置實現打包出的html內自動引入dll.js檔案。

關於HtmlWebpackPlugin詳細配置可以看這篇文章:
html-webpack-plugin用法全解
關於add-asset-html-webpack-plugin詳細配置可以看這篇文章:
add-asset-html-webpack-plugin配置

另外使用cdn引入包然後加 externals配置的方式也可以,思路和dll一致,都是抽離第三方包,只打包業務程式碼,只不過這種方式第三方包直接引用cdn上的。

2.減少不必要的resolve

  1. 看下webpack的每個rule下面include裡面是不是有多餘的resolve,或者看看有沒有把node_modules資料夾exclude掉。
  2. 用到babel-loader的地方,記得設定cacheDirectory,以利用bable的快取。
  3. resolve裡面的extensions可以刪除不必要的字尾名自動補全,減少webpack的查詢時間,比如extensions: ['.js', '.vue', '.json','.scss','.css'],寫這麼多自動補全寫程式碼的時候是省了字尾名了,但是這需要webpack打包時去自動查詢字尾增加了時間開銷。
  4. import時多使用完整路徑而不是目錄名,如import './components/scroll/index.js'而不是import './components/scroll,減少webpack的路徑查詢。

2.去除不必要的功能開銷

指導思想:減少打包過程中要做的額外的工作

我們的目的就是優化打包速度,那麼與這個無關的不必要的功能可以先暫停掉,用到時再開。

關掉source map。

sourcemap有以下幾個配置值:

eval: 生成程式碼 每個模組都被eval執行,並且存在@sourceURL

cheap-eval-source-map: 轉換程式碼(行內) 每個模組被eval執行,並且sourcemap作為eval的一個dataurl

cheap-module-eval-source-map: 原始程式碼(只有行內) 同樣道理,但是更高的質量和更低的效能

eval-source-map: 原始程式碼 同樣道理,但是最高的質量和最低的效能

cheap-source-map: 轉換程式碼(行內) 生成的sourcemap沒有列對映,從loaders生成的sourcemap沒有被使用

cheap-module-source-map: 原始程式碼(只有行內) 與上面一樣除了每行特點的從loader中進行對映

source-map: 原始程式碼 最好的sourcemap質量有完整的結果,但是會很慢
複製程式碼

當我們不需要除錯時,可以關掉sourcemap或降低sourcemap的級別來加快打包的速度。

3.優化打包方式:並行

指導思想:並行打包速度當然快。

1.UglifyJSPlugin並行

這個比較好配置,UglifyJSPlugin外掛下加一個屬性parallel設為true即可。

new UglifyJSPlugin({
        parallel: true
        ......
})
複製程式碼

還可以設定打包快取,具體見下面的配置

UglifyJSPlugin

2.Happypack

Happypack通過多程式模型,來加速程式碼構建。
比如說以前使用vue-loader處理vue檔案,以前是序列處理,現在利用happypack可以並行使用vue-loader處理vue檔案。

  1. 首先安裝HappyPack
    npm install --save-dev happypack
  2. 修改webpack.base.config.js
const HappyPack = require('happypack');
const vueLoaderConfig = require('./vue-loader.conf')
exports.module = {
  rules: [
    {
      test: /\.vue$/,
      //vue-loader替換為happypack/loader,如果遇到vue檔案就用happypack,id指定為vue
      loader: 'happypack/loader?id=vue'
    },
    {
        test: /\.js$/,
      //babel-loader替換為happypack/loader,如果遇到js檔案就用happypack,id指定為js
        loader: 'happypack/loader?id=js'
    }
    ......
  ]
};
 
exports.plugins = [
  new HappyPack({
    id:'vue',
    //同時開多少執行緒進行打包,也可以用ThreadPool控制
    threads: 4,
    loaders: [{
        //這是真實的處理loader,具體配置和rules裡原本的一致,options也照搬過來就行
        loader:'vue-loader',
        options:vueLoaderConfig
    }]
  }),
  new HappyPack({
    id: 'js',
    threads: 3,
    loaders: [{
        loader:'bable-loader',
    }]
  })
  ......
];
複製程式碼

經過以上配置,我們就可以使用happypack愉快的進行打包了。

更多高階配置可以看文件:Happypack文件

另外,想了解happypack原理的可以看淘寶團隊的這篇文章:happypack 原理解析

4.升級打包工具

指導思想:鳥槍換大炮,升級打包工具。

  1. 升級node
  2. 升級webpack
    webpack4比3快,3比2快,推薦webpack至少升到3以上,4還不太穩定,強行升級坑較多。
  3. 升級各種loader

很多時候,大神們在冥冥之中已經幫我們在底層做了優化,我們根本不需要做什麼配置,我們只需要升級工具即可,當然,升級的同時要保證專案的健壯性。

最後

一圖勝千言,這是經過優化後的打包時間:

優化後的時間

打包時間從原來的的120s減少到了現在的34s,優化率70%以上。再也不用每次npm run 一下就先去上個廁所了。。。

參考文章:
使用 webpack 定製前端開發環境
webpack打包優化解決方案

相關文章