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.
Ich bin neu bei webpack, aber ich glaube, Sie können das Flag
-pfür die Produktion übergeben, das die Node-Umgebung auf Produktion setzt und UglifyJS (--optimize-minimize) verwendet, auch wenn es nicht in der Konfigurationsdatei enthalten ist.Es gab viel Verwirrung um das Flag
-pin Webpack, deshalb habe ich es hier nicht aufgenommen. Ich habe diese Methode gewählt, um zu zeigen, wie man beliebige Konstanten innerhalb des Bundles setzt und wie man Plugins anwendet.Wenn Sie ein kleines Beispielprojekt erstellen, werden Sie sehen, dass es Unterschiede zwischen diesem Setup und der Verwendung von nur dem Flag
-pgibt.Meiner Erfahrung nach minifizierte das Flag
-pden Code, aberprocess.env.NODE_ENVwurde nicht auf production gesetzt.Um Verwirrung zu vermeiden, habe ich diesen Weg gewählt, der konsistenter und ausführlicher ist.
Tolle Einführung! Ich habe mich gefragt, ob jemand weiß, wie man Webpack benutzt, aber Module für Legacy-Code außerhalb der Bundles verfügbar macht? Zum Beispiel habe ich ein Gbase.Utilities-Modul, das ich oft in anderem Code verwende, der noch eine Weile nicht migriert wird. Es wird "statisch" verwendet wie Gbase.Utilities.IsMobile(), aber ich kann nicht zu Webpack wechseln, wenn ich diese Globals für älteren Code nicht beibehalten kann.
Vielen Dank!
James
der ProvidePlugin?
https://webpack.js.org/plugins/provide-plugin/
oder vielleicht der expose loader: https://github.com/webpack-contrib/expose-loader
Ich weiß nicht, ob ich genug Einblick in diese Situation habe, aber Sie haben viele Optionen mit Webpack.
Eine Möglichkeit ist, eine produktionsfertige Version Ihrer Bibliothek über ein Skript-Tag zu laden und sie als externe Bibliothek festzulegen. Webpack wird die Namensräume als Globals festlegen, bis Sie zu einem Modul/Installations-Ansatz wechseln.
Hier ist ein Verweis zum Festlegen von externen Abhängigkeiten in Webpack: https://webpack.js.org/guides/author-libraries/#add-externals
Danke fürs Lesen :)
Ich benutze Sass und das Sass-Resources-Loader-Plugin
Dann muss ich keine Variablen oder Mixins in jeder Sass-Datei importieren.
Ich weiß nicht, ob es einen äquivalenten Sass-Resources-Loader für Less gibt?
Ich glaube, so etwas für LESS gibt es nicht, aber jemand sollte es unbedingt bauen ;)
Vielleicht ist das nicht der Umfang Ihres Artikels, aber es könnte sich lohnen, den Leuten zu erklären, *warum* Webpack eine sinnvolle oder nützliche Wahl ist, was ein Abhängigkeitsgraph ist und die allgemeinen Konzepte hinter Webpack, bevor man direkt mit der Definition von Umgebungen beginnt.
Ich nehme an, ich möchte einfach wissen, ob Sie bei den Grundlagen anfangen und aufbauen werden, denn ich habe das Gefühl, dass dieses Tutorial etwas mehr voraussetzt, als ein Neuling bei Webpack vielleicht gewohnt ist. Vieles von dem, was ich über webpack weiß, stammt aus der Entwicklungserfahrung, die darin bestand, das zusammenzuflicken, was *scheinbar* funktionierte, und zu hoffen, dass alles korrekt gebündelt wurde. Würde es gerne auf die "richtige" Weise lernen. :)
Hallo Kat. Danke für den Vorschlag.
Als ich mit dem Schreiben begann, fragte ich mich selbst, ob eine Einführung in Bundler und Abhängigkeitsgraphen für den Artikel geeignet wäre. Aber irgendwann entschied ich, dass es *zu viel* Theorie für viele Leute und für andere redundant wäre.
Natürlich sind wir alle unterschiedlich und kommen aus verschiedenen Hintergründen, daher ist es verständlich, dass Sie dies als unvollständig empfinden könnten. Ich ging davon aus, dass jeder, der dies liest, weiß, was ein Bundler ist und eine Vorstellung davon hat, wie sie funktionieren.
Ich habe mich im Grunde darauf konzentriert, eine einfache Webpack-Konfiguration praktisch zu skalieren, um ihren grundlegenden Inhalt zu zeigen. Wenn Sie mehr über Bundler und ihre Funktionsweise erfahren möchten, ist dies ein guter Beitrag: https://jvandemo.com/a-10-minute-primer-to-javascript-modules-module-formats-module-loaders-and-module-bundlers/
Toller Artikel, Jeremías!!!!
Danke, Kumpel!
Sehr klar und einfach, um mit Webpack zu beginnen
Das war genau der Grund für diesen Beitrag, um den Leuten zu helfen, ihre Angst verlieren beim Einstieg in Webpack-Konfigurationen. Danke Thien!
Toller Artikel, aber hier sind meine Vorschläge. Machen Sie zu Beginn zumindest für den Leser klar, wo Skripte und Webpack-Konfigurationscode hingehören (z. B. in package.json oder webpack.config.js). Für einen Anfänger (wie mich) ist das vielleicht nicht offensichtlich.
Außerdem gibt es meiner Meinung nach einen Codeausschnitt, der einen Fehler verursacht. Wenn Sie die Variable `lessRules` deklarieren, ist der Test-Regex in der Variablen enthalten, er ist auch in den Regeln deklariert. Als ich versuchte, dies nachzuvollziehen, gab es einen Fehler. Aber sobald ich die Test-Eigenschaft aus der Variablen entfernte, kompilierte es einwandfrei.
Danke für den Vorschlag und dafür, dass Sie den Fehler gemeldet haben, Richard. Ich werde so schnell wie möglich eine Korrektur vornehmen.
Wo sollten `main.css` und `main.js` im Quellcode-Baum erstellt werden?
Ich beziehe mich auf
/helpers/main.js, nicht aufmain.jsim Build-Verzeichnis. (Vielleicht sollten diese Dateinamen anders genannt werden, um Verwirrung zu vermeiden.)Ja, das kann definitiv verwirrend sein, ich werde verschiedene Benennungen untersuchen. Danke fürs Lesen :)
Ich schreibe die Chrome DevTools-Dokumentation hauptberuflich und wollte Ihnen nur sagen, dass dies eine großartige Einführung ist. Ich habe aus diesem Artikel wirklich das Gefühl, dass ich die Vorteile von Webpack sowie die Nutzung gut verstanden habe. Ich werde diesen Artikel studieren, um herauszufinden, warum er so gut funktioniert ;)
Hey Kayce, danke! Von einem technischen Redakteur zu kommen, bedeutet dieses Kompliment sehr viel. Lassen Sie mich wissen, wenn Sie Hilfe benötigen :)
Toller Artikel, Mann! Sie sind sicherlich ein Orakel des Wissens!
LOL, danke Mann :)