Webpack Plugins System

Creating a Custom Loader

Sean Larkin

Sean Larkin

Webpack Plugins System

Check out a free preview of the full Webpack Plugins System course

The "Creating a Custom Loader" Lesson is part of the full, Webpack Plugins System course featured in this preview video. Here's what you'd learn in this lesson:

Prompted by a student question, Sean demonstrates how to code a custom loader.


Transcript from the "Creating a Custom Loader" Lesson

>> Speaker 1: So, say I wanted to write a custom loader.
>> Sean Larkin: Yes.
>> Speaker 1: Is there anything that I should be looking out for there?
>> Sean Larkin: To write a custom loader and develop it locally in your project, there is just a couple pieces that you have to add. So one is, we have a property called resolveLoader.

So resolveLoader, and it actually is identical to the result. The properties that are available are identical to the resolve property. So any custom behavior that you wanna apply to just resolving modules, you can do the same thing for your loaders. So we're gonna add an alias.
>> Sean Larkin: Where's my prettier formatting?

Okay, hold on, I'll fix that.
>> Sean Larkin: Gosh, there we go. All right, so we wanna basically have a request. So in this case, we're gonna hijack the name of our loader and replace it with a local file for where our loader is, right? So let's just say my-loader, and we're gonna do require.resolve, build utils.

>> Sean Larkin: My-loader.
>> Sean Larkin: That make sense so far? So if we're now use it, we'll actually have to hook it up to something, so I'm gonna say, [SOUND] we need to actually use the loader so module we got a real match or a rule set.
>> Sean Larkin: And we'll say test, oops, it's an object.

Test, and let's just say, I don't know, we'll do JS for now. And then we'll say use, and we'll just, now all we have to do is just say my loader, right? Because that's gonna be hijacked, it's gonna be resolved locally
>> Sean Larkin: To, let's actually now add that loader.

So, my-loader.js.
>> Sean Larkin: So the anatomy of a loader is just it is a function, so you can name it whatever you want. Like 'll just say my-loader. And it takes a source string, and it returns a new source. Now in this case, we're just return in source right?

And then for the shake of science, we'll add a debugger statement, and then finally we need to export it. So, module to exports equals my-loader. Cool, so now I think we're finally ready to test and see if it works. So, if we want to use this preset we can say, yarn debug [NOISE] ENV.presets = my loader.

My loader, it looked like it didn't want to pick it up. Well okay, so for the sake of, I guess just having it work, what we can do is we can just move this config over to like our normal existing config. So module rules, resolve loader. Let's just pull it over there, and then I'll fix that bug and push it up.

[LAUGH] Okay, so let's throw it in just our main configuration at the top level.
>> Sean Larkin: So we can just add the resolve loader piece. They all make this much bigger and easier to see.
>> Sean Larkin: And then we get to just transfer this single rule object, right into the existing one.

>> Sean Larkin: The third and only time I'll endorse copy poster [LAUGH]. There we go. Let's see, okay. So, let's just yarn debug now. Yarn debug
>> Sean Larkin: And see what we get.
>> Sean Larkin: Okay, literally, the first module we come across, right? Because loaders are applied at a profile basis. They only know about that source that you're working with, right?

So, let's see what we can actually access. We can look at the debug console, we can literally console that locked source. We can of course see that source here.
>> Sean Larkin: But hey, look, it's our entry point. It's our first file. It's the first file to hit the graph, and before it's being added to the graph, we apply loaders across it, right, and that's how the matchers match up against it.

So of course, [LAUGH] what kind of fun things could we do? [LAUGH] Now, of course, if you look like it's breaking through every single JavaScript file, right? So it's going across every single one it finds. Does it. No, it's going through all of low dash, which is painful, cuz that's a lot of files there.

Okay. So, what we would do is we would take, I think a cool idea is like
>> Sean Larkin: Let's break into it one more time. Because I wanna assure you what other kind of metadata you get about the file inside of a loader. We call this the loader context, and we have a really good docs on this.

So if you just type in you debug counsel as you're broken into it, this, or, there we go. We get this objective information, so our utility that runs loaders against the module injects a bunch of pieces of information that are made available and that's useful to you. So for example, if your loader comes across something and it should emit an error or warning, you could literally call emitWarning and create a new error instance and pass it back to webpack, right?

Or you can take things and say, you can explicitly create another dependency on a separate file that maybe it isn't unrelated but it's relevant to your loader, and so when that file changes, it triggers a rebuild on that file and then of the graph. There's also things like, I think one is called resource.

Yeah resource, which is actually the fully resolved path of the resolver. So it passes that to the loader, so it's like I could say something along the lines of, like this is a great example. So I'm just gonna write some code here, so like if this.resource is equal to that giant dealio.

>> Sean Larkin: Then, I'm gonna say source plus equals
>> Sean Larkin: How would I do this? Probably add a semicolon at the end, just in case, for safety. And then I would say like, console dot log.
>> Sean Larkin: Right, cuz you're actually working with source strings now. So that's something to keep in mind.

I love bananas. I didn't even spell it right.
>> Sean Larkin: Now, [LAUGH] so if we're to do this, now I don't think is gonna actually update that. So lets break out of it and try and run it again, and see what happens.
>> Sean Larkin: All right, and so I could go ahead and I'll unpause.

Does it stop it or does it just unpause it? Cool. It unpauses it. Let's see what happens. Okay, it succeeds. Let's look in our entry point and see what's in there. So dist, bundle,js, like I love bananas. There you go, right? It's just string transformations on raw source files.

Now, if you're adding kind of like complex objects and stuff like that, I usually recommend that you perform like a json.stringify, right? And then whatever things you wanna change or alter, you'd do so there. Or in the other way, Json parse it out first, and then modify stuff and stringify it again.

But really, that is the primitive subloaders. So I'll share the loader API, so essentially it's the same URL, webpackapi/loaders. And now, of course, there's different things like synchronous loaders, asynchronous, pitching loaders, which is like a special way to collect metadata about your code without even needing to transform the files.

There's also, wow, we did a really great example on this. It talks about the router context, right? So like all of the properties on the API in addition to things like there's really a good one. I've talked about the things like you shouldn't also that we're reduplicatng are gonna drop.

And even like the reasons why you might wanna use something. And then there's things like a Raw Loader, which you can actually pass buffers in between loaders if you wanted to. So if you're like dealing with more complex source or image asset types, and it's more optimizes instead of trying to take a basic if you forward something into to keep the buffer data and pass it through, you can do so.

And then to get even, if you wanted to be more elaborate, if you have multiple loaders, instead of having the AST, like instead of going through and parsing. If you can generate an AST out of it, you can pass the AST between each loader, as long as it's an Acorn AST, right?

Because that's what web pack ultimately does after loaders are applied. It has the parse and create the AST, and then walk it. So you have the ability, let me see if it talks about, yes. So it will be useful to pass an abstract syntax tree the fourth argument to speed up build time, if you wanna share common AST between loaders.

So that's also hyper valuable, and useful to know. Wow, I'm really proud of our documentation team. I don't always look at this everyday, and they have made some incredible updates in the last two months. So these are very up-to-date. So I would encourage you. Of course, you can always reach out to me, or ask me questions.

Does that kind of make sense from it's simple as value how to create a loader? And how to get it set up? Okay, so I'll just add that and create a branch.

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