[路飞]webpack5 源码的构建过程(简略版)

429 阅读2分钟

「这是我参与2022首次更文挑战的第15天,活动详情查看:2022首次更文挑战」。

前言

这是刚出炉的质量有那么一点的面粉, 有点生涩,没有太好也不至于太差。至于后面会不会做成面包或者蛋糕,就看时机吧。

webpack 的原理

webpack的原理是通过读取文件,用不同的 loader 进行编译,根据 chunk 生成新代码。

webpack的构建过程(里面很多生命周期,都是通过 tapable 调用)

主要的过程是读取配置,使用插件进行解析收集module,解析完后生成chunk,再生成文件。

以下步骤节选自 webpack5 源码

  1. 获取 webpack.config.js 的配置后, 执行 webpack(config),内部会调用 new Compiler() 生成解析器,然后调用 compiler.run()。
  2. webpack 使用 tapable 做自定义事件的注册和派发,在 run 里面会执行 this.hooks.run.callAsync(this),
  3. 然后进入 compiler.compile,在里面创建实例 new Compilation(), 实例里带有 ModuleGraph 实例将用来存放 module。
  4. 调用 compilation.seal,是生成依赖的过程。在 seal 里面首先初始化一个存放 chunk 的实例 new ChunkGraph()。
  5. 接下来就是解析添加chunk的过程。分为了 runtimeChunk 和 entryPointChunk。
  6. 然后就是 optimize 的过程。
  7. 最后 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 函数依次执行每一个模块。