# preactjs/compressed-size-action architecture

> Architecture diagram of the GitHub repository preactjs/compressed-size-action, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-06-15). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/preactjs/compressed-size-action
- Repository: https://github.com/preactjs/compressed-size-action

## Overview

1. This repository is a single-purpose GitHub Action: it measures compressed bundle-size changes in a pull request and posts the results back to the PR as a comment. The architecture is centered around one action runtime, not a long-running service.

2. The main entrypoint is the JavaScript action at the repo root (`index.js` / `action.yml`), which delegates into the implementation under `src/`. The action is packaged as a Node-based GitHub Action rather than a container action or compiled binary.

3. The core orchestration lives in `src/index.js`. From the README, its job is to:
   - install dependencies using the detected package manager/lockfile or a user-supplied install command,
   - build the current PR checkout,
   - compare against the target/base ref build,
   - compute compressed sizes,
   - format the comparison into a PR comment or console output.

4. The data flow is intentionally local and ephemeral. The action checks out code in the GitHub Actions runner, builds two states of the repository (PR head and base/target ref), compares their generated artifacts, and never uploads bundle data to an external service. The only persisted output is the PR comment in GitHub.

5. File discovery and comparison rules are configurable. The README indicates the action scans for build artifacts using glob patterns, defaults to JavaScript bundles under any `dist/` directory, and filters out source maps and `node_modules`. This makes file selection a distinct subsystem from the build logic.

6. Compression and thresholding are part of the comparison engine. The action can compare raw, gzip, or brotli sizes, or disable compression entirely, and it can ignore tiny deltas below a configurable minimum-change threshold. That means the “change” calculation is separate from the “find files” and “build files” steps.

7. Filenames are normalized before comparison, especially for hashed assets. A `strip-hash` setting rewrites generated filenames so the same logical bundle can be matched across builds even when content hashes differ. This is important for accurate diffing across release-style outputs.

8. Commenting is a separate output boundary from analysis. The action uses a GitHub comment keyed to the PR, and can optionally partition multiple reports with `comment-key` so multiple bundle sets do not overwrite each other. If the PR comes from a fork, it falls back to printing the would-be comment to stdout because of GitHub permission limits.

9. The build/install lifecycle is configurable to fit different repository layouts. The action supports custom install scripts, custom build scripts, and an optional clean step between the base build and PR build. That clean step exists specifically to reset state that `npm ci && npm run build` does not naturally restore in some monorepo or nested-install setups.

10. The helper module at `src/utils.js` likely contains the reusable pieces for file matching, hash stripping, compression/sizing, sorting, and formatting. The presence of `tests/utils.spec.js` and its snapshot file suggests these utilities are deterministic and heavily snapshot-tested, which is consistent with a formatting-heavy CLI/action.

11. The top-level `tests/` directory is focused on unit-level behavior rather than end-to-end GitHub Actions execution. Snapshot tests indicate the repo validates the generated comparison output and helper transformations, which is a good hint that the user-visible PR comment format is part of the public contract.

12. CI is simple and repository-local: `.github/workflows/ci.yml` runs the test suite for the action package. There are no signs of supporting backend services, queues, databases, or separate frontend/backend subsystems—just the action runtime, its utilities, and tests.

