So macht der Beginn eines Projekts wieder Spaß... mit Feuer!

Jun 24, 2021


Der schwierigste und mühsamste Teil beim Start eines neuen Projekts war schon immer die Einrichtung der Anfangsstruktur. Die Ersteinrichtung nimmt viel Zeit in Anspruch und die meisten Dinge sind bei den meisten Projekten mehr oder weniger gleich.

Nehmen wir an, wir haben eine Anwendung, die entwickelt werden muss und eine Benutzerverwaltung (Rollen, Authentifizierung), ein Dashboard/eine Landing Page, die einige Daten/Ressourcen anzeigt, vielleicht Übersetzungen für die Unterstützung mehrerer Sprachen und vieles mehr enthalten soll.

Warum all das von Grund auf neu entwickeln, wenn wir eine Vorlage erstellen können, die wir nach unseren Bedürfnissen weiter anpassen können?

Um diese Frage zu beantworten, sind wir auf die Idee gekommen, eine Kernvorlage zu haben. Und so wurde Firestarter geboren. Firestarter ist eine Monorepo-Vorlage, die NestJS für das Backend, React (mit Material-UI) für das Frontend und MongoDB als Datenbank verwendet. Es soll die Starthilfe sein, die jedes Projekt braucht. Es kommt mit allen grundlegenden Dingen, die wir brauchen, wie Benutzerauthentifizierung und -verwaltung, Medienupload und -verwaltung, Auditing und mehr.

Code-Generator

Firestarter ist nicht nur eine gewöhnliche Vorlage, sondern verfügt über einen Generator für vollständige Routen (Backend und Frontend) oder nur Endpunkte mit Paginierung, Gebietsschema und Arbeitsbereich. Dazu verwendet es hygen, einen skalierbaren Codegenerator, mit dem wir Vorlagen in EJS schreiben und unsere eigenen Generatoren erstellen können, was immer hilfreich ist.

Um einen neuen API-Endpunkt zu erzeugen, müssen wir nur den folgenden Befehl ausführen:

hygen api new

Nach der Ausführung werden Sie aufgefordert, zusätzliche Informationen wie den Namen der Entität, die mit dem Endpunkt verknüpft ist, die Felder der Entität und die optionalen Funktionen, die wir verwenden möchten, wie z. B. Paginierung und Locales, anzugeben. Nach erfolgreichem Abschluss wird ein neues Modul erstellt und in das App-Modul importiert.

Es gibt einen weiteren Befehl, um eine Seite mit einer Front-End-Route und einem Back-End-Endpunkt unter Verwendung eines von uns definierten Modells zu erzeugen:

hygen page new

Wie bereits erwähnt, fragt dieser Befehl nach dem Namen der zugehörigen Entität, den Feldern der Entität und den optionalen Merkmalen. Danach wird der grundlegende Code generiert, damit wir loslegen können.

Definition von benutzerdefinierten Generatoren

Wenn wir einen Generator definieren wollen, müssen wir eine bestimmte Ordnerstruktur im Ordner _templates im Stammverzeichnis des Projekts erstellen. Die Ordnerstruktur entspricht dem Befehl, den wir eingeben, wenn wir etwas generieren wollen.

Wenn der Befehl zum Beispiel lauten soll:

hygen api new

muss die Ordnerstruktur wie folgt aussehen:

_templates └── api └── new

Der Generator besteht aus mehreren Vorlagen. Jede Vorlage entspricht einer Datei, die erstellt wird. Die Vorlagen verwenden EJS und bestehen aus zwei Teilen:

  • header - für die Regeln für den Generator, wie z.B. das Ziel der Datei;
  • Body - für den Code, der in der Datei erzeugt wird.

Hier ist ein Beispiel für eine Vorlage:

--- to: src/app.module.ts inject: true skip: 'import { <%= name %>Module } from' after: '// import line - do not remove or edit' --- import { <%= name %>Module } from './<%= h.changeCase.headerCase(name) %>/<%= h.changeCase.headerCase(name) %>.module';

Wir sehen, dass der Header mit drei Bindestrichen (-) getrennt ist und eine Reihe von Parametern definiert. Die Parameter dienen als Regeln für den Generator bei der Generierung des Codes. Der to-Parameter legt beispielsweise das Ziel der Datei fest, der after-Parameter definiert, wo der Body in dieser Datei platziert werden soll, falls sie existiert, und so weiter. Außerdem können wir eine Eingabeaufforderung definieren, die vor der Generierung eine Benutzereingabe verlangt. Dies kann verwendet werden, um der Entität, die wir erstellen, einen Namen zu geben oder eine Art von Struktur zu definieren. Die Eingabeaufforderung wird in einer Datei namens prompt.js im selben Ordner wie die Vorlagen definiert.

Hier ist ein Beispiel für einen Prompt:

module.exports = [ { type: "input", name: "name", message: "Geben Sie einen neuen Entitätsnamen ein:" }, { type: "list", name: "model", message: "Bitte geben Sie ein Datenmodell ein:" }, { type: "multiselect", name: "plugins", message: "Select plugins", choices: [ { name: "locales", message: "Locales", value: "locales" }, { name: "paginate", message: "Pagination", value: "paginieren" } ] } ];

Wie im obigen Beispiel beschrieben, können wir Eingaben verschiedener Typen definieren. Im Beispiel haben wir drei verschiedene Eingaben definiert, die uns in der Vorlage als Eigenschaft mit dem hier angegebenen Wertnamen zur Verfügung stehen werden. Die erste ist eine normale Texteingabe, die ein String sein wird, die zweite ist eine Liste, die zu einem Array wird (muss mit**,** getrennt werden) und die dritte ist ein 'multi select', das ein Array mit den Namen der von uns ausgewählten Elemente zurückgeben wird.

Technologien und Funktionen

Die Backend-Anwendung verwendet NestJS, Mongoose ODM und MongoDB und das Frontend verwendet React, das mit TypeScript eingerichtet wurde.

Andere Technologien, die wir verwenden, sind die folgenden:

  • Backend
  • mongoose-autopopulate - für die automatische Aggregation referenzierter Felder
  • mongoose-paginate-v2 - für paginierte Antworten
  • multer - für die Verarbeitung von multipart/form-data, das hauptsächlich für das Hochladen von Dateien verwendet wird
  • nodemailer - für den Versand von E-Mails
  • stripe - für Zahlungen
  • Frontend
  • redux - für die Zustandsverwaltung
  • moment - für die Arbeit mit Zeit/Datum
  • axios - für API-Aufrufe
  • react-hook-form - für die Arbeit mit Formularen
  • react-dropzone - für Datei-Uploads

Das Template bietet viele Funktionen, die sofort einsatzbereit sind, wie z. B:

  • Benutzerverwaltung
  • Rollenverwaltung
  • Verwaltung von Einstellungen
  • Medien-Uploads
  • Zahlungen mit Stripe
  • Überprüfungen
  • Unterstützung von Gebietsschemata
  • Arbeitsbereiche
  • ... und viele andere Dinge.

Backend-Struktur

Das Backend verwendet NestJS und folgt der Philosophie des Frameworks. Die Architektur ist stark von Angular inspiriert. Die Organisation unseres Codes in verschiedene funktionale Module hilft bei der Entwicklung komplexer Anwendungen und ermöglicht die Wiederverwendbarkeit. Module kapseln die gesamte Logik für einen bestimmten Bereich.

Nehmen wir an, wir müssen eine benutzerbezogene Logik implementieren. Wir können ein UserModule erstellen, das UserService, UserController und ein UserSchema enthält. Wir können auch die Tatsache ausnutzen, dass wir TypeScript verwenden, indem wir ein DTO und eine Klasse dafür erstellen, die wir später für eine strenge Typüberprüfung verwenden können. Am Ende hat jede Entität, die eine bestimmte Domäne abdeckt, ihr eigenes Modul mit der folgenden Struktur:

