Eine kurze Diskussion über das Implementierungsprinzip von Webpack4-Plugins

Eine kurze Diskussion über das Implementierungsprinzip von Webpack4-Plugins

Vorwort

In wabpack sind Plugins neben dem Loader die Kernfunktion. Sie senden während der Ausführung von webpack eine Reihe von Ereignissen. Plugins überwachen diese Ereignisse und verarbeiten die Ausgabedateien über die webpack-API. Beispielsweise kopiert hmlt-webpack-plugin die Vorlage index.html in das Verzeichnis dist.

wissen

Lassen Sie uns zunächst die Grundstruktur von Plugins anhand des Quellcodes verstehen
https://github.com/webpack/webpack/blob/webpack-4/lib/Compiler.js Zeile 551

//Erstelle einen CompilercreateChildCompiler(
  Zusammenstellung,
  Compilername,
  CompilerIndex,
  Ausgabeoptionen,
  plugins // enthält Plugins) {

   // neuer Compiler const childCompiler = new Compiler(this.context);
  // Alle vorhandenen Plugins finden if (Array.isArray(plugins)) {
    für (const plugin von plugins) {
       // Falls vorhanden, rufen Sie die Apply-Methode des Plugins auf plugin.apply(childCompiler);
    }
  }
  
  // Durchlaufe und finde die Hooks, die dem Plugin entsprechen
  für (const name in this.hooks) {
    Wenn (
      ![
        "machen",
        "kompilieren",
        "emittieren",
        "nachEmit",
        "ungültig",
        "Erledigt",
        "dieseZusammenstellung"
      ].enthält(Name)
    ) {
    
      // Finde die entsprechenden Hooks und rufe sie auf, 
      wenn (childCompiler.hooks[name]) {
        childCompiler.hooks[name].taps = this.hooks[name].taps.slice();
      }
    }
  }
 
 // .... ausgelassen....

  gibt den untergeordneten Compiler zurück;
}

Aus dem obigen Quellcode können wir erkennen, dass das Plugin im Wesentlichen eine Klasse ist. Zuerst wird eine Compilerklasse erstellt, der aktuelle Kontext wird übergeben und dann wird ermittelt, ob er vorhanden ist. Wenn er vorhanden ist, wird die Apply-Methode des entsprechenden Plugins direkt aufgerufen und dann der vom entsprechenden Plugin aufgerufene Hook-Ereignisstrom gefunden und an das entsprechende Hook-Ereignis gesendet.
Woher kommen Haken?

https://github.com/webpack/webpack/blob/webpack-4/lib/Compiler.js Zeile 42

