Skip to content

Bundle size tooling #17697

@jdhuntington

Description

@jdhuntington

This feature will be completed in two phases to provide maximum impact as soon as possible.

✅ Phase 1

Includes CI/local builds & reporting on PRs. We want to test different scenarios (current tooling tests a single export). For example, we can measure impact of build time and runtime version of makeStyles(). It will be possible with fixtures.

Fixtures

Are defined in Storybook like format:

  • file body contains imports and code to measure
  • default export initially used to provide a name for a fixture, but later we can expand this if needed

A fixture for runtime version for @fluentui/react-make-styles

import { makeStyles, mergeClasses } from "@fluentui/react-make-styles";
// ^ necessary imports
console.log(makeStyles, mergeClasses);
// ^ console.log() is a simplest way to ensure that required imports will be kept in a bundle

export default {
  name: "makeStyles + mergeClasses (runtime)"
};
// ^ will be removed during build to be skipped from results

A fixture for build time version for @fluentui/react-make-styles

import { __styles, mergeClasses } from "@fluentui/react-make-styles";

console.log(__styles, mergeClasses);

export default {
  name: "makeStyles + mergeClasses (build time)"
};

Research

Before implementing a custom solution we should ensure that there is nothing that we can reuse.

research results

Size Auditor (existing tool)

  • No support for scoped builds (requires to build everything)
  • No measurements for GZIP sizes (shows only minified sizes)
  • No public analysis i.e. dashboard
    • hard to grab a report as on PRs as it shows only changed entries

size-limit & Github action

  • Github action builds base and current branches (double build)
  • Outputs only minified size
  • Will require custom builds in our scenario

Material UI

Has own tooling and reporting via danger.js.

pkg-size

  • Nice reporting, but still not suitable for monorepo
  • Provides only CLI output and minified sizes (build is required by us)

https://github.com/pkg-size/pkg-size/blob/f907c58f32b50abb61a7be1188e0290d27c1d071/src/pkg-size.ts#L36-L40

  • Github action builds base and current branches (double build)

https://github.com/pkg-size/action/blob/cc5eef94b3703031cfc048ee8acbcf9bfbd35510/src/lib/generate-size-report.js#L41-L56

size-plugin

  • Webpack 5 is not supported
  • Works well for local rebuilds while we need to compare with another branch/master

https://github.com/GoogleChromeLabs/size-plugin/blob/cc61db7282c1f0642acc28ca8de0db57d3367971/src/index.js#L121-L129

preactjs/compressed-size-action

✅ Local reporting (#18010)

Implements only local builds and reporting based of fixtures that are created per package. Is a base for other changes.

  • Should work per package (to allow scoping)
  • Use fixtures to measure different scenarios
  • Relies on build artifacts (i.e. requires build first) as we want to test the same output as customers will consume
Sample output from CLI
yarn workspace @fluentui/react-make-styles bundle-size
yarn workspace v1.22.0
yarn run v1.22.0
$ bundle-size measure
[i] artifacts dir is cleared
[i] Measuring bundle size for 3 fixture(s)...
  - bundle-size/makeStaticStyles-runtime.fixture.js
  - bundle-size/makeStyles-runtime.fixture.js
  - bundle-size/makeStyles.fixture.js
[i] "makeStaticStyles-runtime.fixture.js": Webpack in 0.92s
[i] "makeStaticStyles-runtime.fixture.js": Terser in 0.36s
[i] "makeStyles-runtime.fixture.js": Webpack in 0.27s
[i] "makeStyles-runtime.fixture.js": Terser in 0.54s
[i] "makeStyles.fixture.js": Webpack in 0.19s
[i] "makeStyles.fixture.js": Terser in 0.11s
┌────────────────────────────────────────┬───────────────┬───────────┐
│ Fixture                                │ Minified size │ GZIP size │
├────────────────────────────────────────┼───────────────┼───────────┤
│ makeStaticStyles (runtime)             │ 8.51 kB       │ 3.66 kB   │
├────────────────────────────────────────┼───────────────┼───────────┤
│ makeStyles + mergeClasses (runtime)    │ 22 kB         │ 8.34 kB   │
├────────────────────────────────────────┼───────────────┼───────────┤
│ makeStyles + mergeClasses (build time) │ 2.82 kB       │ 1.34 kB   │
└────────────────────────────────────────┴───────────────┴───────────┘
Completed in 2.75s

✅ Store results (#18322)

To avoid double builds we need to store our data (results for previous runs) somewhere, after discussion with @ling1726 we agreed to Azure Tables as the simplest and $$$ effective option. A storage account, tables and a resource group are completely separate from existing tools.

Current PR (#18322) uses Azure Tables directly on our side, this functionality will be re-implemented as a backend app and will be moved to Azure Functions.

We will currently store only the last build for a base branch (master, v7), this will allow us to implement comparisons locally and on CI.

✅ Local & CI comparison (#18256)

On this step we will focus on bundle-size comparison for CI and locally. The last step is important because no existing tools allow you to understand bundle size impact before pushing to CI.

Functionality will be implemented via an additional command that generates report for CLI & in Markdown:

A sample markdown report (results are random)
Package & Exports Baseline (minified/GZIP) PR Change
react-divider
Divider
17.892 kB
5.83 kB
18.266 kB
5.941 kB
374 B
111 B
react-image
Image
11.521 kB
4.344 kB
10.784 kB
4.238 kB
-737 B
-106 B
react-make-styles
makeStaticStyles (runtime)
8.27 kB
3.566 kB
8.514 kB
3.66 kB
244 B
94 B
react-make-styles
makeStyles + mergeClasses (runtime)
21.926 kB
8.326 kB
22.994 kB
8.841 kB
1.068 kB
515 B
react-make-styles
makeStyles + mergeClasses (build time)
2.67 kB
1.263 kB
2.823 kB
1.342 kB
153 B
79 B

Any failures on increases will not be implemented on this step, only reporting. For reporting we will reuse existing functionality in our pipeline (GithubPRComment@0 task).

🛠 Phase 2

On this phase we will replace existing SizeAuditior with a new bundle size tool.

💭 Phase 3 (to be discussed)

  • Publicly graph the size of each component over time
  • Publicly graph the total size of the library over time

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions