Webpack Plugins System

Plugin Instance Hooks

Sean Larkin

Sean Larkin

Microsoft
Webpack Plugins System

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

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

Sean continues building a custom plugin to demonstrate the available hooks and features.

Preview
Close

Transcript from the "Plugin Instance Hooks" Lesson

[00:00:00]
>> Sean Larkin: Why don't we just hook into something different just so that we can see how the hook triggers, right? So I think why don't we go to something in the compilation. So how do you plug in to something that's not the compiler? So if you wanna plug into a different instance you still have to go through the compiler though.

[00:00:19]
So compiler.hooks and then I know just by heart but we should through the practice of how you might wanna compilation. There's a hook there and it gives us that instance. And it gives us some other stuff that's not as valuable or needed to know right now, compilation. And so just as we've done before we'll tap into it.

[00:00:43]
Was that a sink hook or an esink hook? Let's see. It's a sink hook so I don't need a call back, and I just call tap. So MyfirstwebpackPlugin, cool. And then we'll get the compilation, and then there was an argument called perams and I'm just gonna keep it there for safekeeping.

[00:01:03]
And so, well now, we have the compilation, right, at our fingertips. So we can now access it's hooks. So I think, a valuable hook to know, that I think that people have wanted to know about in the past is how do I access the graph, or how do I hook into web pack, just before it starts to render the code?

[00:01:36]
So that's a phase we call a seal phase, so we have a hook for that. Now, we're not going to get any state back, but we already have access to the compilation in our plugin. So this is just a way for us to stop synchronously at this event and then perform some functionality, and then allow webpack to continue.

