Transcript
00:00:00This is Bun Image, a built-in image processing API shipped with Bun 1.3.14 that can resize,
00:00:06crop, and convert images between different formats with zero native dependencies,
00:00:10and the whole thing runs off the main thread, meaning it won't block your server while it's
00:00:14processing. But Bun is already a runtime, a package manager, a bundler, a test runner,
00:00:19and now it's an image processor? Is that all way too much, or is it telling us something
00:00:24bigger about where Bun is heading? Hit subscribe and let's find out.
00:00:30If you've ever processed images on the server with JavaScript, you may have used a library called
00:00:35Sharp without even knowing, which has more than 55 million downloads on npm a week, and it's even
00:00:41used by Next.js under the hood for image optimization. But Sharp relies on a native binary called libvips,
00:00:47which means every install has to pull the right build for your platform. And if you've ever had
00:00:51a Docker build or CI pipeline fail because of it, you know just how frustrating this is. So Bun decided
00:00:57to just build image processing into the runtime itself, and it's actually faster than Sharp in
00:01:02most benchmarks. Metadata reads as 70 times faster, and resizing is about 30% faster. Now a lot of
00:01:08developers are really confused as to why Bun added this, but I kind of see where this is all going,
00:01:13and I'll tell you a bit about that later. But for now, let's go through a few demos of how to use
00:01:17the Bun image API. And we're going to try it on my blog, which is a static Waku site, which has
00:01:22some huge images. To start things off, let's go through a simple script that optimizes one image,
00:01:27which is the profile picture with my face, and it's able to reduce the size by 99%, which is insane.
00:01:33Let's see how. First, we get the image, and note we're using Bun.image here, but you could also do
00:01:37Bun file with the image function. Then we resize the image to reduce its size, giving it a width of 800
00:01:43pixels, and the height is automatically calculated based on the aspect ratio. But if you wanted to,
00:01:47we could add that here as well. We then give it an output format of WebP with reduced quality. Of
00:01:52course, other output formats are supported, and then we output the new image to a file,
00:01:56which is a promise, and so it requires the await keyword. And you can see just how simple this is.
00:02:01In fact, all of this code here is unnecessary, so we could remove it and make the code even simpler.
00:02:06We could also set a resize filter, changing the resampling kernel, further reducing the image size.
00:02:10We could rotate or flip the image, and this is really cool. We could even change the brightness or
00:02:15saturation, which could lead to some weird looking images. But there is something really clever you
00:02:19can do when it comes to slow connections, which is to use the placeholder function to automatically
00:02:23show a blurry image while the main image is loading in. And to do that, I have this for loop that is
00:02:29going through every single file that contains these extensions inside the directory that contains all
00:02:34the block images. So each image is being resized, scaled down without being cropped, and not being
00:02:39upscaled. Then we create a placeholder for each image, which creates a thumb hash, meaning it encodes
00:02:45any image into a 28-byte hash, perfect as a blurry image placeholder.
00:02:49This hash is being added to a placeholder's object, and then it's been written to a file,
00:02:53which looks like this. Now, the reason the placeholder is a base64 image instead of a
00:02:58separate smaller WebP image is so that the network doesn't have to make a request to fetch it.
00:03:02So what I could do is import all the placeholders and add them as a background image in CSS,
00:03:07while waiting for the main image to load in, which will work for every image on my blog.
00:03:11But if you wanted to do that for a single image in an MDX file, you could just add the base64 code in
00:03:16manually, which works just as well. Note, you can also get a similar behavior using
00:03:20JPEG images by setting progressive to true. Of course, there are so many other things BUN image
00:03:24supports that I haven't yet gone through, like being able to get images from an S3 compatible
00:03:28bucket, or writing images to a bucket, using the image pipeline as a valid response body,
00:03:33and configuring a fallback format if a specific OS doesn't support one.
00:03:37So is this worth using? Well, if you're on BUN already, then yeah, this is a no-brainer.
00:03:41But if you're using Node, then Sharp works really well and is battle-tested,
00:03:45and there's no need to change to a completely different runtime just for image processing.
00:03:49Remember when I said there's a bigger reason that BUN added this? Well, if you look at what BUN's been
00:03:54doing over the last year, built-in SQLite, S3, Postgres, and now Images, and that's basically
00:03:59everything you need for a full-stack app, except for maybe auth and email. But this makes me wonder,
00:04:04is BUN trying to build the Laravel or Rails for JavaScript, but at the runtime level? If they are,
00:04:11then the next thing they're going to work on is auth. And if it is, remember, you heard it here first.
00:04:15But unfortunately, nowadays, you can't talk about BUN without mentioning the huge Zig to Rust
00:04:20rewrite, which, fingers crossed, will be coming out in the next version. Let's hope it all goes well.
00:04:25Speaking of Zig, if you want to learn more about Vercel's Language Zero that looks like Zig,
00:04:29but isn't Zig, and is built for AI agents, check out this video from James.
Community Posts
No posts yet. Be the first to write about this video!
Write about this video