webpack進階——緩衝與獨立打包的用法,webpack進階

來源:互聯網
上載者:User

webpack進階——緩衝與獨立打包的用法,webpack進階

本文介紹了webpack進階——緩衝與獨立打包的用法,分享給大家,希望對大家有協助

先來看看最基礎的webpack配置:

var path = require('path'); module.exports = { entry: './src/index.js', output: {  filename: 'bundle.js',  path: path.resolve(__dirname, 'dist') }}

在index.js中引入了lodash庫:

src/index.js:

import _ from 'lodash';  function component() {  var element = document.createElement('div');  element.innerHTML = _.join(['Hello', 'webpack'], ' ');   return element; }  document.body.appendChild(component());

打包之後,只會產生一個bundle.js,這樣的話,每次若要載入資源檔,瀏覽器都會載入根本不會改動的lodash庫,這樣很低效。

由於如果每次去訪問瀏覽器,瀏覽器都重新下載資源,由於網路擷取資源可能很慢,可能頁面久久載入不出來,低效且不友好,故瀏覽器會緩衝資源,以避免每次訪問都通過網路去擷取資源。

但是,由於瀏覽器緩衝,又會出現新的問題,如果我們部署版本時不更改資源的檔案名稱,瀏覽器可能認為它沒有更新,就會使用它的緩衝版本。

這樣我們就需要解決兩個問題:第一,分離打包檔案。第二,解決緩衝問題。

