Skip to content
This repository was archived by the owner on Mar 4, 2020. It is now read-only.

chore: bundle size statistics#97

Merged
miroslavstastny merged 33 commits intomasterfrom
chore/statistics-size
Dec 21, 2018
Merged

chore: bundle size statistics#97
miroslavstastny merged 33 commits intomasterfrom
chore/statistics-size

Conversation

@levithomason
Copy link
Member

@levithomason levithomason commented Aug 16, 2018

This PR uses webpack to compute bundle size for individual stardust components as well as for the whole package.

TODO

  • Build bundle size stats for index (entire package)
  • Build bundle size stats for /lib
  • Build bundle size stats for each component
  • Build bundle size stats for each theme
  • Ensure size stats are available in each PR for visibility
    • we are going to implement this in a separate PR
  • Update release workflow to insert stats for the version number being released

Next, we'll make a stats page in the docs for visualizing and advertising this to users. We will extend the stats to include API surface area and render performance later as well.

Implementation details

Computing the statistics

yarn build:stats runs webpack with webpack.config.stats.ts configuration which builds bundles for:

  • entire package,
  • lib (core),
  • all individual components,
  • all individual themes.

All build are run in series to avoid memory issues.

Then Unreleased section of docs/src/bundleStats.json file is updated:

{
  "Unreleased": {
    "bundles": [
      ...
      {
        "name": "component-Animation.js",
        "size": 262818
      },
      ...   
    ]
  },
  "0.12.0": {
    /* the same "bundles" structure */
   }
}

Order of all items in the JSON is deterministic so that only change in size (or a new version or package removed/added) results in this file being changed.

Storing the results

New Store bundle statistics step was added to CircleCI config. This script, if run in PR build, checks that the file changed and if so, it commits it back to GIT (see this commit).

Limitations

Every change which results in changed bundleStats.json triggers two build

Store bundle statistics commits a bundleStats.json back to Github if it has changed. This causes several problems in CI workflow:

  • As we have Auto-cancel redundant builds enabled in the CircleCI, the build is cancelled,
  • as a new commit appears on the branch, it starts a new build.
    • Commiting the stats with [ci skip] does not help as our merge policy says that build for the last commit must be green to allow a merge.
    • If there was a change in the stats (again) the whole loop would happen again - that can happen due to a bug in our stats computation and would always happen for performance stats which have less stable results.

Developers have to deal with mid-air collisions

Every commit on a branch results in a commit from CI - Developers will have to git pull --rebase before pushing, will have to be more careful when force-pushing.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I split the clean tasks so I could target cleaning just the es build.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The corresponding clean task for this is called clean:component-info, the util function is called getComponentInfo, I've then renamed the build task for consistency.

The legacy name docgen through me off when trying to use it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We loop over each component info file in docs/src/componentInfo. We keep totals of components, subcomponents, and their max, min, and gzip sizes as we loop through them. These are keyed by package.json version number.

package.json Outdated
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We build stats on every commit, so that component count and size is updated with each change to the src. This is quite slow, so optimizations to the speed are likely warranted.

package.json Outdated
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We were not formatting js and json files. Now we are.

@codecov
Copy link

codecov bot commented Aug 16, 2018

Codecov Report

❗ No coverage uploaded for pull request base (master@ed50341). Click here to learn what that means.
The diff coverage is n/a.

Impacted file tree graph

@@            Coverage Diff            @@
##             master      #97   +/-   ##
=========================================
  Coverage          ?   88.17%           
=========================================
  Files             ?       42           
  Lines             ?     1455           
  Branches          ?      187           
=========================================
  Hits              ?     1283           
  Misses            ?      167           
  Partials          ?        5

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update ed50341...abf4c0c. Read the comment docs.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's the library-level output we're getting.

Copy link
Member Author

@levithomason levithomason Aug 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's the component-level output we're getting.

I chose to key this by displayName for ease of access later. The displayName is our defacto way of storing values everywhere else. Keeping a flat stats file would require us to construct/deconstruct stats file key names to work with stats effectively.

@levithomason levithomason force-pushed the chore/statistics-size branch 2 times, most recently from 290eaa7 to 30d6958 Compare August 16, 2018 17:04
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We were previously including the umd build with ES and CommonJS module types. Now we exclude it.

@miroslavstastny
Copy link
Member

I spent some time trying to find a way to commit&push updated stats from CI back to github but haven't found any reasonably solution.

  • CircleCI cannot ignore tags,
  • even if that would work, each tag would appear as a release in GitHub.

Instead of hacking a suboptimal solution I would rather merge this and progress to the next step which is an external storage. In the mean time we can:

  1. either push updates to Git as implemented with all its drawbacks,
  2. compute stats on prepush,
  3. or store stats as CircleCI artefacts for now.

Copy link
Member

@layershifter layershifter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left small comments. My overall opinion: let's ship it.

However, I almost sure that we will need to switch to Rollup in the future, it will give more acurate result and will pass the compilation process much faster.

const UNRELEASED_VERSION_STRING = 'Unreleased'
const SEMVER_MATCHER = /(\d+)\.(\d+)\.(\d+)/

const semverCmp = (a, b) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks quite confusing that we need to have a custom function to compare semver 🤔

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we can use a package for that, but then we need to handle UNRELEASED_VERSION_STRING explicitly anyway.
Moreover, this will probably be removed once we implement external storage for bundle size.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

even given this requirement, it seems that the task would reduce to

  • filter out versions with UNRELEASED_VERSION_STRING
    • put them first
  • compare rest entries using logic of dedicated package

This approach would be much more preferable to my mind.

@miroslavstastny miroslavstastny merged commit 39381d2 into master Dec 21, 2018
@miroslavstastny miroslavstastny deleted the chore/statistics-size branch December 21, 2018 11:58
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants