Skip to content

Commit 87952b4

Browse files
seiyabkof
andauthored
fix memory leak in dynamic nested rule (#1563)
* fix memory leak by function nested rule * add test against function nested rule memory leak * add test for update to test both addRule and replaceRule * add functional tests for replaceRule * add integration tests for replaceRule * add test for identical nest (just '&') * add tests for multiple updates with function-nested * refactor code, reduce bundle size * make test description more meaningful Co-authored-by: Oleg Isonen <oleg008@gmail.com> * make test description more meaningful Co-authored-by: Oleg Isonen <oleg008@gmail.com> * make test descriptions clear * update test decription * prevent unnecessary copy * remove RuleList.getByName, StyleSheet.getByName include related change - use almost unique name rather than selector name in nested plugin to prevent accidental replacement - fix strange behavior of global plugin (probably bug) * make replaceRule to return just a newRule * add tests for global container rule Co-authored-by: Oleg Isonen <oleg008@gmail.com>
1 parent 0dc12e9 commit 87952b4

22 files changed

+708
-99
lines changed

packages/css-jss/.size-snapshot.json

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
{
22
"css-jss.js": {
3-
"bundled": 59688,
4-
"minified": 21828,
5-
"gzipped": 7357
3+
"bundled": 60043,
4+
"minified": 21979,
5+
"gzipped": 7382
66
},
77
"css-jss.min.js": {
8-
"bundled": 58613,
9-
"minified": 21205,
10-
"gzipped": 7078
8+
"bundled": 58968,
9+
"minified": 21356,
10+
"gzipped": 7102
1111
},
1212
"css-jss.cjs.js": {
1313
"bundled": 2949,

packages/jss-plugin-global/.size-snapshot.json

+12-12
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
{
22
"jss-plugin-global.js": {
3-
"bundled": 4988,
4-
"minified": 2184,
5-
"gzipped": 919
3+
"bundled": 5294,
4+
"minified": 2313,
5+
"gzipped": 940
66
},
77
"jss-plugin-global.min.js": {
8-
"bundled": 4988,
9-
"minified": 2184,
10-
"gzipped": 919
8+
"bundled": 5294,
9+
"minified": 2313,
10+
"gzipped": 940
1111
},
1212
"jss-plugin-global.cjs.js": {
13-
"bundled": 4263,
14-
"minified": 2310,
15-
"gzipped": 892
13+
"bundled": 4551,
14+
"minified": 2439,
15+
"gzipped": 911
1616
},
1717
"jss-plugin-global.esm.js": {
18-
"bundled": 3917,
19-
"minified": 2036,
20-
"gzipped": 788,
18+
"bundled": 4205,
19+
"minified": 2165,
20+
"gzipped": 806,
2121
"treeshaked": {
2222
"rollup": {
2323
"code": 55,

packages/jss-plugin-global/src/index.js

+10-1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@ class GlobalContainerRule {
4141
return rule
4242
}
4343

44+
/**
45+
* Replace rule, run plugins.
46+
*/
47+
replaceRule(name, style, options) {
48+
const newRule = this.rules.replace(name, style, options)
49+
if (newRule) this.options.jss.plugins.onProcessRule(newRule)
50+
return newRule
51+
}
52+
4453
/**
4554
* Get index of a rule.
4655
*/
@@ -146,7 +155,7 @@ export default function jssGlobal() {
146155
}
147156
}
148157

149-
if (options.scoped === false) {
158+
if (!options.selector && options.scoped === false) {
150159
options.selector = name
151160
}
152161

packages/jss-plugin-global/src/index.test.js

+89-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import nested from 'jss-plugin-nested'
66
import global from './index'
77

88
const settings = {
9-
createGenerateId: () => (rule) => `${rule.key}-id`
9+
createGenerateId: () => rule => `${rule.key}-id`
1010
}
1111

1212
describe('jss-plugin-global', () => {
@@ -37,6 +37,94 @@ describe('jss-plugin-global', () => {
3737
it('should generate correct CSS', () => {
3838
expect(sheet.toString()).to.be('a {\n color: red;\n}\nbody {\n color: green;\n}')
3939
})
40+
41+
describe('addRule', () => {
42+
let globalRule
43+
beforeEach(() => {
44+
globalRule = sheet.getRule('@global')
45+
globalRule.addRule('button', {margin: 0})
46+
globalRule.addRule('li', {float: 'left'})
47+
})
48+
49+
it('should add rule', () => {
50+
expect(globalRule.getRule('button')).to.not.be(undefined)
51+
expect(globalRule.getRule('li')).to.not.be(undefined)
52+
})
53+
54+
it('should generate correct CSS', () => {
55+
expect(sheet.toString()).to.be(stripIndent`
56+
a {
57+
color: red;
58+
}
59+
body {
60+
color: green;
61+
}
62+
button {
63+
margin: 0;
64+
}
65+
li {
66+
float: left;
67+
}
68+
`)
69+
})
70+
})
71+
72+
describe('replaceRule', () => {
73+
let globalRule
74+
let previousA
75+
beforeEach(() => {
76+
globalRule = sheet.getRule('@global')
77+
previousA = globalRule.getRule('a')
78+
globalRule.replaceRule('a', {color: 'yellow'})
79+
globalRule.replaceRule('li', {float: 'left'})
80+
})
81+
82+
it('should replace and add rule', () => {
83+
expect(globalRule.getRule('a')).to.not.be(previousA)
84+
expect(globalRule.getRule('li')).to.not.be(undefined)
85+
})
86+
87+
it('should generate correct CSS', () => {
88+
expect(sheet.toString()).to.be(stripIndent`
89+
a {
90+
color: yellow;
91+
}
92+
body {
93+
color: green;
94+
}
95+
li {
96+
float: left;
97+
}
98+
`)
99+
})
100+
})
101+
102+
describe('addRule / replaceRule with selector', () => {
103+
let globalRule
104+
beforeEach(() => {
105+
globalRule = sheet.getRule('@global')
106+
globalRule.addRule('arbitrary-name-1', {color: 'red'}, {selector: 'span'})
107+
globalRule.replaceRule('arbitrary-name-2', {float: 'left'}, {selector: 'ul'})
108+
globalRule.replaceRule('a', {display: 'block'}, {selector: 'div'})
109+
})
110+
111+
it('should generate correct CSS', () => {
112+
expect(sheet.toString()).to.be(stripIndent`
113+
div {
114+
display: block;
115+
}
116+
body {
117+
color: green;
118+
}
119+
span {
120+
color: red;
121+
}
122+
ul {
123+
float: left;
124+
}
125+
`)
126+
})
127+
})
40128
})
41129

42130
describe('@global linked', () => {

packages/jss-plugin-nested/.size-snapshot.json

+12-12
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
{
22
"jss-plugin-nested.js": {
3-
"bundled": 4456,
4-
"minified": 1618,
5-
"gzipped": 881
3+
"bundled": 4505,
4+
"minified": 1640,
5+
"gzipped": 894
66
},
77
"jss-plugin-nested.min.js": {
8-
"bundled": 4016,
9-
"minified": 1402,
10-
"gzipped": 754
8+
"bundled": 4065,
9+
"minified": 1424,
10+
"gzipped": 768
1111
},
1212
"jss-plugin-nested.cjs.js": {
13-
"bundled": 3729,
14-
"minified": 1578,
15-
"gzipped": 808
13+
"bundled": 3776,
14+
"minified": 1600,
15+
"gzipped": 822
1616
},
1717
"jss-plugin-nested.esm.js": {
18-
"bundled": 3310,
19-
"minified": 1255,
20-
"gzipped": 693,
18+
"bundled": 3357,
19+
"minified": 1277,
20+
"gzipped": 705,
2121
"treeshaked": {
2222
"rollup": {
2323
"code": 64,

packages/jss-plugin-nested/src/index.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,8 @@ export default function jssNested() {
1818

1919
warning(
2020
false,
21-
`[JSS] Could not find the referenced rule "${key}" in "${
22-
container.options.meta || container.toString()
23-
}".`
21+
`[JSS] Could not find the referenced rule "${key}" in "${container.options.meta ||
22+
container.toString()}".`
2423
)
2524
return key
2625
}
@@ -88,7 +87,8 @@ export default function jssNested() {
8887
// Replace all $refs.
8988
selector = selector.replace(refRegExp, replaceRef)
9089

91-
container.addRule(selector, style[prop], {...options, selector})
90+
const name = `${styleRule.key}-${prop}`
91+
container.replaceRule(name, style[prop], {...options, selector})
9292
} else if (isNestedConditional) {
9393
// Place conditional right after the parent rule to ensure right ordering.
9494
container

packages/jss-plugin-nested/src/index.test.js

+80-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import functionPlugin from 'jss-plugin-rule-value-function'
99
import nested from '.'
1010

1111
const settings = {
12-
createGenerateId: () => (rule) => `${rule.key}-id`
12+
createGenerateId: () => rule => `${rule.key}-id`
1313
}
1414

1515
describe('jss-plugin-nested', () => {
@@ -127,6 +127,85 @@ describe('jss-plugin-nested', () => {
127127
})
128128
})
129129

130+
describe('identical nest', () => {
131+
describe('single nest', () => {
132+
let sheet
133+
134+
beforeEach(() => {
135+
sheet = jss.createStyleSheet({
136+
a: {
137+
float: 'left',
138+
'&': {color: 'blue'}
139+
}
140+
})
141+
})
142+
143+
it('should add rule', () => {
144+
expect(sheet.getRule('a')).to.not.be(undefined)
145+
})
146+
147+
it('should generate correct CSS', () => {
148+
expect(sheet.toString()).to.be(stripIndent`
149+
.a-id {
150+
float: left;
151+
}
152+
.a-id {
153+
color: blue;
154+
}
155+
`)
156+
})
157+
})
158+
159+
describe('deep nest', () => {
160+
let sheet
161+
162+
beforeEach(() => {
163+
sheet = jss.createStyleSheet({
164+
a: {
165+
float: 'left',
166+
'&': {
167+
color: 'blue',
168+
'&': {
169+
width: 0,
170+
'&.b': {
171+
'z-index': 1,
172+
'&': {
173+
top: 0
174+
}
175+
}
176+
}
177+
}
178+
}
179+
})
180+
})
181+
182+
it('should add rules', () => {
183+
expect(sheet.getRule('a')).to.not.be(undefined)
184+
expect(sheet.getRule('.a-id.b')).to.not.be(undefined)
185+
})
186+
187+
it('should generate correct CSS', () => {
188+
expect(sheet.toString()).to.be(stripIndent`
189+
.a-id {
190+
float: left;
191+
}
192+
.a-id {
193+
color: blue;
194+
}
195+
.a-id {
196+
width: 0;
197+
}
198+
.a-id.b {
199+
z-index: 1;
200+
}
201+
.a-id.b {
202+
top: 0;
203+
}
204+
`)
205+
})
206+
})
207+
})
208+
130209
describe('.addRules()', () => {
131210
let sheet
132211

0 commit comments

Comments
 (0)