styled-components / jest-styled-components

🔧 💅 Jest utilities for Styled Components
MIT License
1.58k stars 145 forks source link

Performance issues with styled components v5 #316

Open ceari opened 4 years ago

ceari commented 4 years ago

Since we upgraded our project to styled-components v5 (5.1.0) and jest-styled-components from 6.3.3 to 7.0.2, Jest storyshots take a very long time to run.

I tracked the issue down to this line in the extract function in utils.js: https://github.com/styled-components/jest-styled-components/blob/f8e6f79e70f0baae4906adb5d9762928c9438ac3/src/utils.js#L23

getHTML() is called repeatedly and calls masterSheet.toString() in our setup. This seems to be quite expensive leading to a lot of GC activity in NodeJS according to the profiler. Assuming getHTML() does not have side effects, it should be possible to call getHTML() only once within extract:

  const html = getHTML();
  while ((matches = regex.exec(html)) !== null) {
    style += `${matches[1]} `;
  }

Before:

$ /usr/bin/time -v npx jest storyshots
[...]
Test Suites: 1 passed, 1 total
Tests:       686 passed, 686 total
Snapshots:   685 passed, 685 total
Time:        885.862s
Ran all test suites matching /storyshots/i.
    Command being timed: "npx jest storyshots"
    User time (seconds): 944.13
    System time (seconds): 62.46
    Percent of CPU this job got: 113%
    Elapsed (wall clock) time (h:mm:ss or m:ss): 14:46.84
    Average shared text size (kbytes): 0
    Average unshared data size (kbytes): 0
    Average stack size (kbytes): 0
    Average total size (kbytes): 0
    Maximum resident set size (kbytes): 1147988
    Average resident set size (kbytes): 0
    Major (requiring I/O) page faults: 0
    Minor (reclaiming a frame) page faults: 42452348

After applying this fix locally:

$ /usr/bin/time -v npx jest storyshots
[...]
Test Suites: 1 passed, 1 total
Tests:       686 passed, 686 total
Snapshots:   685 passed, 685 total
Time:        79.71s, estimated 883s
Ran all test suites matching /storyshots/i.
    Command being timed: "npx jest storyshots"
    User time (seconds): 90.96
    System time (seconds): 1.51
    Percent of CPU this job got: 114%
    Elapsed (wall clock) time (h:mm:ss or m:ss): 1:20.59
    Average shared text size (kbytes): 0
    Average unshared data size (kbytes): 0
    Average stack size (kbytes): 0
    Average total size (kbytes): 0
    Maximum resident set size (kbytes): 713032
    Average resident set size (kbytes): 0
    Major (requiring I/O) page faults: 0
    Minor (reclaiming a frame) page faults: 276378

Could you look into this please?

ceari commented 4 years ago

Update: The extreme slow down issue was caused by many new empty media queries that appeared in the generated storyshots with our updates. After we managed to remove these again as described in https://github.com/styled-components/jest-styled-components/issues/276#issuecomment-618958757 the the performance is acceptable again because the number of regex matches in the while loop is limited.

However, I think this code could be optimized anyway.