dll預編譯提高webpack打包速度

weixin_33938733發表於2018-11-23

部落格連結 http://blog.poetries.top/2018/11/23/webpack-dll

關注公眾號獲取更多資訊

一、webpack的dll功能

基於webpack3構建

1.1 dll介紹

我們構建前端專案的時候,往往希望第三方庫(vendors)和自己寫的程式碼可以分開打包,因為第三方庫往往不需要經常打包更新。對此Webpack的文件建議用CommonsChunkPlugin來單獨打包第三方庫

  • 我們這裡的dll.js 是提前打包好了的,而不是在每次build的時候去打包輸出的;這樣才能做到依賴包一次構建,無限次使用
  • webpack輸出的檔名都帶有hash值; 而用dll構建後輸出的檔名是固定的
entry: {
  vendor: ["jquery", "other-lib"],
  app: "./entry"
}
new CommonsChunkPlugin({
  name: "vendor",

  // filename: "vendor.js"
  // (Give the chunk a different name)

  minChunks: Infinity,
  // (with more entries, this ensures that no other module
  //  goes into the vendor chunk)
})

通常為了對抗快取,我們會給售出檔案的檔名中加入hash的字尾——但是——我們編輯了app部分的程式碼後,重新打包,發現vendorhash也變化了

1480597-9c58ec3982be0665
image

這麼一來,意味著每次釋出版本的時候,vendor程式碼都要重新整理,即使我並沒有修改其中的程式碼。這樣並不符合我們分開打包的初衷

  • DllWebpack最近新加的功能
  • Dll這個概念應該是借鑑了Windows系統的dll。一個dll包,就是一個純純的依賴庫,它本身不能執行,是用來給你的app引用的
  • 打包dll的時候,Webpack會將所有包含的庫做一個索引,寫在一個manifest檔案中,而引用dll的程式碼(dll user)在打包的時候,只需要讀取這個manifest檔案,就可以了。

優勢

  • Dll打包以後是獨立存在的,只要其包含的庫沒有增減、升級,hash也不會變化,因此線上的dll程式碼不需要隨著版本釋出頻繁更新
  • App部分程式碼修改後,只需要編譯app部分的程式碼,dll部分,只要包含的庫沒有增減、升級,就不需要重新打包。這樣也大大提高了每次編譯的速度
  • 假設你有多個專案,使用了相同的一些依賴庫,它們就可以共用一個dll

1.2 dll使用

首先要先建立一個dll的配置檔案,entry只包含第三方庫

第一步:新建webpack.dll.conf.js

  • webpack.DllPlugin的選項中,pathmanifest檔案的輸出路徑;namedll暴露的物件名,要跟output.library保持一致
// build/webpack.dll.conf.js

const path = require('path')
const webpack = require('webpack')

module.exports = {
  entry: {
    // 把這些資源打包成dll,提高編譯速度
    react: ['react','react-router-dom','redux','redux-immutable','immutable','react-redux','react-router','redux-logger','redux-thunk','styled-components'],
    ui: ['antd-mobile','antd'],
    others: ['react-icons','axios','clipboard','humps','lodash','md5','moment','normalizr']
  },
  output: {
    path: path.resolve(__dirname, "../dist/static/js"),
    filename: `[name].dll.js`,
    library: '[name]_library'
  },
  plugins: [
 ...Object.keys(['react','ui','others']).map(name => {
      return new webpack.DllReferencePlugin({
        context: '.',
        manifest: require(`../static/${name}.manifest.json`),
      })
    }),
    new webpack.optimize.UglifyJsPlugin()
  ]
}

第二步:加一個命令

// package.json
"scripts": {
  "dll": "webpack --config config/webpack.dll.conf.js"
}

執行npm run dll

  • 執行Webpack,會輸出兩個檔案一個是打包好的vendor.js,一個就是manifest.json,長這樣
{
  "name": "vendor_ac51ba426d4f259b8b18",
  "content": {
    "./node_modules/antd/dist/antd.js": 1,
    "./node_modules/react/react.js": 2,
    "./node_modules/react/lib/React.js": 3,
    "./node_modules/react/node_modules/object-assign/index.js": 4,
    "./node_modules/react/lib/ReactChildren.js": 5,
    "./node_modules/react/lib/PooledClass.js": 6,
    "./node_modules/react/lib/reactProdInvariant.js": 7,
    "./node_modules/fbjs/lib/invariant.js": 8,
    "./node_modules/react/lib/ReactElement.js": 9,
    
    ............

Webpack將每個庫都進行了編號索引,之後的dll user可以讀取這個檔案,直接用id來引用

1480597-bed6305c04fb2197.png

第三步: 在plugins中增加配置

// build/webpack.prod.conf.js
module.exports = {
   plugins: [
        new webpack.DllReferencePlugin({
          manifest: require('../dll/react-manifest.json')
        }),
        new webpack.DllReferencePlugin({
          manifest: require('../dll/ui-manifest.json')
        }),
        new webpack.DllReferencePlugin({
          manifest: require('../dll/others-manifest.json')
        })
   ]
}

再次執行npm run build

之前


1480597-016eedc71c63fdb5.png

之後


1480597-bd2b95bbac325e1c.png

二、happypack 多執行緒打包

一般情況下,js是單執行緒執行的,但node不是。利用node提供的多執行緒環境,happypack是可以多執行緒打包的。基本上開啟官網看了一下readme就可以配置了,特別是我只針對js的編譯進行優化,配置還是比較簡單的。

https://www.npmjs.com/package/happypack

  • happyPack把所有序列的東西並行處理,使得loader並行處理,較少檔案處理時間
// build/webpack.prod.conf.js

// @file: webpack.config.js
const HappyPack = require('happypack');
 
exports.module = {
  rules: [
    {
      test: /.js$/,
      // 1) replace your original list of loaders with "happypack/loader":
      // loaders: [ 'babel-loader?presets[]=es2015' ],
      use: 'happypack/loader',
      include: [ /* ... */ ],
      exclude: [ /* ... */ ]
    }
  ],
  plugins: [
     // 2) create the plugin:
    new HappyPack({
        // 3) re-add the loaders you replaced above in #1:
        loaders: [ 'babel-loader?presets[]=es2015' ]
    })
  ]
}

這時的編譯時間也減小了一些

1480597-1cee221ca808dce0.png

更多詳情 http://blog.poetries.top/2018/11/21/webpack-review/#6-1-%E5%88%86%E6%9E%90%E6%89%93%E5%8C%85%E7%BB%93%E6%9E%9C

三、更多參考

相關文章