FullHuman / purgecss

Remove unused CSS
https://purgecss.com
MIT License
7.79k stars 247 forks source link

CSS Modules classes removed in .vue file #52

Closed JounQin closed 6 years ago

JounQin commented 6 years ago

When reporting a bug, please be sure to include the following:

reproduce repository: https://github.com/JounQin/blog/tree/purgecss branch: purgecss reproduce step:

Add a .env.local file in project directory like following

NODE_ENV=development

APP_KEYS=APP_KEYS

GITHUB_TOKEN= # add an usable token for GitHub API

Then run yarn dev to see correct UI and run yarn build && yarn start to see generated version after purgecss enabled.

jsnanigans commented 6 years ago

Hi, I cant seem to get your project running; its loading extremely long, after 120s the GET / request timesout.

Im also not sure what the problem here is, could you give us a bit more information?

JounQin commented 6 years ago

I'm using CSS Modules in https://github.com/JounQin/blog/blob/purgecss/src/views/App.vue#L288 , and they are all been removed after purgecss enabled.

Have you added required .env.local variables? It's a SSR project, so maybe it will take a bit long time to run at the first time.

jsnanigans commented 6 years ago

Ok so the problem is that purgecss only sees span(:class="$style.brandName") in your template from which it extracts the possible class selector: brandName which does not match the selector .brand-name in your styles.

The best solution here would be a custom extractor for pug, but we didn't get to make one yet.. its on the todo. If you would like to help we would be very thankful for any contribution. https://www.purgecss.com/extractors.html

Other solutions would be to whitelist brand-name https://www.purgecss.com/whitelisting.html

Or change the naming convention, for example use $style.brand_name in pug and in your styles .brand_name

JounQin commented 6 years ago

@jsnanigans Not exactly. All classes in module style tag are removed except keyframes(.main for example) what means brand_name will not work. You can run yarn build and view app.*.css in dist/static.

jsnanigans commented 6 years ago

Ah I see, I though that was pug syntax; not vue.

I think I found the issue now. If you check here: https://vue-loader.vuejs.org/en/features/css-modules.html

console.log(this.$style.red)
    // -> "_1VyoJ-uZOjlOxP7jWUy19_0"
    // an identifier generated based on filename and className.

the class name that ends up in the html is random, I have also tried this in my own vue project and found this to be true.. so lets say you use :class="$style.red" in your template, you will end up with something like this: class="_280xmiVrPlYKraZZBRvQvC_1". Purgecss cannot know of that classname before vue has been compiled so there is no way to fix this at the moment.. sorry.

If it works for you you could use <style lang="scss" scoped> instead of <style lang="scss" module> and just add the class normally, I think the result is more-or-less the same but purgecss will be able to find the classnames

Ps. I am working on a similar kind of project at the moment and have used purgecss not in the build process but on the live server. css is purged for every site individually on request and then just put into the html "inline", with some clever caching this also does not slow down your site.

JounQin commented 6 years ago

@jsnanigans I know classes with be compiled into hash string after building, so I title this issue CSS Modules classes are removed.

And after reading purifycss-webpack's suggestion about CSS Modules, I find out that I can simply set localIdentName to prefix with _ and add whitelistPatterns: [/^_/] option (I was thinking whitelist and whitelistPatterns are matching source classnames 😂) and it works.

Util a better solution to deal with CSS Modules, it can be documented as a workaround like purifycss-webpack.

jsnanigans commented 6 years ago

Great! We need some documentation on how to use purgecss with vue, when we get to that ill make sure that this is mentioned. Maybe we can use the algorithm in the vue source to predict the classname, but that will be a task for the purge-from-vue extractor.

Thank you for reporting and the workaround!

JounQin commented 6 years ago

@jsnanigans Is that related to Vue only? CSS Modules can be used with any other frameworks, right?

Doogiemuc commented 3 years ago

Just would like to add this reference. Therre is a more general RegEx pattern for whitelisting vue's scoped css:

https://github.com/FullHuman/purgecss/issues/361 mentions:

whitelistPatterns: [ /data-v-.*/ ],

According to the most current PurgecssPlugin documentation this should actually be:

new PurgecssPlugin({
  safelist: { greedy: [ /data-v-.*/ ]   }
}),