webpack打包優化(VUE Project)

五角六芒星_發表於2018-02-17

祝大家新年快樂,萬事如意,新年發大財??

臨近春節,公司很多同事都提前回家過年,剩餘人員根據禪道去修改bug,當bug修正完畢以後,我們需要重新打包給運維,上測試服給測試同事提測,但是由於專案本體比較龐大,所以打包時間太過漫長(二十五分鐘以上?),所以有了打包優化的想法(其實想法早就有了,但是因為平時工作計劃比較充實,所以一直沒有去完成這個工作),這次正好有時間,所以去重新考慮了這個問題!

話不多說,直接開始正文吧

先給大家看一下專案的目錄結構:

webpack打包優化(VUE Project)

就是正常的專案結構,簡單說一下吧:

  • build資料夾包含的是一些打包配置的一下東西
  • config資料夾是專案的基礎配置
  • dist是打包之後的檔案
  • node_modules是專案的依賴包
  • src資料夾裡面是專案的原始碼
  • static資料夾裡面放的是一些專案使用的靜態資源
  • index.html是專案的首頁
  • package.json檔案是專案的配置json
  • yarn.lock是使用yarn鎖定專案用的依賴

優化思路

專案打包時間長,原因無外乎就是專案整體比較龐大、依賴複雜、元件之前拆分不夠合理。

對於這三個問題呢,我們可以針對下面這幾個方面去做一下處理:

  • 對專案進行路由遮蔽,只打包自己需要打包的部分(我司就是好幾個專案合併在了一起,至於原因則是 需求類似,所以放在一起比較省事 -_-||| 開發過程中是省了不少事,但是現在一樣要還的!!!!)
  • 依賴關係複雜,這裡說的是專案中的依賴模組比較多,像我們現在這個專案,光算依賴包的話就有40+,另外一個重要原因就是元件之間存在相同引用的依賴。解決思路是把專案中重用的依賴抽離出來進行單獨打包。
  • 元件在寫的過程中,需要考慮好這個元件的使用方向,以及實現功能,不能混為一談。

實際操作

有了整體的思路,那麼開搞就可以啦 去webpack文件去看了一下有一個DllPlugin,這個外掛就是幫助我們解決問題的關鍵,下面是我webpack.dll.config的程式碼:

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

function resolve (dir) {
  return path.join(__dirname, '..', dir)
}

module.exports = {
  // 你想要打包的模組的陣列
  entry: {
    vendor: ['vue', 'lodash', 'vuex', 'axios', 'vue-router', 'iview', 'element-ui',
      'echarts','xlsx','jquery','vue-fullcalendar','vue-cookie','handsontable']
  },
  output: {
    path: path.join(__dirname, '../dist/vendor-dll-js'), // 打包後檔案輸出的位置
    filename: '[name].dll.js',
    library: '[name]_library'
    // vendor.dll.js中暴露出的全域性變數名。
    // 主要是給DllPlugin中的name使用,
    // 故這裡需要和webpack.DllPlugin中的`name: '[name]_library',`保持一致。
  },
  resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src'),
    }
  },
  plugins: [
    new webpack.DllPlugin({
      path: path.join(__dirname, '.', '[name]-manifest.json'),
      name: '[name]_library',
      context: __dirname
    }),
    // 壓縮打包的檔案,與該文章主線無關
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      }
    })
  ]
};
複製程式碼

我們需要將專案中具有重用性的包抽離出來,放在vendor陣列裡面,然後在下面output裡面定義一下打包輸出的檔案路徑,然後在resolve裡面配置解析引數,最後定義使用的DllPlugin外掛,UglifyJsPlugin是壓縮js的外掛

Dllplugin裡的path,會輸出一個vendor-manifest.json,這是用來做關聯id的,打包的時候不會打包進去,所以不用放到static裡 然後執行一下 webpack -p --progress --config build/webpack.dll.conf.js

成功以後,static下會有dll.vendor.js,根目錄下會有vendor.manifest.json 各自開啟看一下,就會看到依賴庫的原始碼和匹配id

ok,到這裡,抽離依賴庫的事情就完成了,那麼接下來問題就是怎麼引用呢,怎麼在dev和build跑呢?

