Webpack源代码解析

webpack其实也就是一个函数的调用,返回一个Compile的对象,再调用Compile的run方法就可以完成项目的构建

那么我们肯定是先要从webpack这个函数去理解它在构建的过程中都做了些什么

如果我们没有传入callback那么他就会执行else中的代码,首先是create函数

那么我们核心的代码就在createCompiler函数中

插件的执行是贯穿于webpack的整个生命周期的,webpack当中很多的东西其都是插件,比如entry,他会把它转成插件

转换的过程就在WebapackOptionsApply当中

它注册插件的目的就是将compiler对象传入插件的apply函数中去,在apply函数中监听compiler对象的hooks,那么在webpack执行到某一个生命周期的时候compiler会去回调hooks

那么我们再看看hooks是什么东西

我们肯定先看打开Compiler这个类

你会发现有很多的hooks(钩子),实际上他们是用了一个tapable的库有兴趣的可以去看

我们的插件都会去调用它的apply传入compiler,apply的函数中都会去执行compiler.hooks.xxx(钩子),如其中一个hooks.xxx.tap('xxx',回调)这个注册的事件会在webpack编译的某个生命周期里面compiler.hook.xxx.call('xxx')去回调

那么我们真正构建的时候是去调用compiler的run方法

接下来分析run方法做了什么事情

编译的过程在this.compile(onCompiled)中,onCompiled是没有错误的回调函数

Compiler和Compilation的区别
 Compiler:在webpack构建的之初就会创建的一个对象, 并且在webpack的整个生命周期都会存在
Compilation是到准备编译模块(比如main.js), 才会创建Compilation对象
主要是存在于 compile(之后) - make(之前) 阶段主要使用的对象
watch -> 源代码发生改变就需要重新编译模块
Compiler可以继续使用(如果我修改webpack的配置, 那么需要重新执行run run build)
Compilation需要创建一个新的Compilation对象
 
 
接下来就是Compilation对模块的处理
我们之前理解到对模块的处理是在make阶段进行的,那么我们首先一步步来分析从plugin到make阶段的过程
之前有一个WebpackOptionsApply.process的函数里面是对配置转成一个个插件的处理,那么我们从入口开始

打开apply函数

它会调用EntryOptionPlugin的静态方法applyEntryOption

我们再打开applyEntryOption

打开EntryPlugin的apply方法

那么这个hooks到make阶段的时候回调就开始执行了,并且把compilation传入

打开这个_addEntryItem私有函数

他的本质就是想调用addModuleTree

根据当前模块,把他加入到模块树中去

处理这个模块并且把他创建

最终会调用factorizeModule方法

加入到队列中去

最终的执行都是按照队列的方式进行执行的

他将处理好的模块传入到newModule中去

看看addModule做了什么

把模块加入到了modulequeue中去

当监听到某个hooks后他会去回调callback

构建模块

把即将构建的模块又加入到buildqueue中去了

在我们buildqueue中其实已经有很多我们加进去的模块了

而这个队列中是有一个处 理的方法的

具体的构造模块其实就是在这里

调用_buildModule的时候就开始真正的构建我们的模块了

打开build方法

其实打开的是一个子类

点击这里

找到实现类

点开doBuild

resource是即将要处理的资源

loaders是要应用的loaders

processResource是对资源的进一步处理

processResult是之前在上面定义的函数(处理结果的函数)

我们最主要的就是看它回调的这个callback

这个callback是在build函数中传入的

this.parser.parse最主要的就是解析js代码,这个parser是一个类,但是是个抽象类,他的实现类是javaScriptParser,但是在处理的时候是使用了acorn库,最主要的就是分析当前模块是否依赖了其他的模块,如果依赖了,他还是会继续回到runLoader函数中去,继续去处理他所依赖的模块,依次处理

如果ast有值的话他会去处理ast,或者去调用source函数得到结果交给parsser的parse函数去处理

当解析完成之后他就会来到Compilation中的seal(封存)方法中

把我们解析好的模块封存到chunk中去(把我们解析好的模块分别放到哪些chunk中去)

最终解析出来的数据其实是放到compilation.assets对象中去,但是他在模块真正转成js文件之前是要进行优化的(optimization)

模块->chunk->optimization->compilation.assets

有特别多的处理代码,我们一直往下翻到codeGeneration

往下找里面有一个函数叫 createChunkAssets

往下翻

输出资源 source中有_source就是要输出的内容

目的就是将资源放到compilation对象中去

this就是compilation

当我们做完这些之后就要去做我们的回调过程了

这个callback是之前传入进来的,经过不断的追溯,最终是在调用seal函数的地方(Compiler的compiler方法中)

他调完之后还会调用一个afterCompile的hook,afterCompile的hook调用完成之后还接着会调用callback,那么这个callback就是compile函数的参数,compile是在run方法中调用的所以我们找到run方法

当我们调用完成onCompiled之后他接着就会调用emitRecords去输出里面的资源

