question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Using compilation.rebuildModule() on compiler.hooks.emit strange behaviour

See original GitHub issue

Hi everyone!

I just wanted to check if the following is a normal behaviour or something else.

While writing a plugin, I’ve tapped into compiler.hooks.emit and managed to collect an object with information about emitted assets (essentially paths and sizes).

Then my intention was to load that object into an existing module.

I’ve managed to get the target module by looping through compilation.modules and to modify a specific loader option to create a reference to my collected object (to be inserted).

Finally I’ve tried to call compilation.rebuildModule(). Loader is successfully called, no errors, no warnings and I think the module is successfully rebuilt including the new data, but final asset (the chunk containing the module) is not updated.

I’ve read almost every file of Webpack’s source code and it is still not clear for me how to correctly trigger a module rebuild. Is it even possible? Could be a feature request? Am I too late in the compilation process to do what I wanted?

I’ve temporarily solved this by storing the collected data in a json file and then starting again a new compilation that will load it, but it is obviously not an elegant solution.

I’m already working on some documentation improvements to contribute, based on what I’ve learned studying Webpack and I would not mind to add some information about this issue if resolved.

Thank you very much for your help.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:10 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
ernestostifanocommented, Apr 13, 2020

@Krutsch that is because at done, everything has been… “done”, the only pending task at that point is to call the final callback. So, stats has already been created. That is why, in the compiler.compile() callback I had to repeat all the operations that Webpack normally does after that call. (Basically call some hooks, handle responses and update stats).

If you want to temporarily fix your issue, you have to to the following:

In the done hook, you will receive the generated stats instance object as argument. You can’t return a different stat object, but you can leverage on references and modify the passed one.

Create the updated stats passing the latest compilation:

const {Stats} = require('webpack');

function getNewStats(compilation, compilationStartingTime) {
    const stats = compilation ? new Stats(compilation) : null;
    if (stats) {
        stats.startTime = compilationStartingTime;
        stats.endTime = Date.now();
    }
    return (stats);
}

And then update existing stats using new one:

function updateStats(existingStats, newStats) {
    for (const i in newStats) {
        if (!newStats.hasOwnProperty(i)) {
            continue;
        }
        existingStats[i] = newStats[i];
    }
}

That’s it…

1reaction
ernestostifanocommented, Apr 13, 2020

@Krutsch what do you mean with “no console output”?

By further analysing Webpack’s source code, I’ve found that to make sure that changes in files are taken into account, you have to purge the internal filesystem by calling compiler.purgeInputFileSystem() or compiler.inputFileSystem.purge(filePath), the latest accepts an argument which is the path of to file that you want to remove from the internal filesystem cache (otherwise, all files will be removed from the cache, thus impacting performance).

Additionally, to make sure that the intended module is rebuilt during successive compilations, you have to update the corresponding file change timestamp (as Watcher does when in watch mode) compiler.fileTimestamps.set(filePath, Date.now()). (Module last build timestamp will be compared with the file change timestamp to determine if the module needs to be rebuilt) (Maybe @sokra can confirm this).

At the end I was able to fully solve this “issue” by writing a plugin that triggers the second compilation by calling compiler.compile() and replicates normal Webpack behaviour in the passed callback. Additionally I discovered a way to “freeze” every plugin after shouldEmit hook while the second compilation completes and then resumes from where the process was left, so for other plugins it is like if nothing happened. Obviously stats are updated each time.

I will publish that plugin as recompile-webpack-plugin once I finish testing and adjusting minor details for production. Then I will close this.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Compiler Hooks | webpack
The Compiler module is the main engine that creates a compilation instance with all the options passed through the CLI or Node API....
Read more >
How to retrieve, delete, and emit assets in a webpack 5 plugin?
Trying this, I got something similar to what you want to do to work with compiler.hooks.compilation.tap('DeclarationPlugin', (compilation) ...
Read more >
Building your own Webpack Plugin - DEV Community ‍ ‍
I will be taking a simple example of a plugin which takes few arguments and prints them when webpack's lifecycle hooks are emitted....
Read more >
Creating a Custom webpack Plugin - DigitalOcean
We're going to use the compiler.hooks.done hook which is emitted when the compilation work is done and the bundled file is generated. We...
Read more >
Learn Plugin Instance Hooks – Webpack Plugins System
[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...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found