Uppy 2.0.0: smaller, faster, modular plugins, Preact X, stricter types, and much more
Today, our tails are positively wagging with excitement about the release of Uppy 2.0! This latest version is on average 25% smaller and up to a thousand times faster, thanks to dropping support for IE11 and a lot of refactoring work. We’ve upgraded many dependencies, most notably Preact 8 to Preact X, greatly improved TypeScript support and screen reader accessibility, paid technical debt, and added support for multiple messages in the Informer plugin.
Chow down on all the juicy bits and pieces inside! And make sure to try Uppy live demo.
Uppy is a sleek, modular JavaScript file uploader that integrates seamlessly with any application. It is made for developers who want to provide their users with the ability to see image previews, edit metadata, pick large files directly from Dropbox, restore selected files when a tab was accidentally closed, or crop an image in-browser before sending.
A pup no more
Ever since the first introduction of Uppy five years ago (or 36 in dog-years), we’ve always referred to our project as ‘the next open source file uploader for web browsers’. The release of Uppy 1.0 a little over two years ago, however, soon led to a steep increase in adoption. Uppy now boasts over 24,000 stargazers on GitHub, making it the undisputed top dog in the world of file uploaders 🌍
With that in mind, we felt it was high time to give Uppy some more much-needed trimming. We want to take this opportunity to break with the past, to make the project leaner – and to pave the way for an even brighter future for Uppy!
Table of Contents
- Highlights since 1.0
- Smaller bundles
- Faster
- Preact X and upgraded dependencies
Plugin
is replaced withBasePlugin
andUIPlugin
- Strict TypeScript types by default
- Batch pre-signing URL's for AWS S3 Multipart
- And more
- What future remains for 1.0?
- That's it
Highlights since 1.0
A lot of things have happened since we released Uppy 1.0 in April of 2019. In case you have missed some of our 1.x releases, here is a small overview. We have added:
- Official integrations for Vue (3), Angular, and Svelte
- Hooks for the React integration
- Support for picking files from Box, Unsplash, Facebook, and OneDrive
- “Ghost” files, as part of a revamped Golden Retriever plugin, which makes recovering lost files even more intuitive
- Support for 25 more languages (bringing it to a total of 37)
- Dark mode
- an Image Editor
- And four new core team members: @ajkachnic, @mifi, @aduh95, and @murderlon
Smaller bundles
With 2.0, following in the footsteps of Microsoft, we are dropping support for IE11. As a result, we are able to remove all built-in polyfills, and the new bundle size is 25% smaller! If you want your app to still support older browsers (such as IE11), you may need to add the following polyfills to your bundle:
If you're using a bundler, you need import these before Uppy:
import 'core-js';
import 'whatwg-fetch';
import 'abortcontroller-polyfill/dist/polyfill-patch-fetch';
// Order matters here: AbortController needs fetch, which needs Promise (provided by core-js).
import 'md-gum-polyfill';
import ResizeObserver from 'resize-observer-polyfill';
window.ResizeObserver ??= ResizeObserver;
export { default } from '@uppy/core';
export * from '@uppy/core';
If you're using Uppy from a CDN, we now provide two bundles: one for up-to-date browsers that do not include polyfills and use modern syntax, and one for legacy browsers. When migrating, be mindful about the types of browsers you want to support:
<!-- Modern browsers (recommended) -->
<script src="https://releases.transloadit.com/uppy/v2.0.1/uppy.min.js"></script>
<!-- Legacy browsers (IE11+) -->
<script
nomodule
src="https://releases.transloadit.com/uppy/v2.0.1/uppy.legacy.min.js"
></script>
<script type="module">
import 'https://releases.transloadit.com/uppy/v2.0.1/uppy.min.js';
</script>
Please note that while you may be able to get 2.0 to work in IE11 this way, we do not officially support it anymore.
Faster
Uppy now loads faster thanks to the decreased bundle size. With Uppy 1.0, adding many files (hundreds or even thousands) used to take dozens of seconds. Uppy 2.0 does the same thing in mere milliseconds! So, at least for this specific use case, we feel comfortable in claiming that you may see your loading times go up to a thousand times faster.
This was made possible by avoiding having to re-render all the file components
whenever something changes, using memoize
and virtual-list
(allowing us to
only render what is actually visible on screen). In addition, multiple files are
now added to state in one go via uppy.addFiles(Array)
as opposed to before,
when uppy.addFile(File)
+ uppy.setState
were being called in a loop.
Before optimizations:
And after:
Preact X and upgraded dependencies
We’ve upgraded almost all of Uppy’s dependencies. This includes the migration to
Preact X. All plugins that depend on Preact have been upgraded from 8.2.9
to
the latest version 10.5.13
. If you’d like your custom plugin to continue
working with Uppy 2.0, it also needs to be using latest version of Preact.
Other notable upgrades include browserify to v10
, typescript to v4.3
,
autoprefixer to v10
, and lerna to v4
.
Plugin
is replaced with BasePlugin
and UIPlugin
@uppy/core
provided a Plugin
class for creating plugins. This was
used for any official plugin, but also for users who want to create their own
custom plugin. However, Plugin
always came bundled with Preact, even if the
plugin itself didn't add any UI elements.
As of Uppy 2.0.0, Plugin
has been replaced with BasePlugin
and UIPlugin
.
BasePlugin
is the minimum you need to create a plugin and UIPlugin
adds
Preact for rendering user interfaces.
Note: some bundlers will include UIPlugin
(and therefore Preact) if you
import from @uppy/core
. To make sure this does not happen, you can import
Uppy
and BasePlugin
directly:
import Uppy from '@uppy/core/lib/Uppy.js';
import BasePlugin from '@uppy/core/lib/BasePlugin.js';
Interested in creating your own plugin? Check out the “writing plugins” guide.
Strict TypeScript types by default
Uppy used to have loose types by default and strict types as an opt-in. The
default export was a function that returned the Uppy
class, and the types came
bundled with the default export (Uppy.SomeType
).
import Uppy from '@uppy/core';
import Tus from '@uppy/tus';
const uppy = Uppy<Uppy.StrictTypes>();
uppy.use(Tus, {
invalidOption: null, // this will make the compilation fail!
});
Uppy is now strictly typed by default and loose types have been removed. The
default export is the Uppy
class and not a function. This means you need to
call Uppy
with the new
keyword when initializing it.
// ...
const uppy = new Uppy();
uppy.use(Tus, {
invalidOption: null, // this will make the compilation fail!
});
Uppy types are now individual exports and should be imported separately.
import type { PluginOptions, UIPlugin, PluginTarget } from '@uppy/core';
Event types
@uppy/core
provides an .on
method to listen to events. The types for these events
were loose and allowed for invalid events to be passed, such as
uppy.on('upload-errrOOOoooOOOOOrrrr')
.
Events have received a big update thanks to @Hawxy, making them more strict and accurate.
A breaking change was required to make this happen:
// Before:
type Meta = { myCustomMetadata: string };
// Invalid event
uppy.on<Meta>('upload-errrOOOoooOOOOOrrrr', () => {
// ...
});
// After:
// Normal event signature
uppy.on('complete', (result) => {
const successResults = result.successful;
});
// Custom signature
type Meta = { myCustomMetadata: string };
// Notice how the custom type has now become the second argument
uppy.on<'complete', Meta>('complete', (result) => {
// The passed type is now merged into the `meta` types.
const meta = result.successful[0].meta.myCustomMetadata;
});
Plugins that add their own events can merge with existing ones in @uppy/core
with declare module '@uppy/core' { ... }
. This is a TypeScript pattern called
module augmentation.
For instance, when using @uppy/dashboard
:
uppy.on('dashboard:file-edit-start', (file) => {
const fileName = file.name;
});
Batch pre-signing URLs for AWS S3 Multipart
The @uppy/aws-s3-multipart
plugin can be used to upload
files directly to an S3 bucket using S3’s Multipart upload strategy. With this
strategy, files are chopped up in parts of 5MB+ each, so they can be uploaded
concurrently. It is also very reliable: if a single part fails to upload, only
that 5MB chunk has to be retried.
However, in Uppy 1.0, every part had to make the trip to the server to generate a pre-signed URL. This meant that a 1GB file uploaded in 5MB chunks would require two hundred trips to the server.
As of Uppy 2.0.0, we now pre-sign URLs in batches. That same 1GB file now only takes fifty trips to the server (if the limit was four).
This is now the new default. Thanks to @martin-brennan for this contribution!
Do you care about reliable uploads? You could also consider @uppy/tus
with a self-hosted or Transloadit Tus server. Tus can resume uploads, supports
smaller chunks, and offers increased upload speeds.
And more
- The
.run
method on theUppy
instance has been removed. This method was already obsolete and only logged a warning. As of this major version, it no longer exists. @uppy/informer
now supports showing multiple notifications at the same time. The notifications themselves have also been improved.- Improved screen reader accessibility for checkboxes and the 'remove file'
button for
@uppy/dashboard
. - Sort files and folders alphabetically in the Google Drive provider.
- Polished our code base with improved eslint rules, private field methods, and other modern JavaScript features that help us write more intention-revealing and safe code.
- To make Uppy more friendly towards new contributors, we have renamed our
master
branch tomain
.
What future remains for 1.0?
Uppy 1.0 will continue to receive bug fixes for three more months (until ), security fixes for one more year (until ), but no more new features after today. Exceptions are unlikely, but can be made – to accommodate those with commercial support contracts, for example.
That's it!
We hope you'll waste no time in taking Uppy 2.0 out for a walk. When you do, please let us know what you thought of it on Reddit, HN, ProductHunt, or Twitter. We're howling at the moon to hear from you!