Steve Kinney

Steve Kinney


Check out a free preview of the full Vite course

The "Directives" Lesson is part of the full, Vite course featured in this preview video. Here's what you'd learn in this lesson:

Steve demonstrates the ability to resize images, change file formats, and access image metadata using various image tool directives. They also mention other query parameters available in Vite, such as importing raw text or CSS files. The lesson concludes by discussing the limitations of dynamic sources in Vite and mentioning a plugin that can provide more flexibility.


Transcript from the "Directives" Lesson

>> When last we left off, we brought in this imagetools plugin, which is, honestly in this repo that was just kind of our little playground. The first time we've touched any amount of Vite configuration whatsoever. And what imagetools does is it gives a bunch of additional abilities when we import a URL or an image to process it and actually get other information about it.

If you use Next or something like that, a lot of times, they want the width and the height of the image, maybe you don't have it, so on and so forth. But theoretically, that is knowable information but kind of depends on a bunch of factors. So the imagetools is like the first plugin, and it looks very similar to how we brought in React before, right?

And it will just kind of add a little bit of extra functionality to our ability to use these imports. So when you go back, instead of the favicon, we're gonna go back to my self portrait, steve-after-a-workshop.png. And that might not be the after workshop. It's .jpg, that's the issue.

So .jpg, and good, we're ready to go. And as a reminder, the picture is gigantic. What imagetool gives us is very simply the ability to do something like h=400. Right, and now it will resize the image for us. This is not, just it crushed down, right? This is literally the image was resized on the fly by our buildtools, right?

And we can verify this by doing, we'll do npm run build. And you can see before, the image was 5 kilobytes, or 5 megabytes, 5,000 kilobytes, and now it is 31, right? So we're able to kind of resize, and that is now the one that is produced is a JPEG.

And it is much smaller in this case, and we didn't have to go in there and resize it ourselves. We can add other options too, right? We could say, and I think it's format=webp. And then let's do another build here. And now, you can see that it has actually also changed it to a different file format as well, that's a little bit more performant for the web.

And probably this is the one where we can do the, and for a second, I'm just gonna console.log this. Do console.log(image), and at first, we should see the URL. And we'll go ahead, yeah, and you can see that it's a proxy URL at this point, right? When we do the build process, that's when it's gonna actually spit it out into all the different versions.

This is, quote unquote, the URL for our image. And part of it is that if we wanna use something like source set and bring in multiple sizes, right, this URL will respond with everything that we kinda need for the different versions. But this is effectively the URL we're using, and then I'm pretty sure, if I'm not mistaken, I've never actually tried this before.

So we're gonna live take a look if this works the way I think it's gonna work. Yeah, and so it is the image that URL being served by the Vite server, right? But you can see it is the smaller one based on our preferences at this point. And then we can do, Believe, I'm doing this from memory, this is mostly me showing off.

So if it doesn't work, it'll be the second time it didn't work, it'd be great. So we'll go back, and yeah, so I did that, one more query from as metadata, right? And as you see, now instead of getting just the URL, I'm actually getting a whole bunch of data about the image that I can use in my JavaScript code.

And then at build time, it will have all of that information as we go when we spit it out. So for instance, at this point, I did set the height to 400, we do have that source. Now, if I wanted to use it in the tag, instead of putting the image, I have to say image.source cuz now this is an object instead of just a string, but I can get the width.

So if I was using Next, image where I want some width and a height to put the placeholder in there, I now have access to this, right? And I don't have to go measure it and guess and then resize the image, I have all of this basically for free.

And now, all those things of like, okay, I do wanna make sure I'm using, and I can have multiple formats and do all those things, right? We can actually take a look at the, yeah, that's another example of all the metadata in this case that we kinda saw.

And there's a whole bunch of other directives, which are super cool, and just kinda show you what you might need to do depending on your use case. For the most part, getting into a smaller size and then maybe turn it into a different format that works. I mean, you could literally, I can import multiple times here, so I could say, we can turn this one into, call this one webp.

