diff --git a/blog/2024-07-10-uppy-4.0.md b/blog/2024-07-10-uppy-4.0.md index eaeee34df..60114d137 100644 --- a/blog/2024-07-10-uppy-4.0.md +++ b/blog/2024-07-10-uppy-4.0.md @@ -1,7 +1,7 @@ --- title: 'New Uppy 4.0 major: TypeScript rewrite, Google Photos, React hooks, and much - more.' + more' date: 2024-07-10 authors: [aduh95, evgenia, mifi, murderlon] image: /img/blog/4.0/preview.jpg @@ -10,30 +10,30 @@ published: true toc_max_heading_level: 2 --- -Screenshot of Uppy Dashboad with text outlining the major new features in 4.0 +Screenshot of Uppy Dashboard with text outlining the major new features in 4.0 Hold on to your leashes, folks! Uppy 4.0 is here, and it’s more exciting than a tennis ball at the dog park! Our beloved Uppy mascot, the adorable coding canine, has been hard at work fetching all the latest updates for you. From a full TypeScript makeover to shiny new React hooks, and even Google Photos -integration, this release is packed with treats that will make developers wag -their tails in delight. So, sit, stay, and let’s dig into what makes Uppy 4.0 -the goodest of good boys in file uploading! +integration – this release is so packed with treats that we're almost wagging +our tails in excitement. Without further a-dog, let’s dig into what makes Uppy +4.0 the goodest of good boys in file uploading! ## Migration guide -This post goes into the most exciting new features of Uppy 4.0. We have an +This post covers the most exciting new features of Uppy 4.0. We have an accompanying [migration guide](/docs/guides/migration-guides/) to help you transition to 4.0. ## TypeScript rewrite -In the year 2024 people expect excellent types from their libraries. We used to -author types separately by hand but they were often inconsistent or incomplete. -Now Uppy has been completely rewritten in TypeScript! +In the year 2024, people expect excellent types from their libraries. We used to +author types separately by hand, but they were often inconsistent or incomplete. +As of now, Uppy has been completely rewritten in TypeScript! From now on you’ll be in safe hands when working with Uppy, whether it’s setting the right options, building plugins, or listening to events. @@ -49,13 +49,13 @@ uppy.on('file-added', (file) => { }); ``` -One important thing to note are the new generics on `@uppy/core`. +One important thing to note is the new generics on `@uppy/core`. ```ts import Uppy from '@uppy/core'; -// xhr-upload is for uploading to your own backend. +// xhr-upload is for uploading to your own back end. import XHRUpload from '@uppy/xhr-upload'; // Your own metadata on files @@ -86,8 +86,8 @@ Happy inferring! ## Merging the two AWS S3 plugins -We used to have two separate plugins for uploading to S3 (and S3-compatible -services): `@uppy/aws-s3` and `@uppy/aws-s3-multpart`. They have different use +We used to have two separate plugins for uploading to S3 and S3-compatible +services: `@uppy/aws-s3` and `@uppy/aws-s3-multpart`. They have different use cases. The advantages of multipart uploads are: - Improved throughput – You can upload parts in parallel to improve throughput. @@ -105,33 +105,33 @@ uploading files that are only a couple kilobytes with a 100ms roundtrip latency, you are spending 400ms on overhead and only a few milliseconds on uploading. This really adds up if you upload a lot of small files. -AWS, and generally the internet from what we found, tend to agree that **you -don’t want to use multipart uploads for files under 100MB**. But this sometimes -puts users of our libraries in an awkward position, as their end users may not -only upload very large files, or only small files. In this case a portion of -their users get a subpar experience. +AWS – and the internet in general, from what we found – tends to agree that +**you don’t want to use multipart uploads for files under 100 MB**. This +sometimes puts users of our libraries in an awkward position, though, as their +end users may not exclusively upload very large files, or only small files. +In this case, a portion of their users get a subpar experience. --- We’ve merged the two plugins into `@uppy/aws-s3` with a new -[`shouldUseMultipart`](/docs/aws-s3/#shouldusemultipartfile) option! By default -it switches to multipart uploads if the file is larger than 100MB. You can pass -a `boolean` or a function to determine it per file. +[`shouldUseMultipart`](/docs/aws-s3/#shouldusemultipartfile) option! By default, +it switches to multipart uploads if the file is larger than 100 MB. You can pass +a `boolean` or a function to determine this per file. ## React hooks People working with React are more likely to create their own user interface on -top of Uppy than those working with “vanilla” setups. Working with our pre-build +top of Uppy than those working with “vanilla” setups. Working with our pre-built UI components is a plug-and-play experience, but building on top of Uppy’s state with React primitives has been tedious. -To address this we’re introducing to new hooks: `useUppyState` and +To address this, we’re introducing two new hooks: `useUppyState` and `useUppyEvent`. Thanks to the TypeScript rewrite, we can now do powerful inference in hooks as well. ### `useUppyState(uppy, selector)` -Use this hook when you need to access Uppy’s state reactively. +Use this hook when you need to read Uppy’s state. ```ts import { useState } from 'react'; @@ -144,7 +144,7 @@ const [uppy] = useState(() => new Uppy()); const files = useUppyState(uppy, (state) => state.files); const totalProgress = useUppyState(uppy, (state) => state.totalProgress); -// We can also get specific plugin state. +// We can also get a specific plugin state. // Note that the value on `plugins` depends on the `id` of the plugin. const metaFields = useUppyState( uppy, @@ -154,8 +154,11 @@ const metaFields = useUppyState( You can see all the values you can access on the [`State`](https://github.com/transloadit/uppy/blob/dab8082a4e67c3e7f109eacfbd6c3185f117dc60/packages/%40uppy/core/src/Uppy.ts#L156) -type. If you are accessing plugin state, you would have to look at the types of -the plugin. +type. + +Using this hook, you can also access the state of any Uppy plugin. For example, +in order to access the state of `ImageEditor`, you would have to look at the +types of the plugin. ```ts import type { State } from '@uppy/core'; @@ -166,12 +169,12 @@ import type { State } from '@uppy/core'; Listen to Uppy [events](/docs/uppy/#events) in a React component. The hook returns `[results, clear]`. `results` is an array of values from the -event. Depending on the event, that can be empty or have up to three values. +event. Depending on the event, this can be empty or have up to three values. `clear` is a function to clear the `results` array. -Values remain in state until the next event (if that ever comes) or if the state -is manually cleared. Depending on your use case, you may want to keep the values -in state or clear the state after something else happened. +Values remain in state until the next event (if that ever comes) or the moment +when the state is manually cleared. Depending on your use case, you may want +to keep the values in state or clear the state after something else happened. ```ts import { useState } from 'react'; @@ -193,40 +196,42 @@ useUppyEvent(uppy, 'cancel-all', () => { ## Google Photos -A long requested feature is finally here: Google Photos support! +An often requested feature is finally here: Google Photos support! :::info Uppy can bring in files from the cloud with [Companion](/docs/companion/). -Companion is a hosted, standalone, or middleware server to take away the +Companion is a hosted, standalone, or middleware server that takes away the complexity of authentication and the cost of downloading files from remote sources, such as Instagram, Google Drive, and others. -This means a 5GB video isn’t eating into your users’ data plans and you don’t -have to worry about OAuth. +This means a 5 GB video isn’t eating into your users’ data plans and you +don’t have to worry about OAuth. ::: -[`@uppy/google-photos`](/docs/google-photos/) is a new plugin so you can use it -next to your existing [`@uppy/google-drive`](/docs/google-drive/) plugin. +[`@uppy/google-drive`](/docs/google-drive/) and +[`@uppy/google-photos`](/docs/google-photos/) are separate plugins. However, +you can use the same OAuth app for both these plugins. Be sure to enable +"Photos Library API" in your OAuth app, though! ## UX improvements for viewing remote files When using [Dashboard](/docs/dashboard) with any of our remote sources (Google Drive, Facebook, etc.) you use our internal `@uppy/provider-views` plugin to -navigate and select files. In Uppy 4.0, we are making a handful of quality of -life improvements for users. -We describe the main changes in a table below. +navigate the folders and select files. In Uppy 4.0, we are making a few quality +of life improvements for users. The main changes are described in the table +below. @@ -240,7 +245,7 @@ We describe the main changes in a table below. @@ -255,7 +260,7 @@ We describe the main changes in a table below. @@ -272,22 +277,23 @@ We describe the main changes in a table below. We’re confident this turns our interface for remote sources into the most advanced one out there. We’ve seen some competing libraries not even aggregating -results beyond the first page API limit of providers. +results beyond the first page returned by the provider API. ## Revamped options for `@uppy/xhr-upload` -Before the plugin had the options `getResponseData`, `getResponseError`, -`validateStatus` and `responseUrlFieldName`. These were inflexible and too -specific. Now we have hooks similar to `@uppy/tus`: +In previous versions, the `@uppy/xhr-upload` plugin had the options +`getResponseData`, `getResponseError`, `validateStatus` and +`responseUrlFieldName`. These were inflexible and too specific. Now +we have hooks similar to `@uppy/tus`: - `onBeforeRequest` to manipulate the request before it is sent. -- `shouldRetry` to determine if a request should be retried. By default 3 +- `shouldRetry` to determine if a request should be retried. By default, three retries with exponential backoff. After three attempts it will throw an error, regardless of whether you returned `true`. -- `onAfterResponse` called after a successful response but before Uppy resolves +- `onAfterResponse` called after a successful response, but before Uppy resolves the upload. -You could for instance use them to refresh your auth token when it expires: +You could, for instance, use them to refresh your auth token when it expires: ```js import Uppy from '@uppy/core'; @@ -318,11 +324,11 @@ new Uppy().use(XHR, { }); ``` -Checkout the `@uppy/xhr-upload` [docs](/docs/xhr-upload/) for more info. +Check out the `@uppy/xhr-upload` [docs](/docs/xhr-upload/) for more info. ## Simpler configuration for `@uppy/transloadit` -To get started with `@uppy/transloadit` you would configure +To get started with `@uppy/transloadit`, you would configure [`assemblyOptions`](/docs/transloadit/#assemblyoptions) with your auth key, template ID, and other optional values. `assemblyOptions` can be an object or a function, which is called per file, which returns an object: @@ -344,7 +350,7 @@ function, which is called per file, which returns an object: } ``` -When you go to production you always want to make sure to set the `signature`. +When you go to production, you always want to make sure to set the `signature`. **Not using [Signature Authentication](https://transloadit.com/docs/topics/signature-authentication/) can be a security risk**. Signature Authentication is a security measure that @@ -365,17 +371,17 @@ new Uppy().use(Transloadit, { }); ``` -But now you are making a request to your backend for _every file_, while the -response likely remains the same, unless you are setting dynamic `fields` per -file. +However, now you are making a request to your back end for _every file_, while +the response likely remains the same, unless you are setting dynamic `fields` +per file. **This has now been improved to**: -- only call `assemblyOptions()` once. +- Only call `assemblyOptions()` once. - `fields` is for global variables in your [template](https://transloadit.com/docs/topics/templates/). -- all metadata on your files is automatically sent along to Transloadit. This - will end up in `file.user_meta` for you to dynamically access in your template +- All metadata on your files is automatically sent along to Transloadit. This + will end up in `file.user_meta` for you to dynamically access in your Template _per file_. You can read more about Assembly Variables in the @@ -385,12 +391,12 @@ You can read more about Assembly Variables in the ### Streaming uploads by default -Streaming uploads are now the default in in Companion. This comes with greatly +Streaming uploads are now the default in Companion. This comes with greatly improved upload speeds and allows uploading up to hundreds of gigabytes without needing a large server storage. We found that this improves speeds by about 37% for a Google Drive upload of a 1 GB file ([source](https://github.com/transloadit/uppy/pull/4046#issuecomment-1235697937)). -This feature was also available before but we wanted to have more real world +This feature was also available before, but we wanted to have more real-world usage before setting it as the default. With streaming upload disabled, the whole file will be downloaded first. The @@ -407,14 +413,14 @@ For more information, see the [Companion docs](/docs/companion/). As a security measure, we now require the [`corsOrigins`](/docs/companion/#corsorigins) option to be set. -It serves two purposes, it sets the `Access-Control-Allow-Origin` header and it -sets the target origin for `window.postMessage()`, which is needed to -communicate the OAuth token from the new tab you used to log-in to a provider +It serves two purposes: it sets the `Access-Control-Allow-Origin` header as well +as the target origin for `window.postMessage()`, which is needed to +communicate the OAuth token from the new tab you used to log in to a provider back to Companion. ## And more -The 4.0 release contained over 170 contributions, many too small to mention, but +The 4.0 release contains over 170 contributions, many too small to mention, but together resulting in Uppy continuing to grow and improve. We closely listen to the community and are always looking for ways to improve the experience.
Folder states: checked, unchecked, partial -

In 4.0, we introduce a new folder state - a "partially checked" folder. A folder acquires this state when some files within the folder are "checked", and some files are "unchecked".

+

In 4.0, we introduce a new folder state – a "partially checked" folder. A folder acquires this state when certain files within the folder are "checked", and other files are "unchecked".

Cache -

When navigating in and out of folders, you no longer have to wait for the same API call — results get cached.

+

When navigating in and out of folders, you no longer have to wait for the same API call — results are cached.

Restrictions

- Uppy supports file restrictions, such as maximum number of files and maximum file size. In 4.0, we reworked our restrictions UI - users will get immediate feedback upon exceeding the number of selected files, and users get a chance to reenter the correct number of files after their first upload attempt. + Uppy supports file restrictions, such as maximum number of files and maximum file size. In 4.0, we reworked our restrictions UI – users will get immediate feedback upon exceeding the number of selected files, and get a chance to re-enter the correct number of files after their first upload attempt.