Skip to content

Commit 47daec4

Browse files
authored
Delete rule perf (#1424)
* Update changelog.md * impove deleteRule performance * add changelog
1 parent cf1b714 commit 47daec4

5 files changed

Lines changed: 63 additions & 32 deletions

File tree

changelog.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@ Since you are interested in what happens next, in case, you work for a for-profi
77
- [jss] Restores TypeScript support for Observable styles [1402](https://github.com/cssinjs/jss/pull/1402)
88
- [jss-plugin-default-unit] Fix missing default unit for 0ms and 0% [1413](https://github.com/cssinjs/jss/pull/1413)
99

10+
### Improvements
11+
12+
- [*] Improved docs [1384](https://github.com/cssinjs/jss/pull/1384), [1387](https://github.com/cssinjs/jss/pull/1387), [1391](https://github.com/cssinjs/jss/pull/1391),
13+
- [*] Remove test files from the package [1406](https://github.com/cssinjs/jss/pull/1406)
14+
- [jss-plugin-default-unit] aAdd gap unit [1403](https://github.com/cssinjs/jss/pull/1403)
15+
- [jss-plugin-default-unit] Add default units to logical properties [1415](https://github.com/cssinjs/jss/pull/1415)
16+
- [jss] Improve deleteRule() performance [1424](https://github.com/cssinjs/jss/pull/1424)
17+
1018
---
1119

1220
## 10.4.0 (2020-8-14)

packages/jss/.size-snapshot.json

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,30 @@
11
{
22
"dist/jss.js": {
3-
"bundled": 61966,
4-
"minified": 22868,
5-
"gzipped": 6898
3+
"bundled": 62568,
4+
"minified": 22988,
5+
"gzipped": 6925
66
},
77
"dist/jss.min.js": {
8-
"bundled": 60569,
9-
"minified": 22100,
10-
"gzipped": 6545
8+
"bundled": 61171,
9+
"minified": 22220,
10+
"gzipped": 6572
1111
},
1212
"dist/jss.cjs.js": {
13-
"bundled": 56677,
14-
"minified": 24785,
15-
"gzipped": 6896
13+
"bundled": 57259,
14+
"minified": 24977,
15+
"gzipped": 6934
1616
},
1717
"dist/jss.esm.js": {
18-
"bundled": 56145,
19-
"minified": 24350,
20-
"gzipped": 6805,
18+
"bundled": 56727,
19+
"minified": 24542,
20+
"gzipped": 6843,
2121
"treeshaked": {
2222
"rollup": {
23-
"code": 20081,
23+
"code": 20201,
2424
"import_statements": 345
2525
},
2626
"webpack": {
27-
"code": 21562
27+
"code": 21682
2828
}
2929
}
3030
}

packages/jss/src/DomRenderer.js

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -260,15 +260,8 @@ const getNonce = memoize(
260260
const insertRule = (
261261
container: CSSStyleSheet | CSSMediaRule | CSSKeyframesRule,
262262
rule: string,
263-
index?: number
263+
index: number
264264
): false | any => {
265-
const maxIndex = container.cssRules.length
266-
// In case previous insertion fails, passed index might be wrong
267-
if (index === undefined || index > maxIndex) {
268-
// eslint-disable-next-line no-param-reassign
269-
index = maxIndex
270-
}
271-
272265
try {
273266
if ('insertRule' in container) {
274267
const c = ((container: any): CSSStyleSheet)
@@ -286,6 +279,19 @@ const insertRule = (
286279
return container.cssRules[index]
287280
}
288281

282+
const getValidRuleInsertionIndex = (
283+
container: CSSStyleSheet | CSSMediaRule | CSSKeyframesRule,
284+
index?: number
285+
): number => {
286+
const maxIndex = container.cssRules.length
287+
// In case previous insertion fails, passed index might be wrong
288+
if (index === undefined || index > maxIndex) {
289+
// eslint-disable-next-line no-param-reassign
290+
return maxIndex
291+
}
292+
return index
293+
}
294+
289295
const createStyle = (): HTMLElement => {
290296
const el = document.createElement('style')
291297
// Without it, IE will have a broken source order specificity if we
@@ -311,6 +317,10 @@ export default class DomRenderer {
311317

312318
hasInsertedRules: boolean = false
313319

320+
// Will be empty if link: true option is not set, because
321+
// it is only for use together with insertRule API.
322+
cssRules: AnyCSSRule[] = []
323+
314324
constructor(sheet?: StyleSheet) {
315325
// There is no sheet when the renderer is used from a standalone StyleRule.
316326
if (sheet) sheets.add(sheet)
@@ -386,8 +396,13 @@ export default class DomRenderer {
386396
const parent: ContainerRule = (rule: any)
387397
let latestNativeParent = nativeParent
388398
if (rule.type === 'conditional' || rule.type === 'keyframes') {
399+
const insertionIndex = getValidRuleInsertionIndex(nativeParent, index)
389400
// We need to render the container without children first.
390-
latestNativeParent = insertRule(nativeParent, parent.toString({children: false}), index)
401+
latestNativeParent = insertRule(
402+
nativeParent,
403+
parent.toString({children: false}),
404+
insertionIndex
405+
)
391406
if (latestNativeParent === false) {
392407
return false
393408
}
@@ -407,13 +422,15 @@ export default class DomRenderer {
407422

408423
if (!ruleStr) return false
409424

410-
const nativeRule = insertRule(nativeParent, ruleStr, index)
425+
const insertionIndex = getValidRuleInsertionIndex(nativeParent, index)
426+
const nativeRule = insertRule(nativeParent, ruleStr, insertionIndex)
411427
if (nativeRule === false) {
412428
return false
413429
}
414430

415431
this.hasInsertedRules = true
416432
rule.renderable = nativeRule
433+
this.cssRules[insertionIndex] = nativeRule
417434
return nativeRule
418435
}
419436

@@ -425,18 +442,15 @@ export default class DomRenderer {
425442
const index = this.indexOf(cssRule)
426443
if (index === -1) return false
427444
sheet.deleteRule(index)
445+
this.cssRules.splice(index, 1)
428446
return true
429447
}
430448

431449
/**
432450
* Get index of a CSS Rule.
433451
*/
434452
indexOf(cssRule: AnyCSSRule): number {
435-
const {cssRules} = this.element.sheet
436-
for (let index = 0; index < cssRules.length; index++) {
437-
if (cssRule === cssRules[index]) return index
438-
}
439-
return -1
453+
return this.cssRules.indexOf(cssRule)
440454
}
441455

442456
/**
@@ -448,6 +462,7 @@ export default class DomRenderer {
448462
const index = this.indexOf(cssRule)
449463
if (index === -1) return false
450464
this.element.sheet.deleteRule(index)
465+
this.cssRules.splice(index, 1)
451466
return this.insertRule(rule, index)
452467
}
453468

packages/jss/src/StyleSheet.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,14 @@ export default class StyleSheet {
154154
deleteRule(name: string | Rule): boolean {
155155
const rule = typeof name === 'object' ? name : this.rules.get(name)
156156

157-
if (!rule) return false
157+
if (
158+
!rule ||
159+
// Style sheet was created without link: true and attached, in this case we
160+
// won't be able to remove the CSS rule from the DOM.
161+
(this.attached && !rule.renderable)
162+
) {
163+
return false
164+
}
158165

159166
this.rules.remove(rule)
160167

packages/jss/tests/functional/sheet.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -405,10 +405,11 @@ describe('Functional: sheet', () => {
405405
describe('.deleteRule()', () => {
406406
it('should delete a rule from the sheet and DOM', () => {
407407
const sheet = jss.createStyleSheet({a: {width: '1px'}}, {link: true}).attach()
408-
expect(computeStyle(sheet.classes.a).width).to.be('1px')
408+
const className = sheet.classes.a
409+
expect(computeStyle(className).width).to.be('1px')
409410
expect(sheet.deleteRule('a')).to.be(true)
410411
expect(sheet.getRule('a')).to.be(undefined)
411-
expect(computeStyle(sheet.classes.a).width).not.to.be('1px')
412+
expect(computeStyle(className).width).not.to.be('1px')
412413
sheet.detach()
413414
})
414415
})

0 commit comments

Comments
 (0)