Was ist Tinkoff Business?
Tinkoff Business bietet Lösungen für kleine und mittlere Unternehmen: ein Gehaltsprojekt, Bargeld- und Abrechnungsdienste, einen Dokumentendesigner und etwa 20 weitere Produkte.
All dies ist in Anwendungen implementiert. Diese Anwendungen werden von separaten Teams entwickelt und haben ihre eigenen Release-Zyklen. Alle diese Anwendungen arbeiten mit einer einzigen Berechtigung, enthalten einen gemeinsamen Teil der Geschäftslogik in einer separaten Bibliothek und verwenden gemeinsame UI-Komponenten.
Gehen wir zurück vor 2 Jahren
Eine typische Tinkoff Business-Anwendung sah ungefähr so aus:
Oben - eine Kopfzeile mit Navigation durch die Anwendung und rechts - eine Seitenleiste mit Produktnavigation.
Damals war die Idee einer Mikrofront noch nicht so beliebt, aber wir bewegten uns bereits in diese Richtung: Die Seitenleiste war eine separate Angular-Anwendung. Die Hauptanwendung lud die Seitenleiste in einen Iframe, wodurch die Anwendung unabhängig freigegeben werden konnte.
Dieser Ansatz hatte seine Nachteile: Beim Wechseln zwischen Produkten musste mit zwei Angular-Anwendungen auf das vollständige Laden der Seite gewartet werden. Und da die meisten Anwendungen dieselben Backend-API-Anforderungen verwenden, mussten Benutzer warten, bis sie erneut ausgeführt wurden.
Frame Manager Idee
Wir haben mit einer solchen Architektur gelebt, bis eine globale Aufgabe für alle Anwendungen auftauchte - das Redesign. Dann kam die Idee auf: Warum nicht eine Art Umkehrung der Steuerung durchführen und anstatt dass Anwendungen die Seitenleiste in sich selbst laden, würde die Seitenleiste selbst Anwendungen laden?
Dies ermöglichte es, die Vorteile der aktuellen Architektur zu bewahren und die oben genannten Probleme zu beseitigen (und neue zu bringen, haha).
Erster Prototyp
Zunächst haben wir einen Prototyp mit der minimalen Funktionalität erstellt, die zum Laden anderer Anwendungen erforderlich ist. Auf dem Prüfstand wurde eine separate Domäne erstellt. Die Routen in Nginx für die Anwendungsstatik haben sich geändert: Zuvor wurde die Statik der entsprechenden Anwendungen entlang der Pfade / sme , / account , / Gehalt usw. geladen. Jetzt wurde die Frame Manager-Statik entlang aller Pfade gesendet, und das Postfix / Static wurde zu den statischen Routen der Anwendungen selbst hinzugefügt .
Schauen wir uns zur Verdeutlichung ein Beispiel an: Sie müssen eine Anwendung im Pfad / some-app mit some-route laden . Lassen Sie die Details beiseite und sehen wir uns an, was beim Laden von / some-app / some-route / passiert :
- Nginx sendet Frame Manager-Statiken auf diesem Pfad.
- Frame Manager wird geladen. Basierend auf der Route versteht es, eine App zu laden .
- Mit src = '/ some-app / static /' wird ein iframe erstellt, in den die Haupt-App geladen wird.
Gleichzeitig waren erhebliche Verbesserungen in den Anwendungen selbst erforderlich. Aus diesem Grund haben wir den Master des Anwendungszweigs gegabelt und dort die erforderlichen Änderungen hinzugefügt. Anschließend haben wir mit den vorgenommenen Änderungen einzelne Kopien der Anwendungen selbst erstellt.
Erste Probleme
Also haben wir 4 Anwendungen an Frame Manager übertragen und sichergestellt, dass die Lösung funktioniert. Alle anderen Anträge sollten übersetzt werden. Und hier stießen wir auf ein Problem: Es stellte sich als zu teuer heraus, gleichzeitig die reguläre Version und die Version für die Arbeit mit Frame Manager zu warten.
Wir mussten ständig neue Versionen von Anwendungen für jede Änderung am Master älterer Versionen aktualisieren, aufkommende Konflikte lösen, vorhandene Funktionen oft kaputt machen, die Kosten für Regressionstests fast verdoppeln - all dies dauerte zu lange. Es war klar, dass eine neue Lösung benötigt wurde.
Verbesserungen
Wenn eine Version der App sowohl mit der Seitenleiste als auch mit dem Frame Manager funktionieren könnte, würde dies uns viele Probleme ersparen. Mal sehen, was getan werden kann.
Zunächst müssen Sie irgendwie feststellen, ob die Anwendung im Frame Manager ausgeführt wird. Dies ist ganz einfach: Sie müssen die Referenzen von window.top und window.self vergleichen. Wenn sie nicht gleich sind, befinden wir uns in einem Frame, dh im Frame Manager! Wenn es jedoch Anwendungen gibt, die standardmäßig in einem Iframe geöffnet werden, müssen Sie zusätzliche Logik hinzufügen. Wir hatten also eine Widget-Anwendung, die anfänglich in einem Frame geöffnet wurde und davon ausging, dass sie sich immer im Frame Manager befindet, weshalb sie im alten Modus fehlerhaft war.
Schauen wir uns nun genauer an, welche Änderungen in Anwendungen erforderlich sind und wie Sie die Arbeit in zwei Modi unterstützen können:
- url. iframe, . , - , — . url’ Frame Manager, . .
- . Frame Manager’ . : . . , , , post messages custom events. Frame Manager.
- . , Frame Manager. , Angular .
- . , , TCS, config.js . Frame Manager .
- base href. nginx, base href ( /static/). : , base href , . , , , , base href, .
- Genehmigung. Für die Autorisierung in allen Anwendungen wird ein separates Skript verwendet, das in index.html eingebettet ist. In der neuen Version ist dieses Skript in Frame Manager eingebettet, und seine Wiederverwendung in Anwendungen führt zu Fehlern. Sie können die Skriptlogik so ändern, dass sie ignoriert wird, wenn die Anwendung im Frame Manager geladen wird.
Dies sind alles funktionierende Lösungen, aber sie sind nicht flexibel genug. Es wurden neue Zweige mit Logik hinzugefügt, die auch an verschiedenen Orten gepflegt werden müssen. Im Allgemeinen sieht alles wie eine überkomplizierte und ziemlich instabile Struktur aus.
Den Iframe neu erfinden
Dann kam die Idee auf, den Prozess des Ladens der index.html-Anwendung ein wenig zu hacken. Anstatt die Anwendung in einen Iframe zu laden, der das src-Attribut angibt, können Sie eine xhr-Anforderung für index.html stellen, die Seite in Textform abrufen, rendern und in den Iframe laden. Dies gibt Ihnen die vollständige Kontrolle über die geladene Anwendung: Sie können Basis-Href definieren, unnötige Skripte, Patch-Stile entfernen, Variablen überschreiben und vieles mehr!
Ja, Mokey-Patches werden von Entwicklern nicht empfohlen und gelten als schlechte Praxis. Wenn das Angular-Team sie jedoch in der Bibliothek zone.js verwendet, wie geht es uns dann schlechter? Leistungszweifel können auftreten: Das Parsen von HTML sieht nach einer teuren Operation aus. In der Regel überschreitet die Startseite einer Angular-Anwendung jedoch nicht mehr als 50 Zeilen, und in allen Browsern (sogar IE 10!) Gibt es eine praktische APIDOMParser , mit dem Sie das DOM aus einer Zeichenfolge abrufen können.
Schauen wir uns an, was der Frame Manager beim Laden der Anwendung tut (der Frame Manager selbst ist bereits geladen):
- Lädt basierend auf dem Pfad die index.html der Anwendung.
- Analysiert die Seite, konvertiert sie in DOM, entfernt unnötige Skripte im Speicher, ersetzt Basis-HRE, globale Variablen durch Konfigurationen und Stile.
- Erstellt ein iframe-Element, das das resultierende Dokument (zurück in eine Zeichenfolge konvertiert) mit document.write () schreibt.
- Legt der Anwendung eine Route fest, an die sie angeschlossen werden soll. Es speist auch die Modelle ein, die erforderlich sind, damit die Geschäftslogik den Datenaustauschdienst durchläuft.
Von den oben genannten sechs notwendigen Änderungen in der Logik muss also nur die erste (URL-Synchronisation) in der Anwendung implementiert werden, der Rest wird vom Frame Manager übernommen!
Was hat
Wir haben das Erscheinungsbild der Anwendung vollständig geändert, praktisch ohne Änderungen am Code der Anwendung selbst vorzunehmen.
Vor. Die Seitenleiste ist rot eingekreist. Eingebettet in einen Iframe
Nach dem. Der Frame Manager ist rot hervorgehoben. App in Iframe geladen
Erhielt die Möglichkeit, globale Variablen und Stile zu überschreiben oder hinzuzufügen.
So sieht beispielsweise die Stilkonfiguration für die Anwendung aus
export const business = {
'sidebar.b-main__sidebar': {
display: 'none'
},
'.b-main': {
'margin-left': '260',
position: 'relative',
display: 'block',
width: '1104px',
'min-height': '100vh',
margin: '0 auto'
}
};
Und so - die Konfiguration der Anwendung selbst
{
id: 'products',
name: ' ',
icon: 'products',
frameSupported: true,
applications: [
{
id: 'products',
path: '/products',
apiPrefix: '/products',
hasMenuConfig: true,
dynamicCompanyChange: true,
}
]
}
In diesem Fall befinden sich die Konfigurationen in einem vom Frame Manager getrennten Repository, mit dem Sie einige Parameter des Anwendungsvorgangs ändern können, ohne sie freizugeben.
Wir haben auch nahtlose Übergänge zwischen Anwendungen erstellt und die Autorisierung im Frame Manager vorgenommen. Wir haben festgestellt, dass aufgrund des Datenaustauschs zwischen Frame Manager und Anwendungen keine unnötigen Anforderungen gestellt werden.
Nicht ohne Probleme: Einige Chrome-Plugins (CryptoPro, Redux Devtools) funktionierten in der heruntergeladenen Anwendung nicht mehr, da der Link zum Fenster während der Interaktion verloren ging. Zusätzliche Verbesserungen waren erforderlich.
Infolgedessen haben wir Ende 2019 alle Anwendungen erfolgreich an Frame Manager übertragen, und die Seitenleiste ist in Vergessenheit geraten. Die Arbeit am Frame Manager wurde jedoch fortgesetzt, und es stellte sich eine neue Frage: Ist es möglich, die Arbeit des Frontends in Tinkoff Business irgendwie zu verbessern und zu optimieren? Es stellte sich heraus, dass Sie können! Aber mehr dazu im nächsten Artikel.