webpack打包慢的解决方案

作者: 下一站深圳 | 来源:发表于2018-02-08 22:34 被阅读0次

    现在很多人用webpack的HRM热部署更新,以便在开发过程中,修改业务代码时,浏览器能够自动显示更改,不需要刷新浏览器也不需要重启服务,所以DllPlugin和DllReferencePlugin这两个插件用得少了,实际上,dllplugin的方式对webpack的构建打包速度是大大的提高,而且也可以用于生产环境中。想一想:把所有第三方包独立打成library库来应用,不仅可以抽离我们业务代码,同时也命中浏览器缓存,放在cdn上加快速度。我们看一下这种方式是如何使用:
    项目工程 = 第三方库 + 业务代码
    我们的思想: 将所有第三方库打包成一个 library库,然后去引用它,webpack打包业务代码时候,就不用处理第三方库,从提高构建速度


    新建项目webpack-dll,目录结构:
    webpack.config.js: 业务代码构建的webpack配置
    webpack.dll.js: 第三方库打包成library的配置
    dist: 发布目录
    src: 业务代码,以及业务代码的入口文件main.js
    这次例子中,npm install vue vue-router axios模拟众多的第三方库,接下来我们要:
    1.把第三方库打包成一个library
    2.修改webpack.config.js的配置,使得不会将第三方库构建到业务代码中

    *************************************************** 第一步 :打包第三方库*********************************************************

    // webpack.dll.js
    const webpack = require('webpack')
    const path = require('path')
    const vendors = [
        'vue',
        'vue-loader',
        'axios'
    ]
    
    module.exports = {
         output: {
            path:  path.resolve(__dirname,'./dist'),
            filename:'[name].js',
            library: '[name]'
        },
        entry: {
            "lib": vendors
        },
        plugins: [
            new webpack.DllPlugin({
                path: 'manifest.json',
                name: '[name]',
                context: __dirname
            }),
        ]
    }
    

    然后我们打包一下: webpack --config webpack.dll.js,可以看到生成了dist目录下生成一个lib.js,项目根目录下生成了manifest.json文件。这个文件是用来对应模块的,比如业务需要require('vue'),通过这个文件,就可以找到lib.js里面的vue模块。
    注意:filename指定为[name].js,不加chunkhash值可以命中缓存
    DllPlugin是我们用来打包library库的插件,其中:
    path:指manifest.json的生成路径
    name:要与output的library一致

    *************************************************** 第二步 :处理业务代码*********************************************************

    // webpack.config.js
    const webpack = require('webpack');
    const path = require('path');
    var HtmlWebpackPlugin = require('html-webpack-plugin');
    module.exports = {
        output: {
            path: path.resolve(__dirname, './dist'),
            filename: '[name]-[chunkhash:7].js'  // 加chunkhash避免缓存
        },
        entry: {
            app: './src/main.js'
        },
        plugins: [
            new webpack.DllReferencePlugin({
                context: __dirname,
                manifest: require('./manifest.json')
            }),
            new HtmlWebpackPlugin({
                template: 'index.html',
                inject: 'body' 
            })
        ],
    };
    

    注意:再HTMLwebpackplugin的配置里,我将生成app[chunhash].js注入到body里面,而HTML,我引入了我们的lib.js。因为webpack只会根据我们manifest.json做映射而不会将模块打包进来。

    <!DOCTYPE html>
    <html>
    <head>
        <title>webpack-dll</title>
        <meta charset="utf-8">
        <script type="text/javascript" src="lib.js"></script>
    </head>
    <body>
    <div id="app"></div>
    </body>
    </html>
    
    // main.js入口文件,引入vue
    import Vue from 'vue'
    new Vue({
      el: '#app',
      render: function (createElement) {
        return createElement(
          'span',   // tag name 标签名称
          this.message // 子组件中的阵列
        )
      },
      data: {
        message: 'Hello Vue!'
      }
    })
    

    然后我们打包一下,发现不用1秒。


    打包结果

    这是webpack对于第三方模块的会通过manifest做映射,而不会去引入它,我们看打包后生成的业务bundle:app[chunkhash].js: 前面的代码是webpack manifest代码,后面的就是我们的main.js,然后就没了

    /******/ (function(modules) { // webpackBootstrap
    /******/    // The module cache
    /******/    var installedModules = {};
    /******/
    /******/    // The require function
    /******/    function __webpack_require__(moduleId) {
    /******/
    /******/        // Check if module is in cache
    /******/        if(installedModules[moduleId]) {
    /******/            return installedModules[moduleId].exports;
    /******/        }
    /******/        // Create a new module (and put it into the cache)
    /******/        var module = installedModules[moduleId] = {
    /******/            i: moduleId,
    /******/            l: false,
    /******/            exports: {}
    /******/        };
    /******/
    /******/        // Execute the module function
    /******/        modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
    /******/
    /******/        // Flag the module as loaded
    /******/        module.l = true;
    /******/
    /******/        // Return the exports of the module
    /******/        return module.exports;
    /******/    }
    /******/
    /******/
    /******/    // expose the modules object (__webpack_modules__)
    /******/    __webpack_require__.m = modules;
    /******/
    /******/    // expose the module cache
    /******/    __webpack_require__.c = installedModules;
    /******/
    /******/    // define getter function for harmony exports
    /******/    __webpack_require__.d = function(exports, name, getter) {
    /******/        if(!__webpack_require__.o(exports, name)) {
    /******/            Object.defineProperty(exports, name, {
    /******/                configurable: false,
    /******/                enumerable: true,
    /******/                get: getter
    /******/            });
    /******/        }
    /******/    };
    /******/
    /******/    // getDefaultExport function for compatibility with non-harmony modules
    /******/    __webpack_require__.n = function(module) {
    /******/        var getter = module && module.__esModule ?
    /******/            function getDefault() { return module['default']; } :
    /******/            function getModuleExports() { return module; };
    /******/        __webpack_require__.d(getter, 'a', getter);
    /******/        return getter;
    /******/    };
    /******/
    /******/    // Object.prototype.hasOwnProperty.call
    /******/    __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
    /******/
    /******/    // __webpack_public_path__
    /******/    __webpack_require__.p = "";
    /******/
    /******/    // Load entry module and return exports
    /******/    return __webpack_require__(__webpack_require__.s = 0);
    /******/ })
    /************************************************************************/
    /******/ ([
    /* 0  这里就是我们的业务代码了*/
    /***/ (function(module, __webpack_exports__, __webpack_require__) {
    
    "use strict";
    Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
    /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_vue__ = __webpack_require__(1);
    
    new __WEBPACK_IMPORTED_MODULE_0_vue__["default"]({
      el: '#app',
      render: function (createElement) {
        return createElement(
          'span',   // tag name 标签名称
          this.message // 子组件中的阵列
        )
      },
      data: {
        message: 'Hello Vue!'
      }
    })
    
    /***/ }),
    /* 1 */
    /***/ (function(module, exports, __webpack_require__) {
    
    module.exports = (__webpack_require__(2))(10);
    
    /***/ }),
    /* 2 */
    /***/ (function(module, exports) {
    
    module.exports = lib;
    
    /***/ })
    /******/ ]);
    

    最后总结:
    这种方式的构建速度比用commonschunkplugin提取公共代码还要更快,因为webpack不需要分析哪些是第三方模块提取出来再打包处理。实际上,业务代码你也可以配合commonschunkplugin将manifest和业务的基础组件再提取出来,有利于代码模块的分离,提高构建速度。

    系列文章:
    《什么是构建? webpack打包思想?》
    《webpack基础使用》
    《从vue-cli学webpack配置1——针对webpack2》
    《从vue-cli学webpack配置2——针对webpack3》
    《webpack 、mainfest 、runtime 、缓存与CommonsChunkPlugin》
    《webpack打包慢的解决方案》

    相关文章

      网友评论

        本文标题:webpack打包慢的解决方案

        本文链接:https://www.haomeiwen.com/subject/ttzwzxtx.html