FullHuman / purgecss

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

Can't handle attribute pattern selector #303

Closed bangzek closed 3 years ago

bangzek commented 4 years ago

purgecss doesn't understand attribute pattern selector like this one from bootstrap 4:

.form-row > [class*="col-"]

emilio-martinez commented 4 years ago

I ran into this issue as well—not within bootstrap, but I did notice attribute selectors being stripped.

Jon-Salmon commented 4 years ago

I am also experiencing this, but only when using a custom defaultExtractor

Ffloriel commented 4 years ago

do you have an example to reproduce the issue?

jayvanhu commented 4 years ago

@Ffloriel I'm not the original poster, but this other issue seems to be the same bug with a config for reproducing the issue

divinerites commented 3 years ago

I can confirm that I face the same issue. (Using Tailwind/PurgeCSS in Hugo). The [class^="tf-"], [class*=" tf-"] is removed from the css, while (for example) the used tf-ion-ios-telephone is well taken care of.

Really related to https://github.com/FullHuman/purgecss/issues/475

[class^="tf-"], [class*=" tf-"] {
  /* use !important to prevent issues with browser extensions that change fonts */
  font-family: 'themefisher-font' !important;
  speak: none;
  font-style: normal;
  font-weight: normal;
  font-variant: normal;
  text-transform: none;
  line-height: 1;

  /* Better Font Rendering =========== */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
const theme = require('tailwindcss/defaultTheme');
const typography = require('@tailwindcss/typography');

//const colorBrand = 'var(--color-pretty)';

// Utils
const round = (num) => num.toFixed(7).replace(/(\.[0-9]+?)0+$/, '$1').replace(/\.0$/, '');
const rem = (px) => `${round(px / 16)}rem`;
const em = (px, base) => `${round(px / base)}em`;
const px = (px) => `${px}px`;

module.exports = {
    important: true, // See https://tailwindcss.com/docs/configuration#important
    experimental: {
        // See https://github.com/tailwindlabs/tailwindcss/pull/2159
        applyComplexClasses: true
    },
    purge: {
        enabled: process.env.HUGO_ENVIRONMENT === 'production',
        content: [ './hugo_stats.json' ],
        mode: 'all',
        options: {
            //whitelist: [ 'pl-1', 'pl-3' ],
            defaultExtractor: (content) => {
                let els = JSON.parse(content).htmlElements;
                els = els.tags.concat(els.classes, els.ids);
                return els;
            }
        }
    },
    plugins: [ typography ]
};
xorock commented 3 years ago

I've also experienced this bug (using laravel-mix-purgecss + tailwind).

/* purgecss start ignore */
    input[type="submit"] {  /* this simple rule is ignored */
        color: red;
    }
    /*! purgecss end ignore */

But what's weird here, if I add "purgecss start/end ignore" comments, the resulting file size suddenly grows from 7kB to 1.48MB.

lubomirblazekcz commented 3 years ago

I have similiar problem when [href^="tel:"] is being removed , or ::-ms-input-placeholder

one of the reasons I am still not migrating from 1.x.x version..

kien5436 commented 3 years ago

Same problem. Here's my reproduction: https://github.com/shhlkien/purgecss-bug @Ffloriel @divinerites

Ffloriel commented 3 years ago

@shhlkien Thanks a lot for the repro repository! Attributes are treated separately between name and value.
You would need to safelist the name of the attribute: class and the value: icon-

Which in your example will be:

safelist: ['icon', 'class', ' icon-'],
kien5436 commented 3 years ago

@Ffloriel That worked but I wish we could have option for attributes because they maybe very complex. I.e, if I have

[class^="icon-"] {}
[class^="unused"] {}

then "unused" class won't be removed. There're many more cases.

Ffloriel commented 3 years ago

In which situation do you have CSS rules being wrongfully removed? Attribute pattern selector should be correctly handled by PurgeCSS. So if you do have something like

<div class="icon-blue"></div>

in your code, it will keep [class^="icon-"]

lubomirblazekcz commented 3 years ago

[class^="icon-"] works but [class="icon-"] gets deleted by PurgeCSS. In my case all attribute selectors are incorrectly removed. That did not happen in 1.x.x versions

Ffloriel commented 3 years ago

@evromalarkey [class*="icon-"] is working as expected on my side. Do you have a repo that reproduces your issue?

kien5436 commented 3 years ago

@Ffloriel I think attributes should be treated as one element instead of separate. For example:

Html
<i class="icon-blue"></i>
Css
[class^="icon-"] {}
[class^="unused-"] {}
Js
...
safelist: ['class', 'icon-'],
// try this but not work
// blocklist: ['class', 'unused-']

Then both classes will be keep though I need "icon-" only. So, if we can define them

safelist: ['class^="icon-"'] // or use regex

Then the result will be as expected.

@evromalarkey the solution works in my case

lubomirblazekcz commented 3 years ago

@Ffloriel here is the repo https://github.com/evromalarkey/purgecss-attribute-bug

[class=" col"] gets removed, but [class="col"] works correctly. I think that is the main issue here. [class^="col"] works also correctly.

The next issue, not related to attributes is ::-ms-input-placeholder being removed, but that's not such a big deal.

Ffloriel commented 3 years ago

@evromalarkey ah I see, it's this issue then: https://github.com/FullHuman/purgecss/issues/392. I'll look into it.

kb-coder commented 3 years ago

Is there an ETA on the fix for this? I am running into this issue when there is a space: [class*=" col"]

Ffloriel commented 3 years ago

v4.0.2 contains a fix to handle attribute selectors with spaces. Let me know if you are experiencing any issues.