Provide a hook to replace module sources after visiting all sources
See original GitHub issueFeature request
Provide a means to replace the (complete or partial) sources of a module after all sources are visited/loaders have processed all files, but before the bundling/optimization phase.
What is the expected behavior?
There should be a hook plugin developers can tap into in order to replace the sources of a module after the registered loaders have processed all files.
What is motivation or use case for adding/changing the behavior?
We are trying to make a JavaScript optimization tool available as a webpack plugin. After browsing the sources of both webpack itself and a lot of existing webpack plugins and loaders, and after a lot of trial and error, we have the impression that our tool’s requirements are impossible to fit into webpack’s plugin architecture:
- We need to analyze the JavaScript sources of each file after e.g. TypeScript compilation (ts-loader), but before any other optimization tools like terser, and before webpack replacements like
new Foo() --> new moduleName['exportName']()
) - We need to adjust these sources in that same unoptimized state, but we can only start adjusting after we have seen all sources.
One possible approach we thought of was to run the analysis in a custom loader that is added by the plugin, and use the gathered information in a hook later on (e.g. seal
), where all module sources are available. However, we have not been able to replace the module sources in any of the hooks we tried.
How should this be implemented in your opinion?
Maybe by introducing an additional hook between loading and bundling/optimizing, or by modifying the seal
hook to allow the replacement of the module sources.
Are you willing to work on this yourself? yes, if a webpack dev could provide a rough concept/hints for the implementation.
It might of course be possible that there already is a way to implement this kind of plugin functionality using the existing plugin API that we just could not figure out yet. I already asked for help on this topic on stackoverflow, which earned me the tumbleweed badge 😃
Issue Analytics
- State:
- Created 5 years ago
- Reactions:3
- Comments:5 (3 by maintainers)
For anyone else who comes across this issue after going down a rabbit hole (which I think is the only way you will find this issue)…
My use case:
optimizeModules
) worked but resulted in the same cache buster if translations changed. Additionally, I had to handle double encoding from various sourcemap options manually.I found this issue most helpful to help me reduce requests + still have cachebusting work, etc.
Per @sokra suggestion above, plus this implementation I found as a reference guideline…
this._module
andthis._compilation
compilation.hooks.finishModules.tapAsync(
, do whatever async work you need to do. Attach data back tomodule
. Rebuild necessary modules.I tried a bunch of things, and this seems like simplest approach.
One issue is that changing the source code could affect the module graph. You could add new dependencies, etc.
Anyway there is a way to achieve what you want to do. You need a combination of loader and plugin. The loader should do nothing without whole compilation information available. In the first step do the normal compilation until a hook like seal or optimizeModule. Here you have all information available from all modules. Now trigger a rebuild for all modules that should be changed (or for all) with
compilation.rebuildModule
. This will invoke the loader again and it has now whole compilation information available it can do additional optimizations. But you will be unable to do major changes to the module graph. You are not allowed to add new dependencies, but it’s possible to remove dependencies.