Implement code coverage heat map#145
Conversation
|
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. |
|
@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 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). |
|
@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! |
|
@nikolay-borzov I've gone ahead & fixed those final items per your request, thanks again for the review! |
|
Thanks for your contribution! I'll incorporate this feature when I'm through 2.1.2 issues |
- [ESLint] Require empty line after `const`/`let` - [ESLint] Enable `object-shorthand` - Move code coverage related methods to `coverage.ts` - Add `CannotOpenCoverageFile` and `NoCoverageMatches` errors - Replace `FileSizeMap` with `FileData` so that additional data can be stored along with mapping size - Implement mapping coverages to bundles by comparing coverage URL with bundle name. - Convert coverage ranges (one-line) to per line range to ease matching with mapping ranges - When calculating file sizes first get mapping ranges with sources, then merge consecutive ranges and then calculate bytes - Calculate cover bytes size - Fix bytes calculation - get bytes length from source ranges' string rather than columns count. One column can have byte length 4 bytes (e.g. 🍰) - Move mapping reference EOL check before invalid mapping column check - Add `rewiremock` to mock dependencies during tests - Add `mappedBytes` value to result
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).
This PR adds an [optional]
--coverageflag to thesource-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):
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.
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.tsthat 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: