使用DllPlugin優化webpack打包性能(基於vue-cli)

本文主要介紹兩個插件的使用,DllPlugin 和 DllReferencePlugin,後者配合前者使用。css

項目 Github 地址:https://github.com/luxiancan/vue-permission-managehtml

介紹

打包會輸出一個類 dll 包(dll 包源於 windows 的動態連接庫),這些代碼自己不會執行,主要是提供給咱們的業務代碼引用。(好比 dll 中有一個工具方法爲獲取本月日期數組,這個方法自己並不會執行,可是當咱們的業務中須要獲取本月日期時,就會引用這個方法在咱們的業務中執行相關邏輯)。vue

DllPlugin 能夠將特定的類庫提早打包而後引入。這種方式能夠極大的減小打包類庫的次數,只有當類庫更新版本纔有須要從新打包,而且也實現了將公共代碼抽離成單獨文件的優化方案。node

簡單來講就是:
將靜態資源文件(運行依賴包)與業務代碼源文件分開打包,先使用 DllPlugin 給靜態資源打包,再使用 DllReferencePlugin 讓源文件引用資源文件。webpack

做用

當咱們一個項目引入了多個較大的包之後,這些包自己並不會運行,咱們也不會修改這些包的代碼,可是每當咱們修改了業務代碼以後,這些包也會被從新打包。極大的浪費了時間,這時咱們就須要使用這個工具預先把靜態資源提早打包,之後修改源文件再打包時就不會打包這些靜態資源文件了。ios

開始搬磚

咱們以 vue-cli 生成的項目爲例:git

1.基礎安裝

## 全局安裝 vue-cli 腳手架 和 webpack
cnpm install -g vue-cli webpack-dev-server

## 初始化項目
winpty vue.cmd init webpack vue-permission-manage
cd vue-permission-manage

## 安裝基礎配置包
cnpm install

## 安裝依賴模塊(靜態資源)
cnpm install vuex axios element-ui echarts -S

安裝完成後的目錄結構 (此處已經隱藏 node_modules 文件夾):
image.pnggithub

2.使用依賴及打包測試

咱們編輯 main.js,引入咱們所安裝的靜態資源,結果爲:web

import 'babel-polyfill';
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue';
import App from './App';
import router from './router';
import store from './store/store.js';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import '@/assets/css/normalize.css';
import '@/assets/css/common.scss';
import httpRequest from '@/assets/js/service/http.js';
import '@/assets/js/service/mock.js';

Vue.config.productionTip = false;
Vue.use(ElementUI);
Vue.prototype.$http = httpRequest;

/* eslint-disable no-new */
new Vue({
    el: '#app',
    router,
    store,
    components: { App },
    template: '<App/>'
});

回到命令窗口,執行打包命令:vue-router

## 編譯打包
npm run build

image.png

截圖中能夠看見 Time:65164ms,打包花費了65秒,vue 全家桶以及剛纔引入的各類包和源代碼所有被打包了。(打包時間也跟電腦配置有關,你們的都不同,可能個人筆記本比較low因此有點慢吧,影響不大,往下走)

咱們才引入了5-6個包而已,就已經花費了65秒,若是之後還要加上各類包及靜態資源,打包時間確定會更久。

這就是咱們爲何要引入 DllPlugin 的緣由!

3.預打包依賴模塊

咱們知道,咱們剛纔所引入的 vue 或者 axios 之類的,咱們只是使用它們,並不會改變它們的源碼,它們自己也不會運行,那麼咱們就能夠把這些模塊拆分出來提早打包。
那麼如何提早打包它們呢? 咱們在根目錄的 build 文件夾下建立一個 webpack 配置文件(webpack.dll.conf.js),既然這個文件是 webpack 配置文件,那麼它的格式確定也和 webpack 的其餘配置文件同樣:

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

/* 將特定的類庫提早打包而後引入,不但可以極大減小打包時間,
也實現了將公共代碼抽離成單獨文件的優化方案,能夠很大程度的減少打包以後的文件體積。 */

