欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

細(xì)說webpack源碼之compile流程-入口函數(shù)run

 更新時間:2017年12月26日 09:09:28   作者:書生小龍  
Webpack 是一個前端資源加載/打包工具。它將根據(jù)模塊的依賴關(guān)系進(jìn)行靜態(tài)分析,然后將這些模塊按照指定的規(guī)則生成對應(yīng)的靜態(tài)資源。這篇文章主要介紹了webpack源碼之compile流程-入口函數(shù)run,需要的朋友可以參考下

Webpack是目前基于React和Redux開發(fā)的應(yīng)用的主要打包工具。我想使用Angular 2或其他框架開發(fā)的應(yīng)用也有很多在使用Webpack。

本節(jié)流程如圖:

  現(xiàn)在正式進(jìn)入打包流程,起步方法為run:

Compiler.prototype.run = (callback) => {
  const startTime = Date.now();
  const onCompiled = (err, compilation) => { /**/ };
  this.applyPluginsAsync("before-run", this, err => {
    if (err) return callback(err);
    this.applyPluginsAsync("run", this, err => {
      if (err) return callback(err);
      this.readRecords(err => {
        if (err) return callback(err);
        this.compile(onCompiled);
      });
    });
  });
}

  為什么不介紹compiler對象?因?yàn)闃?gòu)造函數(shù)中并沒有一個初始化的方法,只是普通的變量聲明,沒啥好講的。

  在run方法中,首先是調(diào)用了tapable的applyPluginsAsync執(zhí)行了before-run事件流,該事件流的定義地點(diǎn)如下:

// NodeEnvironmentPlugin
compiler.plugin("before-run", (compiler, callback) => {
  if (compiler.inputFileSystem === inputFileSystem)
    inputFileSystem.purge();
  callback();
});

  在對compiler對象的文件系統(tǒng)方法的掛載插件中,注入了before-run這個事件流,這里首先看一下applyPluginsAsync(做了小幅度的修改以適應(yīng)webpack源碼):

// tapable
Tapable.prototype.applyPluginsAsync = (name, ...args, callback) => {
  var plugins = this._plugins[name];
  if (!plugins || plugins.length === 0) return callback();
  var i = 0;
  var _this = this;
  // args為[args,next函數(shù)]
  args.push(copyProperties(callback, function next(err) {
    // 事件流出錯或者全部執(zhí)行完后調(diào)用回調(diào)函數(shù)
    if (err) return callback(err);
    i++;
    if (i >= plugins.length) {
      return callback();
    }
    // 執(zhí)行下一個事件
    plugins[i].apply(_this, args);
  }));
  // 執(zhí)行第一個事件
  plugins[0].apply(this, args);
};

  當(dāng)時在第八節(jié)沒有講這個系列的事件流觸發(fā)方式,這里簡單說下:

1、copyProperties用于對象屬性的拷貝,類似于Object.assign,然而在這里傳入的是兩個函數(shù),一點(diǎn)用都沒有!?。。?!(當(dāng)時沒寫講解就是因?yàn)橐恢笨ㄔ谶@個對象拷貝方法在這里有什么毛用)

2、在webpack中,args為一個this,指向compiler的上下文

3、注入該事件流的事件必須要執(zhí)行callback方法(如上例),此時執(zhí)行的并不是外部的callback,而是next函數(shù)

4、有兩種情況下會執(zhí)行外部callback,中途出錯或者所有事件流執(zhí)行完畢

  這樣就很明白了,注入before-run中的函數(shù)形參的意義如下:

// before-run
// compiler => this
// callback => next
(compiler, callback) => {
  if (compiler.inputFileSystem === inputFileSystem)
    inputFileSystem.purge();
  callback();
}

  由于before-run中只有一個事件,所以在調(diào)用內(nèi)部callback的next方法后,會由于i大于事件長度而直接調(diào)用外部callback。 

  這里的purge方法之前見過,這里復(fù)習(xí)下內(nèi)容:

// NodeEnvironmentPlugin
compiler.inputFileSystem = new CachedInputFileSystem(new NodeJsInputFileSystem(), 60000);
// CachedInputFileSystem
CachedInputFileSystem.prototype.purge = function(what) {
  this._statStorage.purge(what);
  this._readdirStorage.purge(what);
  this._readFileStorage.purge(what);
  this._readlinkStorage.purge(what);
  this._readJsonStorage.purge(what);
};
// CachedInputFileSystem => Storage
Storage.prototype.purge = function(what) {
  if (!what) {
    this.count = 0;
    clearInterval(this.interval);
    this.nextTick = null;
    this.data.clear();
    this.levels.forEach(function(level) {
      level.clear();
    });
  } else if (typeof what === "string") { /**/ } else { /**/ }
};

  一句話概括就是:清除所有打包中緩存的數(shù)據(jù)。

  由于假設(shè)是第一次,所以這里并沒有什么實(shí)際操作,接著調(diào)用外部callback,用同樣的方式觸發(fā)了run事件流。

  run事件流也只有一個方法,來源于CachePlugin插件:

Compiler.plugin("run", (compiler, callback) => {
  // 這個屬性我暫時也不知道是啥 反正直接callback了
  if (!compiler._lastCompilationFileDependencies) return callback();
  const fs = compiler.inputFileSystem;
  const fileTs = compiler.fileTimestamps = {};
  asyncLib.forEach(compiler._lastCompilationFileDependencies, (file, callback) => {
    // ...
  }, err => {
    // ...
  });
});

  在第一次觸發(fā)run事件流時,那個屬性是undefined,所以會直接跳過,因?yàn)槲沂沁吙丛创a邊解析,所以也不知道是啥,哈哈。

  接下來下一個callback是這個:

this.readRecords(err => {
  if (err) return callback(err);
  this.compile(onCompiled);
});

  這是另一個原型方法,源碼如下:

Compiler.prototype.readRecords = (callback) => {
  // 這個屬性也沒有
  if (!this.recordsInputPath) {
    this.records = {};
    return callback();
  }
  this.inputFileSystem.stat(this.recordsInputPath, err => {
    // ...
  });
}

  這里第一次也會跳過并直接callback,看源碼大概是傳入一個路徑并讀取里面的文件信息緩存到records中。

  這下連跳兩步,直接進(jìn)入原型方法compile中,預(yù)覽一下這個函數(shù):

Compiler.prototype.compile = (callback) => {
  const params = this.newCompilationParams();
  // 依次觸發(fā)事件流
  this.applyPluginsAsync("before-compile", params, err => {
    if (err) return callback(err);
    this.applyPlugins("compile", params);
    const compilation = this.newCompilation(params);
    this.applyPluginsParallel("make", compilation, err => {
      if (err) return callback(err);
      compilation.finish();
      compilation.seal(err => {
        if (err) return callback(err);
        this.applyPluginsAsync("after-compile", compilation, err => {
          if (err) return callback(err);
          return callback(null, compilation);
        });
      });
    });
  });
}

  編譯打包的核心流程已經(jīng)一覽無遺,方法中依次觸發(fā)了before-compile、compile、make、after-compile事件流,最后調(diào)用了回調(diào)函數(shù)。

總結(jié)

以上所述是小編給大家介紹的webpack源碼之compile流程-入口函數(shù)run,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!

相關(guān)文章

最新評論