Frontend¶
Blöbbu is fully compatible with any tus client. We recommend using Uppy,
as it is highly extensible and well-maintained by the team behind the tus protocol.
Using Uppy with Blöbbu¶
To use Uppy with Blöbbu, you need the @uppy/core and @uppy/tus packages.
1. Installation¶
npm install @uppy/core @uppy/tus
2. Basic Configuration¶
The core of the integration is configuring the Tus plugin to point to your Blöbbu server's upload endpoint.
import Uppy from '@uppy/core';
import Tus from '@uppy/tus';
const uppy = new Uppy();
uppy.use(Tus, {
endpoint: 'https://your-blobbu-server.com/files/',
headers: (file) => {
return {
Authorization: `Bearer ${file.meta['auth'] as string}`,
};
},
// Other tus options
});
3. Getting an Upload Token¶
A client needs a JWT token to upload a file to Blöbbu. Your frontend should get this token from your application server, see also JWT Generation
In Uppy, you can use a preProcessor to ensure the registration happens
before the upload begins.
The fileIDs passed to the preprocessor are ids generated by Uppy.
In the following example we used the field blobbu-id to store an internal, domain id for a file which is determined by the app server.
This could for example be a URN that contains more context or UUID.
The ID is directly being used as the Blob name, so it should only contain characters supported by Azure Blob Storage.
Make sure that this ID is unique.
uppy.addPreProcessor(async (fileIDs) => {
// 1. Call your App Server to get a JWT token
const response = await fetch('/api/your-app/files', {
method: 'POST',
body: JSON.stringify({ ids: fileIDs })
});
const registrations = await response.json();
// 2. Store the returned JWT token in Uppy's metadata
Object.entries(registrations).forEach(([key, value]) => {
uppy.setFileMeta(key, {
'auth': value.token,
'blobbu-id': value.fileId,
});
});
});
UI Components¶
Uppy provides several UI plugins that work seamlessly with Blöbbu:
- Dashboard: A full-featured UI for selecting, previewing, and monitoring uploads.
- Drag & Drop: A simple dropzone.
Refer to the Uppy documentation for more details on UI customization.
Headless¶
You can interact with Uppy fully via JavaScript and Events, therefore allowing you to build your own custom UI. See the Uppy documentation for all the methods and events Uppy supports.
Angular Example¶
Uppy Service¶
If you are using Angular, you can wrap the Uppy logic in a service.
@Injectable({ providedIn: 'root' })
export class UppyService {
private uppy = new Uppy();
constructor(private http: HttpClient) {
this.uppy.use(Tus, {
endpoint: 'https://your-blobbu-server.com/files/',
headers: (file) => {
return {
Authorization: `Bearer ${file.meta['auth'] as string}`,
};
},
});
this.uppy.addPreProcessor(async (fileIDs) => {
const request$ = this.http
.post<Record<string, { token: string; }>>('/api/your-app/files/', { ids: fileIDs })
.pipe(
tap((r) => {
Object.entries(r).forEach(([key, value]) => {
this.uppy.setFileMeta(key, {
'auth': value.token,
});
});
}),
take(1)
);
return await lastValueFrom(request$);
});
this.uppy.on('upload-success', (uploaded) => {
// ... notify backend
});
}
getUppy(): Uppy<Meta, Record<string, unknown>> {
return this.uppy;
}
}
Component¶
An example component using the Uppy Dashboard.
dashboard.component.ts¶
import { ChangeDetectionStrategy, Component, effect, ElementRef, inject, viewChild } from '@angular/core';
import '@uppy/core/css/style.min.css';
import '@uppy/dashboard/css/style.min.css';
import { UppyService } from '../uppy.service';
@Component({
selector: 'app-dashboard',
imports: [],
templateUrl: './dashboard.component.html',
styleUrl: './dashboard.component.css',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true
})
export class DashboardComponent {
dashboardTarget = viewChild<ElementRef>('dashboard');
uppyService = inject(UppyService);
constructor() {
effect(() => {
const element = this.dashboardTarget();
this.addDashboard(element);
});
}
addDashboard(element: ElementRef | undefined): void {
const dashboardPluginId = "my-dashboard-plugin";
if (element) {
const existing = this.uppy.getPlugin(dashboardPluginId);
if (existing) {
this.uppyService.getUppy().removePlugin(existing);
}
this.uppyService.getUppy().use(Dashboard, { id: dashboardPluginId, target: element.nativeElement, inline: true });
} else {
throw new Error("reference to the dashboard not found")
}
}
}
Why use effect?
The following example uses viewChild to obtain a reference to the HTML element where the dashboard will be rendered.
During local development with ng serve, hot-reloading (HMR) can cause the DOM element to be replaced while the
component instance persists.
If this happens, Uppy loses its connection to the dashboard element and may throw errors.
By wrapping the dashboard initialization in an effect, the plugin is automatically re-attached whenever the
viewChild reference changes, ensuring Uppy always has a valid target element.
dashboard.component.html¶
<main>
<h2>Uppy Dashboard</h2>
<p>
This showcases the
<a href="https://uppy.io/docs/dashboard/">dashboard component</a>
provided by Uppy.
</p>
<div #dashboard style="min-height: 400px; min-width: 400px"></div>
</main>
Demo Project¶
You can find the full Angular demo project on Gitlab