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 zum Problem der CSS-Klassennamen

Die folgenden CSS-Klassennamen, die mit einer Zah...

Miniprogramm zur Implementierung des Paging-Effekts

In diesem Artikelbeispiel wird der spezifische Co...

Detaillierte Erklärung zur Verwendung von React.cloneElement

Inhaltsverzeichnis Die Rolle von cloneElement Anw...

JavaScript-Canvas zum Erzielen von Regentropfeneffekten

In diesem Artikelbeispiel wird der spezifische Co...

Wie CSS die Zeit des weißen Bildschirms während des ersten Ladens beeinflusst

Rendering-Pipeline mit externen CSS-Dateien In de...

So fügen Sie Docker dynamisch Ports hinzu, ohne das Image neu zu erstellen

Manchmal müssen Sie während des Betriebs freigege...

Detaillierte Erläuterung des Linux-CRM-Bereitstellungscodes

Linux-Grundkonfiguration Kompilieren und installi...

HTML-Tag Marquee realisiert verschiedene Scroll-Effekte (ohne JS-Steuerung)

Der automatische Bildlaufeffekt der Seite kann du...

Tutorial zu XHTML-Webseiten

<br />Dieser Artikel soll Anfängern hauptsäc...

Detaillierte Erklärung der Stile in uni-app

Inhaltsverzeichnis Stile in uni-app Zusammenfasse...