We'll keep the metadata on for a second, but then theoretically, if I also wanted the URL of just the JPEG one, I can import it again without changing the format. And so if I wanted to have fallbacks that we see a lot of times in the picture element, right, I can actually generate multiple versions of this image, have URLs.

And then as we'll see, instead of calling import webp, we'll call this one jpg, right? And this is one of those things where I would probably do it once in some kind of reusable code. Either if I'm using React, I would do it in a React component, Svelte, I'll do it in a Svelte component, where now I've got an image tag, it'll automatically, I'll give it the source, it will then try to generate all the different versions, so on and so forth.

So we can see jpg as well, and then we should see both of those loaded, but then the more interesting part is when I go to build it. That's not the right server, there we go. We got it, I'm just gonna make sure I'm in the right one, let's run the build process real quick.

So we've got both of those in there, let's do npm run build. And now, you can see it spit out both the jpeg and the webp, and I'm getting basically any file format. If I need multiple sizes for multiple purposes, I can even give it a stack, I believe, I can do.

I believe I can throw this, and will say, give me a 400 one, and an 800 pixel one, and then you can see that now it generated two of them. And I can reference both of them, and we can actually see, server's definitely running, there it is. Now, I've got the two webp ones in this case, right?

So you could see that webp before was a single one, now it's an array of two images, right? And so I've got the one that's got the width of 300 and the height of 400, the width of 600, the height of 800, right? They are the stack based on the way that I ordered the params.

And so now if I need multiple versions of the image, and if you look closely at the directives, there's the very practical stuff, like, get a source set, get different sizes. But there's also a bunch of different filters as well, so you can blur it. And the blurring, you can do things of generating one that's a much lower quality as the placeholder that loads faster.

The other one in that case, you could theoretically go in base 64 encoded, depending on what you're trying to do. You have all these tools, and really just putting the one plugin there, Vite is able to then generate all of these for you depending on what you wanna do.

The metadata will give you all the data, but then if I take off the app metadata, I will just get the URLs, and I can just use them directly. I might not need all that metadata, it mostly show you can do stuff with it, but there are also the various different outputs.

So in this case, you can literally just generate the source set in this way as well, where you basically, you get all of it for free and you can generate it. And we really didn't have to do much, and these are the things where it's a lot of times, if it is a part of our core app, for me, yeah, I will spend the time, by hand, it's not that big a deal.

But there's some times when we're working on the conference website, and there's a deadline to get it out so that marketing could get all these things happen. Sometimes you can't do the perfect thing unless you have tooling that does it for you, right? And a lot of this tooling takes the things that we know we're supposed to do on the web and the things that we know.

You can do stuff around font optimization with different plugins, but a lot of this becomes just part of your build process and you kinda set everything up. And with Vite, there's no lag in that time it took to generate that page. It was incredibly fast, right? It was not a whole lot of extra work, right?

The details of what you might wanna do might take you a story in a sprint, right, to get exactly what you need for the given setup. But as you can see, you can pull it in different sizes, different formats, right? Set up all the fallbacks, depending on what you're trying to do in this case, right, as the picture and have those all in place.

And at build time, it will optimize all the images for you exactly the way that you need. And again, I would most likely put this in reusable code, right? Some kinda component that kind of generates exactly what you need, but the heavy lifting is done incredibly easy. And this is kinda like I said before, as we move from Vite is easy, almost did it.

I call it myself, that doesn't count, to its powerful, which is now I'm getting a lot of these best practices kind of just built in without the overhead of having to do it directly, right? So that's super powerful. And there's other really interesting things that you can do as well, which is, for instance.

imagetools is not the only query param that we have available to us, right? And there are some that are just built into Vite without any plugins whatsoever. A lot of them, honestly, I use some of them, but I use them for very specific use cases. So for instance, I can, for instance, import, let's get that addBanner function again.

Let's say, I'm gonna do addBanner, and you'll see what I'm about to do here. From banner.js, and I am just gonna give it and export default so I don't get yelled at real quick, as well of the same function. And so when that happens, you can see that, for the most part, we got, yeah, that one.

