Einführung in Webpack: Entry, Output, Loader und Plugins

Avatar of Jeremias Menichelli
Jeremias Menichelli am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Die Frontend-Entwicklung hat sich zu einem modularen Ansatz entwickelt, der die Kapselung und Struktur von Codebasen verbessert. Tooling ist zu einem entscheidenden Bestandteil jedes Projekts geworden, und derzeit gibt es viele mögliche Optionen.

Webpack hat in den letzten Jahren aufgrund seiner Leistungsfähigkeit und Skalierbarkeit an Popularität gewonnen, aber einige Entwickler fanden den Konfigurationsprozess verwirrend und schwer zu übernehmen.

Wir werden Schritt für Schritt von einer leeren Konfigurationsdatei zu einem einfachen, aber vollständigen Setup für das Bündeln eines Projekts vorgehen. Dieser Artikel setzt ein grundlegendes Verständnis der CommonJS-Notation und der Funktionsweise von Modulen voraus.

Konzepte

Im Gegensatz zu den meisten anderen Bundlern ist die Motivation hinter Webpack, alle Ihre Abhängigkeiten (nicht nur Code, sondern auch andere Assets) zu sammeln und einen Abhängigkeitsgraphen zu generieren.

Zuerst mag es seltsam erscheinen, wenn eine `.js`-Datei eine Stylesheet-Datei erfordert oder eine Stylesheet-Datei ein Bild abruft, das wie ein Modul modifiziert wurde, aber dies ermöglicht es Webpack, zu verstehen, was in Ihrem Bundle enthalten ist, und hilft Ihnen, diese zu transformieren und zu optimieren.

Installation

Lassen Sie uns zuerst die anfänglichen Pakete hinzufügen, die wir verwenden werden

npm install webpack webpack-dev-server --save-dev

Als Nächstes erstellen wir eine Datei `webpack.config.js` im Stammverzeichnis unseres Projekts und fügen zwei Skripte zu unserer `package.json`-Datei hinzu, sowohl für die lokale Entwicklung als auch für die Produktionsfreigabe.

"scripts": {
  "start": "webpack-dev-server",
  "build": "webpack"
}

Webpack-Befehle greifen auf die gerade erstellte Konfigurationsdatei zu, es sei denn, wir geben eine andere Aktion an.

Entry (Einstiegspunkt)

Es gibt viele Möglichkeiten, unseren "Einstiegspunkt" anzugeben, der die Wurzel unseres Abhängigkeitsgraphen sein wird.

Die einfachste ist, einen String zu übergeben

var baseConfig = {
  entry: './src/index.js'
};

Wir könnten auch ein Objekt übergeben, falls wir in Zukunft mehr als einen Einstiegspunkt benötigen.

var baseConfig = {
  entry: {
    main: './src/index.js'
  }
};

Ich empfehle die letzte Variante, da sie mit wachsendem Projekt besser skalierbar ist.

Output (Ausgabe)

Der Output in Webpack ist ein Objekt, das den Pfad enthält, wohin unsere Bundles und Assets gehen sollen, sowie den Namen, den die Einstiegspunkte annehmen werden.

var path = require('path');

var baseConfig = {
  entry: {
    main: './src/index.js'
  },
  output: {
    filename: 'main.js',
    path: path.resolve('./build')
  }
};

// export configuration
module.exports = baseConfig;

Wenn Sie den Entry mit einem Objekt definieren, anstatt den Ausgabedateinamen fest zu codieren, können Sie tun:

output: {
  filename: '[name].js',
  path: path.resolve('./build')
}

Auf diese Weise, wenn neue Einstiegspunkte hinzugefügt werden, wird Webpack ihren Schlüssel verwenden, um den Dateinamen zu bilden.

Mit nur dieser kleinen Konfiguration sind wir bereits in der Lage, einen Server auszuführen und lokal mit npm start oder npm run build zu entwickeln, um unseren Code für die Veröffentlichung zu bündeln. Durch die Kenntnis der Abhängigkeiten des Projekts wird webpack-dev-server diese überwachen und die Website neu laden, wenn er erkennt, dass sich eine davon geändert hat.

Loader (Lader)

Das Ziel von Webpack ist es, alle unsere Abhängigkeiten zu verarbeiten.