// Die obige Compiler-Klasse erbt von der Tapable-Klasse, und Tapable definiert diese Hooks Ereignisflüsse Klasse Compiler erweitert Tapable {
 Konstruktor(Kontext) {
            super();
            dies.hooks = {
                    /** @type {SyncBailHook<Kompilierung>} */
                    shouldEmit: neuer SyncBailHook(["Kompilierung"]),
                    /** @type {AsyncSeriesHook<Stats>} */
                    fertig: neuer AsyncSeriesHook(["stats"]),
                    /** @type {AsyncSeriesHook<>} */
                    zusätzlicherPass: neuer AsyncSeriesHook([]),
                    /** @type {AsyncSeriesHook<Compiler>} */
                    beforeRun: neuer AsyncSeriesHook(["Compiler"]),
                    /** @type {AsyncSeriesHook<Compiler>} */
                    ausführen: neuer AsyncSeriesHook(["Compiler"]),
                    /** @type {AsyncSeriesHook<Kompilierung>} */
                    emittieren: neuer AsyncSeriesHook(["Kompilierung"]),
                    /** @type {AsyncSeriesHook<string, Buffer>} */
                    assetEmitted: neuer AsyncSeriesHook(["Datei", "Inhalt"]),
                    /** @type {AsyncSeriesHook<Kompilierung>} */
                    afterEmit: neuer AsyncSeriesHook(["Kompilierung"]),

                    /** @type {SyncHook<Kompilierung, KompilationParams>} */
                    dieseKompilierung: neuer SyncHook(["Kompilierung", "Parameter"]),
                    /** @type {SyncHook<Kompilierung, KompilationParams>} */
                    Kompilierung: neuer SyncHook(["Kompilierung", "Parameter"]),
                    /** @type {SyncHook<NormalModuleFactory>} */
                    normalModuleFactory: neuer SyncHook(["normalModuleFactory"]),
                    /** @type {SyncHook<ContextModuleFactory>} */
                    KontextModulFactory: neuer SyncHook(["KontextModulFactory"]),

                    /** @type {AsyncSeriesHook<CompilationParams>} */
                    vor dem Kompilieren: neuer AsyncSeriesHook(["params"]),
                    /** @type {SyncHook<CompilationParams>} */
                    kompilieren: neuer SyncHook(["params"]),
                    /** @type {AsyncParallelHook<Kompilierung>} */
                    make: neuer AsyncParallelHook(["Kompilierung"]),
                    /** @type {AsyncSeriesHook<Kompilierung>} */
                    nach der Kompilierung: neuer AsyncSeriesHook(["Kompilierung"]),

                    /** @type {AsyncSeriesHook<Compiler>} */
                    watchRun: neuer AsyncSeriesHook(["Compiler"]),
                    /** @type {SyncHook<Fehler>} */
                    fehlgeschlagen: neuer SyncHook(["Fehler"]),
                    /** @type {SyncHook<Zeichenfolge, Zeichenfolge>} */
                    ungültig: neuer SyncHook(["Dateiname", "changeTime"]),
                    /** @Typ {SyncHook} */
                    watchClose: neuer SyncHook([]),

                    /** @type {SyncBailHook<string, string, any[]>} */
                    Infrastrukturprotokoll: neuer SyncBailHook (["Ursprung", "Typ", "Argumente"]),

                    // TODO die folgenden Hooks sind seltsamerweise hier platziert
                    // TODO, verschiebe sie für Webpack 5
                    /** @Typ {SyncHook} */
                    Umgebung: neuer SyncHook([]),
                    /** @Typ {SyncHook} */
                    nachUmgebung: neuer SyncHook([]),
                    /** @type {SyncHook<Compiler>} */
                    nachPlugins: neuer SyncHook(["Compiler"]),
                    /** @type {SyncHook<Compiler>} */
                    nachResolvern: neuer SyncHook(["Compiler"]),
                    /** @type {SyncBailHook<string, Eintrag>} */
                    Eintragsoption: neuer SyncBailHook(["Kontext", "Eintrag"])
            };
            
            // TODO webpack 5 entferne dies
            dies.hooks.infrastructurelog = dies.hooks.infrastructureLog;
               
            // Rufen Sie den entsprechenden Compiler über die Tabulatortaste auf und übergeben Sie eine Rückruffunktion this._pluginCompat.tap("Compiler", options => {
                    Schalter (Optionen.Name) {
                            Fall "Zusatzpass":
                            Fall "vor dem Ausführen":
                            Fall "laufen":
                            Fall "emittieren":
                            Fall „Nachemission“:
                            Fall "vor dem Kompilieren":
                            Fall "machen":
                            Fall „nach dem Kompilieren“:
                            Fall „Watch-Run“:
                                    Optionen.async = true;
                                    brechen;
                    }
            });
            // Unten ausgelassen......
  }

Nachdem Sie die Grundstruktur verstanden haben, können Sie auf die Grundstruktur und Verwendung des Plugins schließen, die wie folgt lautet:

