classnames
classnames copied to clipboard
Refactored index.js to reduce size by 30-70%
Refactored index.js to reduce bundle size whilst keeping performance
- Changed final condition check in parseValue into an expression
- this allows the entire function to be turned into an inlined expression
- inlined this into the top function
- swapped from accumilators to map and joins
- by using expressions instead, bundlers can inline more code
- removed parseValue
- it was only used it one place and the classNames function was 3 lines before changes
- removed appendClass
- after reworking everything I realised I was only using it a single place and it no longer made sense to use
- swapped to
..argsinstead of arguments- args is an array by default, meaning we can use
.mapwithout any additional steps - we don't have to convert it to an array or do a for loop
- args is an array by default, meaning we can use
- removed
typeof arg !== "object"check- the
!argcovers
- the
Bundle Size
When compiled using microbundle in isolation:
Original:
308 B: classnames.js.gz
254 B: classnames.js.br
New Version:
218 B: classnames.js.gz
178 B: classnames.js.br
When built into an actual project I created an empty preact project using npm create vite to get the build difference in an actual project
No classNames:
11,372 (gzip: 4,820) ./dist/assets/index-CGD-ssac.js
Original:
12,262 (gzip: 5,220) ./dist/assets/index-D8rnffc0.js
New Version:
11,671 (gzip: 4,940) ./dist/assets/index-hh12ETg_.js
Uncompressed(33%): +890 -> +299 Gzip(30%): +400 -> +120
Note: I think the difference is so big is because the inability to convert into a tunary is really expensive in this case
Benchmark Results
Performance appears unchanged
Benchmarking 'strings'.
| Task name | Latency avg (ns) | Latency med (ns) | Throughput avg (ops/s) | Throughput med (ops/s) | Samples |
| --------- | ---------------- | ---------------- | ---------------------- | ---------------------- | ------- |
| reworked | 121.51 ± 0.19% | 111.00 ± 1.00 | 8587128 ± 0.01% | 9009009 ± 81900 | 8229759 |
| original | 123.50 ± 0.13% | 120.00 ± 9.00 | 8440112 ± 0.01% | 8333333 ± 675676 | 8097160 |
Benchmarking 'object'.
| Task name | Latency avg (ns) | Latency med (ns) | Throughput avg (ops/s) | Throughput med (ops/s) | Samples |
| --------- | ---------------- | ---------------- | ---------------------- | ---------------------- | ------- |
| reworked | 123.12 ± 1.14% | 110.00 ± 0.00 | 8552463 ± 0.01% | 9090909 ± 0 | 8122470 |
| original | 120.44 ± 0.12% | 111.00 ± 1.00 | 8594657 ± 0.01% | 9009010 ± 81900 | 8303130 |
Benchmarking 'strings, object'.
| Task name | Latency avg (ns) | Latency med (ns) | Throughput avg (ops/s) | Throughput med (ops/s) | Samples |
| --------- | ---------------- | ---------------- | ---------------------- | ---------------------- | ------- |
| reworked | 153.61 ± 0.17% | 141.00 ± 1.00 | 6776792 ± 0.01% | 7092199 ± 50659 | 6509904 |
| original | 154.21 ± 0.16% | 150.00 ± 9.00 | 6727520 ± 0.01% | 6666667 ± 425532 | 6484668 |
Benchmarking 'mix'.
| Task name | Latency avg (ns) | Latency med (ns) | Throughput avg (ops/s) | Throughput med (ops/s) | Samples |
| --------- | ---------------- | ---------------- | ---------------------- | ---------------------- | ------- |
| reworked | 233.67 ± 0.68% | 211.00 ± 1.00 | 4543994 ± 0.01% | 4739336 ± 22568 | 4279555 |
| original | 237.36 ± 0.88% | 221.00 ± 1.00 | 4436742 ± 0.01% | 4524887 ± 20568 | 4213018 |
Benchmarking 'arrays'.
| Task name | Latency avg (ns) | Latency med (ns) | Throughput avg (ops/s) | Throughput med (ops/s) | Samples |
| --------- | ---------------- | ---------------- | ---------------------- | ---------------------- | ------- |
| reworked | 375.24 ± 0.11% | 361.00 ± 1.00 | 2730653 ± 0.01% | 2770083 ± 7695 | 2664987 |
| original | 373.86 ± 0.12% | 361.00 ± 10.00 | 2743952 ± 0.01% | 2770083 ± 78920 | 2674781 |