danvk / source-map-explorer

Analyze and debug space usage through source maps
Apache License 2.0
3.83k stars 101 forks source link

Implement code coverage heat map #145

Closed joshribakoff closed 4 years ago

joshribakoff commented 4 years ago

In Google Chrome, you can collect code coverage stats while loading/browsing around your local build (documented here https://developers.google.com/web/tools/chrome-devtools/coverage).

Screen Shot 2019-11-07 at 10 42 36 AM

Screen Shot 2019-11-07 at 10 42 47 AM

This PR adds an [optional] --coverage flag to the source-map-explorer, which takes in a JSON export of the Chrome code coverage.

Passing the coverage data will attempt to color code the heat map like so (I obscured the file names for this screenshot):

Screen Shot 2019-11-18 at 1 16 25 PM

This allows you to find the code that is not strictly needed for the initial page load & helps to identify the ideal ways to code split.

Coverage decreased (-6.4%) to 91.247% when pulling eb195c6 on joshribakoff:master into 98b13b2 on danvk:master.

FYI, my actual business logic should have 100% coverage, but I suspect this is due to adding lines of code to cli.ts, explore.ts, api.ts that basically just plumbs the path of the json down to my function (which is 100% tested).

Also, FYI I've taken care to ensure the algorithm scales in O(n) where n is the size of the bundle, by using a ratcheting pointer technique, rather than using a naive nested loop O(n^2) solution.

Also, your tests do not pass on my machine & fail with the below errors, I commented these 2 tests out locally:


  63 passing (2s)
  2 failing

  1) api
       explore
         when output filename specified
           should save html to file:
     Error: Unable to save HTML to file: EEXIST: file already exists, mkdir '.'
      at saveOutputToFile (src/output.ts:67:13)
      at explore (src/api.ts:78:3)
      at <anonymous>

  2) api
       explore
         when output filename specified
           should save html to file creating nested directories:
     Error: Unable to save HTML to file: ENOENT: no such file or directory, mkdir './tmp/nested'
      at saveOutputToFile (src/output.ts:67:13)
      at explore (src/api.ts:78:3)
      at <anonymous>
coveralls commented 4 years ago

Coverage Status

Coverage decreased (-6.1%) to 92.701% when pulling 9dd5dc35489c8de3bd2b2ece9db8edee14ce8709 on joshribakoff:master into 4b95f6e7dfe0058d791dcec2107fee43a1ebf02e on danvk:master.

danvk commented 4 years ago

I'll defer to @nikolay-borzov for the code review, but I wanted to say that this is a great idea!

Out of curiosity, given the screenshot you included, how would you split/pare down your bundle? It doesn't look like there are very many red modules at the top level.

joshribakoff commented 4 years ago

@danvk thanks!

Those red boxes correspond to code that would only be executed if the user took some action, or if some condition was met. For example it may be a component inside of a dropdown the user never interacted with, or components that are only needed if the user opens a modal. In cases where the parent is green but the boxes inside are red, that means maybe some "initialization" logic ran, but the inner code never ran. Maybe we mounted a button, but not the other components in that module that are only needed if & when the user clicks the button, in that case I would have the button trigger the rest of the code to load.

Another example of this is code that attaches a function to window that never actually gets called, or modules that just re-export react components, the barrel export will always run but sometimes the react component never actually gets mounted. A popular tool Sentry that's used for error logging has a big SDK and it doesn't need to run unless there is actually an error to report, so they have a "lazy loader" that registers a listener, buffers errors, and loads the code to process & submit the errors on demand (only if and when an error happens). Things like this can split out, even if not at the top level.

For those features we deem as less important, we would evaluate if they need to be in the critical path, and if not we would split them out & defer them until some condition is met (eg. the user has interacted, or the rest of the page finished loading, or some event has actually fired).

I actually have another tool I'm working on, for a followup PR, which would color code according to how frequently the code changes according to git.

I would recommend (if code splitting manually) to try to create 3 chunks for a heavy page, more if using http2:

The heatmap feature in this PR helps you identify the code that is needed for a fast initial page load (green), as well as helps to identify the code that can be [potentially] deferred because it doesn't run until the user interacts with some feature (red).

joshribakoff commented 4 years ago

@nikolay-borzov feedback has been incorporated or addressed, and conflicts fixed. Would you mind either meeting me halfway on these other 2 items, or giving some reasoning why you desire those changes? Thanks for the review!

joshribakoff commented 4 years ago

@nikolay-borzov I've gone ahead & fixed those final items per your request, thanks again for the review!

nikolay-borzov commented 4 years ago

Thanks for your contribution! I'll incorporate this feature when I'm through 2.1.2 issues