webpack bundle.js文件分析

前言

之前我一直不太明白webpack的模块引入机制。正好看到了bundle.js文件的解析才更加了解一些

首先要知道所有模块的内容都被整合到一个文件中了。
你可能会说这样做不就是违背了模块化的思想吗?

实际上并没有,因为内部模块化的实现是基于函数的,也就说不通模块内容被封锁在不同的函数中

这样每一个函数都是一个函数作用域,形成了一个私有的作用域。

另一方面,浏览器没有像Node.js那样对于模块化定义了Commonjs规范,所以需要在浏览器中模拟Node的模块加载机制

分析

先给出一个整体代码

(
    // webpackBootstrap 启动函数
    // modules 即为存放所有模块的数组,数组中的每一个元素都是一个函数
    function (modules) {
        // 安装过的模块都存放在这里面
        // 作用是把已经加载过的模块缓存在内存中,提升性能
        var installedModules = {};

        // 去数组中加载一个模块,moduleId 为要加载模块在数组中的 index
        // 作用和 Node.js 中 require 语句相似
        function __webpack_require__(moduleId) {
            // 如果需要加载的模块已经被加载过,就直接从内存缓存中返回
            if (installedModules[moduleId]) {
                return installedModules[moduleId].exports;
            }

            // 如果缓存中不存在需要加载的模块,就新建一个模块,并把它存在缓存中
            var module = installedModules[moduleId] = {
                // 模块在数组中的 index
                i: moduleId,
                // 该模块是否已经加载完毕
                l: false,
                // 该模块的导出值
                exports: {}
            };

            // 从 modules 中获取 index 为 moduleId 的模块对应的函数
            // 再调用这个函数,同时把函数需要的参数传入
            modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
            // 把这个模块标记为已加载
            module.l = true;
            // 返回这个模块的导出值
            return module.exports;
        }

        // Webpack 配置中的 publicPath,用于加载被分割出去的异步代码
        __webpack_require__.p = "";

        // 使用 __webpack_require__ 去加载 index 为 0 的模块,并且返回该模块导出的内容
        // index 为 0 的模块就是 main.js 对应的文件,也就是执行入口模块
        // __webpack_require__.s 的含义是启动模块对应的 index
        return __webpack_require__(__webpack_require__.s = 0);

    })(

    // 所有的模块都存放在了一个数组里,根据每个模块在数组的 index 来区分和定位模块
    [
        /* 0 */
        (function (module, exports, __webpack_require__) {
            // 通过 __webpack_require__ 规范导入 show 函数,show.js 对应的模块 index 为 1
            const show = __webpack_require__(1);
            // 执行 show 函数
            show('Webpack');
        }),
        /* 1 */
        (function (module, exports) {
            function show(content) {
                window.document.getElementById('app').innerText = 'Hello,' + content;
            }
            // 通过 CommonJS 规范导出 show 函数
            module.exports = show;
        })
    ]
);

整体代码分三个部分
1.主体执行代码webpackBootstrap(webpack启动程序)
2.__webpack_require__函数
3.模块数组(作为参数传递进去)

__webpack_require__函数

这个函数可以说是核心函数,它的作用是什么?

        function __webpack_require__(moduleId) {
            // 如果需要加载的模块已经被加载过,就直接从内存缓存中返回
            if (installedModules[moduleId]) {
                return installedModules[moduleId].exports;
            }

            // 如果缓存中不存在需要加载的模块,就新建一个模块,并把它存在缓存中
            var module = installedModules[moduleId] = {
                // 模块在数组中的 index
                i: moduleId,
                // 该模块是否已经加载完毕
                l: false,
                // 该模块的导出值
                exports: {}
            };

            // 从 modules 中获取 index 为 moduleId 的模块对应的函数
            // 再调用这个函数,同时把函数需要的参数传入
            modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
            // 把这个模块标记为已加载
            module.l = true;
            // 返回这个模块的导出值
            return module.exports;
        }

传入的参数是一个moduleID,由于传入webpackBootstrap的参数是一个模块数组,模块数组的index就是moduleID

1.函数内第一个功能是分析这个模块有没有被加载过

判断依据是一个所有模块共同拥护的对象中是否存在

 var installedModules = {};

如果存在就将对象中已经加载过的内容返回

2.如果没有加载过

自然是要为这个这个模块设置一些信息

比如说模块id,是否已经加载过,以及最为重要的模块加载需要暴露出的内容(这相当于一个进程执行前创建的PCB)

这里要注意一下模块加载是一次性执行的,export暴露的出的内容也是一个值拷贝

之后就是将这个模块的内容(对应就是一个函数)执行,而且是基于module

最终将这个模块返回回去

从一个模块开始的执行流程

首先是从模块数组序号为0的开始调用__webpack_require__()函数

如果这个函数内部又调用其他模块,那么采取同样的策略

执行完毕之后,可以在当前模块访问到其他模块暴露的内容

后面还有一个异步加载时的代码,放在另外一篇

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值