Just doing the import as we saw in the very beginning will import the function itself. So let's go ahead and we'll console.log it. And you're gonna see a JavaScript function, you're gonna see exactly what you expect to see, really. So we can go ahead, cool, that is the function, but that's the way that the console represents functions in and of itself.

We could give it, The query from at raw, and now, it is literally the text of the file, right? And so as this is a little more of an esoteric one, the way that I use this one is we're building a new version of the homepage for our site, where we have a bunch of code samples, right?

I would prefer to have syntax highlighting and all that stuff as I have the code samples, but ultimately, I don't wanna run that code in the browser. What I wanna do is I want to show it in a little code block, right? And so I can import it with the raw query param, get the raw text and put it in there as well.

The other one that you can do is, We have that import, styles from, I think, let's grab the banner one. Banner, oop, nope, banner.module.css, cool, we'll see that it's an object. And there's something very similar, whoop, ./, that's why I had that up before. There we go. Cool, that's the object, but I can also do, inLine and actually get, again, effectively the same thing with the raw CSS, if I needed to use it for some reason, right?

So if I wanted to populate the script tag, automatically, I can actually get, the query params basically will import it differently. And again, this does fall into the Vite-specific stuff, this is not part of the core web platform. The other one that I can do is, for anything, I can do and just get the actual URL, in this case, of the CSS file that I was trying to pull in, right?

And so there's various different ways to do it depending on what you need, to be clear. You will know it if you need one of these, right? This one is a little bit more specific, I use the raw one because of a very specific purpose, but the more important part is imagetools added a bunch of those.

So you can also, theoretically, if you need two for various different purposes, if there's not a plugin that exists when we look into how to make plugins. You'll see that, okay, well, I need this file like this sometimes, or maybe I need it parsed a different way, especially if you're dealing with things that maybe not necessarily just JavaScript but some other file, where it's like, someone asked before in the chat about SVG sprites, right?

Or maybe you wanna have the SVG turned into a PNG, I don't know if you can do that one in imagetools off the top of my head, but you probably can. But for various different places, if there's not a plugin, well, this is one how the plugins work.

But if there's not a plugin, we'll look at how one could begin to do some of this themselves as well, but there's a lot of power in the fact that we can get the raw JSON. Or the raw JavaScript, or the inline CSS, or something along that line, and we have that flexibility.

Again, without a lot of deep configuration and playing around with things, everything's kind of a little bit on easy mode.
>> Are these imagetools only for static images, or can you pass dynamic sources to them?
>> So interestingly, out of the box, Vite, actually it's a good segue to when we get to, going back to those import statements, the import promises, Vite has a lot of rules that they have to be just strings.

And I'll kinda show you real quick, actually, yeah, I'll show you, I think I have some code. So the entire course website itself is also built on Vite and use some of this as well. So I'll show you where I have it, I don't have that browser open, so we'll go, So for the website, it's built on top of Vite because that makes sense, and I've got all of these markdown files that eventually get rendered as the page, right?

Basically, this is a Svelte app, that part's not particularly important for our use case at this point. But if I go into routes and for the given page, Nope, not that one. Might actually be there. For the content, I can import just this piece, but for the glob imports and stuff like that, it doesn't let you get away with a lot.

So in a lot of cases, I have to put it all together, so you can be somewhat dynamic, but there's actually a plugin that I reference later. There's a plugin, I think it's called vite-dynamic-import, I have a link to it in the slide somewhere that I use in one of the apps that we have, let's see.

Yeah, I'll show it to you down here. In all things, you can actually truly interpolate. There are rules around how much you're allowed to get away with without a plugin. It'll let you do a little bit of interpolation, especially with glob import and stuff like that, I haven't talked about glob imports yet.

It wants very strict lines, but this dynamic import plugin will allow you to kind of then be able to compose stuff a little bit easier. But yeah, without a given plugin to add an extra level of support, you are somewhat stuck with just raw strings, but you can play around with it a little bit, and this plugin will give you a little bit more flexibility as well.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now