vue-windicss-preprocess
vue-windicss-preprocess copied to clipboard
Gridsome: dynamic class bindings not working [Purging issue]
Describe the problem
In Gridsome, the following code is not working as expected (where isFalse equals false):
<h2
class="mb-2 text-4xl font-medium"
:class="[isFalse ? 'text-gray-50' : 'text-gray-700']"
>
You'd expect text-gray-700 to be applied in this case, however, the element just inherits the parent text color without applying the class. I tried in both compiled and interpreted modes with rebuilding the app and clearing browser cache but was met with unstable behavior where about 1 in 10 times the dynamic class would be applied.
How I've installed WindiCSS
// gridsome.config.js
...
configureWebpack: (config) => {
config.module.rules.push({
test: /\.vue$/,
use: [
{
loader: 'vue-windicss-preprocess',
options: {
config: 'tailwind.config.js', // tailwind config file path OR config object (optional)
compile: true, // false: interpretation mode; true: compilation mode
globalPreflight: true, // set preflight style is global or scoped
globalUtility: true, // set utility style is global or scoped
prefix: 'windi-', // set compilation mode style prefix
},
},
],
});
},
...
Browser: Brave - Version 1.20.103 Chromium: 88.0.4324.152 (Official Build) (64-bit)
Semi-workaround
~~Using vue-windicss-preprocess in combination with gridsome-plugin-tailwindcss makes dynamic class bindings work just fine. I haven't found any issues with that setup besides when trying to use the windi/plugins, which spits out a bunch of errors where it's searching for functions in tailwind and PostCSS instead of Windi CSS, leading to the app not building.~~
UPDATE: trying to reproduce this from scratch, the gridsome-plugin-tailwindcss now isn't working alongside Windi as a workaround
Diving deeper, I'm pretty sure this is a class purging problem. If you have compile: false and a certain class is declared only once in your app, in the dynamic class binding, it gets incorrectly purged from the build when it should be included. If you use a class in a dynamic binding and that class has been declared elsewhere in the regular class attribute, then it works. But for example, if the only time text-gray-700 is declared in your app is in that dynamic class binding, it gets purged. If compile: true, it doesn't matter if you have the class declared elsewhere, it gets purged 100% of the time.
I encountered a similar issue when configuring Tailwind for Sapper a while back and adding this defaultExtractor to the purge options of the Tailwind config was the solution:
// considers dynamic class bindings when purging unused classes
// credit: https://github.com/matebek https://dev.to/matebek
defaultExtractor: (content) => [
...(content.match(/[^<>"'`\s]*[^<>"'`\s:]/g) || []),
...(content.match(/(?<=class:)[^=>\/\s]*/g) || []),
],
@voorjaar I'd be happy to help in any way I can. Could you point me in the direction of where I should look at applying something similar to that defaultExtractor under the hood?
Diving deeper, I'm pretty sure this is a class purging problem. If you have
compile: falseand a certain class is declared only once in your app, in the dynamic class binding, it gets incorrectly purged from the build when it should be included. If you use a class in a dynamic binding and that class has been declared elsewhere in the regular class attribute, then it works. But for example, if the only timetext-gray-700is declared in your app is in that dynamic class binding, it gets purged. Ifcompile: true, it doesn't matter if you have the class declared elsewhere, it gets purged 100% of the time.I encountered a similar issue when configuring Tailwind for Sapper a while back and adding this
defaultExtractorto the purge options of the Tailwind config was the solution:// considers dynamic class bindings when purging unused classes // credit: https://github.com/matebek https://dev.to/matebek defaultExtractor: (content) => [ ...(content.match(/[^<>"'`\s]*[^<>"'`\s:]/g) || []), ...(content.match(/(?<=class:)[^=>\/\s]*/g) || []), ],@voorjaar I'd be happy to help in any way I can. Could you point me in the direction of where I should look at applying something similar to that defaultExtractor under the hood?
I think this method is not what I want. We have an htmlparser for parsing vue's grammar, and currently the directive is not supported. Add some directive support, it should be fine.