Webpack的dll功能

最近使用Webpack遇到了一個坑。html

咱們構建前端項目的時候,每每但願第三方庫(vendors)和本身寫的代碼能夠分開打包,由於第三方庫每每不須要常常打包更新。對此Webpack的文檔建議用CommonsChunkPlugin來單獨打包第三方庫。前端

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部分的代碼後,從新打包,發現vendor的hash也變化了!node

兩次打包,並無修改vendor部分的代碼,然而hash變化了

這麼一來,意味着每次發佈版本的時候,vendor代碼都要刷新,即便我並無修改其中的代碼。這樣並不符合咱們分開打包的初衷。react

帶着問題我瀏覽了Github上的討論,發現了一個神器:dll。jquery

Dll是Webpack最近新加的功能,我在網上並無找到什麼中文的介紹,因此在這裏我就簡單介紹一下。webpack

Dll這個概念應該是借鑑了Windows系統的dll。一個dll包,就是一個純純的依賴庫,它自己不能運行,是用來給你的app引用的。git

打包dll的時候,Webpack會將全部包含的庫作一個索引,寫在一個manifest文件中,而引用dll的代碼(dll user)在打包的時候,只須要讀取這個manifest文件,就能夠了。github

這麼一來有幾個好處:web

  1. Dll打包之後是獨立存在的,只要其包含的庫沒有增減、升級,hash也不會變化,所以線上的dll代碼不須要隨着版本發佈頻繁更新。json

  2. App部分代碼修改後,只須要編譯app部分的代碼,dll部分,只要包含的庫沒有增減、升級,就不須要從新打包。這樣也大大提升了每次編譯的速度。

  3. 假設你有多個項目,使用了相同的一些依賴庫,它們就能夠共用一個dll。

如何使用呢?

首先要先創建一個dll的配置文件,entry只包含第三方庫:

const webpack = require('webpack');

const vendors = [
  'antd',
  'isomorphic-fetch',
  'react',
  'react-dom',
  'react-redux',
  'react-router',
  'redux',
  'redux-promise-middleware',
  'redux-thunk',
  'superagent',
];

module.exports = {
  output: {
    path: 'build',
    filename: '[name].[chunkhash].js',
    library: '[name]_[chunkhash]',
  },
  entry: {
    vendor: vendors,
  },
  plugins: [
    new webpack.DllPlugin({
      path: 'manifest.json',
      name: '[name]_[chunkhash]',
      context: __dirname,
    }),
  ],
};

webpack.DllPlugin的選項中,path是manifest文件的輸出路徑;name是dll暴露的對象名,要跟output.library保持一致;context是解析包路徑的上下文,這個要跟接下來配置的dll user一致。

運行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來引用。

Dll user的配置:

const webpack = require('webpack');

module.exports = {
  output: {
    path: 'build',
    filename: '[name].[chunkhash].js',
  },
  entry: {
    app: './src/index.js',
  },
  plugins: [
    new webpack.DllReferencePlugin({
      context: __dirname,
      manifest: require('./manifest.json'),
    }),
  ],
};

DllReferencePlugin的選項中,context須要跟以前保持一致,這個用來指導Webpack匹配manifest中庫的路徑;manifest用來引入剛纔輸出的manifest文件。

運行Webpack以後,結果以下:

分離出dll後打包

對比一下不作分離的狀況下打包的結果:

不分離的打包

速度快了,文件也小了。

平時開發的時候,修改代碼後從新編譯的速度會大大減小,節省時間。

若是有多個項目,使用相同的一套庫,你能夠在打包的時候引用相同的manifest文件,這樣就能夠在項目之間共享了。

參考:

相關文章
相關標籤/搜索