• wepack的模块化原理及配置方法


    我们都知道,webpack的特点之一就在于其的模块化,将各个文件都使用loader功能转换为js文件,并将其模块化,那么其模块化的原理是什么呢?

    首先我们需要了解CommonJS规范,以及AMD、CMD、UMD规范都是什么及其原理。

    首先,CommonJS是在服务器端用于模块化的规范,因为是同步的,所以只能在服务器端实现,而浏览器端因为缺少node的四个字段:

    • module
    • exports
    • require
    • global
    // foobar.js 
    
    //私有变量 
    var test = 123; 
    
    //公有方法 
    function foobar () { 
    
        this.foo = function () { 
            // do someing ... 
        } 
        this.bar = function () { 
            //do someing ... 
        } 
    } 
    
    //exports对象上的方法和变量是公有的 
    var foobar = new foobar(); 
    exports.foobar = foobar; 
    
    //require方法默认读取js文件,所以可以省略js后缀 
    var test = require('./boobar').foobar; 
    
    test.bar(); 

    因为没办法在浏览器使用这个规范,所有就用了AMD规范和CMD规范。

    AMD规范是RequireJS 在推广过程中对模块定义的规范化产出的,异步使用回调来实现模块化:

    通过数组引入依赖 ,回调函数通过形参传入依赖 
    define(['someModule1', ‘someModule2’], function (someModule1, someModule2) { 
    
        function foo () { 
            /// someing 
            someModule1.test(); 
        } 
    
        return {foo: foo} 
    }); 
    AMD规范允许输出模块兼容CommonJS规范,这时define方法如下: 
    
    define(function (require, exports, module) { 
         
        var reqModule = require("./someModule"); 
        requModule.test(); 
         
        exports.asplode = function () { 
            //someing 
        } 
    }); 

    而CMD是SeaJS 在推广过程中对模块定义的规范化产出的

    CMD和AMD的区别有以下几点: 

    1.对于依赖的模块AMD是提前执行,CMD是延迟执行。不过RequireJS从2.0开始,也改成可以延迟执行。 

    2.CMD推崇依赖就近,AMD推崇依赖前置。 

    //AMD 
    define(['./a','./b'], function (a, b) { 
    
        //依赖一开始就写好 
        a.test(); 
        b.test(); 
    }); 
    
    //CMD 
    define(function (requie, exports, module) { 
         
        //依赖可以就近书写 
        var a = require('./a'); 
        a.test(); 
         
        ... 
        //软依赖 
        if (status) { 
         
            var b = requie('./b'); 
            b.test(); 
        } 
    }); 

    那么我们接下来再看下webpack的模块化是如何去实现的:

    当我将一个依赖于main.js的entry.js打包的时候,整理其打包后的文件可以看到其结构如下:

    (function (modules) {/* 省略函数内容 */})
    ([
    function (module, exports, __webpack_require__) {
        /* 模块index.js的代码 */
    },
    function (module, exports, __webpack_require__) {
        /* 模块bar.js的代码 */
    }
    ]);

    其中函数内容:

    // 1、模块缓存对象
    var installedModules = {};
    // 2、webpack实现的require
    function __webpack_require__(moduleId) {
        // 3、判断是否已缓存模块
        if(installedModules[moduleId]) {
            return installedModules[moduleId].exports;
        }
        // 4、缓存模块
        var module = installedModules[moduleId] = {
            i: moduleId,
            l: false,
            exports: {}
        };
        // 5、调用模块函数
        modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
        // 6、标记模块为已加载
        module.l = true;
        // 7、返回module.exports
        return module.exports;
    }
    // 8、require第一个模块
    return __webpack_require__(__webpack_require__.s = 0);

    我们可以看出:

    1.首先webpack声明了一个installedModules对象,用于缓存模块

    2.声明了__webpack_require__内部函数,用于实现require功能,首先检查缓存中是否存在要引用的模块,如有的话return缓存中的该模块,否则初始化该模块,再返回该模块

    3.用完成后,模块标记为已加载。

    require入口模块时,入口模块会收到收到三个参数,下面是入口模块代码:

    function(module, exports, __webpack_require__) {
        "use strict";
        var bar = __webpack_require__(1);
        bar();
    }

    webpack传入的第一个参数module是当前缓存的模块,包含当前模块的信息和exports;第二个参数exportsmodule.exports的引用,这也符合commonjs的规范;第三个__webpack_require__ 则是require的实现。

    在我们的模块中,就可以对外使用module.exportsexports进行导出,使用__webpack_require__导入需要的模块,代码跟commonjs完全一样。

    这样,就完成了对第一个模块的require,然后第一个模块会根据自己对其他模块的require,依次加载其他模块,最终形成一个依赖网状结构。webpack管理着这些模块的缓存,如果一个模块被require多次,那么只会有一次加载过程,而返回的是缓存的内容,这也是commonjs的规范。

    这样就完成了webpack hack commonjs的过程。

  • 相关阅读:
    目录
    DRF的分页
    Django Rest Framework 视图和路由
    爬虫基本原理
    C# System.Threading.Timer的使用
    C# Task的使用
    C# 线程池的使用
    C# 异步委托回调函数使用
    C#异步委托等待句柄的使用
    C# 异步委托的使用
  • 原文地址:https://www.cnblogs.com/cheerup/p/8371592.html
Copyright © 2020-2023  润新知