浅谈webpack运行机制与工作原理

通过Webpack 官网banner图很直观的读懂它的功能。就是将应用的各种互相依赖的资源文件分类归纳聚集打包输出。整个打包过程主要做了2件事:

  1. 通过loader处理各种特殊的资源文件,例如样式,图片,vue文件。
  2. 通过plugin自动化处理各种复杂的任务,例如代码压缩,自动发布。

当 webpack 处理应用程序时,它会根据命令行参数中或配置文件中定义的模块列表开始处理, 从 入口 开始,webpack 会递归的构建一个 依赖关系图,这个依赖图包含着应用程序中所需的每个模块,然后将所有模块打包为少量的 bundle。

有了这个依赖关系树过后, Webpack 会遍历(递归)这个依赖树,找到每个节点对应的资源文件,然后根据配置选项中的 Loader 配置,交给对应的 Loader 去加载这个模块,最后将加载的结果放入 bundle.js(打包结果)中,从而实现整个项目的打包。

Webpack原理剖析

Webpack是一个开箱即用的工具,若在日常开发使用一些前端框架的脚手架比如vue-cli,那基本上不需要接触到webpack细节。但开发中往往还是会遇到各种各样的问题,如果不了解webpack的一些基础原理,届时就会手忙脚乱了,方寸大乱了。

在深入了解webpack原理之前最好还是带着问题去查阅源码,否则进入到源码的世界就会像无头苍蝇一样到处乱撞,耗时费力。

因为webpack的核心机制是loader和plugin,所以大多数问题会围绕它们展开如下:

  1. webpack-cli是如何启动打包流程。
  2. Webpack工作的打包编译核心模块compiler对象。
  3. Webpack怎么注册插件,通过什么方式使用插件。
  4. Webpack如何生成依赖树,交给loader处理。
  5. Webpack如何将loader处理完的结果打包输出到dist目录

Webpack调试

1. 在当前webpack项目工程文件夹下面,执行命令行:

node --inspect-brk ./node_modules/webpack/bin/webpack.js 

其中参数--inspect-brk就是以调试模式启动node:

会观察到输出:

2.打开Chrome浏览器,地址栏里输入chrome://inspect/#devices:

 在弹出窗口点击超链接"Open Dedicated DevTools for Node.

此时在第一步的命令行窗口里,出现一行新的提示信息:debugger attached。

 此时Chrome窗口弹出来了,断点停留在webpack.js第一行处,这时候就可以开始调试webpack了。

 Webpack-cli

紧接着代码会进入到webpack-cli文件,Webpack CLI 的作用就是将 CLI 参数和 Webpack 配置文件中的配置整合,得到一个完整的配置对象。

 有了配置选项过后,开始载入 Webpack 核心模块,传入配置选项,创建 Compiler 对象,这个 Compiler 对象就是整个 Webpack 工作过程中最核心的对象了,负责完成整个项目的构建工作。

创建Compiler 对象

观察代码,发现 options 不仅仅可以是一个对象,还可以是一个数组。如果options是一个数组,那么 Webpack 内部创建的就是一个 MultiCompiler,也就是说 Webpack 应该支持同时开启多路打包,配置数组中的每一个成员就是一个独立的配置选项。而如果我们传入的是普通的对象,就会按照我们最熟悉的方式创建一个 Compiler 对象,进行单线打包。

这里是单线打包,核心代码是compiler = createCompiler(webpackOptions);此处代码大概分3个阶段。

  1. 创建compiler。
  2. 注册插件,确保在后续的生命周期命中插件的钩子。
  3. 触发特定hook。

 webpack开始构建

完成 Compiler 对象的创建过后,紧接着这里的代码开始判断配置选项中是否启用了监视模式,我们这里没有开启,就直接运行run方法开始构建应用。

 run方法内部先触发了beforeRun 和 run 两个钩子,然后调用了当前对象的 compile 方法,开始真正开始编译整个项目。这个(代码在compiler.js)

compile 方法内部主要就是创建了一个 Compilation 对象,可以理解为一次构建过程中的上下文对象,里面包含了这次构建中全部的资源和信息。

创建完 Compilation 对象过后,紧接着触发了一个叫作 make 的钩子,整个构建过程最核心的 make 阶段。

 make 阶段

由于webpack采用事件触发机制,所以这里代码调试会比较困难。调试最好的方式是找到在哪里注册了make事件。Webpack 的插件系统是基于官方自己的 Tapable 库实现的,我们想要知道在哪里注册了某个事件,需要知道如何注册的事件。

Tapable注册事件方式:

所以开发工具搜索源代码中的 hooks.make,就应该能够找到事件注册的位置

 make 阶段主体的目标就是:根据 entry 配置找到入口模块,开始依次递归出所有依赖,形成依赖关系树,然后将递归到的每个模块交给不同的 Loader 处理。这个插件中调用了 Compilation 对象的 addEntry 方法,开始解析我们源代码中的入口,可以从这里开始进入调试。

 后续的流程大概如下:

  1. addEntry 方法中调用了 __addEntryItem方法,将入口模块添加到模块依赖列表中;
  2. 紧接着通过 Compilation 对象的 buildModule 方法进行模块构建;
  3. buildModule 方法中执行具体的 Loader,处理特殊资源加载;
  4. build 完成过后,通过 acorn 库生成模块代码的 AST 语法树;
  5. 根据语法树分析这个模块是否还有依赖的模块,如果有则继续循环 build 每个依赖;
  6. 所有依赖解析完成,build 阶段结束;
  7. 最后合并生成需要输出的 bundle.js 写入 dist 目录。 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值