12k
All articles

Uppy 6.0 und fortsetzbare Datei-Uploads

Richten Sie fortsetzbare Uploads mit Uppy und Tus ein, erfahren Sie mehr zu S3-Signierung und Core-Paketen in Uppy 6.0 und prüfen Sie die Migration von Version 5.

OpenReplay Team
OpenReplay Team
Uppy 6.0 und fortsetzbare Datei-Uploads

Uppy ist ein Open-Source-Datei-Uploader in JavaScript. In Kombination mit dem Plugin @uppy/tus setzt er große Uploads nach einem Verbindungsabbruch oder einem geschlossenen Tab fort, sodass Nutzer die Datei nicht noch einmal von vorn senden müssen.

Die meisten Teams greifen nach demselben Bug-Report zu einer Bibliothek: Jemand im Hotel-WLAN hat 90 % eines 2 GB großen Videos hochgeladen, die Verbindung bricht ab, und der Upload springt auf null zurück. Wenn Sie Ihren eigenen Uploader anhand unserer Anleitungen zum Erstellen einer Dropzone für Datei-Uploads oder zum individuellen Datei-Upload in React gebaut haben, stößt dieser Ansatz genau an dieser Stelle an seine Grenzen.

Dieser Artikel erläutert, warum fortsetzbare Uploads wichtig sind, zeigt ein minimales Uppy-Setup, stellt die Neuerungen in Uppy 6.0 vor und beschreibt, wie viel Aufwand das Upgrade von 5.x bedeutet.

Die wichtigsten Punkte

  • Tus ist ein offenes, auf HTTP basierendes Protokoll, das Uploads fortsetzbar macht. Bei einem Verbindungsabbruch oder einem geschlossenen Tab geht der Fortschritt nicht verloren: Der Upload wird ab dem letzten Byte fortgesetzt, das der Server empfangen hat.
  • Uppy 6.0 baut @uppy/aws-s3 rund um drei Signiermodi neu auf (getCredentials, signRequest und companionEndpoint), wobei jede Konfiguration genau einen davon verwendet.
  • In Uppy 6.0 werden @uppy/utils, @uppy/store-default, @uppy/companion-client und @uppy/provider-views als Subpath-Exports direkt in @uppy/core ausgeliefert.
  • Projekte, die das Metapaket uppy oder das CDN-Bundle verwenden, benötigen für den Umstieg auf 6.0 nur wenige oder gar keine Codeänderungen.
  • Selbst gehostetes Companion muss auf Companion 7 aktualisiert werden, bevor der Client auf @uppy/core 6 umgestellt wird, da OAuth-Tokens jetzt über den WebSocket von Companion übertragen werden. Companion 7 läuft außerdem auf Express 5.

Warum Uppy statt eines selbst entwickelten Uploaders?

Ein selbst entwickelter Uploader, der auf einem einzelnen fetch- oder XMLHttpRequest-POST basiert, kann nicht an der Stelle weitermachen, an der er unterbrochen wurde. Bricht die Verbindung ab, sind alle bereits gesendeten Bytes verloren. Tus löst dieses Problem auf Protokollebene: Der Client fragt den Server, wie viele Daten bereits vorliegen, und sendet dann nur noch den Rest. Mit Session Replay lässt sich gut erkennen, was das Fehlen dieser Funktion kostet: Nach einem fehlgeschlagenen Upload sieht man, wie der Nutzer zur Dateiauswahl zurückkehrt und dieselbe große Datei erneut auswählt.

Fortsetzbare Uploads mit Tus erfordern allerdings ein serverseitiges Gegenstück. Die Dokumentation zu @uppy/tus empfiehlt tusd; Tus-Server können Dateien lokal oder in externem Speicher wie S3 ablegen.

Minimales Uppy-Setup mit Dashboard und Tus

Drei Pakete ergeben einen vollständigen, fortsetzbaren Uploader: @uppy/core verwaltet den State, @uppy/dashboard stellt die Benutzeroberfläche bereit und @uppy/tus übernimmt die Übertragung.

import Uppy from '@uppy/core';
import Dashboard from '@uppy/dashboard';
import Tus from '@uppy/tus';
import '@uppy/core/css/style.min.css';
import '@uppy/dashboard/css/style.min.css';