user ├── classes │ └── user.class.ts ├── dto │ └── user.dto.ts ├── user.module.ts ├── user.controller.ts ├── user.service.ts └── user.schema.ts

Aufbau des Frontends

Das Frontend verwendet React. Die Anwendung ist wie folgt aufgebaut:

src ├── components │ └── Navbar │ ├── Navbar.scss │ └── Navbar.tsx ├── containers │ └── User │ ├── UserTypes.ts │ ├── UserActions.ts │ ├── UserReducer.ts │ ├── User.tsx │ ├── UserView.tsx │ └── User.scss ├── layouts │ └── AdminLayout │ ├── AdminLayout.scss │ └── AdminLayout.tsx ├── routes │ └── AdminRoutes.ts ├── repository │ └── user.ts ├── services │ └── permissions.ts ├── theme │ ├── main.scss │ └── theme.ts ├── reducers.ts ├── store.ts └── index.tsx

Nun werden wir uns mit der Struktur befassen, die alle im vorherigen Baum aufgeführten Funktionen enthält:

  • components - enthält die Bausteine für die Benutzeroberfläche der Anwendung. Sie enthält die Schaltflächen, Datumspicker, Tabellen, Kopfzeilen, Eingaben, Dropdowns und viele weitere wichtige Komponenten;
  • Container - sind dafür verantwortlich, die Daten zu holen, sie zu organisieren und die entsprechenden Unterkomponenten zu rendern; das gesamte Zustandsmanagement mit Redux wird hier definiert, da der Container für die Verwaltung des Zustands verantwortlich ist;
  • Layouts - Komponenten, die zu einer Art statischem DOM-Element führen; müssen möglicherweise nicht häufig aktualisiert werden; werden verwendet, um uns zum entsprechenden Container zu leiten;
  • Routen - zur Festlegung, welcher Container welcher Route entspricht; wird für jedes Layout durchgeführt;
  • repository - für die Definition der API-Aufrufe entsprechend den Aktionen aus den Containern; getrennt nach dem Bereich, den sie abdecken (in user.ts definieren wir zum Beispiel alle Aufrufe für benutzerbezogene Aktionen);
  • services - für die Definition unserer Hilfsfunktionen; getrennt nach dem Bereich, den sie abdecken (z.B. werden die Hilfsfunktionen für die Verwaltung von Berechtigungen in permissions.ts gespeichert);
  • theme - bestehend aus zwei Dateien (die Datei theme.ts, die die Definition des Themas für die Material-UI-Bibliothek enthält, und die Datei main.scss für die Definition der Stile, die nicht von Material-UI abgedeckt werden, oder für einige Überschreibungen, die wir integrieren wollen);
  • reducers.ts - hier registrieren wir alle unsere Reducer aus den Containern;
  • store.ts - für die Redux-Konfiguration;

index.tsx - Wurzel der Anwendung.

How_To_Make_Starting_A_Project_Fun_Again_With_Fire_2.webp

Zusammenfassung

Der Kunde möchte, dass das Produkt in kürzester Zeit mit den von ihm gewünschten Funktionen entwickelt wird. Mit dieser Anwendung können wir ein Produkt viel schneller liefern, da wir das Rad nicht jedes Mal neu erfinden müssen, wenn wir ein neues Projekt beginnen.

Tanja Zlatanovska

Tanja Zlatanovska

Buchen Sie eine kostenlose Beratung

Wählen Sie Ihre Branche*

Bitte wählen Sie Ihre Branche*

Wählen Sie Ihren Servicetyp

Bitte wählen Sie Ihren Servicetyp

calendarWann passt es Ihnen am besten für ein kurzes Gespräch

Die mit * gekennzeichneten Felder sind Pflichtfelder

Alle Beiträge anzeigen