开发起因:
因为我的项目是vue的页面级组件有差不多100个,举个case:
因为用了 webpack-preftech-pulgin 插件, 页面里会插入 100个

<link href="xxx" as="script" rel="preftech">

标签.
通过在chrome 外面调试发现 当页面里有过多preftech 会阻塞主文件的下载速度,也就是会抢占重要资源的下载速度。所以我采纳另一种实现形式,限度最大同时预下载(未来须要)的 资源的数量,缩小因为资源下载过多,造成首页渲染过慢。
包地址
插件主代码

// 插件地址const  fs  = require('fs')const path = require('path');const Entrypoint = require('webpack/lib/Entrypoint.js');const assert = require('assert');class HtmlWebpackPreFetch {  constructor(options = { paralleMax: 3 }) {      this.options = options  }  apply(complier) {   complier.hooks.compilation.tap(this.constructor.name, compilation => {      // hook HtmlWebpackPlugin 输入 index.html之前的钩子,为了革新输入 index.html 文件内容(来自某个webpack 插件)      let hook = compilation.hooks.htmlWebpackPluginAfterHtmlProcessing;      if (!hook) {        const [HtmlWebpackPlugin] = complier.options.plugins.filter(            (plugin) => plugin.constructor.name === 'HtmlWebpackPlugin');        assert(HtmlWebpackPlugin, 'Unable to find an instance of ' +            'HtmlWebpackPlugin in the current compilation.');        hook = HtmlWebpackPlugin.constructor.getHooks(compilation).beforeEmit;      }      // 对对应的钩子 注册事件,我是这个认为????      hook.tapAsync(        this.constructor.name,        (htmlPluginData, callback) => {          try {            const { outputOptions: { publicPath = '' } , chunks, chunkGroups} = compilation;            // split chunks 找到非入口文件             const sourceList = chunkGroups.filter(chunkGroup => {               return !(chunkGroup instanceof Entrypoint) && !chunkGroup.isInitial()             }).map(chunkGroup => chunkGroup.chunks.reduce((p, q) => {               return {                 files: [...p.files, q.files]               }             ,  {files: []} })).reduce((p, n) => {              return {                files: [...p.files, ...n.files]              }            } , {files: []}).files.map(path => (`${publicPath}${path}`))            // loadTemplate.js 实现并发加载模版文件            let loadJsTemplate = fs.readFileSync(path.join(__dirname, './loadTemplate.js'), {              encoding: 'utf-8'            })            // 获取要下载的文件 和 配置参数            const templateOptions = JSON.stringify({              sourceList,              ...this.options            })                        loadJsTemplate = loadJsTemplate.replace('/*injectOptions*/',  templateOptions)            let htmlTemplate = htmlPluginData.html                        const htmlTemplateList = htmlTemplate.split('</body>')            htmlTemplateList.splice(1, 0, `<script>${loadJsTemplate}</script></body>`)            htmlTemplate = htmlTemplateList.join('');                        htmlPluginData.html = htmlTemplate            callback(null, htmlPluginData);          } catch (error) {            callback(error);          }        }    );    })}}module.exports = HtmlWebpackPreFetch

并行下载文件 loadTemplate.js

(function(options) {  var win = window;  var doc = win.document;  var sourceList = options.sourceList;  var paralleMax = options.paralleMax;  var attr = options.attr;  var jsReg = /\.js/;  var cssReg = /\.css/;  // 结构队列下载类  function QueueLoadPlugin (sourceList, paralleMax, attr) {    this.sourceList = sourceList;    this.paralleMax  = paralleMax || 3;    this.sourceIndex = 0;    this.queueList = [];    this.attr = attr || {      rel: 'preload'      //rel: 'prefetch'    };    this.handleLoadLogic();  };  QueueLoadPlugin.prototype.loadSingleSouce = function(href, attr, cb) {    var head = doc.head;    var link  = doc.createElement('link');    link.href = href;    for(var key in attr) {      if (attr.hasOwnProperty(key)) {         link.setAttribute(key, attr[key]);      }    }    if(jsReg.test(href)) {      link.setAttribute('as','script');    }    if(cssReg.test(href)) {      link.setAttribute('as','style');    }    link.onload = function() {      cb(true)    };    link.onerror = function() {      cb(false)    };    head.appendChild(link);  };  QueueLoadPlugin.prototype.handleLoadLogic = function() {    var paralleMax = this.paralleMax;    var sourceList = this.sourceList;    var sourceLg = sourceList.length;    var sourceIndex = this.sourceIndex;    if (sourceIndex === 0) {      for(; sourceIndex < sourceLg  &&  sourceIndex < paralleMax; sourceIndex ++) {        var href = sourceList[sourceIndex];        this.queueList.push(sourceIndex);        this.loadPartLogic(sourceIndex, href, this);      }    } else {      if (sourceIndex < sourceLg) {        const href = sourceList[sourceIndex];        this.loadPartLogic(sourceIndex, href, this);        sourceIndex ++;      }    }    this.sourceIndex = sourceIndex;  };  //  QueueLoadPlugin.prototype.loadPartLogic = function(idx, href, context) {    var href = this.sourceList[idx];    this.loadSingleSouce(href, context.attr, function() {      var sourceLg = sourceList.length;      var curIndex = context.queueList.findIndex(d => d === idx);      context.queueList.splice(curIndex, 1, 0);      if(idx < sourceLg - 1)      context.handleLoadLogic()    })  };  new QueueLoadPlugin(sourceList, paralleMax, attr);})(/*injectOptions*/)