new Uppy()
	.use(Dashboard, { inline: true, target: 'body' })
	// Point this at your own tus server, e.g. a tusd instance
	.use(Tus, { endpoint: 'https://your-tus-server/files/' });

Mit inline: true wird das Dashboard direkt im Zielelement gerendert, anstatt als Modal geöffnet zu werden. Wenn Sie lieber eine eigene Fortschrittsanzeige bauen möchten, finden Sie in unserem Artikel zum Erstellen einer Upload-Fortschrittsanzeige die zugrunde liegenden Events.

Remote-Quellen wie Google Drive laufen über Companion, die Serverkomponente von Uppy. Companion ruft die Datei auf dem Server ab, sodass die Daten nie den Browser des Nutzers passieren. Ein Detail ist dabei wichtig: Die Einstellung chunkSize in @uppy/tus gilt nur für Dateien, die vom Gerät des Nutzers gesendet werden. Uploads über Companion folgen der eigenen chunkSize-Einstellung von Companion. Setzen Sie daher beide Werte, wenn Sie die Größe pro Request begrenzen müssen.

Standardmäßig wiederholt @uppy/tus einen fehlgeschlagenen Chunk nach einer Reihe von Wartezeiten und begrenzt die Anzahl gleichzeitig laufender Uploads. Gibt der Server HTTP 429 zurück, pausiert die Standardlogik von onShouldRetry alle Requests in der Warteschlange und wartet vor dem nächsten Versuch, wobei sie die in retryDelays definierten Verzögerungen nacheinander durchläuft.

Was ist neu in Uppy 6.0?

Uppy 6.0 bringt drei zentrale Änderungen: @uppy/aws-s3 wurde von Grund auf neu geschrieben, vier Hilfspakete wurden in @uppy/core zusammengeführt und @uppy/instagram wurde entfernt. Laut dem Release-Beitrag zu Uppy 6.0 haben sechs Pakete ein Major-Update erhalten: @uppy/core, @uppy/companion, @uppy/aws-s3, @uppy/tus, @uppy/components und uppy.

In Uppy 5 hatte das alte Plugin @uppy/aws-s3 bis zu acht Callbacks, und welche davon benötigt wurden, hing vom jeweiligen Setup ab: Multipart- oder Einzel-Upload, mit oder ohne Companion, Signierung im Browser oder auf einem Server. Die Neufassung ersetzt all das durch drei Signiermodi, von denen Sie genau einen auswählen:

ModusWo signiert wirdCompanion erforderlich
getCredentialsIm Browser (SigV4), mit temporären Credentials von Ihrem EndpunktNein
signRequestIhr eigener SignerNein
companionEndpointCompanionJa
import Uppy from '@uppy/core';
import AwsS3 from '@uppy/aws-s3';

new Uppy().use(AwsS3, {
	// Swap this for an R2, MinIO or Spaces endpoint
	s3Endpoint: 'https://my-bucket.s3.eu-west-1.amazonaws.com',
	region: 'eu-west-1',
	getCredentials: async () => fetch('/s3-credentials').then((r) => r.json()),
});

Für Uploads nach S3 ist Companion nicht mehr erforderlich. Mit getCredentials signiert der Browser jeden Request selbst, und das Plugin funktioniert mit jedem S3-kompatiblen Dienst, darunter Cloudflare R2, MinIO und DigitalOcean Spaces. Die Referenz zu @uppy/aws-s3 listet die Felder auf, die getCredentials zurückgeben muss; im obigen Beispiel muss Ihr Endpunkt /s3-credentials also genau diese Struktur liefern. Laut Release-Beitrag hat die Neufassung außerdem seit Langem bestehende Bugs bei Retry-Backoff, Ablauf von Credentials, Offline-Erkennung sowie beim Pausieren und Fortsetzen von Multipart-Uploads behoben. Die CI-Tests des Plugins laufen jetzt gegen einen echten MinIO-Server statt gegen Mocks.

Wie gelingt das Upgrade von Uppy 5 auf 6?

