• Webpack-CodeSplit(静态文件篇)


    何为CodeSplitting?

    webpack从入口文件开始遍历,找到所有依赖文件,然后打包成最终的一个文件,即bundle.js文件,这是我们经常使用的方式,当一个项目慢慢变得复杂的时候会导致这个bundle.js文件越来越大,浏览器加载的速度也会越来越慢,这个过程还不排除我们需要引用的第三方文件,这样每次无论是构建,还是浏览器加载这个最终文件,都会存在效率问题,webpack提供了codesplitting功能来解决这个问题,这可以最大限度的减少浏览器加载必要代码时间(比如首屏渲染优化)。这个过程我们可以分为两种情况来讨论,第三方的分为静态文件处理,浏览器加载必要文件作为动态文件处理(按需加载,懒加载)

    具体方案参考“webpack分离第三方解决方案“,这里我们仅仅对optimization.splitChunks分离进行阐述。

    先看一个简单例子

    demo.js

    import $ from "jquery";

    webpack.js

    module.exports = {
      mode: "development",
      entry: {
        app: "./demo.js",
      },
      output: {
        path: path.resolve(__dirname, "./build/"),
        filename: "[name]-[chunkhash].js",
      },
      devtool: "source-map",
    }

    构建结果

     添加chunk,并指定加载第三方类库

    entry: {
        app: "./demo.js",
        vendor: ["jquery"],
      },

    构建结果

     然后会发现,vendor跟app中均出现了第三方的代码,明显不能满足我们的需求,改进如下

    optimization: {
        splitChunks: {
          chunks: "all",
          cacheGroups: {
            default: false,
            vendors: false,
            vendors: {
              test: /[\/]node_modules[\/]/,
              name: "vendor",
              priority: -10,
              chunks: "all",
              reuseExistingChunk: true,
              enforce: true,
            },
          },
        }
      },

    这里通过正则从node_modules里面获取第三方类库,然后通过业务代码检测引用过哪些第三方,最后将引用的第三方文件打包到vendor.js中

    构建结果

     app文件结构

     (function(modules) { // webpackBootstrap
    /******/     // install a JSONP callback for chunk loading
    /******/     function webpackJsonpCallback(data) {
    /******/         var chunkIds = data[0];
    /******/         var moreModules = data[1];
    /******/         var executeModules = data[2];
    /******/
    /******/         // add "moreModules" to the modules object,
    /******/         // then flag all "chunkIds" as loaded and fire callback
    /******/         var moduleId, chunkId, i = 0, resolves = [];
    /******/         for(;i < chunkIds.length; i++) {
    /******/             chunkId = chunkIds[i];
    /******/             if(Object.prototype.hasOwnProperty.call(installedChunks, chunkId) && installedChunks[chunkId]) {
    /******/                 resolves.push(installedChunks[chunkId][0]);
    /******/             }
    /******/             installedChunks[chunkId] = 0;
    /******/         }

    vendor文件结构

    (window["webpackJsonp"] = window["webpackJsonp"] || []).push([["vendor"],{
    /***/ "taue":
    /***/ (function(module, exports, __webpack_require__) {
    var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;
    ( function( global, factory ) {
    
        "use strict";
    
        if (  true && typeof module.exports === "object" ) {
            module.exports = global.document ?
                factory( global, true ) :
                function( w ) {
                    if ( !w.document ) {
                        throw new Error( "jQuery requires a window with a document" );
                    }
                    return factory( w );
                };
        } else {
            factory( global );
        }
    
    // Pass this if window is not defined yet
    } )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) {

    可以看出将第三方跟运行时代码打到了一起,网上查看以前webpack版本会发现,如果修改业务逻辑,会导致运行代码改变,从而改变打包出来的vendor.js,但是在这里我试过,并没有发生改变,而且查看运行时的代码,在业务逻辑中,并不在vendor中。

    原因有三种(查明原因更新此文章)

    1.webpack本身对运行代码做了优化,降低了运行代码与加载类库的耦合性从而保证了运行代码的独立性。(可能性很大)

    2.类库的挂载形式不同导致了运行时不一样(可能性不大)

    3.demo写的有局限性

    具体原因等查明再更新该文章。在这里留个疑问。

    然后我们如何避免运行时代码的改变,我们要提取运行时的代码,改进如下

    optimization: {
        splitChunks: {
          chunks: "all",
          cacheGroups: {
            default: false,
            vendors: false,
            vendors: {
              test: /[\/]node_modules[\/]/,
              name: "vendor",
              priority: -10,
              chunks: "all",
              reuseExistingChunk: true,
              enforce: true,
            },
          },
        },
        runtimeChunk: {
          name: "manifest",
        },
      }

    构建结果

     我们可以检查下manifest.js代码

    (function(modules) { // webpackBootstrap
    /******/     // install a JSONP callback for chunk loading
    /******/     function webpackJsonpCallback(data) {
    /******/         var chunkIds = data[0];
    /******/         var moreModules = data[1];
    /******/         var executeModules = data[2];
    /******/
    /******/         // add "moreModules" to the modules object,
    /******/         // then flag all "chunkIds" as loaded and fire callback
    /******/         var moduleId, chunkId, i = 0, resolves = [];

    保留了运行时的代码

    查看业务代码

    (window["webpackJsonp"] = window["webpackJsonp"] || []).push([["app"],{
    
    /***/ "fhko":
    
    /***/ (function(module, __webpack_exports__, __webpack_require__) {
    
    "use strict";
    __webpack_require__.r(__webpack_exports__);
    /* harmony import */ var jquery__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! jquery */ "taue");
    /* harmony import */ var jquery__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(jquery__WEBPACK_IMPORTED_MODULE_0__);

    已经没有了运行时的代码。

    总结

    到这里其实我们已经看到了webpack加载模块代的方式了。大致流程就是将模块代码放入了window["webpackJsonp"],window["webpackJsonp"]是数组类型,数组中的每一项为一个chunk文件

    chunk又包含了chunk[0]依赖文件名(可多个),chunk文件内容。然后运行文件也就是manifest遍历这个数组,然后挨个执行目标函数,我们在回忆下怎么调用的。

    /******/     var jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] || [];
    /******/     var oldJsonpFunction = jsonpArray.push.bind(jsonpArray);
    /******/     jsonpArray.push = webpackJsonpCallback;
    /******/     jsonpArray = jsonpArray.slice();
    /******/     for(var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]);
    /******/     var parentJsonpFunction = oldJsonpFunction;

    好了针对静态的code split的总结就这些,具体细节可以查看官方文档,别看中文的,已经不更新了。关于webpack如何运行的,以后整理。

  • 相关阅读:
    Web.config配置详解
    vs2010下创建webservice
    WinForm如何调用Web Service
    Android动画的两种使用方式。
    ES6介绍
    django批量form表单处理
    django生命周期示意图
    django中的构造字典(二级菜单,评论树,购物车)
    django中介模型,CBV模型,及logging日志配制
    django中csrftoken跨站请求伪造的几种方式
  • 原文地址:https://www.cnblogs.com/moran1992/p/12834484.html
Copyright © 2020-2023  润新知