// Definiere eine Plugin-Klasse class MyPlugins {
    // Wie oben erwähnt, wird eine neue Compilerinstanz erstellt und die Apply-Methode der Instanz ausgeführt, wobei die entsprechende Compilerinstanz übergeben wird apply (compiler) {
        // Rufen Sie den Hook-Ereignisfluss unter der neuen Compilerinstanz auf, lösen Sie ihn über die Registerkarte aus und erhalten Sie eine Rückruffunktion compiler.hooks.done.tap('normalerweise der Spitzname des Plugins', (Standard-Empfangsparameter) => {
            console.log('Ausführungshauptteil eingeben');
        })
    }
}
// Exportmodule.exports = MeinePlugins

OK, das Obige ist eine einfache Vorlage. Probieren wir die interne Hook-Funktion aus, um zu sehen, ob sie wie erwartet aufgerufen und ausgelöst wird.

Konfigurieren von Webpack

let path = require('Pfad')
let DonePlugin = require('./plugins/DonePlugins')
let AsyncPlugins = erfordern('./plugins/AsyncPlugins')

modul.exporte = {
    Modus: "Entwicklung",
    Eintrag: './src/index.js',
    Ausgabe: {
        Dateiname: „build.js“,
        Pfad: Pfad.auflösen(__dirname, 'dist')
    },
    Plugins: [
        new DonePlugin(), // Interne Synchronisations-Hooks
        new AsyncPlugins() // Interne asynchrone Hooks
    ]
}

Synchroner Plugin-Plugin-Simulationsaufruf

Klasse DonePlugins {
    anwenden (Compiler) {
        compiler.hooks.done.tap('DonePlugin', (Statistiken) => {
            console.log('Ausführung: Kompilierung abgeschlossen');
        })
    }
}

module.exports = FertigPlugins

Asynchroner Plugin-Plugin-Simulationsaufruf

Klasse AsyncPlugins {
    anwenden (Compiler) {
        compiler.hooks.emit.tapAsync('AsyncPlugin', (abgeschlossen, Rückruf) => {
            setzeTimeout(() => {
                console.log('Ausführung: Datei ausgegeben');
                Rückruf()
            }, 1000)
        })
    }
}

module.exports = AsyncPlugins

Kompilieren Sie abschließend Webpack. Sie sehen dann die Kompilierungskonsole, die Folgendes druckt und ausführt: „Kompilierung abgeschlossen, Ausführung: Die Datei wird ausgegeben und zeigt damit an, dass der Ereignisfluss des Hooks aufgerufen und ausgelöst werden kann.“

Übung macht den Meister

Nachdem wir nun die Grundstruktur und ihre Verwendung verstanden haben, schreiben wir ein Plugin. Schreiben wir also ein Dateibeschreibungs-Plugin. Bei unserer täglichen Verpackung können wir eine xxx.md-Datei in das dist-Verzeichnis packen und eine Verpackungsbeschreibung erstellen, um eine so kleine Funktion zu erreichen.

Dateibeschreibungs-Plugin

Klasse FileListPlugin {
    // Initialisierung, hole den Dateinamenkonstruktor ({filename}) {
        this.filename = Dateiname
    }
    // Gleiches Vorlagenformat, definiere die Apply-Methode apply (Compiler) {
        compiler.hooks.emit.tap('FileListPlugin', (Kompilierung) => {
            // Assets statische Ressourcen, können Kompilierungsparameter ausdrucken, und es gibt viele Methoden und Eigenschaften let asset = compilation.assets;
            
            // Definieren Sie die Struktur des Ausgabedokuments let content = `## Dateiname Ressourcengröße\r\n`
            
            // Statische Ressourcen durchlaufen und Ausgabeinhalte dynamisch kombinieren Object.entries(assets).forEach(([filename, stateObj]) => {
                Inhalt += `- ${Dateiname} ${stateObj.size()}\r\n`
            })
            
            // Ausgaberessourcenobjekt asset[this.filename] = {
                Quelle () {
                    Inhalt zurückgeben;
                },
                Größe () {
                    Inhalt.Länge zurückgeben
                }
            }
            
        })
    }
}
// Exportieren module.exports = FileListPlugin

Webpack-Konfiguration

