Wenn Sie nach einem alternativen Bundler zu webpack suchen, sollten Sie sich FuseBox ansehen. Es baut auf dem auf, was webpack bietet – Code-Splitting, Hot Module Reloading, dynamische Imports usw. – aber Code-Splitting in FuseBox erfordert standardmäßig keine Konfiguration (obwohl webpack dasselbe ab Version 4.0 anbieten wird).
Stattdessen ist FuseBox auf Einfachheit (in Form von weniger komplizierter Konfiguration) und Leistung (durch aggressive Caching-Methoden) ausgelegt. Außerdem kann es um unzählige Plugins erweitert werden, die alles abdecken können, was Sie über die Standardfunktionen hinaus benötigen.
Ach ja, und wenn Sie ein Fan von TypeScript sind, wird es Sie vielleicht interessieren, dass FuseBox es als erstklassigen Bürger behandelt. Das bedeutet, dass Sie eine Anwendung in TypeScript schreiben können – ohne Konfiguration! – und es wird standardmäßig den TypeScript-Transpiler verwenden, um Skripte zu kompilieren. Planen Sie nicht, TypeScript zu verwenden? Keine Sorge, der Transpiler wird jedes JavaScript handhaben. Noch ein Bonus!
Um zu veranschaulichen, wie schnell es einsatzbereit ist, erstellen wir das Grundgerüst einer Beispielanwendung, die normalerweise mit create-react-app erstellt wird. Alles, was wir tun, finden Sie auf GitHub, wenn Sie mitverfolgen möchten.
FuseBox ist natürlich nicht die einzige Alternative zu webpack. Es gibt viele, und tatsächlich hat Maks Akymenko eine großartige Abhandlung über Parcel geschrieben, was eine weitere großartige Alternative ist, die es wert ist, untersucht zu werden.
Die Grundeinrichtung
Beginnen Sie damit, ein neues Projektverzeichnis zu erstellen und es mit npm zu initialisieren
## Create the directory
mkdir csstricks-fusebox-react && $_
## Initialize with npm default options
npm init -y
Jetzt können wir einige Abhängigkeiten installieren. Wir werden die App in React erstellen, daher benötigen wir diese sowie react-dom.
npm install --save react react-dom
Als Nächstes installieren wir FuseBox und Typescript als Abhängigkeiten. Wir werden Uglify ebenfalls hinzufügen, um unsere Skripte zu minimieren, und Unterstützung für das Schreiben von Stilen in Sass hinzufügen.
npm install --save-dev fuse-box typescript uglify-js node-sass
Okay, nun erstellen wir einen src Ordner im Stammverzeichnis des Projektverzeichnisses (dies kann manuell erfolgen). Fügen Sie die folgenden Dateien (`app.js` und index.js) darin ein, einschließlich ihres Inhalts
// App.js
import * as React from "react";
import * as logo from "./logo.svg";
const App = () => {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Welcome to React</h1>
</header>
<p className="App-intro">
To get started, edit `src/App.js` and save to reload.
</p>
</div>
)
};
export default App;
Sie haben vielleicht bemerkt, dass wir eine SVG-Datei importieren. Sie können sie direkt aus dem GitHub-Repo herunterladen.
// index.js
import * as React from "react";
import * as ReactDOM from "react-dom";
import App from "./App"
ReactDOM.render(
<App />, document.getElementById('root')
);
Sie sehen, dass die Art und Weise, wie wir Dateien importieren, etwas anders ist als bei einer typischen React-App. Das liegt daran, dass FuseBox Imports standardmäßig nicht polyfillt.
Anstatt also dies zu tun
import React from "react";
... machen wir das
import * as React from "react";
<!-- ./src/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<title>CSSTricks Fusebox React</title>
$css
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
$bundles
</body>
</html>
Styling ist eigentlich nicht der Punkt dieses Beitrags, aber lassen Sie uns etwas einfügen, um die Dinge etwas aufzupeppen. Wir werden zwei Stylesheets haben. Das erste ist für die App Komponente und wird als App.css gespeichert.
/* App.css */
.App {
text-align: center;
}
.App-logo {
animation: App-logo-spin infinite 20s linear;
height: 80px;
}
.App-header {
background-color: #222;
height: 150px;
padding: 20px;
color: white;
}
.App-intro {
font-size: large;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform:
rotate(360deg);
}
}
Das zweite Stylesheet ist für index.js und sollte als index.css gespeichert werden
/* index.css */
body {
margin: 0;
padding: 0;
font-family: sans-serif;
}
Okay, wir sind mit der anfänglichen Organisation fertig. Weiter geht es mit der Erweiterung von FuseBox mit einigen Goodies!
Plugins und Konfiguration
Wir haben bereits erwähnt, dass die Konfiguration von FuseBox viel weniger komplex sein soll als die von webpack – und das stimmt! Erstellen Sie eine Datei namens fuse.js im Stammverzeichnis der Anwendung.
Wir beginnen damit, die Plugins zu importieren, die wir verwenden werden. Alle Plugins stammen aus dem installierten FuseBox-Paket.
const { FuseBox, CSSPlugin, SVGPlugin, WebIndexPlugin } = require("fuse-box");
Als Nächstes initialisieren wir eine FuseBox-Instanz und teilen ihr mit, was wir als Home-Verzeichnis verwenden und wohin kompilierte Assets gelegt werden sollen.
const fuse = FuseBox.init({
homeDir: "src",
output: "dist/$name.js"
});
Wir informieren FuseBox, dass wir den TypeScript-Compiler verwenden möchten.
const fuse = FuseBox.init({
homeDir: "src",
output: "dist/$name.js",
useTypescriptCompiler: true,
});
In der ersten Zeile der Konfigurationsdatei haben wir Plugins identifiziert, aber jetzt müssen wir sie aufrufen. Wir verwenden die Plugins weitgehend unverändert, aber werfen Sie auf jeden Fall einen Blick darauf, was der CSSPlugin, der SVGPlugin und der WebIndexPlugin zu bieten haben, wenn Sie mehr feingranulare Kontrolle über die Optionen wünschen.
const fuse = FuseBox.init({
homeDir: "src",
output: "dist/$name.js",
useTypescriptCompiler: true,
plugins: [ // HIGHLIGHT
CSSPlugin(),
SVGPlugin(),
WebIndexPlugin({
template: "src/index.html"
})
]
});
const { FuseBox, CSSPlugin, SVGPlugin, WebIndexPlugin } = require("fuse-box");
const fuse = FuseBox.init({
homeDir: "src",
output: "dist/$name.js",
useTypescriptCompiler: true,
plugins: [
CSSPlugin(),
SVGPlugin(),
WebIndexPlugin({
template: "src/index.html"
})
]
});
fuse.dev();
fuse
.bundle("app")
.instructions(`>index.js`)
.hmr()
.watch()
fuse.run();
FuseBox ermöglicht uns die Konfiguration eines Entwicklungsservers. Wir können Ports, SSL-Zertifikate definieren und die Anwendung sogar beim Erstellen im Browser öffnen.
Wir verwenden für dieses Beispiel einfach die Standardumgebung.
fuse.dev();
Es ist wichtig, die Entwicklungsumgebung *vor* den nachfolgenden Bundle-Anweisungen zu definieren.
fuse
.bundle("app")
.instructions(`>index.js`)
.hmr()
.watch().
Was zum Teufel ist das? Als wir die FuseBox-Instanz initialisiert haben, haben wir eine Ausgabe mit dist/$name.js angegeben. Der Wert für $name wird durch die bundle() Methode bereitgestellt. In unserem Fall haben wir den Wert auf app gesetzt. Das bedeutet, dass das Ausgabeverzeichnis, wenn die Anwendung gebündelt wird, dist/app.js sein wird.
Die instructions() Methode definiert, wie FuseBox mit dem Code umgehen soll. In unserem Fall sagen wir ihm, er soll mit index.js beginnen und es nach dem Laden ausführen.
Die hmr() Methode wird für Fälle verwendet, in denen wir den Benutzer über Dateänderungen informieren möchten, was normalerweise das Aktualisieren des Browsers bei jeder Dateänderung beinhaltet. watch() bündelt den gebündelten Code nach jeder gespeicherten Änderung neu.
Damit schließen wir ab, indem wir den Build-Prozess mit fuse.run() am Ende der Konfigurationsdatei starten. Hier ist alles, was wir gerade behandelt haben, zusammengefasst:
const { FuseBox, CSSPlugin, SVGPlugin, WebIndexPlugin } = require("fuse-box");
const fuse = FuseBox.init({
homeDir: "src",
output: "dist/$name.js",
useTypescriptCompiler: true,
plugins: [
CSSPlugin(),
SVGPlugin(),
WebIndexPlugin({
template: "src/index.html"
})
]
});
fuse.dev();
fuse
.bundle("app")
.instructions(`>index.js`)
.hmr()
.watch()
fuse.run();
Jetzt können wir die Anwendung vom Terminal aus ausführen, indem wir node fuse eingeben. Dies startet den Build-Prozess, der den dist Ordner erstellt, der den gebündelten Code und die in der Konfiguration angegebene Vorlage enthält. Nachdem der Build-Prozess abgeschlossen ist, können wir den Browser auf https://:4444/ richten, um unsere App zu sehen.
Aufgaben mit Sparky ausführen
FuseBox enthält einen Task-Runner, der zur Automatisierung eines Build-Prozesses verwendet werden kann. Er heißt Sparky und Sie können ihn sich als eine Art Grunt und Gulp vorstellen. Der Unterschied besteht darin, dass er auf FuseBox aufbaut und integrierten Zugriff auf FuseBox-Plugins und die FuseBox-API bietet.
Wir müssen ihn nicht verwenden, aber Task-Runner machen die Entwicklung erheblich einfacher, indem sie Dinge automatisieren, die wir sonst manuell tun müssten, und es ist sinnvoll, das zu verwenden, was speziell für FuseBox entwickelt wurde.
Um ihn zu verwenden, aktualisieren wir die Konfiguration in fuse.js, beginnend mit einigen Importen, die am Anfang der Datei stehen
const { src, task, context } = require("fuse-box/sparky");
Als Nächstes definieren wir einen Kontext, der dem bereits Vorhandenen ähneln wird. Wir verpacken im Grunde genommen, was wir getan haben, in einem Kontext und setConfig() und initialisieren dann FuseBox in der Rückgabe.
context({
setConfig() {
return FuseBox.init({
homeDir: "src",
output: "dist/$name.js",
useTypescriptCompiler: true,
plugins: [
CSSPlugin(),
SVGPlugin(),
WebIndexPlugin({
template: "src/index.html"
})
]
});
},
createBundle(fuse) {
return fuse
.bundle("app")
.instructions(`> index.js`)
.hmr();
}
});
Es ist möglich, eine Klasse, Funktion oder ein einfaches Objekt an einen Kontext zu übergeben. Im obigen Szenario übergeben wir Funktionen, insbesondere setConfig() und createBundle(). setConfig() initialisiert FuseBox und richtet die Plugins ein. createBundle() tut, was man vom Namen her erwarten würde, nämlich den Code bündeln. Der Unterschied zu dem, was wir zuvor getan haben, ist, dass wir beide Funktionalitäten in verschiedene Funktionen einbetten, die im Kontextobjekt enthalten sind.
Wir möchten, dass unser Task-Runner Aufgaben ausführt, richtig? Hier sind ein paar Beispiele, die wir definieren können
task("clean", () => src("dist").clean("dist").exec());
task("default", ["clean"], async (context) => {
const fuse = context.setConfig();
fuse.dev();
context.createBundle(fuse);
await fuse.run()
});
Die erste Aufgabe wird für die Bereinigung des dist Verzeichnisses zuständig sein. Das erste Argument ist der Name der Aufgabe, während das zweite die Funktion ist, die aufgerufen wird, wenn die Aufgabe ausgeführt wird.
Um die erste Aufgabe aufzurufen, können wir im Terminal node fuse clean eingeben.
Wenn eine Aufgabe default heißt (was das erste Argument in der zweiten Aufgabe ist), wird diese Aufgabe standardmäßig aufgerufen, wenn node fuse ausgeführt wird – in diesem Fall ist dies die zweite Aufgabe in unserer Konfiguration. Andere Aufgaben müssen explizit im Terminal aufgerufen werden, z. B. node fuse <task_name>.
Unsere zweite Aufgabe ist also die Standardaufgabe, und ihr werden drei Argumente übergeben. Das erste ist der Name der Aufgabe (`default`), das zweite (["clean"]) ist ein Array von Abhängigkeiten, die vor der eigentlichen Ausführung der Aufgabe aufgerufen werden sollten, und das dritte ist eine Funktion (fuse.dev()), die die initialisierte FuseBox-Instanz erhält und den Bündelungs- und Build-Prozess startet.
Nun können wir die Dinge mit node fuse im Terminal ausführen. Sie haben die Möglichkeit, diese zu Ihrer package.json Datei hinzuzufügen, wenn Ihnen das angenehmer und vertrauter ist. Der Skriptbereich würde so aussehen:
"scripts": {
"start": "node fuse",
"clean": "node fuse clean"
},
Das ist ein Abschluss!
Alles in allem ist FuseBox eine interessante Alternative zu webpack für alle Ihre Anwendungsbündelungsanforderungen. Wie wir gesehen haben, bietet es die gleiche Art von Leistung, die wir alle an webpack mögen, aber mit einem viel einfacheren Konfigurationsprozess, der es dank integrierter TypeScript-Unterstützung, Performance-Überlegungen und einem Task-Runner, der darauf ausgelegt ist, die FuseBox-API zu nutzen, wesentlich einfacher macht, schnell einsatzbereit zu sein.
Was wir uns angesehen haben, war ein ziemlich einfaches Beispiel. In der Praxis werden Sie wahrscheinlich mit komplexeren Anwendungen arbeiten, aber die Konzepte und Prinzipien sind dieselben. Es ist schön zu wissen, dass FuseBox mehr verarbeiten kann als nur das, was eingebaut ist, aber dass die Ersteinrichtung immer noch super optimiert ist.
Wenn Sie weitere Informationen zu FuseBox suchen, sind seine Website und Dokumentation offensichtlich ein großartiger Ausgangspunkt. Die folgenden Links sind ebenfalls sehr hilfreich, um mehr Perspektiven darauf zu bekommen, wie andere es einrichten und in Projekten verwenden.