這裡補了一點dll和commonsChunk概念上的區別,commonsChunk之所以慢和大,是因為每次run的時候,都會去做一次打包,而實際上我們不會一直去更新我們引用的依賴庫,所以dll的做法就等於是,事先先打包好依賴庫,然後只對每次都修改的js做打包。

繼續上面的步驟,我們需要根據生成的json檔案去修改webpack.base.config檔案:

const manifest = require('../vendor-manifest.json')
......
plugins: [
    new webpack.DllReferencePlugin({
      manifest
    })
  ]
複製程式碼

然後開啟index.html,在底部加上<script src="./static/dll.vendor.js"></script>

執行一下npm run build,一起正常的話,表示你的操作是正確的。

升級處理

至此優化的問題基本已經解決了,但是在處理過程中需要進行復制貼上,還要對index.html檔案進行操作,如果是對於專案不熟悉的人來進行開發專案的話,就會出現一些小的問題,所以我決定繼續往下研究一下:

思路還是上面的思路,我們下面需要進行的操作呢就是對與之前的處理進行優化,通過配置檔案,和命令去實現我們想要的效果

首先我們將上面 webpack.dll.config 檔案裡面的entry配置項拿出來,在config資料夾下新建一個dll.js

module.exports = {
  entry: {
    // 這裡的依賴順序必須是:物件從上往下依賴,陣列從右到左依賴(如果互不依賴的可以忽略順序)
    ui: ['iview', 'element-ui'],
    tool: ['lodash', 'jquery', 'axios', 'vue-fullcalendar'],
    vue: ['vue', 'vuex', 'vue-router', 'vue-cookie'],
    xlsx: ['xlsx'],
    echarts: ['echarts'],
    other: ['handsontable'],
  },
  outFile: '../static/dll'
};
複製程式碼

這裡面其實就是我們一開始寫的entry的配置項,根據這個js去打包的檔案有一個順序,就是我總結的這個:

這裡的依賴順序必須是:物件從上往下依賴,陣列從右到左依賴(如果互不依賴的可以忽略順序)

如果不按照這個順序去寫的話,會出現依賴錯誤的問題!!!

然後在output裡面再進行一下配置:

output: {
    path: path.join(__dirname, dllConfig.outFile), // 打包後檔案輸出的位置
    filename: '[name].dll.[chunkhash].js',
    library: '[name]_library'
    // 主要是給DllPlugin中的name使用,
    // 故這裡需要和webpack.DllPlugin中的`name: '[name]_library',`保持一致。
  },
複製程式碼

這樣在執行webpack -p --progress --config build/webpack.dll.conf.js指令的時候會生成如下:

webpack打包優化(VUE Project)
是不是看到檔案後面的hash就一臉懵逼,這怎麼辦,我們沒有辦法去進行復制貼上了!!(我們的目的不就是不進行復制貼上嗎 正經臉-_-)

要實現命令操作之後不進行復制貼上操作就需要使用webpack的 HtmlWebpackPlugin外掛

在plugins裡面配置一下HtmlWebpackPlugin

new HtmlWebpackPlugin({
  filename: path.join(__dirname, '../', config.dev.index),
  template: 'index.ejs',
  inject: false
}),
複製程式碼

然後在根目錄新增一個index.ejs模版(ejsGitHub地址), index.ejs中程式碼如下:

<body>
    <div id="app"></div>
    <!-- dll files will be auto injected -->
    <% for (var chunk in htmlWebpackPlugin.files.chunks) { %><script type="text/javascript" src="/<%= htmlWebpackPlugin.files.chunks[chunk].entry %>"></script>
    <% } %>
    <!-- built files will be auto injected -->
</body>
複製程式碼

最後需要在config資料夾下的index.js進行一下修改: 在dev中新增:index: 'index.html',

專案在執行dev指令或者build指令之前需要先執行:webpack -p --progress --config build/webpack.dll.conf.js 在dll指令結束後 執行其他操作就可以完美的玩耍了?

總結

至此程式碼打包優化的整個過程就基本結束了,測試一下,15分鐘左右就可以完成打包,比之前打包快了將近10分鐘,可以說是非常成功的一次嘗試!!

最後祝各位勤勞、睿智、悶騷正念,外表冷漠內心狂熱,顏值負分,人設冰點的程式猿們,節日快樂!

相關文章