资讯专栏INFORMATION COLUMN

你想要的——webpack构建过程分析

Lycheeee / 1052人阅读

摘要:类定义了方法,用于注册插件,将插件及其回调函数以的形式保存在内部对象中又定义了,等方法来触发插件的回调函数。所以当类继承类后,也同样具有注册插件和触发回调函数的功能。

说起webpack,相信对于前端工程师们而言早已经不是什么新鲜的事物。但是由于webpack有着较为复杂和灵活的配置项,所以给人的第一感觉是难以完全掌握。

这次就跟大家分享一下有关webpack构建过程的相关知识,希望对大家进一步理解webpack有所帮助。

本次分析的对象是webpack(v3.6.0),这是gayhub地址 摸我

由于webpack的内容实在太多,一下子讲太多东西容易懵逼,我们这次就从最最最简单的例子开始讲起。

以下是我写的一个炒鸡简单的例子:

// webpack.config.js

var path = require("path");
module.exports = {
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, "build"),
    filename: "bundle.js"
  }
}

假设我们的工作目录下有一个这样的webpack.config.js文件,那么当我们执行webpack命令的时候【前提是你已经安装了webpack】,那么首先会执行的是 /bin 目录下的webpack.js

OK,作为入口文件,我们首先要分析的就是: /bin/webpack.js

这个文件主要做了以下几件事:

引入yargs模块,对命令行参数进行注释和重命名等工作

添加处理默认参数(比如当我们没有指定--config参数的时候,默认去找当前目录下的 webpack.config.js文件作为配置文件)

处理完参数相关的内容之后,就引入lib目录下的webpack.js文件,得到编译对象compiler,然后进行编译(compiler.run())

var webpack = require("../lib/webpack.js");
...
...
try {
    // 这里的options就是转换之后的参数,convert-argv文件主要负责这些工作
    // 得到compiler对象
    compiler = webpack(options);
}catch(e) {
    ...
    ...
}
...
...
// 执行编译
compiler.run(compilerCallback)

由于这里讲的例子比较简单,不涉及到其他参数相关的内容,感兴趣的同学可以进一步了解参数处理的部分,这里就不多做解释了。重点我们还是看一下这个编译的过程。

作为complier的入口文件,我们接下来看一下: /lib/webpack.js

这个文件首先调用validateSchema方法对传入的options进行格式校验

然后又调用了WebpackOptionsDefaulter实例的process方法对options进一步的处理(保存了两个实例属性 default={} , config= {},分别往这两个对象上面挂属性,然后再挂载到options上)

然后实例化Compiler类,由于这个类继承自Tapable类,所以他具有父类上实现插件的一套机制(applyPlugin,plugin等方法,后面会具体分析这两个类),得到compiler对象

然后执行NodeEnvironmentPlugin插件,主要是使用enhanced-resolve模块修饰compiler对象,注册“before-run”回调方法

然后调用complier的apply方法,内部其实调用插件的apply方法,相当于注册各种插件的回调方法

触发“environment” 和 “after-environment” 回调方法

实例化WebpackOptionsApply类,调用process方法;后面我们会展开分析这个方法

往webpack这个方法上挂一下静态属性(各种插件方法)

导出webpack这个方法

接下来我们先分析WebpackOptionsApply类:/lib/WebpackOptionsApply.js

从上面看到,在编译之前,webpack会先实例化WebpackOptionsApply类,然后调用其process方法
我们看到process方法其实就是注册了N多个插件,然后触发了某些插件的回调函数

首先判断options.target,如果值为“web”的话(这种情况是最常见的,其他情况的逻辑也是类似的),则注册插件JsonpTemplatePlugin【注册“this-compilation”回调】,FunctionModulePlugin【注册“compilation”回调】,NodeSourcePlugin【注册“compilation” & “after-resolver”回调】,LoaderTargetPlugin【注册“compilation”回调】。

注册插件LibraryTemplatePlugin【注册“compilation”回调】,ExternalsPlugin【注册“compile”回调】

注册插件EntryOptionPlugin【注册“entry-option”回调】

触发“entry-option”回调,所以进入了EntryOptionPlugin插件的回调函数

EntryOptionPlugin类中,通过itemToPlugin方法判断单入口还是多入口文件,这里以单入口为例,所以进入了SingleEntryPlugin类中,注册插件SingleEntryPlugin【“compilation” & “make”回调】

继续回到WebpackOptionsApply的process方法,然后又继续通过compile.apply方法添加插件,插件太多了,不一一列举,感兴趣的可以跟踪代码了解详情

最后触发“after-plugins” 和 “after-resolvers” 的回调函数

以上就是WebpackOptionsApply实例调用process的全过程

在/bin/webpack中,得到的是/lib/webpack返回的compiler对象,最后调用compiler对象的run方法。

作为编译过程的核心类,我们接下来看看Compiler这个类:/lib/Compiler.js

我们看到Compiler类继承自Tapable类 github地址