Wenn Sie das Metapaket uppy oder das CDN-Bundle verwenden, erfordert das Upgrade auf 6.0 nur wenige oder gar keine Codeänderungen. Alle anderen sollten die folgende Liste abarbeiten; ausführliche Details finden Sie im offiziellen Migrationsleitfaden:

  • Einzelne Pakete: Stellen Sie Importe aus @uppy/utils, @uppy/store-default, @uppy/companion-client und @uppy/provider-views auf die entsprechenden Subpaths von @uppy/core um. Die alten Pakete sind auf npm als deprecated markiert.
  • Selbst gehostetes Companion: Aktualisieren Sie zuerst auf Companion 7 und stellen Sie erst danach den Client auf @uppy/core 6 um. Companion 7 unterstützt weiterhin ältere Uppy-Clients, ein Uppy-6-Client funktioniert jedoch nicht mit Companion 6 oder älter. Companion 7 basiert auf Express 5 und funktioniert nicht als Middleware in einer Express-4-Anwendung. Migrieren Sie Ihre Anwendung daher vor der Umstellung auf Express 5. companion.socket() benötigt jetzt companionOptions als zweites Argument. Nutzer des gehosteten Companion müssen nichts unternehmen.
  • Tus-Error-Handler: Überprüfen Sie Ihren upload-error-Code erneut, da response jetzt befüllt wird.
- import { fetcher } from '@uppy/utils'
+ import { fetcher } from '@uppy/core/utils'

- import { RequestClient } from '@uppy/companion-client'
+ import { RequestClient } from '@uppy/core/companion-client'

CompanionClientProvider und CompanionClientSearchProvider wurden ebenfalls entfernt. Importieren Sie stattdessen Provider aus @uppy/core/companion-client. Die Zusammenführung soll ein ganz bestimmtes Problem verhindern: Ein Lockfile, das eine alte Version von @uppy/utils neben einem neueren @uppy/core festhielt, führte dazu, dass sich zwei Kopien desselben Pakets in einem Abhängigkeitsbaum befanden.

Seit Uppy 6.0 übergibt @uppy/tus den Status und den Response-Body des Servers an das Event upload-error und an file.response. Frühere Versionen lösten den Fehler ohne die Antwort des Servers aus.

uppy.on('upload-error', (file, error, response) => {
	if (error.isNetworkError) return showOfflineNotice(); // placeholder helper
	console.log(response?.status);
	console.log(response?.body.xhr.responseText);
});

In zwei Fällen erhalten Sie für response weiterhin undefined: wenn der Server nie geantwortet hat (etwa weil er nicht erreichbar war) oder wenn es sich um eine Remote-Datei handelt, die über Companion hochgeladen wurde.

Uppy mit React und anderen Frameworks verwenden

Mit den Framework-Wrappern von Uppy können Komponenten den Uppy-State abonnieren, ohne Events manuell verknüpfen zu müssen. In React nimmt der Hook useUppyState aus @uppy/react eine Uppy-Instanz und einen Selektor entgegen und rendert die Komponente neu, sobald sich der ausgewählte Teil des States ändert. Die vollständige API ist in der Dokumentation zur React-Integration beschrieben.

import { useState } from 'react';
import Uppy from '@uppy/core';
import Tus from '@uppy/tus';
import { useUppyState } from '@uppy/react';

function UploadStatus() {
	const [uppy] = useState(() =>
		new Uppy().use(Tus, { endpoint: 'https://your-tus-server/files/' }),
	);
	const files = useUppyState(uppy, (state) => state.files);
	const progress = useUppyState(uppy, (state) => state.totalProgress);
	return <p>{Object.keys(files).length} files, {progress}% uploaded</p>;
}

Der Lazy Initializer von useState erzeugt die Uppy-Instanz einmal pro Komponente statt bei jedem Rendern. Uppy bietet außerdem Wrapper für Vue, Svelte und Angular.

Wann Sie auf Uppy verzichten sollten

Für eine einzelne kleine Datei, etwa einen Profil-Avatar, brauchen Sie weder Uppy noch Tus. Ein einfacher Formular-POST an Ihren eigenen Endpunkt reicht aus, während Tus eine Serverintegration mit sich bringen würde, die Sie anschließend betreiben müssen. Wenn Sie später die Benutzeroberfläche von Uppy nutzen, aber einen regulären HTTP-Endpunkt beibehalten möchten, ist @uppy/xhr-upload die richtige Wahl: Das Plugin kann einen klassischen Multipart-Formular-Upload oder einen PUT-Request senden. Unsere Anleitung zum Datei-Upload mit Multer in Node zeigt die Empfängerseite.

