⚠️超长代码预警,需要几个小时的时间去啃,但读懂以后应该会很开心。
commonjs
新建一个 json
文件夹,包含几个 json
文件,和一个 add
方法。
其中 add.js
就是一个简单的加法模块。
// src/commonjs/json/add.js
console.log("add开始引入");
module.exports.add = (a, b) => {
return a + b;
};
test1.json
和 test2.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"));
可以看一下控制台是正常输出:
看一下打包产物:
主要看一下保存所有模块的 __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.json
和 test2.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");
};
export