[00:01:56]
>> Sean Larkin: Beautiful, so .hooks.seal.tap ("MyFirstWebpackPlugin".
>> Sean Larkin: Then you get nothing in return. All right, let's set a debugger here, right? This is cool. And let's see what happens when we run our debug script, yarn debug.
>> Sean Larkin: And I'll cheat and just doing the VS code. We can do it on Chrome too.

[00:02:25]
If anybody wants to see me do it in Chrome, I can do the same thing, the steps are the same. So cool. You can see here that really building up the graph was like, whoa that was fast. We just built the entire graph with that web app.
>> Sean Larkin: Now let's see, what can we access in this scope?

[00:02:51]
This. Now obviously, you kinda have to have like a reference to it because we're using aero functions. So maybe what I'll do is unplug it. I'll say comst thisCompilationIWantToInspect = compilation. And I'll do it inside of here. Cool, let's try it again. We're in debug. I'll attach. Fun, fun.

[00:03:17]
Okay, step through the initial break point. Here we go so now I think I have this compilation. Where is that? I think I need to actually type it out. Wait, where is that? Debug console there it is.
>> Sean Larkin: That's right. So this is a little gotcha that's good to know.

[00:03:44]
So like if you don't actually use it with it stops in debug mode, I think the inspector protocol doesn't actually provided into the scope that you can read. So I can do something like console.log()this.compilation or like ThisCompilationIWantToInspect. I had to put it down here, that's right, it does some fancy scoping stuff.

[00:04:08]
So I'll try and attach, let's start it again. There we go, so now I should have access to it. Yes, from the closure. But isn't that weird? I always find that weird. But so cool, I can even see the modules that were consumed. Technically you could take and you could call other methods, and you could make modifications to the code.

[00:04:35]
You could access information. Like, the information is a wealth of knowledge. And so, I always feel bad when I say, like you're not gonna know when you're wanting one until you actually need one. I had a really cool idea the other day and it was like, this would be great for a plugin and now I can't even think about it.

[00:04:58]
But there's all sorts of stuff that is in here. A very common example is that, let's say if you wanted to, in a certain environment, whenever somebody references a specific path in the resolver, you could hook into it and say let's switch this path to something else and give me that module instead.

[00:05:21]
So you could essentially fake an entire resolution instance happening and that happens during the NormalModuleFactory.beforeResolve. So beforeResolve, you basically pass the request. And then what happens is that gets sent to the resolver. So you can hook into this, alter this property, and send it back. And so now, the resolver is going to go find some other file and give back what you requested.

[00:05:55]
Even the moment JS trick, the ContextReplacementPlugin, that's exactly what it's doing. I'll just search ContextReplacementPlugin momentjs. So how to optimize momentjs with webpack? So essentially this ContextReplacementPlugin. The reason why is because there's a dynamic AMD module that forces everything to be bundled up because it can be resolvable from a partial path.

[00:06:30]
And so what you're passing here is a redex that just says whenever you come across any of these paths in a before resolve hook it just says, return no op functions. And then it returns nothing so it proves out all the locals you don't actually need, except for the ones you actually want to filter through.

[00:06:48]
Even if we looked at the ContextReplacementPlugin, like the source code.
>> Sean Larkin: New ContextExclusionPlug, I haven't seen that one lately. If we look at the source code here for this plug-in, we can even step through it and understand what's happening. So we're going to have a resource. So resource just means the path that was originally requested.

[00:07:18]
Now it's going to have a regex. And so like if you wanted to take options into your plugin, you just pass it through the constructor.
>> Sean Larkin: So what's happening here is it's going to hook into the compiler, into the module factory and to the before resolve hook. And it's basically going to say, well apply this RegExp against whatever request that was, whatever it is, so moment.js, which is the path.

[00:07:45]
Well, what it's doing now, is it's going to filter it out with that regular expression. And then we pass back this new map, which is gonna be only the locals that we want. And so, that's essentially like if you wanted say like how to I write a resolver plugin, or how do I alter a request with a plugin?

[00:08:07]
This one and the normal replacement plug-in are the two best that you could use, and we have those out of the box with webpack. So there's this one, and then there is, I think it's just under,
>> Sean Larkin: Let me search for it, NormalModuleReplacementPlugin. So this is the same concept where you have a regular expression against the resource and then you apply [LAUGH] basically a new resource to it.

[00:08:38]
So it takes the request and then we tap into afterResolve and pass it a new value. So that's kinda like the short of it, I would say. And there's just literally a myriad of different ways that you can use the plugin hooks. And we even have our documentation gives some description on like when you wanna access these things, you can plugin to these hooks.

[00:09:02]
And so I think it's API plugins. Yeah, and we kinda describe what's Tapable, and what kinds of plugin types do we have? Like is it an async plugin, or a sync plugin? And you can even, how to create custom hooks. And you can even go and see the compiler hooks on different instances, right?

[00:09:24]
So the watching compiler. And it kind of talks about, hook into the compiler before it reads records, or before it creates a module, or before it's going to emit some files. Like, you could totally just wipe files if you wanted to from the build. I've seen reasons to do that.

[00:09:45]
And so we're adding more hooks as we go. There's also the compilation hooks like trigger before module build occurs or like when you rebuild you can hook into this to see what module was being rebuilt. Or things like if something failed and you want to handle that failure gracefully you could do so.

[00:10:07]
Also really cool ones. The ironic thing is that we write these plugins already out-of-the-box, that do as much optimizations as possible. But there are some times where people are like, I wanna mess with this. And so, the optimize hooks are really cool.
>> Sean Larkin: And there's also ones like creation of chunks before the assets are generated, additional assets.

[00:10:34]
Here's a great one. I love it when they show use cases. So here I'll make this really large.
>> Sean Larkin: So if you wanted to go and download an image that you needed for your build and serve it up. And let's say you could even compress it if you wanted to, like from a CDN.

[00:10:53]
You could literally write a hook to do this and store it in compilation.assets. The cool thing about this is it's different from event emitter because you get state and you can alter the state, right. Now some would say yeah, but what if you don't know what's altering the state.

[00:11:12]
For the most part, we have enough hooks and we set our writable and readable properties, the right way to ensure you're not messing with something that would break or whatever. But yeah, compilation.assets is a great example where you could essentially tap into it, pull down something from whatever,.

[00:11:34]
And then you could go ahead and store it so that it outputs in your build and instantly is added depending on what kind of asset it is. Like a CSS file, that's a really cool one. If you had just like a big CSS file that was hosted somewhere but you wanted to be injected properly into your HTML, with HTML webpack plugin, perfect opportunity.

[00:11:59]
This is great. I didn't even know that people are adding this stuff. Like if you have a good example and you wanna, please, please add one. afterOptimizeChunkAssets, so boopathi is one of the maintainers of the billy or the babel-minify-plugin? And so he's written a bunch of webpack plugins and so this is a good example of how you can control or see exactly what goes into every chunk.

[00:12:28]
And so he kind of writes this little code example which let's you console log it and identify. Technically, we could even I think that would yeah that's still webpack four valid. And so there's all sorts of hooks. Now, we're slowly adding more documentation as we go to, show you, what are all these things?

[00:12:48]
And you might wonder, well, our loaders added via plugin? And yes, my friend, they are. The LoaderOptionsPlugin, how loaders are actually applied, literally happens through the loader plug in.
>> Sean Larkin: You can look at how this even is tapped into. We tap into the compilation to get to it and then we listen to the normal module loader hook.

[00:13:22]
And then as this is happening we apply any of the loaders. We add dependencies for them and they're traversed. So to me this is fascinating. And I know most of you guys are like, Sean, I just wanna build web apps man. Like, all right. But this is beginnings of master.

[00:13:42]
If you really want to take ownership and like the sky's the limit, really.

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