DEV Community

Cover image for 7 Best Practices of File Upload With JavaScript & React
Çağatay Kaydır
Çağatay Kaydır

Posted on • Originally published at storagebowl.net

7 Best Practices of File Upload With JavaScript & React

I've been working on StorageBowl, a modern all-in-one storage bucket that includes placeholder images, media streaming, shadcn-like components, and much more, for months now. As you can guess, it requires knowing the best practices for uploading functionalities. In one of my previous blogs, I said "Uploading functionality is not a one-time to-do list, it's recursive. You'll need to come again and again throughout scaling your app to meet your needs" One thing I can do to help you to come back less is to give you real actionable best practices, including codes below. Following these practices will increase the performance of your websites and the speed of your uploading functionality in an instant, only by copying & pasting the example codes I give.

Before we start, StorageBowl is giving up to 100GB of free storage for life! We gifted a terabyte of storage already to lots of our users, so get yours or see how much storage we gifted at https://storagebowl.net.

1. Optimize Your Images

One important thing to remember when building an uploading functionality is that users don't care about image formats. They don't even know the differences between various image extensions. Poorly optimized files not only result in a higher bill but also greatly reduce your site's performance, so you'll need to fix your users' ignorance. Think about these two when you fix it:

  1. What will be the image size/sizes you'll use in your application? If it's a profile image for example, what is the biggest size you'll use in your app?
  2. Which image format will work best for you? The answer will almost always be WebP since it's supported in almost every browser, encodes images efficiently resulting in smaller file sizes, and supports alpha channel (which means that it supports transparent images too).

If you're writing in JavaScript, you can optimize images using sharp, an npm package for image processing. Here's a small code snippet:

const optimizedImage = await sharp(input)
 .resize({ width: 400, height: 400, kernel: sharp.kernel.nearest }) // Max size that I'll use for a profile picture
 .toFile("name.webp"); // Saves image. If you don't want to save, use toBuffer() instead
Enter fullscreen mode Exit fullscreen mode

But 2 important notes here:

  1. Even though the sharp package is written astonishingly, JavaScript is not the most efficient language you can use for image processing.
  2. Optimizing images on the client side before sending them to your backend and checking if they're optimized on the backend is much more efficient than doing optimization on your backend. It decreases bandwidth usage, upload times, and needed processing power on your backend.

StorageBowl provides ready-to-use components that include WebAssembly written in Rust to ensure the best efficiency.

2. Set Boundaries

This is a well-known one. However, people sometimes implement it poorly. Don't forget to check properties like min and max size, width and height, file count, file formats, etc.
Sharp provides a solution for this one too:

const metadata = await sharp(input).metadata();

if (
 metadata.hasAlpha ||
 (metadata.width ?? 500) > 400 ||
 (metadata.height ?? 500) > 400
) {
 throw new Error("File doesn't match the requirements");
}
Enter fullscreen mode Exit fullscreen mode

Metadata has lots of properties you can use alongside hasAlpha, width, and height. It's full of stuff, isn't it? But the same note is valid here too: JavaScript might not be an effective solution when you need performance to scale up.

3. Use Placeholders

One of the best solutions to make your website faster is to use placeholder images. There is more than one solution to create placeholders: 16x16 blurry WebP, BlurHash, and ThumbHash are the usual suspects. I can write a blog covering the advantages of each one. Let me know in the comments if you want it. However, to avoid getting off-topic, I'll just cover ThumbHash.

ThumbHash is one of the most effective algorithms to generate hash strings of blurred images. To put it more simply, it takes your image and turns it into a string, and you can use this string as a blurred placeholder using ThumbHash's converter. This solution results in a smaller binary size than you could have with resizing images.

To learn how to use ThumbHash, you can visit its GitHub page or you can take a look at some examples here. ThumbHash is available in Rust, Swift, and Java as well as JavaScript.

4. Empower Users

You can help users, and they can help you back. Using tools like cropping lets users have a better experience when they choose an image and, at the same time allows you to store these images in smaller spaces.

5. Send Before Pressing Send

This is one of the oldest tricks in the book and feels like playing mind games to your users. So, this one is cool, but again, it's not like we've discovered quantum mechanics. When users finish selecting a picture, you don't need to wait for them to press send, you already have the information you need. Use onChange to trigger a pre-upload function, and when a user presses the send button, you then validate these files. This one is a bit tricky on the setup process, you'll need endpoints to upload unvalidated files, you'll need to validate these files when the user presses the send button, and you'll also need to delete the ones that aren't validated. While being tricky, providing this on StorageBowl for our users increased their website efficiency significantly.

6. Upload in Parallel

This will increase your uploading speed a lot. JavaScript has a parallel promise support, meaning that you'll increase efficiency without any trouble. Here's an example to upload in parallel:

const files = inputElement.files; // Assume 5 files are selected
const uploadPromises = [];

for (const file of files) {
 const formData = new FormData();
 formData.append('file', file);

 const uploadPromise = fetch('/upload-endpoint', {
 method: 'POST',
 body: formData,
 });
 uploadPromises.push(uploadPromise);
}

try {
 const responses = await Promise.all(uploadPromises);
 console.log('All files uploaded successfully');
} catch (error) {
 console.error('Uploading failed:', error);
}
Enter fullscreen mode Exit fullscreen mode

It seems okay, isn't it? But to make this step much more efficient, we'll combine it with the next one.

7. Slice Big Files

Just like arrays, JavaScript file blobs have a slice(start, end) function. Look at the metadata of each file, if any one of them is larger than, let's say 20MB, slice that into smaller ones and add it to your files array with a name "${bigFileName}-chunk-${number}". Combining this with the previous step will increase the speed of upload significantly for any kind of file, of any size. Trust me, your users will notice it.

Conclusion

Uploading is a deep topic that has been around for decades. It was an important problem to fix for early computing, and it still is for any kind of application to keep users engaged without losing interest. The goal of this blog was to provide real actionable steps to increase performance. All other blogs I saw were either too beginner-focused or didn't provide actionable steps with code you could copy. Even though I believe I achieved my goal, this is still just the infancy steps of an efficient uploading functionality. You'll need a flexible structure to meet users' needs, a streaming infrastructure, a CDN, and more. If you don't want to spend lots of time creating a fast uploading functionality, check out StorageBowl. It has many tools for many languages and is focused on uploading and storing your files as efficiently as possible. Check it out to get your 100GB of free storage today.

Top comments (0)