Webpack 打包 commonjs 和 esmodule 动态引入模块的产物对比

⚠️超长代码预警,需要几个小时的时间去啃,但读懂以后应该会很开心。

commonjs

新建一个 json 文件夹,包含几个 json 文件,和一个 add 方法。

其中 add.js 就是一个简单的加法模块。

// src/commonjs/json/add.js
console.log("add开始引入");
module.exports.add = (a, b) => {
    return a + b;
}; 

test1.jsontest2.json 都是一个 json 对象。

// src/commonjs/json/test1.json
{
    "data": "test1"
}

// src/commonjs/json/test2.json
{
    "data": "test2"
} 

然后我们提供一个 hello 模块,可以根据用户传入的参数,来引入不同的 json 文件返回给用户。

module.exports = function (filename) {
    const data = require("./json/" + filename + ".json");
    return data;
}; 

需要注意的上边 require 传入的模块名一定不能是一个纯变量,比如 require(filename) ,不然 webpack 就不知道该打包哪些文件了。

上边我们限定了目录位置 ./json 和文件名后缀 .json 。这样 Webpack 就会把 json 文件夹下所有的 .json 文件进行打包。

主函数 index.js 来调用 hello 方法。

console.log("commonjs开始执行");
const hello = require("./hello");
console.log(hello("test1")); 

可以看一下控制台是正常输出:

image-20220503173736921

看一下打包产物:

主要看一下保存所有模块的 __webpack_modules__ 变量,其它的可以看一下上篇 Webpack 打包 commonjs 和 esmodule 模块的产物对比

var __webpack_modules__ = {
        "./src/commonjs/hello.js": ( module,
            __unused_webpack_exports,
            __webpack_require__ ) => {
            module.exports = function (filename) {
                const data = __webpack_require__(
                    "./src/commonjs/json sync recursive ^\\.\\/.*\\.json$"
                )("./" + filename + ".json");
                return data;
            };
        },

        "./src/commonjs/json sync recursive ^\\.\\/.*\\.json$": ( module,
            __unused_webpack_exports,
            __webpack_require__ ) => {
            ...
        },

        "./src/commonjs/json/test1.json": (module) => {
            "use strict";
            module.exports = { data: "test1" };
        },

        "./src/commonjs/json/test2.json": (module) => {
            "use strict";
            module.exports = { data: "test2" };
        },
    }; 

主要是四个模块 ./src/commonjs/hello.js./src/commonjs/json sync recursive ^\\.\\/.*\\.json$./src/commonjs/json/test1.json./src/commonjs/json/test2.json

./src/commonjs/json/test1.json./src/commonjs/json/test2.json 这两个模块就是把我们的 json 文件用 module.exports 来导出。

./src/commonjs/hello.js 模块中先调用 ./src/commonjs/json sync recursive ^\\.\\/.*\\.json$ 模块的方法,再进行传参。

此外将我们原本的 "./json/" + filename + ".json" 参数转为了 "./" + filename + ".json"

重点来看下 ./src/commonjs/json sync recursive ^\\.\\/.*\\.json$ ,详见下边的注释

"./src/commonjs/json sync recursive ^\\.\\/.*\\.json$": ( module,
            __unused_webpack_exports,
            __webpack_require__ ) => {
  					// 映射 key
            var map = {
                "./test1.json": "./src/commonjs/json/test1.json",
                "./test2.json": "./src/commonjs/json/test2.json",
            };

            function webpackContext(req) {
                var id = webpackContextResolve(req); // 得到映射后的 key
                return __webpack_require__(id); // 通过 __webpack_require__ 导入文件
            }
  					// 返回映射后的 key
            function webpackContextResolve(req) {
                if (!__webpack_require__.o(map, req)) {
                    var e = new Error("Cannot find module '" + req + "'");
                    e.code = "MODULE_NOT_FOUND";
                    throw e;
                }
                return map[req];
            }
            webpackContext.keys = function webpackContextKeys() {
                return Object.keys(map);
            };
            webpackContext.resolve = webpackContextResolve;
            module.exports = webpackContext;
            webpackContext.id =
                "./src/commonjs/json sync recursive ^\\.\\/.*\\.json$";
        }, 

commonjs 模块整体上就是把匹配 "./json/" + filename + ".json" 这个格式的文件 test1.jsontest2.json 都进行了打包,并且略过了 add.js 文件。

可以再看下整体的产物:

(() => {
    var __webpack_modules__ = {
        "./src/commonjs/hello.js": ( module,
            __unused_webpack_exports,
            __webpack_require__ ) => {
            module.exports = function (filename) {
                const data = __webpack_require__(
                    "./src/commonjs/json sync recursive ^\\.\\/.*\\.json$"
                )("./" + filename + ".json");
                return data;
            };
        },

        "./src/commonjs/json sync recursive ^\\.\\/.*\\.json$": ( module,
            __unused_webpack_exports,
            __webpack_require__ ) => {
            var map = {
                "./test1.json": "./src/commonjs/json/test1.json",
                "./test2.json": "./src/commonjs/json/test2.json",
            };

            function webpackContext(req) {
                var id = webpackContextResolve(req);
                return __webpack_require__(id);
            }
            function webpackContextResolve(req) {
                if (!__webpack_require__.o(map, req)) {
                    var e = new Error("Cannot find module '" + req + "'");
                    e.code = "MODULE_NOT_FOUND";
                    throw e;
                }
                return map[req];
            }
            webpackContext.keys = function webpackContextKeys() {
                return Object.keys(map);
            };
            webpackContext.resolve = webpackContextResolve;
            module.exports = webpackContext;
            webpackContext.id =
                "./src/commonjs/json sync recursive ^\\.\\/.*\\.json$";
        },

        "./src/commonjs/json/test1.json": (module) => {
            "use strict";
            module.exports = { data: "test1" };
        },

        "./src/commonjs/json/test2.json": (module) => {
            "use strict";
            module.exports = { data: "test2" };
        },
    };

    var __webpack_module_cache__ = {};

    function __webpack_require__(moduleId) {
        var cachedModule = __webpack_module_cache__[moduleId];
        if (cachedModule !== undefined) {
            return cachedModule.exports;
        }

        var module = (__webpack_module_cache__[moduleId] = {
            exports: {},
        });

        __webpack_modules__[moduleId](
            module,
            module.exports,
            __webpack_require__
        );

        return module.exports;
    }

    (() => {
        __webpack_require__.o = (obj, prop) =>
            Object.prototype.hasOwnProperty.call(obj, prop);
    })();

    var __webpack_exports__ = {};

    (() => {
        console.log("commonjs开始执行");
        const hello = __webpack_require__("./src/commonjs/hello.js");
        console.log(hello("test1"));
    })();
})(); 

esmodule

esmodule 提供了 import() 方法进行动态引入,会返回一个 Promise 对象。

The ES2015 Loader spec defines import() as method to load ES2015 modules dynamically on runtime.

我们来用 esmodule 的形式改写下上边 commonjs 的代码。

首先是 hello.js

// src/esmodule/hello.js
const hello = (filename) => {
    return import("./json/" + filename + ".json");
};
expor
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值