let path = require('Pfad')
let HtmlWebpackPlugin = erfordern('html-webpack-plugin')
// Das Plugin-Verzeichnis befindet sich auf derselben Ebene wie node_modules, benutzerdefinierte Plugins, ähnlich dem Loader let FileListPlugin = require('./plugins/FileListPlugin')

modul.exporte = {
    Modus: "Entwicklung",
    Eintrag: './src/index.js',
    Ausgabe: {
        Dateiname: „build.js“,
        Pfad: Pfad.auflösen(__dirname, 'dist')
    },
    Plugins: [
        neues HtmlWebpackPlugin({
            Vorlage: './src/index.html',
            Dateiname: „index.html“
        }),
        neues FileListPlugin({
            Dateiname: „list.md“
        })
    ]
}

OK, durch die obige Konfiguration können wir sehen, dass beim erneuten Verpacken bei jedem Verpacken eine Datei xxx.md im Verzeichnis „dist“ angezeigt wird und der Inhalt dieser Datei der obige Inhalt ist.

Dies ist das Ende dieses Artikels über das Implementierungsprinzip von Webpack4-Plugins. Weitere verwandte Inhalte zu Webpack4-Plugins finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, dass jeder 123WORDPRESS.COM in Zukunft unterstützen wird!

Das könnte Sie auch interessieren:
  • Detaillierte Erläuterung der Platzhalter für die Webentwicklung in JS-Zeichenfolgenverkettung und der Conlose-Objekt-API
  • Beispielcode für die JS-Funktion „Anti-Shake“ und „Throttling“ zur Entwicklung von Webprojekten
  • Mehrere Lösungen für domänenübergreifende Gründe in der Webentwicklung
  • js zur Realisierung der Web-Message-Board-Funktion
  • Der JavaScript-Artikel zeigt Ihnen, wie Sie mit Webformularen spielen
  • Detaillierte Erläuterung zur Entwicklung von JavaScript-Webseiten auf Einstiegsniveau

<<:  Detaillierte Erläuterung der Verwendung des MySQL-Vergleichsoperators für reguläre Ausdrücke REGEXP

>>:  Zusammenfassung gängiger Befehle für Ubuntu-Server

Artikel empfehlen

Detaillierte Erklärung der Top-Befehlsausgabe in Linux

Vorwort Ich glaube, jeder hat den Befehl top unte...

Tutorial-Diagramm zur Installation von Zabbix2.4 unter Centos6.5

Die feste IP-Adresse des Centos-DVD1-Versionssyst...

CSS3 Flexible Box Flex, um ein dreispaltiges Layout zu erreichen

Wie der Titel schon sagt: Die Höhe ist bekannt, d...

Natives JS zur Implementierung einer Echtzeituhr

Teilen Sie einen Echtzeituhreffekt, der mit nativ...

Wie implementiert MySQL ACID-Transaktionen?

Vorwort Kürzlich wurde ich in einem Interview gef...

Gängige Reparaturmethoden für die Trennung der MySQL Master-Slave-Replikation

Inhaltsverzeichnis 01 Problembeschreibung 02 Lösu...

js zur Realisierung der automatischen Sperrbildschirmfunktion

1. Anwendungsszenarien Es gibt eine solche Anford...

Sechs Methoden zur Nginx-Optimierung

1. Optimieren Sie die Nginx-Parallelität [root@pr...

In JavaScript integrierter Zeit- und Datumsformatierungsbeispielcode

1. Grundkenntnisse (Methoden von Datumsobjekten) ...

18 allgemeine Befehle in der MySQL-Befehlszeile

Bei der täglichen Wartung und Verwaltung von Webs...

Natives JS zum Erstellen eines verschiebbaren Anmeldefelds

Dieser Artikel zeigt ein verschiebbares Anmeldefe...

10 beliebte Windows-Apps, die auch unter Linux verfügbar sind

Laut dem Datenanalyseunternehmen Net Market Share...