Skip to content
This repository was archived by the owner on Apr 6, 2021. It is now read-only.

Bust persistent cache (webpack 5) on module load #6

Merged
merged 1 commit into from
Mar 3, 2021

Conversation

bradlc
Copy link
Contributor

@bradlc bradlc commented Mar 3, 2021

Edit: 2 seconds after opening this I realised there's already a PR for this 🤦

webpack 5 has a persistent cache option. This stores cache on the filesystem so that it can be reused across builds. Our current implementation has an issue with stale CSS when this option is enabled.

How to reproduce the issue in a Next.js app:

  1. Set future.webpack5 to true in next.config.js:
module.exports = {
  future: { webpack5: true },
}
  1. Delete the .next directory if it exists
  2. npm run dev
  3. We register a touch file as a dependency of our CSS build. This touch file has a random filename.
  4. Close the dev server (i.e. ctrl + c)
  5. npm run dev
  6. At this point webpack checks whether the dependencies have changed. Our config and touch file have not changed so the CSS from the previous dev process is reused (our module is loaded but the PostCSS plugin function does not run). The CSS is now stale. Any changes made to template files since closing the first dev server will not be reflected in the CSS output.
  7. Any further changes to templates will continue to be ignored because the original touch file will remain untouched going forward (it has a random file name and we no longer know what it is)

Solution

This PR proposes a solution to this problem:

  • All touch files are stored in a common directory: path.join(os.homedir() || os.tmpdir(), '.tailwindcss', 'touch')
  • Because we know where all of the touch files are we can invalidate the cache on module load by deleting them all. This solves the problem of not knowing our previous touch file name: we don't know which file it is exactly but we know which directory it's in.

Why os.homedir()?

The home directory seems like a more stable place to put the touch files. I don't fully understand tmp directories or when and why they change. My concern would be that os.tmpdir() starts returning a different directory name but the previous one still exists.

In terms of whether this is acceptable to do, my home directory looks like this:

image

I looked at the source code for degit and it uses the home-or-tmp module to pick a folder (the module is literally module.exports = os.homedir() || os.tmpdir())

this has the effect of invalidating any caches associated with these files
@thecrypticace
Copy link
Collaborator

I think this is the better approach! It would completely negate the need to register any "purgable" file as a dependency (though I don't think the perf impact is significant in doing so). It didn't even dawn on me that the module still gets loaded so you can clear out the touch files then.

My concern would be that os.tmpdir() starts returning a different directory name but the previous one still exists.

This will happen on macOS. The temp folder given to a process may not be the same across reboots. And I think it can even change across process invocations though I'm not 100% sure about this.

Something I'm thinking about though is if you happen to have multiple tailwind builds running at once in parallel (from separate processes for example). The touch file for a running build could get removed. Does postcss / webpack handle the removal and re-addition of a registered dependency properly? I believe it does but it would be good to verify.

@adamwathan adamwathan merged commit 72fb1e0 into master Mar 3, 2021
@adamwathan adamwathan deleted the bust-persistent-cache branch March 15, 2021 16:46
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants