Tobias Koppers has written a migration guide for plugins / loaders as well - take a read here. It's very useful.
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.
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.
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.applyPluginsAsync('async-hook-name', with calls to
compiler.hooks.asyncHookName.callAsync(. So to migrate our
fork-ts-checker-service-before-start hook we'd write:
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
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
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
What this means is, code that would once have looked like this:
Now looks more like this:
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.