Main entry points: [`src/index.js`](https://github.com/preactjs/compressed-size-action/blob/master/src/index.js) (Orchestrator), [`src/utils.js`](https://github.com/preactjs/compressed-size-action/blob/master/src/utils.js) (Helpers), [`tests/utils.spec.js`](https://github.com/preactjs/compressed-size-action/blob/master/tests/utils.spec.js) (Utility tests), [`index.js`](https://github.com/preactjs/compressed-size-action/blob/master/index.js) (Action entry)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_g1["Action runtime"]
  node_n1["Action entry<br/>node action<br/>[index.js]"]
  node_n2["Action config<br/>action spec<br/>[action.yml]"]
  node_n18["Package metadata<br/>node package<br/>[package.json]"]
end

subgraph group_g2["Comparison engine"]
  node_n3["Orchestrator<br/>runtime<br/>[index.js]"]
  node_n4["Helpers<br/>utility lib<br/>[utils.js]"]
  node_n5{{"Install step<br/>lifecycle"}}
  node_n6{{"Build step<br/>lifecycle"}}
  node_n7["Artifact scan<br/>matcher"]
  node_n8["Name normalize<br/>transform"]
  node_n9["Size compare<br/>engine"]
  node_n10(("Delta filter<br/>threshold"))
  node_n11["Comment format<br/>formatter"]
  node_n12["PR comment<br/>github output"]
  node_n13["Stdout fallback<br/>fallback output"]
  node_n14{{"Clean step<br/>lifecycle"}}
end

subgraph group_g3["Verification"]
  node_n15["Utility tests<br/>unit tests<br/>[utils.spec.js]"]
  node_n16["Snapshots<br/>[utils.spec.js.snap]"]
  node_n17["CI workflow<br/>[ci.yml]"]
end

node_n1 -->|"loads"| node_n3
node_n2 -->|"configures"| node_n3
node_n18 -.->|"depends on"| node_n3
node_n3 -->|"installs"| node_n5
node_n3 -->|"builds"| node_n6
node_n6 -.->|"optionally resets"| node_n14
node_n6 -->|"emits artifacts"| node_n7
node_n4 -.->|"matches files"| node_n7
node_n7 -->|"normalizes names"| node_n8
node_n8 -->|"pairs artifacts"| node_n9
node_n9 -->|"filters deltas"| node_n10
node_n10 -->|"summarizes"| node_n11
node_n11 -->|"posts"| node_n12
node_n11 -.->|"falls back to"| node_n13
node_n3 -->|"formats"| node_n11
node_n4 -.->|"sizes"| node_n9
node_n15 -->|"covers"| node_n4
node_n15 -->|"snapshots"| node_n16
node_n17 -->|"runs"| node_n15

click node_n1 "https://github.com/preactjs/compressed-size-action/blob/master/index.js"
click node_n2 "https://github.com/preactjs/compressed-size-action/blob/master/action.yml"
click node_n3 "https://github.com/preactjs/compressed-size-action/blob/master/src/index.js"
click node_n4 "https://github.com/preactjs/compressed-size-action/blob/master/src/utils.js"
click node_n15 "https://github.com/preactjs/compressed-size-action/blob/master/tests/utils.spec.js"
click node_n16 "https://github.com/preactjs/compressed-size-action/blob/master/tests/__snapshots__/utils.spec.js.snap"
click node_n17 "https://github.com/preactjs/compressed-size-action/blob/master/.github/workflows/ci.yml"
click node_n18 "https://github.com/preactjs/compressed-size-action/blob/master/package.json"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_n1,node_n2,node_n18 toneBlue
class node_n3,node_n4,node_n5,node_n6,node_n7,node_n8,node_n9,node_n10,node_n11,node_n12,node_n13,node_n14 toneAmber
class node_n15,node_n16,node_n17 toneMint
```

## Components

### Action runtime

GitHub Action entrypoints and execution flow

- [Action entry](https://github.com/preactjs/compressed-size-action/blob/master/index.js): node action · GitHub Action entrypoint wiring into the implementation · `index.js`
- [Action config](https://github.com/preactjs/compressed-size-action/blob/master/action.yml): action spec · Action metadata and inputs definition · `action.yml`
- [Package metadata](https://github.com/preactjs/compressed-size-action/blob/master/package.json): node package · Dependencies, scripts, and package settings for the action · `package.json`

### Comparison engine

Build, discover, compare, and format bundle-size results

- [Orchestrator](https://github.com/preactjs/compressed-size-action/blob/master/src/index.js): runtime · Main action runtime that coordinates install, build, compare, and reporting · `src/index.js`
- [Helpers](https://github.com/preactjs/compressed-size-action/blob/master/src/utils.js): utility lib · Reusable file matching, normalization, sizing, and formatting helpers · `src/utils.js`
- **Install step**: lifecycle · Detects or runs package installation before builds
- **Build step**: lifecycle · Builds the base ref and pull request checkout
- **Artifact scan**: matcher · Finds generated bundle artifacts with glob-based rules and filters
- **Name normalize**: transform · Strips hashes and aligns filenames across builds
- **Size compare**: engine · Computes raw, gzip, brotli, or uncompressed size deltas
- **Delta filter**: threshold · Suppresses tiny changes below the minimum-change threshold
- **Comment format**: formatter · Renders the comparison for PR comment or console output
- **PR comment**: github output · Writes the report back to the pull request as a comment
- **Stdout fallback**: fallback output · Prints the would-be comment when GitHub permissions block commenting
- **Clean step**: lifecycle · Optional reset between base and PR builds for tricky repo layouts

### Verification

Tests and CI coverage for deterministic helpers and output

- [Utility tests](https://github.com/preactjs/compressed-size-action/blob/master/tests/utils.spec.js): unit tests · Snapshot-driven tests for helper behavior and output stability · `tests/utils.spec.js`
- [Snapshots](https://github.com/preactjs/compressed-size-action/blob/master/tests/__snapshots__/utils.spec.js.snap): test snapshots · Expected snapshots for helper and formatting transformations · `tests/__snapshots__/utils.spec.js.snap`
- [CI workflow](https://github.com/preactjs/compressed-size-action/blob/master/.github/workflows/ci.yml): ci · Repository workflow that runs the test suite · `.github/workflows/ci.yml`

## Connections

- Action entry → Orchestrator: loads · Root entry delegates to the implementation
- Action config → Orchestrator: configures · Action inputs and runtime wiring feed the orchestrator
- Package metadata → Orchestrator: depends on · Package scripts and dependencies support the action runtime
- Orchestrator → Install step: installs · Prepares repository dependencies before building
- Orchestrator → Build step: builds · Runs the base and PR builds
- Build step → Clean step: optionally resets · Can clean state between the two build phases
- Build step → Artifact scan: emits artifacts · Build outputs are scanned after generation
- Helpers → Artifact scan: matches files · Helper logic provides glob and filtering behavior
- Artifact scan → Name normalize: normalizes names · Matched files are aligned across build states
- Name normalize → Size compare: pairs artifacts · Normalized filenames feed comparison
- Size compare → Delta filter: filters deltas · Tiny size changes are suppressed when configured
- Delta filter → Comment format: summarizes · Filtered results are converted into a report
- Comment format → PR comment: posts · Primary output is a PR comment
- Comment format → Stdout fallback: falls back to · When commenting is unavailable, print the report
- Orchestrator → Comment format: formats · Orchestrator sends comparison data to the formatter
- Helpers → Size compare: sizes · Helpers provide compression and size calculation routines
- Utility tests → Helpers: covers · Tests exercise the utility module
- Utility tests → Snapshots: snapshots · Snapshot assertions lock formatting and transforms
- CI workflow → Utility tests: runs · CI executes the unit test suite
