【webpack核心】- 4、webpack编译结果分析

1、分析编译结果的目的 ?

对webpack的编译结果的认识对分析编译过程有帮助,理解了编译过程对后面使用webpack的加载器和插件的理解有帮助;

2、自己尝试手写dist/main.js

自己尝试手写dist/main.js
webpack的作用:根据入口文件./src/index.js 分析文件的依赖关系,然后把依赖的模块合并成一个文件

my-main.js :

//合并两个模块
//  ./src/a.js
//  ./src/index.js

(function (modules) {
    var moduleExports = {}; //用于缓存模块的导出结果

    //require函数相当于是运行一个模块,得到模块导出结果
    function __webpack_require(moduleId) { //moduleId就是模块的路径
        if (moduleExports[moduleId]) {
            //检查是否有缓存
            return moduleExports[moduleId];
        }

        var func = modules[moduleId]; //得到该模块对应的函数
        var module = {
            exports: {}
        }
        func(module, module.exports, __webpack_require); //运行模块
        var result = module.exports; //得到模块导出的结果
        moduleExports[moduleId] = result; //缓存起来
        return result;
    }

    //执行入口模块
    return __webpack_require("./src/index.js"); //require函数相当于是运行一个模块,得到模块导出结果
})({ //该对象保存了所有的模块,以及模块对应的代码
    "./src/a.js": function (module, exports) {
        eval("console.log(\"module a\")\nmodule.exports = \"a\";\n //# sourceURL=webpack:///./src/a.js")
    },
    "./src/index.js": function (module, exports, __webpack_require) {
        eval("console.log(\"index module\")\nvar a = __webpack_require(\"./src/a.js\")\na.abc();\nconsole.log(a)\n //# sourceURL=webpack:///./src/index.js")
      
    }
});

3、手写思路

合并./src/index.js./src/a.js两个模块,合并的结果里就是原始的js代码,不存在任何模块化的内容
---------------step1-----------------------------------------

1、避免全局变量污染,避免模块化代码(module,exports,require)找不到

问题:

  1. 合并前的模块化代码(module,exports,require)怎么办?—传参
  2. 模块化的模块里不会有 全局变量污染,合并后怎么确保也不会污染全局变量? --模块里的内容放在函数里

方案
我们可以如下,写成对象的模式, 定义一个变量modules 是一个对象该对象保存了所有的模块,以及模块对应的代码

var modules = {   
    "./src/a.js ": function(module,exports,require){
        console.log('a 模块');
        module.exports = 'a';
    },     
    "./src/index.js ": function(module,exports,require){
    	// var a = require('./a');
        var a = require('./src/a.js');  //用统一的路径书写方式,require('./src/a.js)的时候,就找到对应的函数去执行
        console.log(a);
        
        console.log('index模块');
    },   
}
  • 模块的路径 作为对象里的属性名,因为每个模块的路径是唯一的,所以通过这个唯一的属性名就可以找到一个唯一的模块
  • 对象的属性值可以写成一个函数,把模块里的代码放到函数环境里,
  • 在函数里用到了module,在普通的js里是没有module的,我们可以使用函数的参数 给传进来(commonjs里还可能用到exports.a =1;我们把exports 也传进来)

这样每一个模块里面的代码就没有污染全局变量!!!

总结:
因为每个模块对应一个唯一的路径,所以我们把路径用作属性名属性值是函数(模块里的代码放在函数里)
./src/index.js 和 ./src/a.js 这两个模块,运行一个模块,就相当于运行一个函数,就是执行函数里的模块代码

---------------step2-----------------------------------------

2、对象modules交给立即执行函数来处理

问题3:那对象modules交给谁来处理呢? –给立即执行函数来处理
方案:我们可以写一个立即执行函数,因为我们尽量的避免污染全局变量,所以把模块modules给立即执行函数,来处理里面的模块

var modules = {
	"./src/a.js ": function(){ //...}
}
(function(modules){})(modules)   //把modules 给立即执行函数,来执行来处理里面的所有模块

问题4:var modules = {} 然后传参给立即执行函数,会有全局变量污染
方案:为了不污染全局变量,直接把modules对应的内容,作为字面量传给立即执行函数

(function(modules){ })({
	"./src/a.js ": function(){ //...}
})   //把modules 给立即执行函数,来执行来处理里面的所有模块

这样就不会污染全局变量,同时又把模块构建好了,所有的模块对保存在对象里{模块的路径:模块的函数},然后把这个对象给立即执行函数
---------------step3-----------------------------------------

3、手写执行函数,执行入口模块

立即执行函数里面要执行入口模块 require('./src/index.js) --require(’./src/a.js)就是找到./src/a.js对应的函数去执行
require函数相当于运行一个模块,并得到模块的导出结果,这个require函数要自己写

(function(modules){
	    function webpack_require(moduleId){   //moduleId就是模块的路径,为了避免require  和node环境的require重名,改用webpack_require
        var func = modules[moduleId];   //得到模块对应的函数
        var module = {
            exports:{

            }
        }
        var exports = module.exports;
        func(module,exports,webpack_require); //执行模块对应的函数,传入参数
        var result = modules.exports; //得到模块导出的结果
        return result;
    }
    //执行入口模块
    return __webpack_require("./src/index.js"); //require函数相当于是运行一个模块,得到模块导出结果
})({
	"./src/a.js ": function(){ //...}
})   //把modules 给立即执行函数,来执行来处理里面的所有模块

---------------step4-----------------------------------------

4、加载模块缓存问题

问题:加载模块缓存问题?就是一个模块加载了多次怎么办?

(function(modules){
    var moduleExports = {
        // "./src/a.js":'a'   //这种方式缓存结果
    };//1-----------------用于缓存模块的导出结果
    
    function webpack_require(moduleId){   //moduleId就是模块的路径,为了避免require  和node环境的require重名,改用webpack_require
        if(moduleExports[moduleId]){
            //2-------------- 检查是否有缓存
            return moduleExports[moduleId];
        }
        //3-----------如果没有
        var func = modules[modules];   //得到模块对应的函数
        var module = {
            exports:{

            }
        }
        var exports = module.exports;
        func(module,exports,webpack_require); //执行模块对应的函数,传入参数
        var result = modules.exports; //得到模块导出的结果
        moduleExports[moduleId] = result; //4-----------缓存结果
        return result;
    }
	//执行入口模块
    return __webpack_require("./src/index.js"); //require函数相当于是运行一个模块,得到模块导出结果
})({   
    "./src/a.js ": function(module,exports,require){
        console.log('a 模块');
        module.exports = 'a';
    },     
    "./src/index.js ": function(module,exports,require){
        var a = require('./src/a.js');  
        console.log(a);
        
        console.log('index模块');
    },   
}) 

---------------step5-----------------------------------------

5、模块里的代码放到eval()里,方便调试

问题:为什么模块合并后,把模块里的代码放到对应函数里的eval()里面?
这和浏览器有关,最终运行的是合并后的代码,如果报错了只能指示到打包文件里,为了更好的调试,查找报错位置,放在eval()里。
eval()里的代码是放到另一个环境执行的,如果报错,就看不到其他代码的干扰了

"./src/a.js": function (module, exports) {
     eval("console.log(\"module a\")\nmodule.exports = \"a\";\n //# sourceURL=webpack:///./src/a.js")
 },

//# sourceURL= webpack:///./src/a.js 告诉浏览器触发调试的时候,显示的错误位置路径是./src/a.js

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值