Tapable类提供了一种调用插件的方式,webpack全部插件都是基于这种方式来注册和调用的。

Tapable类定义了plugin方法,用于注册插件,将插件及其回调函数以key-value的形式保存在内部_plugins={}对象中;
又定义了applyPlugins,applyPluginsWaterfall等方法来触发插件的回调函数。其实就是一个订阅-发布模式的实现。

所以当Compiler类继承Tapable类后,也同样具有注册插件和触发回调函数的功能。

接下来看看Compiler中的run方法

首先触发的“before-run”回调函数,NodeEnvironmentPlugin插件注册了回调函数

然后触发“run”回调函数,CachePlugin插件注册了回调函数

调用readRecords方法()

调用compile方法,进入compile过程

触发“before-compile”回调函数,DllReferencePlugin注册了回调函数

触发“compile”回调函数,ExternalsPlugin & DllReferencePlugin & DelegatedPlugin注册了回调函数

调用newCompilation方法,创建Compilation实例,这个实例包含了编译过程的所有属性和方法

触发“this-compilation”回调函数

触发“compilation”回调函数

触发“make”回调函数

如果是单入口项目,这里就会触发SingleEntryPlugin插件注册的“make”回调,其中调用了compilation的addEntry方法进行模块构建

通过compilation的processModuleDependencies方法收集模块的依赖

最后通过buildModule方法构建模块

调用compilation.finish()方法

调用compilation.seal()方法

触发“after-compile”回调函数

compile方法执行完之后,就执行onCompiled回调

触发“should-emit”回调函数

触发“done”回调函数

调用emitAssets方法,触发了“emit”回调函数

调用emitFiles方法,触发“after-emit”回调函数

最后执行emitRecords方法

这就是compiler的run方法的主要内容分析

以上就是webpack简单的构建流程的分析。哈哈今天就分享到这里,希望大家喜欢,祝大家周末愉快啊。。。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/89237.html

相关文章

  • Webpack实战 - 使用动态 entry 改善调试体验

    摘要:本文相关代码已经存放在,可自行下载使用多入口复习的优势不言而喻,因此在实际应用中我们也常常使用它调试多入口应用,所谓多入口是指多个页面会使用多个入口文件,在官方教程介绍了如何配置这里指定了个入口文件,打包之后分别会在文件夹中生成个打包之后 本文相关代码已经存放在 dynamic-entry,可自行下载使用 0. 多入口 (复习) webpack 的优势不言而喻,因此在实际应用中我们也常...

    oogh 评论0 收藏0
  • 【提高系列】webpack相关知识

    摘要:基本配置项基本配置项。的插件架构主要基于实现的,这个就是专注于事件的广播和操作。开启多进程,加快打包速度。 这次我们主要研究的是webpack框架的相关知识,webpack是一个打包构建的前端框架,用于解决前端开发的模块化问题。 应用场景和纵向比较 说到webpack,肯定你还会想到gulp和grunt这些框架,那么webpack是做什么的呢?他和其他的框架有什么区别呢?我们一起来分析...

    DirtyMind 评论0 收藏0
  • 用十分之一构建时间做一场页面静态资源依赖分析

    摘要:不直接使用的原因很简单首先构建一次实在太慢了,特别是有几十个页面存在的情况下,另一个原因是我只是想拿到资源依赖,我根本不想对整个前端进行一次构建,也不想生成任何。这就达到了本文题目中目的,用十分之一的构建时间做一场页面静态资源依赖分析。原文链接 作者:梯田 前言: 所谓【静态资源依赖分析】,指的是可以通过分析页面资源后,可以以 json 数据或者图表的方式拿到页面资源间的依赖关系。 比如 c...

    B0B0 评论0 收藏0
  • Vue 2019开发者图谱

    摘要:为了便于您更清晰的理解的体系架构,在这里我将为您展示年开发者知识图谱,它包含了所有开发过程中的关键部分。在数据展示前端导入导出图表面板数据绑定等场景无需大量代码开发和测试,可极大节省企业研发成本并降低交付风险。 作为 Vue 的初学者,您或许已经听过很多关于它的专业术语了,例如:单页面应用程序、异步组件、服务器端呈现等,您可能还听过和Vue经常一起被提到的工具和库,如Vuex、Webp...

    cgspine 评论0 收藏0
  • 借助webpack对项目进行分析优化

    摘要:由于项目的不断扩大,只会影响我们定位功能和问题的速度,因此对冗余文件进行清理,是很重要的。我们在项目中使用的,自动将各个图标进行。 进入公司之后,接手的便是前人留下来的一个大项目。庆幸的是整个项目拥有完善的产品功能文档,但是由于项目过于庞大,老旧。包含了打包过慢,冗余文件过多等诸多问题。想要快速的解决这些问题,想要完全把功能重构一遍的话,成本太高了。一个一个文件来过,时间成本也比较大。...

    Me_Kun 评论0 收藏0

发表评论

0条评论

Lycheeee

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<