Appearance
分析webpack源码的执行
- 我们要看的是 webpack底层工作的工具方法
- 新建项目,安装webpack,webpack-cli,之后用webpack进行打包。我们分析打包出来的bundle.js
bundle.js
- 我们模块中的代码经过 webpack 打包之后,就被放在了一个自执行函数中
- 这个自调用函数接收一个参数,它的值是一个对象,这个对象的键就是相对于当前项目来说, 被打包文件的路径(moduleId),它的值就是我们被打包模块中的源代码,这个函数定义的 时候接收了二个参数 module exports
- 我们在写代码的时候会使用 ESmodule 或者 commonjs 规范的 module,而 webpack 都可以处理,因为它的内部自己实现了很多自定义方法(
__webpack_require__
类似这种)
bundle.js 流程
以单模块打包,且这个模块中没有其它的导包操作为例:
外部分析
- 将所有的内容都放置于一个自调用函数中,然后将被打包模块相关信息进行传参
- 相关信息就是一个对象,格式就是 moduleId: 组装后的函数( 函数体就是打包前的源码 )
内部函数体
- 自调用函数体内定义一个空对象用于存储缓存
- 自定义一个
__webpack_require__
函数,它接收一个 ModuleId - 这个 moduleId 是在自调用函数体的最后一行调用时传入的,100%就是入口文件的ID
- 自调用函数逻辑:
- 判断当前 ModuleID 对应的模块是否存在于缓存中
- 如果缓存中不存在的情况下,就自定义的一个 module 存放一个对象
- 同时还将这个 对象存放在了 installModules[moduleId] 缓存里
- 这个对象有三个属性:
- i(存放当前被加载模块的 moduleId)
- l(用于标记当前模块是否已加载, true 就是加载过,false就是没有加载过)
- exports={}(最有用的,打包后的代码都是存在它里面返回)
调用
- 通过 Modules[moduleId] 找到最初组装的那个函数(看2) 以 call 的方式来调用
- 首先修改了this指向
- 然后传入了 module (之前没有缓存定义的module,module里面本身就有exports) 和 module.exports (为啥这么干也是同时考虑到ESModules和CommonJS)
- 最后还有 一个 webpack_require ,为了将来应对被打包模块中还有其它的模块导入(为了递归调用的)
- 余下的就是常见工具定义的方法...
常见工具方法的作用
- o: 可以判断当前对象中是否存在某个指定的属性
- d: 给对象的某个属性添加一个 getter
- r: 将对象标记为 __esModule
- t: 太恶了放在最后看
- n: 依据不同的模块返回一个返回模块内容的 getter
r方法内容补充
Symbol.toStringTag
如何判断一个对象类型
js
console.log(Object.prototype.toString.call(12))
// [object Number]
console.log(Object.prototype.toString.call('12'))
// [object String]
let obj1 = {}
let obj2 = {}
console.log(Object.prototype.toString.call(obj1)) // [object Object]
console.log(Object.prototype.toString.call(obj2)) // [object Object]
// 我们现在就在手写 r 方法
function r (object) {
if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
Object.defineProperty(object, Symbol.toStringTag, {
enumerable: true,
value: 'Module'
});
}
Object.defineProperty(object, '__esModule', { value: true });
}
console.log(obj1) // {}
r(obj1)
console.log(obj1)
// Module {__esModule: true, Symbol(Symbol.toStringTag): "Module"} 浏览器执行(ESModule)
// { [Symbol(Symbol.toStringTag)]: 'Module' } node执行(CommonJS)