Skip to content

Commit d38a9d0

Browse files
authored
feat: Override array methods to avoid proxy creation while iterating and updating (#1184)
* Intercept array methods to skip proxy creation for perf * Add allReassigned flag * Improve isArrayIndex * Drop dead test * Move array methods to a new plugin * Run additional base tests with array method plugin enabled * Add immutability-profiling script * Update benchmarks to use enableArrayMethods * Add additional array method tests * Document array method internal behaviors * Update import size values * Update import size command * Add array plugin docs
1 parent 99e59a8 commit d38a9d0

File tree

20 files changed

+2121
-53
lines changed

20 files changed

+2121
-53
lines changed

__tests__/__prod_snapshots__/base.js.snap

Lines changed: 63 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,27 @@
11
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
22

3+
exports[`base functionality - array-plugin=true:auto-freeze=true:shallow-copy=false:use-listener=false > map drafts > revokes map proxies 1`] = `[Error: [Immer] minified error nr: 3. Full error at: https://bit.ly/3cXEKWf]`;
4+
5+
exports[`base functionality - array-plugin=true:auto-freeze=true:shallow-copy=false:use-listener=false > map drafts > revokes map proxies 2`] = `[Error: [Immer] minified error nr: 3. Full error at: https://bit.ly/3cXEKWf]`;
6+
7+
exports[`base functionality - array-plugin=true:auto-freeze=true:shallow-copy=false:use-listener=false > recipe functions > cannot return a modified child draft 1`] = `[Error: [Immer] minified error nr: 4. Full error at: https://bit.ly/3cXEKWf]`;
8+
9+
exports[`base functionality - array-plugin=true:auto-freeze=true:shallow-copy=false:use-listener=false > set drafts > revokes sets 1`] = `[Error: [Immer] minified error nr: 3. Full error at: https://bit.ly/3cXEKWf]`;
10+
11+
exports[`base functionality - array-plugin=true:auto-freeze=true:shallow-copy=false:use-listener=false > set drafts > revokes sets 2`] = `[Error: [Immer] minified error nr: 3. Full error at: https://bit.ly/3cXEKWf]`;
12+
13+
exports[`base functionality - array-plugin=true:auto-freeze=true:shallow-copy=false:use-listener=false > throws when Object.defineProperty() is used on drafts 1`] = `[Error: [Immer] minified error nr: 11. Full error at: https://bit.ly/3cXEKWf]`;
14+
15+
exports[`base functionality - array-plugin=true:auto-freeze=true:shallow-copy=false:use-listener=false > throws when Object.setPrototypeOf() is used on a draft 1`] = `[Error: [Immer] minified error nr: 12. Full error at: https://bit.ly/3cXEKWf]`;
16+
17+
exports[`base functionality - array-plugin=true:auto-freeze=true:shallow-copy=false:use-listener=false > throws when the draft is modified and another object is returned 1`] = `[Error: [Immer] minified error nr: 4. Full error at: https://bit.ly/3cXEKWf]`;
18+
319
exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=false > map drafts > revokes map proxies 1`] = `[Error: [Immer] minified error nr: 3. Full error at: https://bit.ly/3cXEKWf]`;
420

521
exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=false > map drafts > revokes map proxies 2`] = `[Error: [Immer] minified error nr: 3. Full error at: https://bit.ly/3cXEKWf]`;
622

723
exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=false > recipe functions > cannot return a modified child draft 1`] = `[Error: [Immer] minified error nr: 4. Full error at: https://bit.ly/3cXEKWf]`;
824

9-
exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=false > recipe functions > cannot return an object that references itself 1`] = `[RangeError: Maximum call stack size exceeded]`;
10-
1125
exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=false > set drafts > revokes sets 1`] = `[Error: [Immer] minified error nr: 3. Full error at: https://bit.ly/3cXEKWf]`;
1226

1327
exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=false > set drafts > revokes sets 2`] = `[Error: [Immer] minified error nr: 3. Full error at: https://bit.ly/3cXEKWf]`;
@@ -24,8 +38,6 @@ exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=
2438

2539
exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=true > recipe functions > cannot return a modified child draft 1`] = `[Error: [Immer] minified error nr: 4. Full error at: https://bit.ly/3cXEKWf]`;
2640

27-
exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=true > recipe functions > cannot return an object that references itself 1`] = `[RangeError: Maximum call stack size exceeded]`;
28-
2941
exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=true > set drafts > revokes sets 1`] = `[Error: [Immer] minified error nr: 3. Full error at: https://bit.ly/3cXEKWf]`;
3042

3143
exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=true > set drafts > revokes sets 2`] = `[Error: [Immer] minified error nr: 3. Full error at: https://bit.ly/3cXEKWf]`;
@@ -42,8 +54,6 @@ exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=f
4254

4355
exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=false > recipe functions > cannot return a modified child draft 1`] = `[Error: [Immer] minified error nr: 4. Full error at: https://bit.ly/3cXEKWf]`;
4456

45-
exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=false > recipe functions > cannot return an object that references itself 1`] = `[RangeError: Maximum call stack size exceeded]`;
46-
4757
exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=false > set drafts > revokes sets 1`] = `[Error: [Immer] minified error nr: 3. Full error at: https://bit.ly/3cXEKWf]`;
4858

4959
exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=false > set drafts > revokes sets 2`] = `[Error: [Immer] minified error nr: 3. Full error at: https://bit.ly/3cXEKWf]`;
@@ -60,8 +70,6 @@ exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=t
6070

6171
exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=true > recipe functions > cannot return a modified child draft 1`] = `[Error: [Immer] minified error nr: 4. Full error at: https://bit.ly/3cXEKWf]`;
6272

63-
exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=true > recipe functions > cannot return an object that references itself 1`] = `[RangeError: Maximum call stack size exceeded]`;
64-
6573
exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=true > set drafts > revokes sets 1`] = `[Error: [Immer] minified error nr: 3. Full error at: https://bit.ly/3cXEKWf]`;
6674

6775
exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=true > set drafts > revokes sets 2`] = `[Error: [Immer] minified error nr: 3. Full error at: https://bit.ly/3cXEKWf]`;
@@ -78,8 +86,6 @@ exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=f
7886

7987
exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=false > recipe functions > cannot return a modified child draft 1`] = `[Error: [Immer] minified error nr: 4. Full error at: https://bit.ly/3cXEKWf]`;
8088

81-
exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=false > recipe functions > cannot return an object that references itself 1`] = `[RangeError: Maximum call stack size exceeded]`;
82-
8389
exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=false > set drafts > revokes sets 1`] = `[Error: [Immer] minified error nr: 3. Full error at: https://bit.ly/3cXEKWf]`;
8490

8591
exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=false > set drafts > revokes sets 2`] = `[Error: [Immer] minified error nr: 3. Full error at: https://bit.ly/3cXEKWf]`;
@@ -96,8 +102,6 @@ exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=t
96102

97103
exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=true > recipe functions > cannot return a modified child draft 1`] = `[Error: [Immer] minified error nr: 4. Full error at: https://bit.ly/3cXEKWf]`;
98104

99-
exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=true > recipe functions > cannot return an object that references itself 1`] = `[RangeError: Maximum call stack size exceeded]`;
100-
101105
exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=true > set drafts > revokes sets 1`] = `[Error: [Immer] minified error nr: 3. Full error at: https://bit.ly/3cXEKWf]`;
102106

103107
exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=true > set drafts > revokes sets 2`] = `[Error: [Immer] minified error nr: 3. Full error at: https://bit.ly/3cXEKWf]`;
@@ -114,8 +118,6 @@ exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=fa
114118

115119
exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=false > recipe functions > cannot return a modified child draft 1`] = `[Error: [Immer] minified error nr: 4. Full error at: https://bit.ly/3cXEKWf]`;
116120

117-
exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=false > recipe functions > cannot return an object that references itself 1`] = `[RangeError: Maximum call stack size exceeded]`;
118-
119121
exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=false > set drafts > revokes sets 1`] = `[Error: [Immer] minified error nr: 3. Full error at: https://bit.ly/3cXEKWf]`;
120122

121123
exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=false > set drafts > revokes sets 2`] = `[Error: [Immer] minified error nr: 3. Full error at: https://bit.ly/3cXEKWf]`;
@@ -132,8 +134,6 @@ exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=tr
132134

133135
exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=true > recipe functions > cannot return a modified child draft 1`] = `[Error: [Immer] minified error nr: 4. Full error at: https://bit.ly/3cXEKWf]`;
134136

135-
exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=true > recipe functions > cannot return an object that references itself 1`] = `[RangeError: Maximum call stack size exceeded]`;
136-
137137
exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=true > set drafts > revokes sets 1`] = `[Error: [Immer] minified error nr: 3. Full error at: https://bit.ly/3cXEKWf]`;
138138

139139
exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=true > set drafts > revokes sets 2`] = `[Error: [Immer] minified error nr: 3. Full error at: https://bit.ly/3cXEKWf]`;
@@ -519,3 +519,50 @@ exports[`complex nesting map / set / object > modify deep object 16`] = `
519519
},
520520
]
521521
`;
522+
523+
exports[`complex nesting map / set / object > modify deep object 17`] = `
524+
{
525+
"map": Map {
526+
"set1" => Set {
527+
{
528+
"a": 2,
529+
},
530+
{
531+
"b": 2,
532+
},
533+
},
534+
"set2" => Set {
535+
{
536+
"c": 3,
537+
},
538+
},
539+
},
540+
}
541+
`;
542+
543+
exports[`complex nesting map / set / object > modify deep object 18`] = `
544+
[
545+
{
546+
"op": "remove",
547+
"path": [
548+
"map",
549+
"set1",
550+
0,
551+
],
552+
"value": {
553+
"a": 1,
554+
},
555+
},
556+
{
557+
"op": "add",
558+
"path": [
559+
"map",
560+
"set1",
561+
0,
562+
],
563+
"value": {
564+
"a": 2,
565+
},
566+
},
567+
]
568+
`;

__tests__/__snapshots__/base.js.snap

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,41 @@
11
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
22

3+
exports[`base functionality - array-plugin=true:auto-freeze=true:shallow-copy=false:use-listener=false > array drafts > throws when a non-numeric property is added 1`] = `[Error: [Immer] Immer only supports setting array indices and the 'length' property]`;
4+
5+
exports[`base functionality - array-plugin=true:auto-freeze=true:shallow-copy=false:use-listener=false > array drafts > throws when a non-numeric property is deleted 1`] = `[Error: [Immer] Immer only supports deleting array indices]`;
6+
7+
exports[`base functionality - array-plugin=true:auto-freeze=true:shallow-copy=false:use-listener=false > map drafts > revokes map proxies 1`] = `[Error: [Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}]`;
8+
9+
exports[`base functionality - array-plugin=true:auto-freeze=true:shallow-copy=false:use-listener=false > map drafts > revokes map proxies 2`] = `[Error: [Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}]`;
10+
11+
exports[`base functionality - array-plugin=true:auto-freeze=true:shallow-copy=false:use-listener=false > recipe functions > cannot return a modified child draft 1`] = `[Error: [Immer] An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft.]`;
12+
13+
exports[`base functionality - array-plugin=true:auto-freeze=true:shallow-copy=false:use-listener=false > revokes the draft once produce returns 1`] = `[TypeError: Cannot perform 'get' on a proxy that has been revoked]`;
14+
15+
exports[`base functionality - array-plugin=true:auto-freeze=true:shallow-copy=false:use-listener=false > revokes the draft once produce returns 2`] = `[TypeError: Cannot perform 'set' on a proxy that has been revoked]`;
16+
17+
exports[`base functionality - array-plugin=true:auto-freeze=true:shallow-copy=false:use-listener=false > revokes the draft once produce returns 3`] = `[TypeError: Cannot perform 'get' on a proxy that has been revoked]`;
18+
19+
exports[`base functionality - array-plugin=true:auto-freeze=true:shallow-copy=false:use-listener=false > revokes the draft once produce returns 4`] = `[TypeError: Cannot perform 'set' on a proxy that has been revoked]`;
20+
21+
exports[`base functionality - array-plugin=true:auto-freeze=true:shallow-copy=false:use-listener=false > revokes the draft once produce returns 5`] = `[TypeError: Cannot perform 'get' on a proxy that has been revoked]`;
22+
23+
exports[`base functionality - array-plugin=true:auto-freeze=true:shallow-copy=false:use-listener=false > revokes the draft once produce returns 6`] = `[TypeError: Cannot perform 'set' on a proxy that has been revoked]`;
24+
25+
exports[`base functionality - array-plugin=true:auto-freeze=true:shallow-copy=false:use-listener=false > revokes the draft once produce returns 7`] = `[TypeError: Cannot perform 'get' on a proxy that has been revoked]`;
26+
27+
exports[`base functionality - array-plugin=true:auto-freeze=true:shallow-copy=false:use-listener=false > revokes the draft once produce returns 8`] = `[TypeError: Cannot perform 'set' on a proxy that has been revoked]`;
28+
29+
exports[`base functionality - array-plugin=true:auto-freeze=true:shallow-copy=false:use-listener=false > set drafts > revokes sets 1`] = `[Error: [Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}]`;
30+
31+
exports[`base functionality - array-plugin=true:auto-freeze=true:shallow-copy=false:use-listener=false > set drafts > revokes sets 2`] = `[Error: [Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}]`;
32+
33+
exports[`base functionality - array-plugin=true:auto-freeze=true:shallow-copy=false:use-listener=false > throws when Object.defineProperty() is used on drafts 1`] = `[Error: [Immer] Object.defineProperty() cannot be used on an Immer draft]`;
34+
35+
exports[`base functionality - array-plugin=true:auto-freeze=true:shallow-copy=false:use-listener=false > throws when Object.setPrototypeOf() is used on a draft 1`] = `[Error: [Immer] Object.setPrototypeOf() cannot be used on an Immer draft]`;
36+
37+
exports[`base functionality - array-plugin=true:auto-freeze=true:shallow-copy=false:use-listener=false > throws when the draft is modified and another object is returned 1`] = `[Error: [Immer] An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft.]`;
38+
339
exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=false > array drafts > throws when a non-numeric property is added 1`] = `[Error: [Immer] Immer only supports setting array indices and the 'length' property]`;
440

541
exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=false > array drafts > throws when a non-numeric property is deleted 1`] = `[Error: [Immer] Immer only supports deleting array indices]`;
@@ -663,3 +699,50 @@ exports[`complex nesting map / set / object > modify deep object 16`] = `
663699
},
664700
]
665701
`;
702+
703+
exports[`complex nesting map / set / object > modify deep object 17`] = `
704+
{
705+
"map": Map {
706+
"set1" => Set {
707+
{
708+
"a": 2,
709+
},
710+
{
711+
"b": 2,
712+
},
713+
},
714+
"set2" => Set {
715+
{
716+
"c": 3,
717+
},
718+
},
719+
},
720+
}
721+
`;
722+
723+
exports[`complex nesting map / set / object > modify deep object 18`] = `
724+
[
725+
{
726+
"op": "remove",
727+
"path": [
728+
"map",
729+
"set1",
730+
0,
731+
],
732+
"value": {
733+
"a": 1,
734+
},
735+
},
736+
{
737+
"op": "add",
738+
"path": [
739+
"map",
740+
"set1",
741+
0,
742+
],
743+
"value": {
744+
"a": 2,
745+
},
746+
},
747+
]
748+
`;

0 commit comments

Comments
 (0)