Maison >interface Web >js tutoriel >Interprétation détaillée de la fonction d'entrée exécutée dans webpack

Interprétation détaillée de la fonction d'entrée exécutée dans webpack

亚连
亚连original
2018-06-15 14:35:462278parcourir

Webpack est un outil frontal de chargement/packaging de ressources. Il effectuera une analyse statique basée sur les dépendances des modules, puis générera les ressources statiques correspondantes pour ces modules selon les règles spécifiées. Cet article présente principalement le processus de compilation du code source du webpack - la fonction d'entrée exécutée. Les amis qui en ont besoin peuvent s'y référer

Webpack est actuellement le principal outil de packaging pour les applications développées sur la base de React et Redux. Je pense que de nombreuses applications développées à l'aide d'Angular 2 ou d'autres frameworks utilisent également Webpack.

Le processus de cette section est tel qu'illustré dans la figure :

Nous sommes maintenant officiellement entrés dans le processus d'emballage. La méthode de démarrage est exécutée :

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);
      });
    });
  });
}
Pourquoi ne pas l'introduire comme objet compilateur ? Parce qu'il n'y a pas de méthode d'initialisation dans le constructeur, c'est juste une déclaration de variable ordinaire, il n'y a rien à dire.

Dans la méthode run, applyPluginsAsync de tapable est d'abord appelé pour exécuter le flux d'événements avant l'exécution. Le flux d'événements est défini comme suit :

// NodeEnvironmentPlugin
compiler.plugin("before-run", (compiler, callback) => {
  if (compiler.inputFileSystem === inputFileSystem)
    inputFileSystem.purge();
  callback();
});
Dans le système de fichiers de l'objet compilateur. Dans le plug-in de montage de la méthode, le flux d'événements avant exécution est injecté. Ici, nous examinons d'abord applyPluginsAsync (légèrement modifié pour s'adapter au code source du 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函数]
  args.push(copyProperties(callback, function next(err) {
    // 事件流出错或者全部执行完后调用回调函数
    if (err) return callback(err);
    i++;
    if (i >= plugins.length) {
      return callback();
    }
    // 执行下一个事件
    plugins[i].apply(_this, args);
  }));
  // 执行第一个事件
  plugins[0].apply(this, args);
};
C'était. non mentionné dans la section 8 à l'époque. La méthode de déclenchement du flux d'événements de cette série est brièvement décrite ici :

1 copyProperties est utilisé pour copier les propriétés de l'objet, similaire à Object.assign. Cependant, deux fonctions sont transmises. ici, qui ne servent à rien ! ! ! ! ! (Je n'ai pas écrit d'explication à l'époque parce que j'étais bloqué sur l'utilité de la méthode de copie d'objet ici)

2 Dans webpack, args est un this, pointant vers le contexte du compilateur <.>

3. Les événements injectés dans ce flux d'événements doivent exécuter la méthode de rappel (comme dans l'exemple ci-dessus, ce n'est pas le rappel externe qui est exécuté, mais la fonction suivante

). 4. Il existe deux situations dans lesquelles le rappel externe sera exécuté et une erreur se produit à mi-chemin. Ou tous les flux d'événements ont été exécutés

La signification des paramètres de fonction injectés dans avant l'exécution est la suivante. suit :

Puisqu'il n'y a qu'un seul événement avant l'exécution, donc après avoir appelé la méthode suivante du rappel interne, le rappel externe sera appelé directement car i est supérieur à la longueur de l'événement.
// before-run
// compiler => this
// callback => next
(compiler, callback) => {
  if (compiler.inputFileSystem === inputFileSystem)
    inputFileSystem.purge();
  callback();
}

La méthode de purge ici a déjà été vue. Passons en revue le contenu ici :

En une phrase, elle peut être résumée comme suit : effacer toutes les données mises en cache dans le package.
// 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 { /**/ }
};

Puisqu'il s'agit de la première fois, il n'y a pas d'opération réelle ici. Ensuite, le rappel externe est appelé et le flux d'événements d'exécution est déclenché de la même manière.

Il n'existe qu'une seule méthode pour le flux d'événements d'exécution, qui provient du plug-in CachePlugin :

Lorsque le flux d'événements d'exécution est déclenché pour la première fois, cet attribut est indéfini, donc il sera ignoré directement parce que je l'analysais en regardant le code source, donc je ne sais pas ce que c'est, haha.
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 => {
    // ...
  });
});

Le prochain rappel est le suivant :

Il s'agit d'une autre méthode prototype, le code source est le suivant :
this.readRecords(err => {
  if (err) return callback(err);
  this.compile(onCompiled);
});

Ceci sera également ignoré le premier time Et directement le rappel, en regardant le code source, il s'agit probablement de transmettre un chemin et de lire les informations du fichier à l'intérieur et de les mettre en cache dans des enregistrements.
Compiler.prototype.readRecords = (callback) => {
  // 这个属性也没有
  if (!this.recordsInputPath) {
    this.records = {};
    return callback();
  }
  this.inputFileSystem.stat(this.recordsInputPath, err => {
    // ...
  });
}

Maintenant, sautez deux étapes, entrez directement dans la compilation de la méthode prototype, prévisualisez cette fonction :

Le processus de base de compilation et d'empaquetage a été clairement vu, et la méthode before est déclenchée dans l'ordre. compilez, compilez, make, le flux d'événements après la compilation, et enfin la fonction de rappel est appelée.
Compiler.prototype.compile = (callback) => {
  const params = this.newCompilationParams();
  // 依次触发事件流
  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);
        });
      });
    });
  });
}

Ce qui précède est ce que j'ai compilé pour vous. J'espère que cela vous sera utile à l'avenir.

Articles connexes :

Comment implémenter une page de connexion vidéo en arrière-plan à l'aide de Vue.js 2.0

Comment utiliser Vue pour développer le temps instructions de conversion ?

Comment implémenter l'adaptation de page dans angulairejs ?

Comment surveiller window.resize dans VueJs et comment l'implémenter spécifiquement ?

Explication détaillée du concept d'objet window $window dans AngularJS

Comment implémenter le pontage React-native Android et quels sont les spécificités mesures?

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn