webpack 编译结果分析与实现
我们可以知道,webpack 是可以将我们的代码进行打包,那么打包的结果是如何产生和实现的呢?
- 首先我们知道,webpack 可以实现我们自主使用 ES6/common.js 的模块化导出方式
我们分析一下,webpack 的打包之后的特性:
- 将多个模块合并在一个 main.js 中执行
- 多个模块不会产生环境变量的污染
#思路:
- 在 main.js 合并的文件中,我们可以将多个模块合并到一个对象中
js
//键:模块的路径
//值:函数,这样可以避免了模块之间变量的污染,而函数内部放置模块的代码
//参数:因为在模块代码中,我们用到了module.exports,和require函数,所以我们将这些当作参数传递进来
const module = {
"./a.js": function (module, exports, require) {
exports.a = "我是a";
module.exports = "我是 a 模块";
},
"./index.js": function (module, exports, require) {
const A = require("./a");
console.log("我是主入口", A);
},
};
- 我们需要一个函数来执行我们规整好的模块对象,这里选用了自执行函数
js
/*
我们可以分析出这个函数需要干什么(什么功能)
1.不论如何都会执行index.js文件
2.需要内部实现一个require函数,因为执行模块靠它
2.1 require函数功能:
a.执行模块代码
--require('路径'),将路径传入,通过路径找到modules中的函数执行
b.返回模块的导出对象
--因为模块的函数中需要传入(module,exports,require),所以在require函数内部声明一个module对象,然后当执行模块代码的时候,将module传入,因为在模块代码内部用户会对module重新赋值,所以,直接将module返回出去即可。
3.模块代码具有缓存,不会重复执行
--缓存可以
{
"路径":模块结果
}
*/
(function (modules) {})(传入整合好的模块对象);
#完整代码
js
//将所有的模块合并成一个对象,模块内包含每个模块的代码
// const module = {
// "./a.js": function (module, exports, require) {
// exports.a = "我是a";
// module.exports = "我是 a 模块";
// },
// "./index.js": function (module, exports, require) {
// const A = require("./a");
// console.log("我是主入口", A);
// },
// };
//将模块对象交给一个自执行函数处理
(function (modules) {
//实现模块缓存,缓存模块导出的结果
let moduleCache = {};
/**实现require函数
* 1.执行该模块
* 2.返回模块结果
* @param {string} moduleID 模块的id标识,即模块路径
* @returns {object} 模块导出的结果
*/
function _webpack_require(moduleID) {
//有缓存的话,直接退出函数
if (moduleCache[moduleID]) return;
//创建module对象
let module = {
exports: {},
};
//1.通过模块路径找到模块函数,并执行
const fun = modules[moduleID];
fun(module, module.exports, _webpack_require); //将module传入到模块中,在模块中会将该module重新赋值,所以直接返回结果就是这个module对象
//2.返回模块导出的结果
const result = module.exports;
//3.给模块导出的结果加给缓存
moduleCache[moduleID] = result;
return result;
}
// 执行入口文件
_webpack_require("./index.js");
})({
"./a.js": function (module, exports, _webpack_require) {
exports.a = "我是a";
module.exports = "我是 a 模块";
console.log("我是模块A");
// eval(
// "exports.a = '我是a';\nmodule.exports = '我是 a 模块';\nconsole.log('我是模块A');\n//# sourceURL=webpack:///./src/a.js"
// );
},
"./index.js": function (module, exports, _webpack_require) {
const A = _webpack_require("./a.js");
console.log("我是主入口");
// eval(
// "const A = _webpack_require('./a.js');\nconsole.log('我是主入口');\n//# sourceURL=webpack:///./src/index.js"
// );
},
});
/*
使用eval()的目的:
1.因为我们使用的是编译之后的代码,如果代码出错,在浏览器只会跳到编译后的位置,而不是源代码的位置,这样就不方便调试了
2.而eval()在执行代码的时候,会单独的将内部的代码开辟出一个空间,这样我们就可以在代码出错的时候进行错误定位了
*/