webpack 獨立打包與快取處理

勞卜發表於2017-03-27

關於

前言

先前寫了一篇webpack入門的文章《webpack入門必知必會》,簡單介紹了webpack拆分、打包、壓縮的使用方法。本文將在上篇文章的基礎上進一步講解在使用webpack構建的專案中存在的優化方案與解決方法。

上篇文章中寫了一份webpack最基本的配置檔案來打包壓縮我們的程式碼:

var path = require('path');

module.exports = {
  entry: './app/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
}複製程式碼

在入口檔案index.js中我們引入了jQuery:

// index.js
var $ = require('jquery');
var str = require('./hello.js');

function main() {
    $('body').html(str);
}

main();複製程式碼

這樣我們雖然能夠實現程式碼的統一打包,將jQuery、index.js、hello.js統統打包到了bundle.js裡,但是會存在一個問題:每次打包都會生成一個體積較大的新bundle.js,瀏覽器無法快取像jQuery這樣的基本不會改動的框架庫程式碼檔案,影響載入速度。

發現問題我們就來解決問題,我們最終希望的是將像jQuery這樣的框架庫程式碼與專案自身的程式碼分開打包,生成一個獨立的打包檔案,縮減單個檔案體積,瀏覽器也不用每次都進行載入。

步驟

1.獨立打包

為了解決上述問題,我們需要修改我們的webpack配置檔案:

var webpack = require('webpack');
var path = require('path');

module.exports = {
    entry: {
        main: './app/index.js',
        vendor: ['jquery']
    },
    output: {
        filename: '[name].js',
        path: path.resolve(__dirname, 'dist')
    },
    plugins:[
        new webpack.optimize.CommonsChunkPlugin({
            name: 'vendor'
        }),
    ]
}複製程式碼

上方我們將原本的單入口檔案改成了多入口檔案,並加入了vendor屬性。vendor屬性用於配置打包第三方類庫,寫入陣列的類庫名將統一打包到一個檔案裡。

同時我們將輸出的filename用[name]變數來自動生成檔名,最後我們新增了一個CommonsChunkPlugin的外掛,用於提取vendor。

配置完成後我們執行webpack命令:

Hash: ee1daf95c1986768927a
Version: webpack 2.3.2
Time: 573ms
        Asset       Size  Chunks                    Chunk Names
      main.js  340 bytes       0  [emitted]         main
vendor.js     274 kB       1  [emitted]  [big]  vendor
   [0] ./~/jquery/dist/jquery.js 267 kB {1} [built]
   [1] ./app/hello.js 53 bytes {0} [built]
   [2] ./app/index.js 114 bytes {0} [built]
   [3] multi jquery 28 bytes {1} [built]複製程式碼

最終發現我們成功將jQuery打包到了vendor.js中,實現了獨立打包,但是問題又來了:每次打包後生成的檔名都是一樣的,瀏覽器可能快取上一次的結果而無法載入最新資料。

2.新增hash

為了解決上述問題,我們需要為打包後的檔名新增hash值,這樣每次修改後打包的檔案hash值將改變,修改配置檔案如下:

module.exports = {
    ...
        output: {
            filename: '[name].[chunkHash:5].js',
            path: path.resolve(__dirname, 'dist')
        },
    ...
}複製程式碼

上方我們在輸出檔名中增加了[chunkHash:5]變數,表示打包後的檔案中加入保留5位的hash值。我們再次執行打包命令:

Hash: c7d1295f2f9a27c412d2
Version: webpack 2.3.2
Time: 603ms
          Asset       Size  Chunks                    Chunk Names
  main.2a7ad.js  337 bytes       0  [emitted]         main
vendor.49eb4.js     274 kB       1  [emitted]  [big]  vendor
   [0] ./~/jquery/dist/jquery.js 267 kB {1} [built]
   [1] ./app/hello.js 50 bytes {0} [built]
   [2] ./app/index.js 114 bytes {0} [built]
   [3] multi jquery 28 bytes {1} [built]複製程式碼

