webpack: v5 module dep invalidation not working in cases that do in v4

👋 I wasn’t sure the right format for this observation/bug report/question so gonna drop it here.

I’m the maintainer of astroturf a library that extracts inline css strings into separate files during compilation. Current (v4 and previous) we do this with a hacky but useful approach of not actually writing files to disk, instead tweaking the webpack FS object in a mixed in memory/real-fs approach. The plugin is here: https://github.com/4Catalyzer/astroturf/blob/master/src/VirtualModulePlugin.js

Please 🙏 excuse the terrible cache busting, which allows the sibling loader to bootstrap the plugin mid compilation. I know that’s terrible and can confirm that this issue still persists when the plugin is added manually via config before compilation starts.

The paired loader adds extracted files as dependencies of the processed file, so:

button.js

const styles = css`
  color: blue;
`

Produces button-styles.css and addDependency is called with the new file (added to the in memory fs). NOW in v4, when button.js changes it also invalidates button.css and both rebuild (which is desired). HOWEVER in v5 button.css never invalidates when button.js changes.

I know that this probably isn’t going to work smoothly as is, given that that one must process button.js before knowing if button.css has changed, but the v4 behavior of just always invalidating the dependent CSS files works fine for that, even if it’s a bit inefficient.

I’m wondering if this difference in behavior is expected, or even known, and if there is any place I should start looking to try and make this work in v5? I’ve already seen fileTimestamps have changed in v5 and have attempted to migrate to something similar, but it seems to work too well given the CSS files aren’t being rebuilt. Maybe i need to manually invalidate these style files when a parent changes?

(If it helps this is the unfinished and non functional spike i’ve been working on for v5 support https://github.com/4Catalyzer/astroturf/blob/webpack5/src/VirtualModulePlugin.ts)

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 56 (54 by maintainers)

Commits related to this issue

Most upvoted comments

In general virtual modules is not the way to go in webpack. If you need to transform a file in any way use a loader. Extracting a snippet from a file is also a way for transforming a file. You can also use a loader without an input file if you like to generate files out of the void (maybe from passed options).

So your loader workflow could be as following:

// button.js
const styles = css`
  color: blue;
`

Loader transformation to:

// button.js
const styles = require("./button.js.css!=!your-base64-unpack-loader?Y29sb3I6IGJsdWU7!");

./button.js.css!=! gives the resulting module a name and allows to apply test: /\.css$/ rules to them.


In webpack 5 you could even use data urls directly:

// button.js
const styles = require("data:text/css;base64,Y29sb3I6IGJsdWU7!");

and match rules to them:

module.rules: [
{
  mimetype: "text/css",
  use: ["style-loader", "css-loader"]
}
]

But note that relative urls in data uris are relative to the this.rootContext in the loader, so you might have to change references.


Otherwise the “old” approach above allows to let relative stuff works as expected by adding a resource file:

// button.js
const styles = require("./button.js.css!=!your-base64-unpack-loader?Y29sb3I6IGJsdWU7!./button.js");