「这是我参与2022首次更文挑战的第15天,活动详情查看:2022首次更文挑战」。
前言
这是刚出炉的质量有那么一点的面粉, 有点生涩,没有太好也不至于太差。至于后面会不会做成面包或者蛋糕,就看时机吧。
webpack 的原理
webpack的原理是通过读取文件,用不同的 loader 进行编译,根据 chunk 生成新代码。
webpack的构建过程(里面很多生命周期,都是通过 tapable 调用)
主要的过程是读取配置,使用插件进行解析收集module,解析完后生成chunk,再生成文件。
以下步骤节选自 webpack5 源码
- 获取 webpack.config.js 的配置后, 执行 webpack(config),内部会调用 new Compiler() 生成解析器,然后调用 compiler.run()。
- webpack 使用 tapable 做自定义事件的注册和派发,在 run 里面会执行 this.hooks.run.callAsync(this),
- 然后进入 compiler.compile,在里面创建实例 new Compilation(), 实例里带有 ModuleGraph 实例将用来存放 module。
- 调用 compilation.seal,是生成依赖的过程。在 seal 里面首先初始化一个存放 chunk 的实例 new ChunkGraph()。
- 接下来就是解析添加chunk的过程。分为了 runtimeChunk 和 entryPointChunk。
- 然后就是 optimize 的过程。
- 最后 this.createChunkAssets() 生成资源,进行文件写入。这个方法里面有 manifest,应该就是相关的配置吧。
打包后的结果
在 mode = development 时,打包出的是自执行函数,有一个以引用路径为 key 的对象,里面是每个模块的 eval函数。使用__webpack_require__代替在文件里写的 require。
(function (){
const cachedModule = {
'./index.js': (module, modules.exports, __webpack_require__) => evel(chunk)
}
__webpack_require__('./index.js')
function __webpack_require__(id) {
const f = cachedModule[id]
const module = {
exports: {}
}
// 这样就解释了为什么我们能在写代码的时候能用 module.exports、exports 和 require 了
f(module, module.exports, __webpack_require__)
return module.exports
})()
在 mode = production时, 则没有用 eval。而是直接输出了压缩后的代码。
分了 chunk 之后,webpack 使用 self["webpackChunkdemo"] 控制各个chunk。每一个 chunk 是数组,里面有 [chunkIds, moreModules, runtime]。类型分别是 [array, function, function]。通过 webpackJsonpCallback 函数依次执行每一个模块。