saulhardman / postcss-hover-media-feature

PostCSS plugin that extracts and wraps rules containing `:hover` pseudo-classes in `@media (hover: hover) {}` media queries
MIT License
59 stars 5 forks source link

Encounter a infinite loop seems related to :not(:hover) #20

Closed lackneets closed 2 years ago

lackneets commented 2 years ago

What happened?

I found my webpack-dev-server startup hangs on with 100% cpu usage forever. To find out what happened, I modify the source code with console.log to see what's going on. As a result, It stuck on this rule, keeping looping

image

image

To reproduce this problem

image

source (stylus)

.list
  margin 0
  &__item, &__action
    padding .25rem 1rem
    margin-bottom 1rem
    border-radius 5px
    font-size 17px
  &__item
    box-shadow 0px 1px 1px 0 rgba(170, 170, 170, .2)
    border solid 1px $gray3
    background-color #ffffff
    padding 1rem
    .column
      line-height 2
    .column:first-child
      display flex !important
      line-height 2
      align-items flex-start
      > *
        vertical-align middle
      > .ui-checkbox
        align-self flex-start
        min-height 34px
        display inline-flex
        align-items center

    &:not(:hover):not(.is-editing) .show-on-hover
      visibility hidden
    &:hover
      background-color #f0f8ff
  &__action
    color $gray2
    cursor pointer
    &:hover
      background $gray3

.nav-top
  padding 21px

div.table-list
  display flex
  position relative
  flex-direction column
  justify-content flex-start
  margin 0
  .tr
    padding-left 21px
    padding-right 21px
    &.checked
      background-color #FEF9F4
  .th, .td
    padding .25rem .5rem
  .tbody
    height 100%
  /deep/ .vue-recycle-scroller__item-wrapper
    height 100%
  .tr
    display flex
    width 100%
    min-height 45px
    align-items center
    border-bottom 1px solid $gray4
  > .thead, > .tr
    margin-right 10px
    width auto
  .th
    color $gray2
    font-size 12px
  .center
    text-align center
  .right
    text-align right

.dot-status
  width 5px
  height 5px
  display inline-block
  vertical-align middle
  border-radius 50%
  background-color $gray3
  &--active
    background-color #ff895a

.auto-scroll-y
  overflow-y scroll !important
  overflow-x hidden
  max-height 100%
lackneets commented 2 years ago

My attempt

After I realized that the selector inside :not(), will be split into child selector, that won't be walked through.

Finally, after dig out selector-parser works, I rewrote the detection method. It should walk though each selector to find any one ":hover" pseudo node, instead of walk through whole selectors.

image

Tada!

image

image

image

dustinwilson commented 2 years ago

I also ran into this issue today wondering why there was an infinite loop, and sure enough it was :not(:hover) just like you discovered.

dustinwilson commented 2 years ago

Although, I think it should instead ignore :not(:hover) because in a user agent without hover support the selector would (and should) match.

saulhardman commented 2 years ago

Hey @lackneets and @dustinwilson, thanks for the detailed bug report and confirmation. I'm aiming to take a look at this now and get a release out in the next few hours. As @dustinwilson suggested; I'll change the selector processor to omit selectors where :hover is within a :not or some variation of that logic.

I'll let you know when a patch is out there ready to test 👍

saulhardman commented 2 years ago

Hello again – I've just released a patch which hopefully resolves the issue. I had to do a manual release as it looks like travis-ci.org is no longer operational. I guess that means I'll have to spend some more time migrating to GitHub Actions sometime soon.

Regarding the source of this problem: the way that selectors are identified, parsed, and rewritten definitely needs a rethink at some point, but sadly I don't have the time to dive into it right now.

Thanks again for the bug report, confirmation, and suggestion of solutions 🙏