// index.js file
import helpers from '/helpers/main.js';

// Hey Webpack! I will need these styles:
import 'main.css';

Was ist das? Eine Stylesheet-Datei in JavaScript zu importieren? Ja! Aber Bundler sind nur dafür vorbereitet, JavaScript-Abhängigkeiten out-of-the-box zu verarbeiten. Hier kommen die "Loader" ins Spiel.

Loader bieten eine einfache Möglichkeit, unsere Abhängigkeiten abzufangen und vor dem Bündeln vorzuverarbeiten.

var baseConfig = {
  // ...
  module: {
    rules: [
      {
        test: /* RegEx */,
        use: [
          {
            loader: /* loader name */,
            query: /* optional config object */
          }
        ] 
      }
    ]
  }
};

Damit Loader funktionieren, benötigen wir einen regulären Ausdruck, um die Dateien zu identifizieren, die wir modifizieren möchten, und einen String oder ein Array mit den Loadern, die wir verwenden möchten.

Stile

Damit Webpack unsere Styles verarbeiten kann, wenn sie importiert werden, installieren wir die css- und style-Loader.

npm install --save-dev css-loader style-loader

Der css-loader interpretiert Styles als Abhängigkeiten und der style-loader fügt automatisch ein <style>-Tag mit ihnen auf der Seite ein, wenn das Bundle geladen wird.

var baseConfig = {
  entry: {
    main: './src/index.js'
  },
  output: {
    filename: '[name].js',
    path: path.resolve('./build')
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          { loader: 'style-loader' },
          { loader: 'css-loader' }
        ]
      }
    ]
  }
};

In diesem Beispiel durchläuft main.css zuerst den css-loader und dann den style-loader.

Präprozessoren

Die Unterstützung für LESS oder jeden anderen Präprozessor hinzuzufügen, ist so einfach wie die Installation des entsprechenden Loaders und das Hinzufügen zu den Regeln.

rules: [
  {
    test: /\.less$/,
    use: [
      { loader: 'style-loader' },
      { loader: 'css-loader' },
      { loader: 'less-loader' }
    ]
  }
]

Transpilieren

JavaScript kann auch von Loadern transformiert werden. Ein Beispiel wäre die Verwendung eines Babel-Loaders, um unsere Skripte zu transpilieren.

rules: [
  {
    test: /\.js$/,
    use: [
      { loader: 'babel-loader' }
    ]
  }
]

Bilder

Webpack hat eine großartige Funktion, mit der es url()-Anweisungen in Stylesheets erkennen und es Loadern ermöglichen kann, Änderungen an der Bilddatei und der URL selbst vorzunehmen.

// index.less file

@import 'less/vars';

body {
  background-color: @background-color;
  color: @text-color;
}

.logo {
  background-image: url('./images/logo.svg');
}

Durch das Hinzufügen einer Regel könnten wir den file-loader verwenden, um die Datei einfach zu kopieren, oder den url-loader. Letzterer inline das Bild als Base64-String, es sei denn, es überschreitet ein Byte-Limit, in welchem Fall er die URL-Anweisung durch einen relativen Pfad ersetzt und die Datei für uns an den Ausgabestandort kopiert.

{
  test: /\.svg$/,
  use: [
    {
       loader: 'url-loader',
       query: { limit : 10000 }
    }
  ]
}

Loader können durch Übergabe eines query-Objekts mit Optionen konfiguriert werden, wie hier, wo wir den Loader so konfigurieren, dass die Datei inline eingebunden wird, es sei denn, sie überschreitet eine Größe von 10 KB.

Wenn wir unseren Build-Prozess auf diese Weise verwalten, werden wir nur die notwendigen Ressourcen einbeziehen, anstatt einen hypothetischen Assets-Ordner mit unzähligen Dateien zu verschieben, die möglicherweise nicht in unserem Projekt verwendet werden.

Wenn Sie React oder eine ähnliche Bibliothek verwenden, können Sie die Datei .svg in Ihrer Komponente mit dem svg-inline-loader importieren.

Plugins

Webpack enthält Standardverhalten, um die meisten Ressourcenarten zu bündeln. Wenn Loader nicht ausreichen, können wir Plugins verwenden, um Webpack zu modifizieren oder Funktionen hinzuzufügen.

