webpackcjs运行时分析示例详解
短信预约 -IT技能 免费直播动态提醒
准备工作(接上篇文章的示例也可以):
1. 在index.js文件中引入任一js文件
import sum from './sum';
const result = sum(1,2);
console.log(result);
2. sum文件
const sum = (a, b) => {
return a+b;
}
export default sum
3. build.js文件
const path = require('path');
const webpack = require('webpack');
function wrapBuild() {
return webpack({
entry: './index.js',
mode: 'none',
output: {
path: path.resolve(__dirname, 'build'),
filename: '[name].js'
},
infrastructureLogging: {
debug: true,
level: 'log',
}
})
}
wrapBuild().run((err, stat) => {
const startTime = stat.startTime;
const endTime = stat.endTime;
console.log('构建时间: ', endTime - startTime);
})
4. 命令行执行node ./build.js 生成打包产物main.js。
(截图未完整, 共87行)
5. 什么是运行时代码?
通过webpack打包得到的文件(如/build/main.js的骨架代码), 其中包含了一些webpack如何将多个模块集合在一起的代码, 可粗暴理解为webpack runtime 打包过后的代码。可通过node build/main.js可直接调试。
6. 示例打包js资源后的运行时代码分析:(含注解)
(() => { // webpackBootstrap
"use strict";
var __webpack_modules__ = ([
, // ---模块0, 入口模块 可以理解为index.js模块
// ---模块1,打包过后的sum.js
((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
__webpack_require__.d(__webpack_exports__, {
"default": () => (__WEBPACK_DEFAULT_EXPORT__)
});
const sum = (a, b) => {
return a+b;
}
const __WEBPACK_DEFAULT_EXPORT__ = (sum);
})
]);
// 模块缓存
var __webpack_module_cache__ = {};
// 模块加载器, 模拟实现common.js的require
function __webpack_require__(moduleId) {
// 根据moduleId从缓存中读取module
var cachedModule = __webpack_module_cache__[moduleId];
// 若缓存中存在该模块,则返回当前的module.exports
if (cachedModule !== undefined) {
return cachedModule.exports;
}
// 缓存中不存在该模块,则去__webpack_modules__里取。
// 创建一个新的模块, 写入cache对象, key为moduleId, value 为 exports对象
var module = __webpack_module_cache__[moduleId] = {
// no module.id needed
// no module.loaded needed
exports: {}
};
// 调用包裹函数,计算模块信息,解析出相关模块内容(如:exports)
__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
// 返回当前解析过后的module.exports
return module.exports;
}
var __webpack_exports__ = {};
// 加载入口函数
(() => {
__webpack_require__.r(__webpack_exports__);
var _sum__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
const result = (0,_sum__WEBPACK_IMPORTED_MODULE_0__["default"])(1,2);
console.log(result);
})();
})()
;
该运行时代码一共做了三件事:
- __webpack_modules__ : 维护一个所有模块的数组,通过深度优先遍历将其全部转换为AST,以供给后面的包裹函数解析
- __webpack_require__: 手动实现一个模块加载器;优先从缓存列表__webpack_module_cache__中读取模块,并返回其exports内容。如果缓存中没有,则调用包裹函数解析出模块exports等重要内容,存入缓存列表中并返回exports。
- 调用__webpack_require_(0): 运行入口模块.
7. 疑问?
- 如果不对模块进行缓存,会有什么问题?
- 模块内容重复计算,消耗性能。
- 每个模块只在第一次引用的时候产生一个对象,后面都是引用该对象,减少代码复杂度。
- module.exports和exports有什么区别?
- 默认情况下,Node准备的exports变量和module.exports变量实际上是同一个变量,并且初始化为空对象,我们可以把要输出的东西直接加入在这个空对象里面;但是,如果我们要输出的是一个函数或数组,那么,只能给module.exports赋值,给exports赋值是无效的,因为赋值后,module.exports仍然是空对象。
- 结论:
- 如果要输出一个键值对象{},可以利用exports这个已存在的空对象{},并继续在上面添加新的键值;
- 如果要输出一个函数或数组,必须直接对module.exports对象赋值。
- 建议直接对module.exports赋值,可以应对任何情况;
参考文献
详细的可移步大佬的文章
到此这篇关于webpack cjs运行时分析的文章就介绍到这了,更多相关webpack cjs运行时内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341