This repository was archived by the owner on Apr 6, 2021. It is now read-only.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR reintroduces some previously removed code necessary for reusing contexts in environments where you are processing many inputs with the same Tailwind config (for example a Vue app where you have lots of Vue components with
<style>
blocks).Since build tools run PostCSS in isolation for each input, if we only track contexts by the
sourcePath
, every single Vue file would get its own context (including its own chokidar watchers, and copy of the class cache, etc.). This leads to lots of wasted memory and CPU.Figuring out exactly when it is safe to reuse a context and when it is not is sort of tricky and I'm not fully confident we've worked out all the quirks here but in my testing it seems reliable.
The general idea is that we track contexts by their source path, but we also track them by a hash of the Tailwind config file. If we don't find a matching context for the source path, we look to see if we already have a context matching the config hash. If we do, we use that context for this source path, and update all relevant maps.
If we don't find a cached version we can use, but the context map does have something for the current sourcePath, we need to clean that up. We fetch the old context, then we remove the current sourcePath from a set that's storing all source paths using that context, and if after removing our source the set is empty, we know we need to GC the context, so we delete all references to it and clean up its watchers.
The big breakthrough for solving this was realizing that we don't need to invalidate a context even if the CSS file has changed as long as the CSS file contains no
@tailwind
rules. Prior to this things were broken af because we were considering all CSS file changes to be triggers for invalidating the context. The thinking here was that because CSS files contribute to the config, changing a CSS file was essentially changing the config. This is only true though for@layer
rules, because@layer
rules are converted into plugins when the context is initialized. Now since@layer
rules only have any impact in files that have@tailwind
rules, we can safely reuse the context for any file that doesn't contain@tailwind
.What should we do if two files contain
@tailwind
rules but otherwise try to share the same context? I don't know, likely error. One solution is to not process@layer
rules at init time and instead always process them at run time, then the CSS file would never be a context dependency. This would be slightly slower though since we can't cache the work, which is annoying. It would also introduce complexity in code paths like processing@apply
because that would need to check two possible locations for matches. Also complicates how we handle sorting since we can't calculate the bit offset as easily (may need to switch to fixed reserved bit system if we did that).Either way this is working for any practical situation I can imagine currently. We'll let users find out where it's broken if there are situations I haven't thought to try.