Webpack ist gerade der letzte Schrei! Webpack ist großartig, wenn es um Modulbündelung und die Arbeit mit Frameworks wie Vue oder React geht, aber es ist etwas umständlicher, wenn es um statische Assets (wie CSS) geht. Du bist es vielleicht gewohnt, deine statischen Assets mit etwas wie Gulp zu verwalten, und dafür gibt es einige ziemlich gute Gründe.
Dennoch wächst die Menge an JavaScript in unseren statischen Projekten, also lass uns als Ausgleich Webpack nutzen und dabei bei Gulp bleiben. In diesem Artikel speziell Gulp 4. Wir werden moderne Techniken verwenden, um einen leicht wartbaren Workflow aufzubauen, einschließlich des leistungsstarken und nützlichen Hot Module Reloading (HMR).

Vielleicht möchtest du hier anfangen
Dieser Artikel ist nicht ganz für Anfänger. Wenn du neu bei Webpack oder Gulp bist, beginne vielleicht mit diesen Tutorials.
Gulp-Tutorials
Webpack-Tutorials
- Offizielle Webpack-Dokumentation
- Artikel zur Webpack-Einrichtung 1
- Artikel zur Webpack-Einrichtung 2
- Was ist Hot Module Reloading
Demo
Schau dir das Demo-Repo auf GitHub an. Der Branch "hmr" zeigt, wie man Hot Module Reloading einrichtet.
Voraussetzungen
Führe Folgendes aus, um die notwendigen Pakete zu installieren
npm install babel-core \
babel-preset-es2015 \
browser-sync \
gulpjs/gulp#4.0 \
webpack \
webpack-dev-middleware \
webpack-hot-middleware -D
Ab Node v7.9.0 werden ES6-Module nicht unterstützt. Deshalb installieren wir Babel, um `import`-Anweisungen und andere innovative JS-Features in unseren Aufgaben nutzen zu können.
Wenn du HMR nicht benötigst, lass Hot Middleware ruhig weg. Dev Middleware ist nicht davon abhängig.
Startpunkte
Los geht's! Erstelle einen Ordner tasks im Stammverzeichnis deines Projekts mit drei Dateien: index.js, webpack.js und server.js. Wir haben weniger Unordnung im Stammverzeichnis, da die Indexdatei wie gulpfile.js und die Webpack-Datei wie webpack.config.js fungiert.
Der Ordner site enthält alle Assets deiner Website.
╔ site
║ ╚═══ main.js
╠ tasks
║ ╠═══ index.js
║ ╠═══ server.js
║ ╚═══ webpack.js
╚ package.json
Um Gulp mitzuteilen, wo sich die Aufgaben befinden, müssen wir Flags in unserer `package.json` hinzufügen.
"scripts": {
"dev": "gulp --require babel-register --gulpfile tasks",
"build": "NODE_ENV=production gulp build --require babel-register --gulpfile tasks"
}
Der Befehl babel-register verarbeitet die `import`-Anweisungen und das `--gulpfile`-Flag definiert den Pfad zu `gulpfile.js` oder in unserem Fall zu `index.js`. Wir müssen nur auf den Ordner tasks verweisen, da, wie bei HTML, die Datei namens index den Einstiegspunkt markiert.
Richte eine grundlegende Webpack-Konfiguration ein
In `webpack.js`
import path from 'path'
import webpack from 'webpack'
let config = {
entry: './main.js',
output: {
filename: './bundle.js',
path: path.resolve(__dirname, '../site')
},
context: path.resolve(__dirname, '../site')
}
function scripts() {
return new Promise(resolve => webpack(config, (err, stats) => {
if (err) console.log('Webpack', err)
console.log(stats.toString({ /* stats options */ }))
resolve()
}))
}
module.exports = { config, scripts }
Beachte, wie wir das Objekt nicht direkt exportieren, wie es viele Tutorials zeigen, sondern es zuerst in eine Variable packen. Das ist notwendig, damit wir die Konfiguration sowohl in der untenstehenden Gulp-Aufgabe scripts als auch im Server-Middleware im nächsten Schritt verwenden können.
Kontext
Die `config.context`-Einstellung ist notwendig, um alle Pfade relativ zu unserem `site`-Ordner festzulegen. Andernfalls würden sie vom `tasks`-Ordner ausgehen, was zu Verwirrung führen könnte.
Konfiguration und Aufgabe trennen
Wenn du eine sehr lange Webpack-Konfiguration hast, kannst du diese und die Aufgabe auch in zwei Dateien aufteilen.
// webpack.js
export let config = { /* ... */ }
// scripts.js
import { config } from './webpack'
export function scripts() { /* ... */ }
Hot Module Reloading
So bringst du HMR zum Laufen. Ändere den Entrypoint und die Plugins.
entry: {
main: [
'./main.js',
'webpack/hot/dev-server',
'webpack-hot-middleware/client'
]
},
/* ... */
plugins: [
new webpack.HotModuleReplacementPlugin()
]
Stelle sicher, dass du die zusätzlichen Entrypoints und das HMR-Plugin für die Produktion deaktivierst. Das Paket Webpack Merge hilft beim Einrichten verschiedener Umgebungen für Entwicklung und Produktion.
BrowserSync
Nun eine BrowserSync-Aufgabe einrichten.
import gulp from 'gulp'
import Browser from 'browser-sync'
import webpack from 'webpack'
import webpackDevMiddleware from 'webpack-dev-middleware'
import webpackHotMiddleware from 'webpack-hot-middleware'
import { config as webpackConfig } from './webpack'
const browser = Browser.create()
const bundler = webpack(webpackConfig)
export function server() {
let config = {
server: 'site',
middleware: [
webpackDevMiddleware(bundler, { /* options */ }),
webpackHotMiddleware(bundler)
],
}
browser.init(config)
gulp.watch('site/*.js').on('change', () => browser.reload())
}
Das Dev Middleware ermöglicht es BrowserSync, das zu verarbeiten, was in `webpack.js` als Entrypoint definiert wurde. Um ihm diese Information zu geben, importieren wir das Konfigurationsmodul. Hot Middleware hingegen prüft auf Änderungen in App-Komponenten wie `.vue`-Dateien für Vue.js, um sie zu injizieren.
Da wir keine Dateien wie `main.js` per Hot Reloading ändern können, beobachten wir sie und laden das Fenster bei einer Änderung neu. Auch hier gilt: Wenn du HMR nicht benötigst, entferne webpackHotMiddleware.
Alle Aufgaben importieren
Die Datei `index.js` enthält alle Aufgaben.
import gulp from 'gulp'
import { scripts } from './webpack'
import { server } from './server'
export const dev = gulp.series( server )
export const build = gulp.series( scripts )
export default dev
Die exportierten Variablen definieren, welche Aufgaben unter welchem Befehl ausgeführt werden. Der Standard-Export wird mit gulp ausgeführt.
Wenn du Entwicklungs- und Produktionsumgebungen für Webpack trennst, möchtest du vielleicht eine Aufgabe gulp build ausführen, die Produktionsoptionen nutzt. Dazu importieren wir die `scripts`-Aufgaben separat, da wir hier den Server nicht starten müssen.
Während der Entwicklung wird Webpack von BrowserSync ausgeführt, daher ist es nicht notwendig, die Skriptaufgabe im Entwicklungsbefehl zu enthalten.
Aufgaben ausführen
Um mit der Entwicklung zu beginnen, kannst du nicht einfach gulp oder gulp build ausführen, da es nach einer gulpfile.js im Stammverzeichnis sucht. Wir müssen die npm-Befehle npm run dev und npm run build ausführen, um die definierten Flags zu nutzen.
Erweitern
Jetzt kannst du dir vorstellen, wie einfach es ist, Aufgaben zu erweitern und weitere zu schreiben. Exportiere eine Aufgabe in einer Datei und importiere sie in `index.js`. Sauber und einfach zu warten!
Um dir eine Vorstellung davon zu geben, wie du dein Projektverzeichnis einrichten kannst, hier ist mein persönliches Setup.
╔ build
╠ src
╠ tasks
║ ╠═══ config.js => project wide
║ ╠═══ icons.js => optimize/concat SVG
║ ╠═══ images.js => optimize images
║ ╠═══ index.js => run tasks
║ ╠═══ misc.js => copy, delete
║ ╠═══ server.js => start dev server
║ ╠═══ styles.js => CSS + preprocessor
║ ╚═══ webpack.js
╚ package.json
Nochmal, warum *beides* Webpack und Gulp verwenden?
Statische Datei-Verwaltung
Gulp kann statische Assets besser handhaben als Webpack. Das Copy Webpack Plugin kann zwar auch Dateien von deiner Quelle in deinen Build-Ordner kopieren, aber wenn es um die Überwachung von Dateilöschungen oder Änderungen geht, wie z.B. das Überschreiben eines Bildes, ist gulp.watch die sicherere Wahl.
Server-Umgebung
Webpack bietet auch eine lokale Serverumgebung über Webpack Dev Server, aber die Verwendung von BrowserSync bietet einige Features, die du vielleicht nicht missen möchtest.
- CSS/HTML/Bild-Injektion für Nicht-App-Projekte
- Testen auf mehreren Geräten direkt out-of-the-box
- enthält ein Admin-Panel für mehr Kontrolle
- Bandbreitendrosselung für Geschwindigkeits- und Lade-Tests
Kompilierungszeit
Wie in diesem Beitrag auf GitHub zu sehen ist, wird Sass von node-sass viel schneller verarbeitet als durch die Kombination von sass-loader, css-loader und extract-text-webpack-plugin von Webpack.
Bequemlichkeit
In Webpack musst du beispielsweise deine CSS- und SVG-Dateien in JavaScript importieren, um sie zu verarbeiten, was manchmal ziemlich knifflig und verwirrend sein kann. Mit Gulp musst du deinen Workflow nicht anpassen.
Danke, Autor, für das Beispiel und die Beschreibung.
Es ist großartig, Gulp und Webpack zu kombinieren, um die Nachteile voneinander auszugleichen. Vor einiger Zeit, als ich nur Gulp verwendete, suchte ich nach einem Plugin, um jede JavaScript-Datei zusammenzufügen, fand aber keine bessere Lösung als die Integration von Gulp + Browserify oder Webpack Bundlers. Ich habe Webpack früher in meiner React SPA verwendet und weiß, wie leistungsfähig Webpack für JS sein kann.
Deshalb habe ich mich für diesen Weg entschieden.
Hier ist mein Beispiel für einen Stack aus Gulp 3.9, Browsersync und Webpack Middleware.
https://github.com/wwwebman/gulp-webpack-starter
Das stimmt nicht ganz. Wenn du (S)CSS nicht explizit in deinen JavaScript-Dateien importieren möchtest, füge dein CSS einfach einem Entrypoint hinzu. Du hast gezeigt, dass mehrere Dateien einen Webpack-Entrypoint bilden können, füge einfach `'style!css!./path/to/file.css'` zur Entry-Konfiguration hinzu. Wenn du CSS nicht inline haben und von JavaScript injizieren möchtest, kann Webpack auch statische CSS-Dateien für dich erstellen.
Außerdem ist die hier gezeigte Webpack-Konfiguration für Hot Loading komplexer als nötig. Du musst keine Entry-Dateien für Hot Loading hinzufügen, setze einfach `devServer.hot` auf `true`.
Auch hier muss ich widersprechen. Die Verwaltung statischer Assets in Webpack ist weitaus leistungsfähiger als mit Gulp, besonders wenn man Loader versteht. Wenn du zum Beispiel den `html-loader` verwendest, werden automatisch Webpack-Loader für referenzierte statische Dateien in HTML (Bilder usw.) verwendet. Wenn du keine Dateien inline haben möchtest, verwende einfach `file-loader`, und du hast den zusätzlichen Vorteil eines fehlerhaften Builds, wenn Webpack eine Ressource nicht findet, z.B. wenn du eine Ressource gelöscht und vielleicht eine Referenz vergessen hast. Das verlierst du, wenn du Webpack deine statischen Assets nicht verwalten lässt.
Nicht um negativ zu sein, aber die Kombination von Webpack, Gulp und Browsersync macht alles viel komplizierter als nötig. Ich persönlich würde einfach Webpack verwenden. Wenn du mehr Funktionen von Browsersync benötigst (wie z.B. die Synchronisierung von Benutzerereignissen zwischen Browsern, wofür es ursprünglich entwickelt wurde), dann gibt es ein Browsersync-Plugin für Webpack. Wenn du ein traditionelleres Setup bevorzugst, verwende einfach Gulp und Browsersync. Der Versuch, alles zu kombinieren, schafft nur ein fragiles Setup, das schwer zu aktualisieren ist.
Hey Ken, ich bin kürzlich von Grunt und Webpack 1 auf NPM-Befehle und Webpack 2 umgestiegen. Und ich muss zugeben, ich fühle etwas von Pascals Schmerz. Es scheint, als wäre meine Kompilierungszeit länger als zuvor. Außerdem führen wir unseren Entwicklungs-Server aus unserem `dist`-Ordner aus, aber das verursacht Probleme, wenn wir eine `.json`-Datei ändern, die unseren Ressourcen-String enthält, da diese Datei nicht automatisch in den `dist`-Ordner kopiert wird. Vermeiden die meisten Projekte dies, indem sie vom App-Ordner ausliefern? Oder fehlt mir ein weiteres Plugin? Konzepte wie diese scheinen mit Grunt/Gulp etwas einfacher zu sein.
Ich benutze Webpack täglich und liebe es, aber es ist immer noch 100-mal komplexer zu verstehen, einzurichten und anzupassen als Gulp oder Grunt.
Außerdem kümmern sich die meisten Webpack-Boilerplates da draußen nicht um die Optimierung statischer Assets wie Bildoptimierung, Sprite-Generierung usw. Es scheint, als hätte die Community aus irgendeinem Grund diesen Aspekt beim Wechsel von Grunt/Gulp zu Webpack verloren. Ich habe sie mit Webpack eingerichtet und es war eine echte Qual, also verstehe ich, warum es nützlich sein kann, Gulp parallel dafür zu haben.
Chris hat kürzlich das Thema Abhängigkeiten diskutiert (siehe Kommentar auf dieser Seite https://css-tricks.de/projects-need-react/), und ich denke, es lohnt sich, das zu wiederholen.
Um beispielsweise überhaupt mit Webpack beginnen zu können, muss man sich zu einer ganzen Reihe von Technologien verpflichten. Ich glaube nicht, dass das Problem die Liste ist (wenn ich sage "node.js", antwortest du vielleicht, dass du node.js magst), das Problem ist die Tatsache, dass die Liste einen zu einer komplexen Arbeitsweise zwingt – Kompilierung von Ressourcen, lokale Server, Paketmanager usw. Dies alles fühlt sich sehr nach einer computerwissenschaftlich orientierten Denkweise über Entwicklung an: Betonung von Abstraktion und Optimierung und Werkzeugen. Aber diese Denkweise hat sich für das Web als nicht gut erwiesen, wo Dinge praktisch, aus dem Bauch heraus und fehlerverzeihend sein müssen. HTML5 war meiner Meinung nach ein Gegenreaktion auf diese Überkomplexität und eine Rückkehr zur eher "blauen Kragen"-Sicht auf das Web: Es ist eine ineffiziente, sich ständig bewegende, spaghetti-artige, gehackte Welt, aber sie ist einfach – Textdateien und URLs im Grunde.
Gleichzeitig mit diesem Schritt hin zu zunehmenden Abhängigkeiten und Kompilierung gibt es diesen Versuch, WordPress Teil des "Stacks" zu machen – Teil der Infrastruktur wie Apache, PHP, MySQL usw. Wenn man sich den Code dieser Seite ansieht, zum Beispiel, wird man viele JS-Dateien sehen, die überall geladen werden, oft dynamisch geschrieben – viele davon scheinen auf den ersten Blick der "Optimierung" der Seite zu dienen. Ich sehe ein SEO-Modul, es gibt immer Unmengen von Google-Skripten, Twitter-Skripten, FB-Skripten usw.
Wenn Webpack & Co. die Auslieferung rationalisieren oder die Organisation von Assets erleichtern sollen, dann scheint es irgendwo eine Art von Diskrepanz zu geben. Immer öfter sehe ich WP-Seiten, die Dutzende von Plugins laden, die niemand versteht oder verfolgt; ich sehe Entwickler, die blind "build" und "install" in ihre Konsolen einfügen, immer mehr Alpha- oder Beta-Server-Plugins installieren und verlassene komplexe Frameworks überall zurücklassen, tief in ihren unverständlichen Code eingebunden. Es häuft sich immer mehr Müll – und nicht die Art von Müll, die HTML5 durch die Erlaubnis von Unordnung zu lösen versuchte. Die Dinge werden nicht rationaler oder einfacher. Die Verbreitung von Middleware-Webentwicklungstools ist ein großer, fetter, stinkender Schlamassel.
Ist Gulp 4.0 jetzt sicher zu verwenden? Es ist schon ewig im Beta-Stadium, bis zu dem Punkt, an dem ich mich gefragt habe, ob alle Entwickler es zugunsten von WebPack aufgegeben haben.
Ja, es ist sicher zu verwenden.
Es ist seit über einem halben Jahr Teil meines Workflows.
Im BrowserSync-Task-Setup gibt es meiner Meinung nach einen Tippfehler. Der Code-Snippet besagt, dass der Dateiname webpack.js ist, aber du hast die folgende Zeile:
import { config as webpackConfig } from './webpack'
Das bedeutet, dass du auch benannte Exporte aus einer lokalen Datei namens webpack.js importierst.
Ist der Name der BrowserSync-Task-Datei anders als webpack.js?
Mist, du hast recht. Danke!
Der BrowserSync-Task wäre in
server.js, nicht inwebpack.js.Ich werde einen Administrator kontaktieren.