1

通过解读webpack-manifest-plugin,了解下plugin机制

先简单说一下这个插件的功能,生成一份资源清单的json文件,如下

clipboard.png
如果是服务器端构造的html,就可以根据当前的manifest,引入css和js文件,而且这个文件是必须的,否则服务器端压根不知道hash之后的JS文件名字和CSS名字。

简单说下webpack执行,取得webpack.config.js的配置和默认配置合并,然后执行plugin,这里的执行其实只是简单的绑定hooks,并非执行里面的逻辑,先看下源代码,再给大家撸一撸这里面的细节。

clipboard.png

compiler实例会作为参数传递,可以看到new 之后,他就立刻去遍历的plugin,然后plugin.apply(compiler)去执行了当前的plugin。难道说
plugin在这里就执行了?说对也不对,看一段最简单的plugin的demo

 apply(compiler) {
    compiler.hooks.compilation.tap('xxx', (compilation) => {
     do something
    });
  }

官网的demo,用的compiler.plugin,但这个方法已经不推荐使用了,用hooks代替,更语义化一点。
看上面的代码,apply执行后,其实只是在对应的hooks上注册了一个方法而已,xxx可以理解为一个plugin的标识。注册方法之后,当webpack执行了当前的hooks,那么挂载正在当前hooks上的方法就会被执行。
这个有点类似于发布订阅模式了
综上所述,webpack在 compiler被创建的之后,立刻就去遍历了plugin,就是想要尽早的注册方法,否则挂载在一些hooks上的方法就没办法被正确触发。比如

clipboard.png

在webpack开始编译之前,就能触发beforeRun钩子,webpack-manifest-plugin就用到了当前的hook。因此虽然plugin注册的早,但真正的执行顺序在于它绑定的到底是什么样的钩子。无关于它在webpack配置中plugin里面的顺序。


上面都是前置知识,下面通过解读一个plugin源码来巩固下。

clipboard.png

先看一段简单的源码。
这里他注册了好几个钩子,我们一个一个来说。
compiler.hooks.webpackManifestPluginAfterEmit = new SyncWaterfallHook(['manifest']); 这里是自定义一个hooks,webpack允许自定义hooks,这个hooks是干嘛的,这是给其他组件用的,意思就是,我注册了一个这样的hooks,其他组件就能通过tap绑定对应的方法,仅此而已。

 compiler.hooks.compilation.tap(pluginOptions, function (compilation) {
      compilation.hooks.moduleAsset.tap(pluginOptions, moduleAsset);
    });

hooks.compilation,compilations是compiler众多的hooks的一个,官网的解释是:编译(compilation)创建之后,执行插件。简单的可以理解为某段编译过程(一个文件或者一个chunk),一次webpack,会触发多次的compilation, 而compilation下面又有N多的hooks,具体有哪些可以看官网,这里的moduleAsset,官网的解释是:一个模块中的一个资源被添加到编译中。比如图片资源。
moduleAsset回调函数接收到了两个参数,一个是filename,就是hash后的图片名字,将filename,保存到一个全局对象中。但这里的资源并不包括JS,CSS,需要在其他的hooks中处理。

compiler.hooks.emit.tap(pluginOptions, emit);

emit的钩子官网解释是:生成资源到 output 目录之前。 说白了就是把构建好的JS和CSS文件写入到dist目录之前触发的hooks。
同样的emit函数里面能够拿到 compilation。 compilation.chunks是一个数组,代表着每一个chunk,通常是entry里面定义的文件,以及通过splitChunks,拆开的chunk。chunk里面能拿到一个files字段,里面存到就是生成的css和js名字。

compiler.hooks.emit.tap('xxx', (compilation) => {
      compilation.chunks.forEach((chunk) => {
        console.log(chunk.files);
      });
    });

clipboard.png

到这里webpack-manifest-plugin的主功能就差不多了,将上面得到的各种hash后的name保存到对象里面,key就是chunk名(不一定准),但key具体是什么不重要,到时候服务器端遍历json的时候,判断value的后缀即可,到底是js,css或者其他什么的一目了然。
webpack-manifest-plugin还有一些细节处理,比如取到了publicPath,结合拿到的fileName,组成了文件的真正地址。

plugin其实还可以展开很多内容讲,但官网都有,很多时候也不用我们去写plugin,网上大把,我们只需要知道,他的基本原理即可。
hooks,订阅发布等。


白衣卿相
215 声望13 粉丝