Fazit

Fortsetzbare Uploads sind der Hauptgrund, Uppy einzusetzen. Uppy 6.0 vereinfacht den Betrieb: mit einem einzigen S3-Plugin, das pro Konfiguration genau einen Signiermodus verwendet, und einem Core-Paket statt fünf Paketen, die synchron gehalten werden mussten. Installieren Sie für den Einstieg @uppy/core, @uppy/dashboard und @uppy/tus, richten Sie das Tus-Plugin auf eine tusd-Instanz aus und laden Sie bei gedrosseltem Netzwerk eine große Datei hoch. Wenn Sie bereits 5.x nutzen, beginnen Sie mit den Änderungen an Companion und upload-error, da diese bestehenden Code brechen können.

FAQs

Was muss die Funktion getCredentials in @uppy/aws-s3 zurückgeben?

Sie gibt ein Objekt mit einer Eigenschaft credentials zurück, die temporäre Credentials in camelCase enthält – accessKeyId, secretAccessKey und sessionToken – sowie optional expiration, außerdem eine region, für die signiert wird. AWS STS liefert diese Schlüssel in PascalCase, daher müssen Sie sie zunächst umwandeln. Uppy speichert das Ergebnis für die gesamte Lebensdauer des Plugins im Cache. Bei einem Fehler vom Typ ExpiredToken oder InvalidAccessKeyId ruft es neue Credentials ab und versucht es einmal erneut. Fassen Sie die zugehörige Policy möglichst eng, da der Browser diese Credentials vorhält.

Welche Optionen von @uppy/aws-s3 wurden in Uppy 6.0 entfernt, und funktioniert shouldUseMultipart noch?

shouldUseMultipart funktioniert in @uppy/aws-s3 6.0 weiterhin, ebenso wie getChunkSize, allowedMetaFields und limit. Entfernt wurden die Optionen endpoint, headers, cookiesRule, getTemporarySecurityCredentials, getUploadParameters, signPart, createMultipartUpload, listParts, abortMultipartUpload, completeMultipartUpload, uploadPartBytes und retryDelays. Bestehende Companion-Setups lassen sich migrieren, indem endpoint in companionEndpoint umbenannt wird. Für headers und cookiesRule gibt es keinen direkten Ersatz: Same-Origin-Cookies erreichen Companion weiterhin, für Bearer-Tokens oder Cross-Site-Cookies ist jedoch ein anderes Setup nötig, etwa ein authentifizierender Proxy vor Companion.

Worin unterscheiden sich fortsetzbare Uploads mit Tus und @uppy/golden-retriever?

Mit Tus behält der Server die bereits empfangenen Bytes, sodass die Übertragung fortgesetzt werden kann, während Golden Retriever die browserseitige Dateiauswahl und den Uppy-State nach einem Absturz oder einem geschlossenen Tab wiederherstellt. In Uppy 6.0 speichert Golden Retriever standardmäßig Metadaten, State und lokale Dateien bis 10 MiB in IndexedDB und greift für Metadaten ersatzweise auf localStorage zurück. Größere Dateien erfordern den optionalen Service-Worker-Store, der geschlossene Tabs übersteht, nicht aber einen Neustart des Browsers.

Kann sich ein Uppy-6-Client mit einem älteren Companion-Server verbinden?

Nein. Ein Uppy-6-Client benötigt Companion 7, da OAuth-Tokens jetzt über die WebSocket-Verbindung von Companion statt über window.opener übertragen werden. Companion 7 behält postMessage als Fallback für Uppy-Clients vor Version 6.0 bei. Deployen Sie daher zuerst Companion 7 und aktualisieren Sie anschließend den Client. Übergeben Sie auf dem Server an companion.socket() dasselbe Options-Objekt, das Sie auch an companion.app() übergeben. Nutzer des gehosteten Companion müssen nichts ändern.

DevTools for the frontend

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.