探究 webpack 如何实现模块化加载

本文探讨了webpack如何实现模块化加载,从webpack模块化的概念到同步加载的源码解析,详细介绍了_webpack_require_函数在模块加载中的作用,帮助读者理解webpack编译后的代码如何确保模块的正确执行。

探究 webpack 如何实现模块化加载

最近稍稍比较忙,但还是要腾出时间来写写博客,博客真的是个好东西,只要你坚持。这次主要讲讲 webpack 打包后的代码,分析他是如何实现模块化(同步)加载模块的,然后下次再讲讲如何按需(异步)加载模块。

一、webpack 模块化

关于模块化,可以看看我之前的总结博客 js模块化进程

总结一下,就是按照功能将一个项目切分成许多部分单独开发,然后再组装起来,每一个部分即为模块。

但是不管使用 require 还是 ES6 的 import ,最终都是经过 webpack 编译,模拟该行为,最后得到可执行代码。

二、webpack 同步加载源码

(1)源码

我们直接用一个例子展示,使用打包配置

module.exports = {
  	mode: "development",
  	devtool: "source-map",
	...
}

主文件:

import func from './func.js'
func.add(1,2)

引用文件:

class func{
    add(val1,val2){
        return val1 + val2
    }
}

export default new func()

打包后源码为:

(function (modules) { // 立刻执行函数 webpackBootstrap
	var installedModules = {};	//缓存模块
	function __webpack_require__(moduleId) {	//模块加载函数
		......
	}
	......
	return __webpack_require__(__webpack_require__.s = "./src/index.js");
})({
	({		//引用文件
	 "./src/func.js":
		(function (module, __webpack_exports__, __webpack_require__) {
            class func {
                add(val1, val2) {
                    return val1 + val2
                }
            }
		)}
		__webpack_exports__["default"] = (new func());
	}),
	({		//主文件
	 "./src/index.js":
		(function (module, __webpack_exports__, __webpack_require__) {
			var _func_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/func.js");
			_func_js__WEBPACK_IMPORTED_MODULE_0__["default"].add(1, 2)
	})
});

1.使用了立刻执行函数的形式(webpackBootstrap),密闭空间。传入一个对象 modules ,以文件名为 key,value 是各个模块内的代码。

2.立刻执行函数内:

  • installedModules 对象用于缓存模块
  • _webpack_require_ 是一个模块加载函数,模拟 require 和 import
  • 最后加载了主文件代码,主文件执行了 webpack_require 又引入了引用文件
(2)_webpack_require_ 如何实现模块加载
function __webpack_require__(moduleId) {

       	//使用缓存对象输出模块
        if (installedModules[moduleId]) {
            return installedModules[moduleId].exports;
        }
        //没有缓存则创建新模块
        var module = installedModules[moduleId] = {
            i: moduleId,
            l: false,
            exports: {}
        };
		
		//执行模块
        modules[moduleId].call(module.exports, module,module.exports, __webpack_require__);

        //模块加载完成标志
        module.l = true;

        //返回输出模块
        return module.exports;
    }
  • 首先使用缓存看能否对象输出模块,缓存的目的其实就是加载时加速。
  • 没有缓存则在对象内创建该模块,设置 i(模块ID),l(是否加载完成),exports(一个引用,指向模块的导出对象)
  • 然后就是执行该模块,通过 call 把 this 绑定在输出模块内。

同时观察一下引用文件,它是通过 export 输出内容的,而 export 正就是传入该模块的第三个参数 module.export。并且上述函数绑定的执行环境也是这个输出模块。通过相互循环引用,达成了拆分文件模块后,调用时执行环境不变的效果。

当然,webpack 远不止做了这些操作,本次只讲了一个简化的主流程。方便大家理解这个过程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值