Finding webpack 4 (use a Map)

John Reilly January 29, 2018
Source

Update: 03/02/2018

Tobias Koppers has written a migration guide for plugins / loaders as well - take a read here. It's very useful.

webpack 4

webpack 4 is on the horizon. The beta dropped last Friday. So what do you, as a plugin / loader author need to do? What needs to change to make your loader / plugin webpack 4 friendly?

This is a guide that should inform you about the changes you might need to make. It's based on my own experiences migrating ts-loader and the fork-ts-checker-webpack-plugin. If you'd like to see this in action then take a look at the PRs related to these. The ts-loader PR can be found here. The fork-ts-checker-webpack-plugin PR can be found here.

Plugins

One of the notable changes to webpack with v4 is the change to the plugin architecture. In terms of implications it's worth reading the comments made by Tobias Koppershere and here.

Previously, if your plugin was tapping into a compiler hook you'd write code that looked something like this:

With webpack 4 things done changed. You'd now write something like this:

Hopefully that's fairly clear; we're using the new hooks property and tapping into our event of choice by camelCasing what was previously kebab-cased. So in this case plugin('watch-close' => hooks.watchClose.tap.

In the example above we were attaching to a sync hook. Now let's look at an async hook:

This would change to be:

Note that rather than using tap here, we're using tapAsync. If you're more into promises there's a tapPromise you could use instead.

Custom Hooks

Prior to webpack 4, you could use your own custom hooks within your plugin. Usage was as simple as this:

You can still use custom hooks with webpack 4, but there's a little more ceremony involved. Essentially, you need to tell webpack up front what you're planning. Not hard, I promise you.

First of all, you'll need to add the package tapable as a dependency. Then, inside your plugin you'll need to import the type of hook that you want to use; in the case of the fork-ts-checker-webpack-plugin we used both a sync and an async hook:

Then, inside your apply method you need to register your hooks:

If you're interested in backwards compatibility then you should use the _pluginCompat to wire that in:

With your registration in place, you just need to replace your calls to compiler.applyPlugins('sync-hook-name', and compiler.applyPluginsAsync('async-hook-name', with calls to compiler.hooks.syncHookName.call( and compiler.hooks.asyncHookName.callAsync(. So to migrate our fork-ts-checker-service-before-start hook we'd write:

Loaders

Loaders are impacted by the changes to the plugin architecture. Mostly this means applying the same plugin changes as discussed above. ts-loader hooks into 2 plugin events:

With webpack 4 these become:

Note again, we're using the string "ts-loader" to identify our loader.

I need a Map

When I initially ported to webpack 4, ts-loader simply wasn't working. In the end I tied this down to problems in our watch-run callback. There's 2 things of note here.

Firstly, as per the changelog, the watch-run hook now has the Compiler as the first parameter. Previously this was a subproperty on the supplied watching parameter. So swapping over to use the compiler directly was necessary. Incidentally, ts-loader previously made use of the watching.startTime property that was supplied in webpack's 1, 2 and 3. It seems to be coping without it; so hopefully that's fine.

Secondly, with webpack 4 it's "ES2015 all the things!" That is to say, with webpack now requiring a minimum of node 6, the codebase is free to start using ES2015. So if you're a consumer of compiler.fileTimestamps (and ts-loader is) then it's time to make a change to cater for the different API that a Map offers instead of indexing into an object literal with a string key.

What this means is, code that would once have looked like this:

Now looks more like this:

Happy Porting!

I hope your own port to webpack 4 goes well. Do let me know if there's anything I've missed out / any inaccuracies etc and I'll update this guide.

Discussion in the ATmosphere

Loading comments...