New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Bugfix/separate selectors #1253
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,10 +3,16 @@ let Prefixer = require('./prefixer') | |
let Browsers = require('./browsers') | ||
let utils = require('./utils') | ||
|
||
const SELECTORS_CACHE = {} | ||
|
||
class Selector extends Prefixer { | ||
constructor (name, prefixes, all) { | ||
super(name, prefixes, all) | ||
this.regexpCache = {} | ||
SELECTORS_CACHE[name] = { | ||
possible: this.possible(), | ||
replace: this.replace.bind(this) | ||
} | ||
} | ||
|
||
/** | ||
|
@@ -57,8 +63,29 @@ class Selector extends Prefixer { | |
} | ||
|
||
let prefixeds = {} | ||
for (let prefix of this.possible()) { | ||
prefixeds[prefix] = this.replace(rule.selector, prefix) | ||
|
||
if (rule.selector.includes(',')) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I completely lost the idea behind this method (but I wrote it 😭). Can you describe (you can do it in Russian) what do we do here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll try to do it in english 🤞 This method collects all possible prefixes for the selector, creates prefixed version of the Rule {
type: 'rule',
selector: '.a, .a .b::placeholder, a:read-only',
// lots of properties
_autoprefixerPrefixeds: {
'-webkit-': '.a, .a .b::-webkit-input-placeholder, a:read-only',
'-moz-': '.a, .a .b::-moz-placeholder, a:read-only',
'-ms-': '.a, .a .b::-ms-input-placeholder, a:read-only',
'-o-': '.a, .a .b::-o-placeholder, a:read-only',
'-moz- old': '.a, .a .b:-moz-placeholder, a:read-only',
'-ms- old': '.a, .a .b:-ms-input-placeholder, a:read-only' }
}
} As you can see There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I refactored code, and I think now it's much more easier to reason about. Plus, I decided that each selector has to process only that part of rule that contains the selector and not the whole rule as I did before. |
||
let toProcess = rule.selector | ||
.split(',') | ||
.filter(el => el.includes(':')) | ||
.map(el => el.trim()) | ||
|
||
Object.keys(SELECTORS_CACHE).forEach(name => { | ||
let selector = toProcess.find(el => el.includes(name)) | ||
if (selector) { | ||
prefixeds[name] = {} | ||
SELECTORS_CACHE[name].possible.forEach(prefix => { | ||
prefixeds[name][prefix] = SELECTORS_CACHE[name].replace( | ||
selector, prefix) | ||
}) | ||
} | ||
}) | ||
} else { | ||
prefixeds[this.name] = {} | ||
|
||
for (let prefix of this.possible()) { | ||
prefixeds[this.name][prefix] = this.replace(rule.selector, prefix) | ||
} | ||
} | ||
|
||
rule._autoprefixerPrefixeds = prefixeds | ||
|
@@ -79,8 +106,8 @@ class Selector extends Prefixer { | |
} | ||
|
||
let some = false | ||
for (let key in prefixeds) { | ||
let prefixed = prefixeds[key] | ||
for (let key in prefixeds[this.name]) { | ||
let prefixed = prefixeds[this.name][key] | ||
if (before.selector === prefixed) { | ||
if (prefix === key) { | ||
return true | ||
|
@@ -117,7 +144,7 @@ class Selector extends Prefixer { | |
return | ||
} | ||
|
||
let cloned = this.clone(rule, { selector: prefixeds[prefix] }) | ||
let cloned = this.clone(rule, { selector: prefixeds[this.name][prefix] }) | ||
rule.parent.insertBefore(rule, cloned) | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
.grid { | ||
display: grid; | ||
} | ||
|
||
.a, | ||
.b, | ||
.c::selection, | ||
.d:read-only, | ||
.e::placeholder { | ||
color: yellow; | ||
} | ||
|
||
::selection { | ||
color: red; | ||
} | ||
|
||
:read-only { | ||
color: black; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
.grid { | ||
display: -ms-grid; | ||
display: grid; | ||
} | ||
|
||
.c::-moz-selection { | ||
color: yellow; | ||
} | ||
|
||
.e::-webkit-input-placeholder { | ||
color: yellow; | ||
} | ||
|
||
.e:-moz-placeholder { | ||
color: yellow; | ||
} | ||
|
||
.e::-moz-placeholder { | ||
color: yellow; | ||
} | ||
|
||
.e:-ms-input-placeholder { | ||
color: yellow; | ||
} | ||
|
||
.e::-ms-input-placeholder { | ||
color: yellow; | ||
} | ||
|
||
.d:-moz-read-only { | ||
color: yellow; | ||
} | ||
|
||
.a, | ||
.b, | ||
.c::selection, | ||
.d:read-only, | ||
.e::placeholder { | ||
color: yellow; | ||
} | ||
|
||
::-moz-selection { | ||
color: red; | ||
} | ||
|
||
::selection { | ||
color: red; | ||
} | ||
|
||
:-moz-read-only { | ||
color: black; | ||
} | ||
|
||
:read-only { | ||
color: black; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How we will lean this cache? Will we have a problem if PostCSS will process many very different files (or even different versions of the same files) during the same Node.js session (so the cache will be alive?)
If you want a per-document cache, you can use
node.root().autoprefixerSelectors
cache. It will be attached only for the same CSS root.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, that's a really good question. I need to say I didn't even thought about such cases. I'll try to check them asap. Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't tested it yet. I just thought that
SELECTORS_CACHE
is filled with data during the file/files preprocessing. So probably it should work fine with multiple files. But I'm not 100% sure. By the way the namingSELECTORS_CACHE
is kinda misleading. It's not a cache, it's just a collection.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we replace it to
this.selectors
since we use only instance methods and data there?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, it wouldn't work in such implementation. The idea with this global const is to keep all possible selectors with all relevant prefixes. And with
this.selectors
we only get relevant selectors forthis.name
. But rule might contain several selectors.I like your propose about using
node.root().autoprefixerSelectors
. I haven't checked it yet and actually I don't know how it works but may be It could help to get rid ofSELECTORS_CACHE
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can try to do so. My concern is that
replace
method uses the instance methodthis.prefixed(prefix)
inside. But hacks::placeholder
and:fullscreen
are overriding it. The::placeholder
also overridesthis.possible()
method.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it really rely on instance, you can't detouch it from this instance.
Don't forget that PostCSS can be called on many different CSS files.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's make sense.
I'll try to implement your idea.
Can it process different files with different browser settings?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeap. The same instance can be used for different target browsers or different whitespace settings.
It will be safer just to think that every PostCSS call must be independent from each other.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know what was I thinking when I decided to use global
const SELECTORS_CACHE
. Each instance of classSelector
gets propertyall
on its init. Andall
is just thePrefixes
instance that already contains all the data we need to process grouping rules 😄