module.exports = {
    // 你想要提早打包的類庫的數組。注意 vue 要寫成別名
    entry: {
        // 若是這些類庫有版本更新了(通常不多更新),就須要從新執行 npm run dll 打包類庫,再執行 npm run build 打包項目上線
        // 這裏用 vendor 做爲 key 值表示後文用到的 [name] ,後續生成的打包文件就爲 vendor-manifest.json  vendor.dll.js
        vendor: ['vue/dist/vue.esm.js', 'vuex', 'axios', 'vue-router', 'element-ui', 'echarts']
    },
    output: {
        path: path.join(__dirname, '../static/js'), // 打包後文件輸出的位置,放到項目根目錄的 static/js 下
        filename: '[name].dll.js', // 打包後的文件名 vendor.dll.js
        library: '[name]_library'
        // vendor.dll.js 中暴露出的全局變量名,主要是給 DllPlugin 中的 name 使用。
        // 因此這裏須要和 webpack.DllPlugin 中的 name: '[name]_library', 保持一致。
    },
    plugins: [
        new webpack.DllPlugin({
            // manifest.json 生成的文件夾及名字,這裏路徑寫成 .. 表明上一級目錄,也就是讓它生成在了根目錄下
            path: path.join(__dirname, '../[name]-manifest.json'),
            // 和 output.library 保持一致便可
            name: '[name]_library',
            // manifest 文件中請求的上下文,默認爲本文件的上下文
            context: __dirname
        }),
        // 壓縮打包的文件,使用 UglifyJsPlugin 插件壓縮代碼
        new webpack.optimize.UglifyJsPlugin({
            compress: {
                warnings: false
            }
        })
    ]
};

重點:這裏引入的 Dllplugin 插件,該插件將生成一個 manifest.json 文件,該文件供 webpack.dll.conf.js 中加入的 DllReferencePlugin 使用,使咱們所編寫的源文件能正確地訪問到咱們所須要的靜態資源(運行時依賴包)。相關字段的解釋已經在代碼註釋中寫明。

編寫該 webpack 配置以後,咱們就能夠預打包資源文件了。

## 以指定的 webpack 配置文件執行打包
webpack --config build/webpack.dll.conf.js

emmm。。。感受這命令有點難記哎,那咱們就將它加入 package.json 裏吧

"scripts": {
    "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
    "lint": "eslint --ext .js,.vue src test/unit",
    "dll": "webpack --config build/webpack.dll.conf.js",
    "build": "node build/build.js"
},

預打包資源文件:

npm run dll

image.png

能夠看到 dll 相關的資源文件已經打包成功,此時的目錄結構:

image.png

可見咱們的目錄結構中 static 下生成了 js 子目錄,打包好的 dll 文件(js/vendor.dll.js)就放在該目錄下,除此以外根目錄中還生成了 vendor-manifest.json。
如今咱們已經再也不須要將那些靜態資源包跟源文件一塊兒打包了,可是這也須要在源文件的 webpack.base.conf.js 中配置 DllReferencePlugin 使用 vendor-manifest.json 來引用這個 dll。

4.打包源文件

這一步咱們只須要改寫 vue-cli 爲咱們生成好的 build/webpack.base.conf.js 便可:

image.png

該文件主要是添加了 plugins 配置:

plugins: [
    new webpack.DllReferencePlugin({
        context: __dirname, // 與 Dllplugin 裏的 context 所指向的上下文保持一致,這裏都是指向了當前文件的 build 目錄
        manifest: require('../vendor-manifest.json') // 引入 Dllplugin 所生成的的 manifest
    })
],

到這裏配置完這個就。。哦還沒完別急,咱們須要手動在根目錄的 index.html 裏引入生成的 dll 庫

<body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
    <script src="./static/js/vendor.dll.js"></script>  <!--引入 vendor.dll.js -->
  </body>

好的,激動人心的時刻終於來了!!!咱們如今只須要 npm run build

image.png

看時間Time:20746ms!!!,比起以前的65秒咱們縮短到了20秒左右!時間就是$$,時間就是生命啊!!

日後若是咱們只是改動了業務代碼,就不須要從新打包那些個各類龐大的類庫了。不過還要注意一點,若是相關類庫版本更新了,再次執行 npm install 的時候類庫源碼有更新,此時就須要從新執行一下 npm run dll 再執行 npm run build。爲此,咱們在 package.json 再加一個命令 dll_build:

"scripts": {
    "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
    "lint": "eslint --ext .js,.vue src test/unit",
    "dll": "webpack --config build/webpack.dll.conf.js",
    "build": "node build/build.js",
    "dll_build": "npm run dll && npm run build"
},

第一次打包時,或者類庫版本更新了,執行 npm run dll_build 就行了~

到這裏優化就結束啦,文章有不妥的地方歡迎指出留言哦,以爲不錯的話點個贊點個星吧 hhh,github 源碼地址在文章開頭哦~

參考資料:
webpack 中文文檔 | webpack 中文網
webpack進階——DllPlugin優化打包性能(基於vue-cli)

相關文章
相關標籤/搜索