上方我們發現打包後的檔案成功加上了hash值,這樣每次修改檔案後hash值也會跟著變,就不怕瀏覽器快取了,但是當我們嘗試去修改一個js檔案後再次打包,問題又來了:vendor.js的hash值也變了,我們並沒有修改jQuery的原始碼。

3.修改vendor配置

上述問題產生的原因是因為CommonsChunkPlugin外掛是用於提取公共程式碼的,上方我們只是提取了vendor作為公共程式碼。為了繼續解決上述問題,其實方法很簡單,我們需要修改CommonsChunkPlugin的配置,如下:

module.exports = {
    ...
        plugins:[
            new webpack.optimize.CommonsChunkPlugin({
                names: ['vendor', 'manifest']
            }),
        ]
    ...
}複製程式碼

如此我們修改一下hello.js中的程式碼,發現vendor的hash值並未改變,並且多了一個manifest.js的小檔案。manifest.js為webpack的啟動檔案程式碼,它會直接影響到hash值,用mainfest單獨抽出來了,這樣vendor的hash就不會變了。

4.生成index.html

通過以上對webpack配置檔案的一系列修改,我們成功實現了webpack的獨立打包與快取處理,但是還差最後一步。

因為我們最終打包後生成的檔名中帶有hash值,每次都是會變的,所以我們不能像目前這樣在index.html中寫死路徑。

index.html

...
<body>
    <script src="./dist/main.js"></script>
    <script src="./dist/vendor.js"></script>
    <script src="./dist/manifest.js"></script>
</body>
...複製程式碼

以上寫法是不對的,因為缺少了可變的hash值,因此我們希望每次打包後index.html中的路徑也會自動加上hash值,解決方法如下:

var HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    ...
        plugins:[
            ...
            new HtmlWebpackPlugin({
                title: 'demo',
                template: 'index.html' // 模板路徑
            }),
            ...
        ]
    ...
}複製程式碼

上方我們引入了html-webpack-plugin這一個外掛,該外掛可以幫助我們根據模板生成html檔案。在plugins設定中,title配置了生成html中的title部分,template為模板html的路徑地址。

我們需要下載html-webpack-plugin:

npm install html-webpack-plugin --save-dev複製程式碼

安裝和配置完畢後,執行打包命令:webpack

Hash: 0c4b91e206579b31544d
Version: webpack 2.3.2
Time: 856ms
            Asset       Size  Chunks                    Chunk Names
  vendor.e1868.js     268 kB       0  [emitted]  [big]  vendor
    main.44412.js  337 bytes       1  [emitted]         main
manifest.ed186.js    5.81 kB       2  [emitted]         manifest
       index.html  292 bytes          [emitted]
   [0] ./~/jquery/dist/jquery.js 267 kB {0} [built]
   [1] ./app/hello.js 50 bytes {1} [built]
   [2] ./app/index.js 114 bytes {1} [built]
   [3] multi jquery 28 bytes {0} [built]複製程式碼

我們發現在dist目錄下生成了一個index.html檔案,開啟該檔案後程式碼如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>demo</title>
</head>
<body>
<script type="text/javascript" src="manifest.ed186.js"></script>
<script type="text/javascript" src="vendor.e1868.js"></script>
<script type="text/javascript" src="main.44412.js"></script>
</body>
</html>複製程式碼

至此我們實現了每次打包後index.html中的路徑也會自動加上hash值的功能,因此dist目錄下的index.html即為以後的首頁檔案,最後我們在瀏覽器中開啟該檔案成功顯示:

webpack 獨立打包與快取處理

結語

本文在webpack入門的基礎上講解了webpack獨立打包與快取處理的方式,例項程式碼已上傳我的github,地址為:github.com/luozhihao/w…, 供參考。

如果覺得本文對你有幫助,可以關注我的微信公眾號,來這裡聊點關於前端的事情。

webpack 獨立打包與快取處理

相關文章