25_Webapck原理的更多相关文章

  1. 奇异值分解(SVD)原理与在降维中的应用

    奇异值分解(Singular Value Decomposition,以下简称SVD)是在机器学习领域广泛应用的算法,它不光可以用于降维算法中的特征分解,还可以用于推荐系统,以及自然语言处理等领域.是 ...

  2. node.js学习(三)简单的node程序&&模块简单使用&&commonJS规范&&深入理解模块原理

    一.一个简单的node程序 1.新建一个txt文件 2.修改后缀 修改之后会弹出这个,点击"是" 3.运行test.js 源文件 使用node.js运行之后的. 如果该路径下没有该 ...

  3. 线性判别分析LDA原理总结

    在主成分分析(PCA)原理总结中,我们对降维算法PCA做了总结.这里我们就对另外一种经典的降维方法线性判别分析(Linear Discriminant Analysis, 以下简称LDA)做一个总结. ...

  4. [原] KVM 虚拟化原理探究(1)— overview

    KVM 虚拟化原理探究- overview 标签(空格分隔): KVM 写在前面的话 本文不介绍kvm和qemu的基本安装操作,希望读者具有一定的KVM实践经验.同时希望借此系列博客,能够对KVM底层 ...

  5. H5单页面手势滑屏切换原理

    H5单页面手势滑屏切换是采用HTML5 触摸事件(Touch) 和 CSS3动画(Transform,Transition)来实现的,效果图如下所示,本文简单说一下其实现原理和主要思路. 1.实现原理 ...

  6. .NET Core中间件的注册和管道的构建(1)---- 注册和构建原理

    .NET Core中间件的注册和管道的构建(1)---- 注册和构建原理 0x00 问题的产生 管道是.NET Core中非常关键的一个概念,很多重要的组件都以中间件的形式存在,包括权限管理.会话管理 ...

  7. python自动化测试(2)-自动化基本技术原理

    python自动化测试(2) 自动化基本技术原理 1   概述 在之前的文章里面提到过:做自动化的首要本领就是要会 透过现象看本质 ,落实到实际的IT工作中就是 透过界面看数据. 掌握上面的这样的本领 ...

  8. CRC、反码求和校验 原理分析

    3月份开始从客户端转后台,算是幸运的进入全栈工程师的修炼阶段.这段时间一边是老项目的客户端加服务器两边的维护和交接,一边是新项目加加加班赶工,期间最长经历了连续工作三天只睡了四五个小时的煎熬,人生也算 ...

  9. 菜鸟学Struts2——Struts工作原理

    在完成Struts2的HelloWorld后,对Struts2的工作原理进行学习.Struts2框架可以按照模块来划分为Servlet Filters,Struts核心模块,拦截器和用户实现部分,其中 ...

  10. Objective-C中block的底层原理

    先出2个考题: 1. 上面打印的是几,captureNum2 出去作用域后是否被销毁?为什么? 同样类型的题目: 问:打印的数字为多少? 有人会回答:mutArray是captureObject方法的 ...

随机推荐

  1. 计算机网络基础07 DNS概述

    1 什么是DNS Domain Name System(域名系统),它是一个应用层的服务.它作为将域名和IP地址相互映射的一个分布式数据库,能够使人更方便地访问互联网.当前,对于每一级域名长度的限制是 ...

  2. spring cloud alibaba - Nacos 下载安装

    1.关于名字 前四个字母分别为Naming和Configuration的前两个字母,最后的s为Service 2.是什么 一个更易于构建云原生应用的动态服务发现,配置管理和服务管理中心.是注册中心和配 ...

  3. 在Mariadb中创建数据库-九五小庞

    MariaDB数据库管理系统是MySQL的一个分支,主要由开源社区在维护,采用GPL授权许可 MariaDB的目的是完全兼容MySQL,包括API和命令行,使之能轻松成为MySQL的代替品.在存储引擎 ...

  4. qt元对象系统之 Q_OBJECT宏

    宏展开是这样 #define Q_OBJECT \ public: \ QT_WARNING_PUSH \ Q_OBJECT_NO_OVERRIDE_WARNING \ static const QM ...

  5. 躬身入局,干货分享,2023年春招后端技术岗(Python)面试实战教程,Offer今始为君发

    早春二月,研发倍忙,杂花生树,群鸥竟飞.为什么?因为春季招聘,无论是应届生,还是职场老鸟,都在摩拳擦掌,秣马厉兵,准备在面试场上一较身手,既分高下,也决Offer,本次我们打响春招第一炮,躬身入局,让 ...

  6. vue3 vite 使用NProgress.js纳米级进度条

    NProgress.js 官网:https://ricostacruz.com/nprogress/ 安装方式: npm install nprogress 使用方法 在router 的index.j ...

  7. Slave_IO_Running: Connecting--一种问题的解决方案

    主要有三个原因: 1.网络不同 2.密码不对 3.pos不对 这里只介绍我碰到的问题--不能远程连接数据库.即在从机上对主机进行以下命令 mysql -u**** -p**** -h192.168.* ...

  8. 一个诡异的 Pulsar InterruptedException 异常

    背景 今天收到业务团队反馈线上有个应用往 Pulsar 中发送消息失败了,经过日志查看得知是发送消息时候抛出了 java.lang.InterruptedException 异常. 和业务沟通后得知是 ...

  9. ps抠图小技巧

    1.背景橡皮擦工具 适合分离单一背景. 中括号键可以调整大小. 2.调整边缘抠图(也叫选择并遮住) 适合扣毛发丝. 套索工具框选出大概: 点击选择并遮住后出来一个面板: 视图选择叠加,输出设置勾上净化 ...

  10. vue---:click、:class可以这样表示

    1.:class (1)是否选用class :class="{'active':item.id == id}" (2)根据条件,当前数据dealerId中是否包含当前id,有用cl ...