Funktionsweise der Erweiterungen der Nutzeroberfläche
Lernen Sie das Erweiterungssystem der Nutzeroberfläche kennen und erfahren Sie, wie Sie das Stripe-Dashboard erweitern können.
Mit Erweiterungen der Nutzeroberfläche von Stripe Apps können Sie Ihre eigene Nutzeroberfläche mit TypeScript und React in den Produkten von Stripe rendern. Diese Tools sollten Ihnen vertraut sein, wenn Sie Produkte in React entwickelt haben. Da sie jedoch in einer sicheren Sandbox ausgeführt werden, die in eine andere Webseite eingebettet sind, unterscheiden sie sich in mehrfacher Hinsicht von standardmäßigen browserbasierten React-Anwendungen.
Übersicht
Erweiterungen der Nutzeroberfläche werden in TypeScript erstellt und nutzen React zur Erstellung einer Nutzeroberfläche mit dem UI-Toolkit von Stripe. Anders als bei anderen React-Umgebungen unterstützen Erweiterungen der Nutzeroberfläche kein beliebiges HTML. Stattdessen verwenden Sie ausschließlich die von Stripe bereitgestellten UI-Komponenten. Die Struktur von Nutzeroberflächenerweiterungen umfasst einige wichtige Verzeichnisse und Dateien:
stripe-app.
: Das App-Manifest. Es beschreibt, wie Apps mit Stripe interagieren, einschließlich der erforderlichen Berechtigungen, ob eine Erweiterung der Nutzeroberfläche existiert und, falls dies der Fall ist, wo diese Erweiterung in der Nutzeroberfläche von Stripe angezeigt wird.json package.
: NPM-Paket-Metadaten. Die Erweiterungen der Nutzeroberfläche sind gewöhnliche NPM-Pakete. Abhängigkeiten können mit npm oder yarn verwaltet werden.json src
: Der eigentliche TypeScript-Quellcode für die Erweiterung der Nutzeroberfläche. Standardmäßig platziert die CLI eine allgemeine Ansicht insrc/views
mit einem entsprechenden Eintrag instripe-app.
.json
Die Entwicklung einer Erweiterung der Nutzeroberfläche stützt sich auf das Stripe-CLI-App-Plugin. Die CLI kümmert sich um die Initialisierung von Apps mit der korrekten Struktur, die Konfiguration des App-Manifests, die Ausführung des Entwicklungsservers und die entsprechende Bündelung der App für die Übermittlung an Stripe.
Entwicklung einer Erweiterung der Nutzeroberfläche
- Als App-Entwickler erstellen Sie Ansichten, d. h. React-Komponenten, die immer dann angezeigt werden, wenn ein bestimmtes Darstellungsfeld auf dem Bildschirm angezeigt wird. Damit eine Ansicht beispielsweise immer dann angezeigt wird, wenn eine Seite mit Rechnungsdetails betrachtet wird, registrieren Sie sie für das Darstellungsfeld
stripe.
.dashboard. invoice. detail - Wenn Sie bereit sind, Ihre App hochzuladen, helfen CLI-Befehle Ihnen, Ihren Code zu bündeln, ihn bei Stripe hochzuladen und Ihre App auf dem CDN von Stripe zu hosten.
- Wenn die Erweiterung der Nutzeroberfläche Ihrer App initialisiert wird, lädt Stripe den Code der App in einen Sandbox-iFrame herunter.
- Wenn ein/e Nutzer/in eine Seite aufruft, die ein bestimmtes Darstellungsfeld enthält (zum Beispiel
/invoices/inv_
):1283 - Stripe definiert die Ansicht der Erweiterung der Nutzeroberfläche innerhalb der Sandbox mit dem vom Darstellungsfeld bereitgestellten Kontext.
- Stripe leitet die Ansicht an das Dashboard weiter, damit sie den Nutzer/innen angezeigt werden kann.
- Wenn Nutzer/innen mit der Erweiterung der Nutzeroberfläche interagieren (zum Beispiel durch Klicken auf eine Schaltfläche), empfangen Ereignis-Handler in der Sandbox der Erweiterung das Ereignis und können die Ansicht aktualisieren.
Ansichten und Darstellungsfelder
Um den Nutzer/innen die Nutzeroberfläche einer App anzuzeigen, erstellen Sie eine React-Ansicht registrieren diese bei einem Darstellungsfeld.
Ansichten sind React-Komponenten, die die App exportiert. Darstellungsfelder sind Bezeichner, die angeben, wo die Ansicht angezeigt werden soll. Wenn Sie eine App hochladen, werden alle von der App registrierten Ansichten mit dem zugehörigen Darstellungsfeld registriert.
Ansichten werden automatisch in Darstellungsfeldern erfasst, wenn stripe apps add view
ausgeführt wird. Im Hintergrund wird dabei ein Eintrag zum App-Manifest hinzugefügt.
{ //... other manifest properties "ui_extension": { "views": [ { "viewport": "stripe.dashboard.invoice.detail", // See all valid values at stripe.com/docs/stripe-apps/reference/viewports "component": "NameOfComponent" // This is provided by you } // ... additional views ] } }
Lebenszyklus der Erweiterung einer Nutzeroberfläche
Erweiterungen der Nutzeroberfläche werden in einem unsichtbaren Sandbox-iFrame ausgeführt, der asynchron Aktualisierungen der Nutzeroberfläche an das Stripe-Dashboard sendet, das diese dann anzeigt. Eine Sandbox kann dabei mehrere Ansichten gleichzeitig aufnehmen.
Der Lebenszyklus der Sandbox und der von Ihnen unterstützten Ansichten funktioniert wie folgt:
- Das Dashboard lädt die Sandbox der Erweiterung der Nutzeroberfläche. Dies geschieht zwischen dem Laden des Dashboard und dem Öffnen der App durch die Nutzer/innen.
- Soll eine Ansicht angezeigt werden, wartet das Dashboard darauf, dass die Sandbox initialisiert wird, weist diese dann an, die richtige Ansicht bereitzustellen und übergibt den entsprechenden Kontext.
- Wird die Ansicht geschlossen (z. B. durch Schließen des App-Drawers), wird die Bereitstellung aufgehoben. Dabei wird sie aus dem DOM und aus der React-Baumstruktur der Sandbox entfernt.
- Die Sandbox kann je nach Ressourcenauslastung weiterhin ausgeführt oder abgeschaltet werden. Das Dashboard versucht lediglich, die Ausführung von useEffect und anderen Bereinigungs-Handlern zuzulassen, bevor die Sandbox beendet wird.
Lebenszyklus der Erweiterung der Nutzeroberfläche von Stripe Apps
Sandbox-Beschränkungen
Aufgrund der speziellen Sandbox-Umgebung, in der der Quelltext der Nutzeroberflächenerweiterung ausgeführt wird, können Nutzeroberflächenerweiterungen von Stripe Apps nicht alles, was reguläre React-Apps können, die im Browser ausgeführt werden.
Hauptunterschiede zwischen Stripe Apps und regulären React-Apps
- Stripe Apps haben keinen direkten Zugriff auf das DOM. Sie werden in einem iFrame ausgeführt mit einem separaten DOM, das vom Dashboard aus nicht sichtbar ist.
- Das Dashboard leitet alle Daten an die App weiter und serialisiert diese. Komponenten des UI-Toolkits akzeptieren nur serialisierbare Daten.
- Das Dashboard leitet auch alle Props an die App weiter und serialisiert die App, sodass Funktionen, die an Komponenten des UI-Toolkits übergeben oder von diesen ausgelöst werden, asynchron sind.
Einschränkungen bei React und JavaScript
Die folgenden Einschränkungen wirken sich darauf aus, was Sie mit React und JavaScript tun können, wenn Sie Ihre App entwickeln. Die React-Baumstruktur wird erst dann in das DOM gerendert, wenn die Hostumgebung vom Stripe-Dashboard deserialisiert und ausgewertet wird. Das DOM für die App wird aktualisiert und die React-Instanz im Dashboard verwaltet dann die Dateneingabe.
Globale Dokument- und Fensterobjekte sind eingeschränkt
Die DOM-Umgebung, in der der Erweiterungscode der Nutzeroberfläche ausgeführt wird, ist durch den Sandbox-iFrame gesperrt. Das bedeutet, dass Top-Level-APIs wie localStorage, indexedDB und BroadcastChannel nicht verfügbar sind. DOM APIs, die sich auf die same-origin-Richtlinie stützen, funktionieren nicht wie vorgesehen, da Sandbox-iFrames einen null
-Ursprung haben.
Referenzeigenschaften von React werden nicht unterstützt
UI-Komponenten unterstützen keine ref
-Eigenschaften von React, da die React-Baumstruktur serialisiert und zum Rendern an das Stripe-Dashboard übergeben wird. Das DOM, in das die Komponenten schließlich gerendert werden, ist für den Sandbox-App-Code unzugänglich.
Apps können die React-Version nicht steuern
Die Standarddatei package.
, die von jeder Stripe-App generiert wird, hat keinen dependency
-Eintrag für react
. Durch das Hinzufügen einer bestimmten Version von React in der package.
-Datei der Stripe-App wird nicht gesteuert, welche React-Version Ihre App rendert. Es werden nur Typprüfungen und Komponententests durchgeführt. Das Stripe-Dashboard verwendet seine eigene Version von React (derzeit Version 17.0.2), um die Apps anzuzeigen. Um stets Kompatibilität zu gewährleisten, ändern Sie die Version nur, wenn Stripe Sie dazu auffordert.
Verwendung nicht gesteuerter Komponenten für Interaktionen
Das Dashboard serialisiert alle Dateneingaben und übermittelt sie über einen Proxy an die App. Dies führt zu einer Eingabeverzögerung bei Verwendung von React-gesteuerten Komponenten. Diese Verzögerung ist für die Nutzer/innen wahrnehmbar und kann möglicherweise Zeichen überschreiben, die Nutzer/innen in der Zwischenzeit eingegeben haben. Außerdem kann der Cursor dadurch zum Ende einer Texteingabe springen, wenn sie versuchen, Text am Anfang zu bearbeiten.
Verwenden Sie nicht gesteuerte Benutzereingaben, um die App-Nutzung zu beschleunigen:
import {useState} from 'react'; import {TextArea} from '@stripe/ui-extension-sdk/ui'; const App = () => { const defaultValue = 'Initial TextArea value'; const [text, setText] = useState(defaultValue); return ( <> <TextArea label="Message" // This doesn't work ❌ // Attempting to edit text at the beginning skips the cursor to the end value={text} onChange={e => setText(e.target.value)} /> <TextArea label="Message" // This will work ✅ defaultValue={defaultValue} onChange={e => setText(e.target.value)} /> </> ); };
UI-Komponenten: Einschränkungen
Die folgenden Einschränkungen gelten für Komponenten der Nutzeroberfläche. Während Ihre Erweiterung in einer isolierten Umgebung ausgeführt wird, werden die UI-Komponenten direkt im Dashboard gerendert. Das SDK informiert das Dashboard, um die UI-Komponenten zu rendern, was zu den folgenden Einschränkungen führt.
Komponenten können die Ereignisverbreitung nicht stoppen
Da Ereignis-Handler zeitversetzt aufgerufen werden, hat die Ereignisverbreitung bereits stattgefunden, wenn der Ereignis-Handler der App aufgerufen wird. Daher kann die App Ereignisausbreitung bzw. Bubbling nicht stoppen.
Komponenten akzeptieren nur serialisierbare Datentypen als Eigenschaften
Komponenten der Nutzeroberfläche akzeptieren nur serialisierbare Datentypen. Wenn die nicht serialisierbaren Datentypen wie Map
oder Set
als Eigenschaft an eine Komponente des UI-Toolkits übergeben werden, wird ein Fehler ausgegeben.
Verwenden Sie nur einfache Typen, Funktionen oder React-Ereignisse als Eigenschaften. Folgende Typen werden unterstützt:
- Zeichenfolgen, Zahlen,
true
,false
,null
undundefined
- Objekte, deren Schlüssel und Werte einfache Typen sind
- Arrays, deren Werte einfache Typen sind
- Funktionen, sie werden jedoch asynchron, wenn sie über einen Proxy übermittelt werden. Alle als Argumente übergebene oder zurückgegebene Funktionen unterliegen auch den Typenbeschränkungen
- React-Ereignisse
Komponenten unterstützen keine Rendering-Funktionen
React rendert synchron, aber Funktionen, die an Komponenten der Nutzeroberfläche übergeben werden, werden asynchron, nachdem das Dashboard sie über einen Proxy an die App übermittelt hat. Funktionen, die an eine Komponente der Nutzeroberfläche übergebene Aufschläge generieren, beenden das Rendering nicht rechtzeitig genug, als dass React ihre Ergebnisse verwenden könnte. Infolgedessen akzeptieren Komponenten der Nutzeroberfläche keine Rendering-Funktionen.
Dies bedeutet, dass die folgenden Muster nicht funktionieren:
// This doesn't work ❌ <ItemProvider> {(data) => ( <Item data={data} /> )} </ItemProvider>
// This doesn't work ❌ <Item renderFooter={() => <div>footer</div>} />
JSX kann nur als einfacher Knoten an nicht untergeordnete Eigenschaften übergeben werden
UI-Komponenten unterstützen Eigenschaften, die ein einfaches React-Element verwenden:
// This will work ✅ <Item footer={<div>footer</div>} />
Komplexere JSX-Datenstrukturen werden jedoch nicht unterstützt:
// This doesn't work ❌ <Item footer={[<div>one</div>, <div>two</div>]} />
// This doesn't work ❌ <Item footer={{ one: <div>one</div>, two: <div>two</div> }} />
Wenn Sie mehrere React-Elemente an eine UI-Komponente übergeben müssen, schließen Sie diese in ein Fragment ein:
// This works ✅ <Item footer={ <> <div>one</div> <div>two</div> </> }/>
Eine ähnliche Beschränkung gilt für children
. Arrays und Objekte, die JSX enthalten, werden nicht unterstützt. Mehrere React-Elemente sind jedoch zulässig:
// This works ✅ <Item> <div>one</div> <div>two</div> </Item>
NPM-Pakete installieren
Es gibt keine Einschränkungen beim Hinzufügen von NPM-Paketen von Drittanbietern zu Stripe-Apps. Sie können Pakete nach Belieben installieren. Angesichts der Sandbox-Einschränkungen von Erweiterungen der Nutzeroberfläche funktionieren jedoch nicht alle Pakete wie erwartet.
Eine Dienstprogrammbibliothek wie lodash
kann verwendet werden, da lodash
keinen DOM-Zugriff erfordert:
import { Box, Button } from "@stripe/ui-extension-sdk/ui"; import { useState } from "react"; import kebabCase from "lodash/kebabCase"; const text = "A note to the user"; const App = () => { const [isKebabCase, setIsKebabCase] = useState(false); return ( <> {/* This will work ✅ */} <Box>{isKebabCase ? kebabCase(text) : text}</Box> <Button onPress={() => { setIsKebabCase(!isKebabCase); }} > Toggle kebab-case </Button> </> ); };
Eine Formularbibliothek wie react-hook-form
kann nicht verwendet werden, da react-hook-form
Refs zur Verwaltung des Formularstatus verwendet:
import { TextField } from "@stripe/ui-extension-sdk/ui"; import { useForm } from "react-hook-form"; const App = () => { const { register } = useForm(); const { onChange, name, ref } = register("firstName"); return ( <TextField label="First name" placeholder="Enter your name" name={name} onChange={onChange} // This doesn't work ❌ ref={ref} /> ); };