Wenn Sie nach einer alternativen Bundler-Lösung 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 das Gleiche ab Version 4.0 bieten wird).
Stattdessen ist FuseBox auf Einfachheit (in Form von weniger komplizierter Konfiguration) und Leistung (durch aggressive Caching-Methoden) ausgelegt. Außerdem kann es mit unzähligen Plugins erweitert werden, die alles abdecken, was Sie über die Standardfunktionen hinaus benötigen.
Ach ja, und wenn Sie ein Fan von TypeScript sind, interessiert Sie vielleicht, dass FuseBox es zu einem First-Class-Citizen macht. Das bedeutet, Sie können eine Anwendung in TypeScript schreiben – ohne Konfiguration! – und es wird standardmäßig den TypeScript-Transpiler zum Kompilieren von Skripten verwenden. Planen Sie nicht, TypeScript zu verwenden? Kein Problem, der Transpiler kümmert sich um jedes JavaScript. Noch ein Bonus!
Um zu veranschaulichen, wie schnell es einsatzbereit ist, bauen wir das Grundgerüst einer Anwendung auf, die einer mit create-react-app erstellten Anwendung ähnelt. Alles, was wir tun, wird auf GitHub sein, falls Sie mitmachen 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, das eine weitere großartige Alternative ist, die sich lohnt zu prüfen.
Die Grundeinrichtung
Beginnen Sie mit der Erstellung eines neuen Projektverzeichnisses und der Initialisierung mit npm
## 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 fügen auch Uglify hinzu, um unsere Skripte zu minifizieren, und unterstützen das Schreiben von Styles in Sass.
npm install --save-dev fuse-box typescript uglify-js node-sass
Okay, erstellen wir nun einen src-Ordner im Stammverzeichnis des Projektverzeichnisses (was manuell erfolgen kann). Fügen Sie die folgenden Dateien (app.js und index.js) hinzu, einschließlich des 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 können sehen, dass die Art und Weise, wie wir Dateien importieren, etwas anders ist als bei einer typischen React-App. Das liegt daran, dass FuseBox standardmäßig keine Importe 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 wir fügen etwas hinzu, um die Dinge etwas aufzupeppen. Wir werden zwei Stylesheets haben. Das erste ist für die App-Komponente und 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 Vorbereitung fertig. Jetzt erweitern wir FuseBox mit einigen Goodies!
Plugins und Konfiguration
Wir haben bereits erwähnt, dass die Konfiguration von FuseBox viel einfacher ist als die von Webpack – und das stimmt auch! Erstellen Sie eine Datei namens fuse.js im Stammverzeichnis der Anwendung.
Wir beginnen mit dem Import der Plugins, 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 unser Stammverzeichnis ist und wo kompilierte Assets gespeichert werden sollen.
const fuse = FuseBox.init({
homeDir: "src",
output: "dist/$name.js"
});
Wir lassen FuseBox wissen, dass wir den TypeScript-Compiler verwenden wollen
const fuse = FuseBox.init({
homeDir: "src",
output: "dist/$name.js",
useTypescriptCompiler: true,
});
Wir haben die Plugins in der ersten Zeile der Konfigurationsdatei identifiziert, aber jetzt müssen wir sie aufrufen. Wir verwenden die Plugins weitgehend unverändert, aber schauen Sie sich unbedingt an, was das CSSPlugin, das SVGPlugin und das WebIndexPlugin zu bieten haben, wenn Sie mehr Kontrolle über die Optionen wünschen.
const fuse = FuseBox.init({
homeDir: "src",
output: "dist/$name.js",
useTypescriptCompiler: true,
plugins: [
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 Build im Browser öffnen.
Für dieses Beispiel verwenden wir einfach die Standardumgebung.
fuse.dev();
Es ist wichtig, die Entwicklungsumgebung *vor* den folgenden Bundle-Anweisungen zu definieren.
fuse
.bundle("app")
.instructions(`>index.js`)
.hmr()
.watch()
Was soll das bedeuten? Als wir die FuseBox-Instanz initialisierten, gaben wir einen Output mit dist/$name.js an. Der Wert für $name wird von der Methode bundle() bereitgestellt. In unserem Fall haben wir den Wert auf app gesetzt. Das bedeutet, dass das Ziel des Outputs dist/app.js sein wird, wenn die Anwendung gebündelt wird.
Die Methode instructions() definiert, wie FuseBox mit dem Code umgehen soll. In unserem Fall sagen wir ihm, dass er mit index.js beginnen und ihn nach dem Laden ausführen soll.
Die Methode hmr() wird für Fälle verwendet, in denen wir den Benutzer benachrichtigen wollen, wenn eine Datei geändert wird. Dies beinhaltet normalerweise das Aktualisieren des Browsers, wenn eine Datei geändert wird. Gleichzeitig bündelt watch() 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 besprochen 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 über das Terminal ausführen, indem wir node fuse eingeben. Dies startet den Build-Prozess, der den dist-Ordner mit dem gebündelten Code und der in der Konfiguration angegebenen Vorlage erstellt. Nach Abschluss des Build-Prozesses 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, mit dem ein Build-Prozess automatisiert werden kann. Er heißt Sparky und Sie können ihn als eine Art Grunt und Gulp betrachten, mit dem Unterschied, dass er auf FuseBox aufbaut und integrierten Zugriff auf FuseBox-Plugins und die FuseBox-API hat.
Wir müssen ihn nicht verwenden, aber Task-Runner erleichtern die Entwicklung erheblich, indem sie Dinge automatisieren, die wir sonst manuell erledigen 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 Imports am Anfang der Datei.
const { src, task, context } = require("fuse-box/sparky");
Als Nächstes definieren wir einen Kontext, der dem bisherigen ähneln wird. Wir wickeln das, was wir getan haben, im Grunde in einen Kontext und setConfig() ein und initialisieren dann FuseBox im Rückgabewert.
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() macht, was der Name vermuten lässt, nämlich den Code zu bündeln. Der Unterschied zu dem, was wir zuvor getan haben, besteht darin, dass wir beide Funktionalitäten in verschiedene Funktionen einbetten, die im Kontextobjekt enthalten sind.
Wir wollen, dass unser Task-Runner Aufgaben ausführt, richtig? Hier sind einige 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 ist für die Bereinigung des dist-Verzeichnisses zuständig. Das erste Argument ist der Name der Aufgabe, das zweite ist die Funktion, die aufgerufen wird, wenn die Aufgabe ausgeführt wird.
Um die erste Aufgabe aufzurufen, können wir im Terminal node fuse clean ausführen.
Wenn eine Aufgabe default heißt (was das erste Argument der zweiten Aufgabe ist), wird diese Aufgabe standardmäßig aufgerufen, wenn node fuse ausgeführt wird – in diesem Fall ist das die zweite Aufgabe in unserer Konfiguration. Andere Aufgaben müssen explizit im Terminal aufgerufen werden, wie 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 Ausführung der Aufgabe selbst aufgerufen werden sollen, und das dritte ist eine Funktion (fuse.dev()), die die initialisierte FuseBox-Instanz erhält und den Bündelungs- und Build-Prozess startet.
Jetzt können wir die Dinge im Terminal mit node fuse 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 all 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 den Einstieg erleichtert, dank integrierter TypeScript-Unterstützung, Performance-Überlegungen und einem Task-Runner, der darauf ausgelegt ist, die FuseBox-API zu nutzen.
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 gut zu wissen, dass FuseBox mehr bewältigen kann, als in ihm integriert ist, aber dass die Ersteinrichtung dennoch super optimiert ist.
Wenn Sie weitere Informationen über FuseBox suchen, sind seine Website und Dokumentation offensichtlich großartige Ausgangspunkte. Die folgenden Links sind ebenfalls sehr hilfreich, um mehr Perspektiven darauf zu bekommen, wie andere es einrichten und in Projekten verwenden.