关于webpack4:webpack-插件开发webpackperloadparallelplugin

36次阅读

共计 3822 个字符,预计需要花费 10 分钟才能阅读完成。

开发起因:
因为我的项目是 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*/)

正文完
 0