const path = require('path');const webpack = require('webpack'); module.exports = { entry: {  common: ['lodash'],  app: './src/index.js' }, output: {  filename: '[name].[hash].js',  path: path.resolve(__dirname, 'dist') }, plugins: [  new webpack.optimize.CommonsChunkPlugin({   name: 'common' // 指代index.js引入的lodash庫  }) ]}

主要變動:

  • 添加外掛程式:CommonsChunkPlugin,提取引入的庫,並且更名,實現代碼分離。
  • 輸出上在名字上加了hash,每次打包後,hash值都不一樣解決了瀏覽器緩衝的問題。

結果:index.js打包為app.[hash].js,index.js引入的lodash打包為common.[hash].js。這樣解決了瀏覽器緩衝問題和實現了靜態資源代碼和原始碼的分離,但是新的問題又出現了。

第一次打包後(注意Asset列下的名字):

每次我們修改原始碼時,再次打包,不僅僅index產生app.[hash].js的hash值發生了變化,

而且common.[hash].js的hash值與app的hash值相同也發生了變化(可以自行測試一下,先webpack打包一次,修改index.js後再次打包一次)。

這並不是我們想要的結果,雖然原始碼hash改變解決了瀏覽器使用緩衝版本的問題,但是,如果common.js的hash值也一同發生了變化的話,那麼瀏覽器也還需要每次都請求不會發生改變的靜態代碼common,這樣還是浪費了網路資源,很低效。

註:本案例會多次打包,dist目錄中會產生過多垃圾檔案,在實際使用中都使用了CleanWebpackPlugin外掛程式。

複製代碼 代碼如下:
new CleanWebpackPlugin(['dist']) // 加入在外掛程式數組中,用於在每次打包前,都清空打包檔案夾下之前打包的檔案。

如果修改了index,僅僅只是產生的app的hash值發生變化,而common的hash值不發生變化,那就能夠達到我們的目的,既能緩衝庫又能識別源檔案的更改。
我們進行如下配置: output中將 [name].[hash].js 改為[name].[chunkhash].js ,讓每個檔案產生唯一的hash值:

const path = require('path');const webpack = require('webpack'); module.exports = { entry: {  common: ['lodash'],  app: './src/index.js' }, output: {  filename: '[name].[chunkhash].js',  path: path.resolve(__dirname, 'dist') }, plugins: [  new CleanWebpackPlugin(['dist']),  new webpack.optimize.CommonsChunkPlugin({   name: 'common' // 指代index.js引入的lodash庫  }) ]}

(注意:不要在開發環境下使用 [chunkhash],因為這會增加編譯時間。將開發和生產模式的配置分開,並在開發模式中使用 [name].js 的檔案名稱,在生產模式中使用 [name].[chunkhash].js 檔案名稱,所以如果這個時候使用了熱替換插HotModuleReplacementPlugin,將會導致編譯不成功!)

我們配置好之後,進行webpack打包:

chunkhash是根據檔案內容產生的hash,可見app與common產生的hash值不相同了(對比使用 [name].[hash].js打包)。

我們在index.js中隨便進行修改,再次打包:

奇怪的是,雖然common與app產生了單獨的hash值,但是修改了index.js,common的hash值還是發生了變化。

原因是:為了最小化產生的檔案大小,webpack使用標識符而不是模組名稱,在編譯期間產生標識符,並映射到塊檔案名稱,然後放入一個名為chunk manifest的JS對象中。重點就在於!!當我們使用CommonsChunkPlugin分離代碼時,被分離出來的代碼(本文中的lodash庫,被打包為common。),會預設被移動到entry中最後一個入口進行打包(第一個入口是index.js)。重要的是,chunk manifest將隨著這些被分離出來的代碼共同打包!!!

由於我們更改原始碼後,不但會更新app的hash值,還會產生新的映射,然後新的映射又會和資原始碼一同打包,又由於chunkhash是根據內容產生hash的,那麼加入了新的映射對象chunk manifest的資原始碼被打包後,hash自然也會發生改變。這反過來,產生的新hash將使長效緩衝失效。

那麼接下來我們需要做的就是講 manifest分離出來。這裡我們利用一個CommonsChunkPlugin一個較少有人知道的功能,能夠在每次修改後的構建中將manifest提取出來,通過指定entry中未用到的名稱,此外掛程式會自動將我們需要的內容提取到單獨的包中。

故再額外配置一個CommonsChunkPlugin:

const path = require('path');const webpack = require('webpack'); module.exports = { entry: {  common: ['lodash'],  app: './src/index.js' }, output: {  filename: '[name].[chunkhash].js',  path: path.resolve(__dirname, 'dist') }, plugins: [  new CleanWebpackPlugin(['dist']),  new webpack.optimize.CommonsChunkPlugin({   name: 'common' // 指代index.js引入的lodash庫  }),  new webpack.optimize.CommonsChunkPlugin({   name: 'manifest' // 用於提取manifest  }) ]}

webpack打包後:

從這裡可以證明之前所說的manifest被打包進了common!!!仔細看之前的圖:common的Size都是547kb,到這裡common大小是541kb 而manifest大小正好為5.85kb,加起來正好為547kb。

然後我們修改index.js再次打包:

從這裡可以發現!!我們修改了原始碼,common的hash值已經不再發生改變了!到這裡可以達到我們不緩衝原始碼緩衝資源檔的目的了。

但是可別高興得太早!!我們做了一個很小的修改,交換了entry中 app 和 common的順序(對比上一個程式碼片段):

const path = require('path');const webpack = require('webpack'); module.exports = { entry: {  app: './src/index.js',  common: ['lodash'] }, output: {  filename: '[name].[chunkhash].js',  path: path.resolve(__dirname, 'dist') }, plugins: [  new CleanWebpackPlugin(['dist']),  new webpack.optimize.CommonsChunkPlugin({   name: 'common' // 指代index.js引入的lodash庫  }),  new webpack.optimize.CommonsChunkPlugin({   name: 'manifest' // 用於提取manifest  }) ]}

打包後:

這裡發現對比上一張圖片發現,common的hash值又發生改變了!!而且根本沒有更改index.js的內容app的hash也變了,只是換了一下順序而已!

大家注意看本張圖與上一張圖的模組解析順序([1],[2],[3]...之後所對應的模組)。發現上一張圖,lodash第一個解析,而現在lodash最後一個解析。

這就是hash更變的原因:這是因為每個module.id 會基於預設的解析順序(resolve order)進行增量。也就是說,當解析順序發生變化,ID 也會隨之改變,所以hash值也會發生變化。

有人可能會決定,一般我們都不會更換webpack.config.js中entry的入口順序,那麼是否我就不會遇見這個問題了。答案是否定的,除否你能保證資源檔都寫在entry的頂部。否則會出現這樣的情況:

假如entry的順序為: app -> common, 那麼解析順序為 index.js → lodash。 如果之後index.js引入了 print.js,那麼解析順序變為 index.js → print.js -> lodash。

以上,我們並沒有在entry中更改入口順序,解析的順序還是會發生改變,common的hash還是會發生,不能緩衝。

這裡我們就引入一個新的組件:HashedModuleIdsPlugin:根據hash產生ID(NamedModulesPlugin也具有同樣的效果,但是是根據路徑名產生ID,可讀性更高,也由此編譯時間會相對長一些)。 這樣module.id就不會使用數位識別碼符,而使用hash:

const path = require('path');const webpack = require('webpack'); module.exports = { entry: {  common: ['lodash'],  app: './src/index.js' }, output: {  filename: '[name].[chunkhash].js',  path: path.resolve(__dirname, 'dist') }, plugins: [  new CleanWebpackPlugin(['dist']),  new webpack.HashedModuleIdsPlugin(), // 引入該外掛程式  new webpack.optimize.CommonsChunkPlugin({   name: 'common' // 指代index.js引入的lodash庫  }),  new webpack.optimize.CommonsChunkPlugin({   name: 'manifest' // 用於提取manifest  }) ]}

打包發現,之前[ ]裡都是數字,現在都是一些字元,

接下來,我們再把app和common的順序調換一下,並且隨意修改index.js,再次打包:

現在大功告成,common的hash沒有改變,而因為更變了內容app的hash改變了,這正是我們想要的結果。

參考資料:

webpack文檔 -- 緩衝

webpack獨立打包與緩衝處理

以上就是本文的全部內容,希望對大家的學習有所協助,也希望大家多多支援幫客之家。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.