Zum Beispiel bindet Webpack standardmäßig unsere Stylesheets in unser Bundle ein, aber wir können dies ändern, indem wir ein Plugin einführen.

Assets extrahieren

Eine häufige Verwendung eines Plugins ist das Extrahieren des generierten Stylesheets und das Laden, wie wir es normalerweise mit einem <link>-Tag tun.

var ExtractTextPlugin = require('extract-text-webpack-plugin');

var lessRules = {
  use: [
    { loader: 'css-loader' },
    { loader: 'less-loader' }
  ]
};

var baseConfig = {
  // ...
  module: {
    rules: [
      // ...
      { test: /\.less$/, use: ExtractTextPlugin.extract(lessRules) }
    ]
  },
  plugins: [
    new ExtractTextPlugin('main.css')
  ]
};

Eine `index.html`-Datei generieren

Beim Erstellen von Single-Page-Anwendungen benötigen wir normalerweise eine .html-Datei, um sie bereitzustellen.

Der HtmlWebpackPlugin erstellt automatisch eine `index.html`-Datei und fügt für jedes resultierende Bundle Skript-Tags hinzu. Er unterstützt auch Vorlagensyntax und ist hochgradig konfigurierbar.

var HTMLWebpackPlugin = require('html-webpack-plugin');

var baseConfig = {
  // ...
  plugins: [
    new HTMLWebpackPlugin()
  ]
};

Erstellung für die Produktion

Umgebung definieren

Viele Bibliotheken führen Warnungen ein, die während der Entwicklungszeit nützlich sind, aber in unserem Produktionsbundle keinen Nutzen haben und dessen Größe erhöhen.

Webpack wird mit einem integrierten Plugin geliefert, um globale Konstanten innerhalb Ihres Bundles festzulegen.

var ENV = process.env.NODE_ENV;

var baseConfig = {
  // ...
  plugins: [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify(ENV)
    })
  ]
};

Wir müssen nun die Umgebung in unseren Befehlen angeben

"scripts": {
  "start": "NODE_ENV=development webpack-dev-server",
  "build": "NODE_ENV=production webpack"
}

process.env.NODE_ENV wird durch einen String ersetzt, der es Kompressoren ermöglicht, unerreichbare Entwicklungscode-Zweige zu eliminieren.

Dies ist sehr nützlich, um Warnungen in Ihren Code einzuführen, die für Ihr Team bestimmt sind und die Produktion nicht erreichen.

if (process.env.NODE_ENV === 'development') {
    console.warn('This warning will dissapear on production build!');
  }

Komprimieren

In der Produktion müssen wir den Benutzern das schnellstmögliche Produkt liefern. Durch die Minifizierung unseres Codes und das Entfernen unnötiger Zeichen wird die Größe unseres Bundles reduziert und die Ladezeiten verbessert.

Eines der beliebtesten Werkzeuge dafür ist UglifyJS, und Webpack verfügt über ein integriertes Plugin, um unseren Code damit zu verarbeiten.

// webpack.config.js file
var ENV = process.env.NODE_ENV;

var baseConfig = {
  // ...
  plugins: []
};

if (ENV === 'production') {
  baseConfig.plugins.push(new webpack.optimize.UglifyJsPlugin());
}

Zusammenfassung

Webpack-Konfigurationsdateien sind unglaublich nützlich, und die Komplexität der Datei hängt von Ihren Anforderungen ab. Achten Sie darauf, sie gut zu organisieren, da sie mit wachsendem Projekt schwieriger zu beherrschen sein können.

In diesem Artikel haben wir mit einer leeren Konfigurationsdatei begonnen und sind zu einem Basis-Setup gelangt, das es Ihnen ermöglicht, lokal zu entwickeln und Produktionscode zu veröffentlichen. Es gibt noch mehr in Webpack zu entdecken, aber diese Kernteile und Konzepte können Ihnen helfen, sich damit vertrauter zu machen.

Wenn Sie tiefer eintauchen möchten, empfehle ich die offizielle Dokumentation von Webpack, die für seine zweite große Veröffentlichung aktualisiert und verbessert wurde.