https://github.com/ext/artifact-size-analyzer
Zero-opinion tool to analyze and compare artifact sizes across branches and CI runs.
https://github.com/ext/artifact-size-analyzer
artifact build bundle ci pull-requests size
Last synced: 5 months ago
JSON representation
Zero-opinion tool to analyze and compare artifact sizes across branches and CI runs.
- Host: GitHub
- URL: https://github.com/ext/artifact-size-analyzer
- Owner: ext
- Created: 2025-12-07T01:17:16.000Z (7 months ago)
- Default Branch: main
- Last Pushed: 2026-01-11T13:38:44.000Z (6 months ago)
- Last Synced: 2026-01-11T14:59:45.342Z (6 months ago)
- Topics: artifact, build, bundle, ci, pull-requests, size
- Language: TypeScript
- Homepage:
- Size: 676 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Funding: .github/FUNDING.yml
Awesome Lists containing this project
README
# Artifact size analyzer
A small, zero-opinion tool to analyze and compare the sizes of build artifacts across branches and CI runs.
Ideal for pull requests — it highlights size regressions and tracks compressed and uncompressed artifact sizes.
- ✅ Configurable: include/exclude files and compression algorithms
- ✅ Agnostic: works with any language or toolchain
- ✅ Multi-artifact: measure multiple artifacts in one pass
- ✅ Outputs: JSON, Markdown, and plain text (for Actions, CLI, and API)

## Table of Contents
- [Installation](#installation)
- [Configuration file](#configuration-file)
- [Using with GitHub Actions](#using-with-github-actions)
- [Using with CLI](#using-with-cli)
- [Using with API](#using-with-api)
- [Development](#development)
## Installation
Install as a dev dependency (recommended):
```bash
npm install --save-dev artifact-size-analyzer
```
## Configuration file
The config file describes artifacts to analyze.
```json
{
"artifacts": [
{
"id": "app",
"name": "app",
"include": "dist/**/*.js"
}
]
}
```
### Options
#### `artifacts[].id`
Type: `string`
Required: yes
Unique identifier for this artifact.
#### `artifacts[].name`
Type: `string`
Required: yes
Display name for this artifact.
#### `artifacts[].include`
Type: `string | string[]`
Required: no
Default: `[]`
Files to include for this artifact (globs supported).
#### `artifacts[].exclude`
Type: `string | string[]`
Required: no
Default: `[]`
Files to exclude for this artifact (globs supported).
#### `artifacts[].compression`
Type: `string | string[] | false`
Required: no
Default: `["gzip", "brotli"]`
Compression algorithm(s) to enable for this artifact or `false` to disable compression.
Supported compression algorithms:
- `gzip`
- `brotli`
## Using with GitHub Actions
The recommended pattern is three jobs:
- **Analyze (base)**: on the pull request target branch run the `analyze` action to produce a baseline.
- **Analyze (current)**: on the PR head ref, run the `analyze` action to produce artifact data for the current commit.
- **Compare**: run the `compare` action to compare the two artifacts.
> [!IMPORTANT]
> Both the `analyze` and `compare` actions assume you perform the `checkout` and `setup-node` steps in the workflow (see example workflow below).
On target branch:
```yaml
- name: Run analyzer
uses: ext/artifact-size-analyzer/analyze@v1
with:
config-file: ./example-config.json
artifact-name: base-size
```
On head branch:
```yaml
- name: Run analyzer
uses: ext/artifact-size-analyzer/analyze@v1
with:
config-file: ./example-config.json
artifact-name: current-size
```
To compare:
```yaml
- name: Compare results
id: compare
uses: ext/artifact-size-analyzer/compare@v1
with:
base-artifact: base-size
current-artifact: current-size
```
Example workflow:
artifact-size.yml
```yaml
name: Artifact size
on:
pull_request:
types: [opened, synchronize, reopened]
jobs:
analyze-base:
name: Analyze (base)
runs-on: ubuntu-latest
steps:
- name: Checkout target branch
uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.base.ref }}
- name: Setup Node.js
uses: actions/setup-node@v6
- name: Install & build
run: |
npm ci
npm run build
- name: Run analyzer
uses: ext/artifact-size-analyzer/analyze@v1
with:
config-file: ./example-config.json
artifact-name: base-size
analyze-current:
name: Analyze (current)
runs-on: ubuntu-latest
steps:
- name: Checkout head ref
uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.head.ref }}
- name: Setup Node.js
uses: actions/setup-node@v6
- name: Install & build
run: |
npm ci
npm run build
- name: Run analyzer (current)
uses: ext/artifact-size-analyzer/analyze@v1
with:
config-file: ./example-config.json
artifact-name: current-size
compare:
name: Compare
runs-on: ubuntu-latest
needs: [analyze-base, analyze-current]
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v6
- name: Compare results
id: compare
uses: ext/artifact-size-analyzer/compare@v1
with:
base-artifact: base-size
current-artifact: current-size
- name: Print markdown
run: |
echo "Compare markdown output:"
echo "========================"
echo "${{ steps.compare.outputs.markdown }}"
```
The output from the `compare` action can be used in a pull request comment, this example uses [`marocchino/sticky-pull-request-comment`](https://github.com/marocchino/sticky-pull-request-comment) but you can use any you like.
````yaml
- name: Post sticky PR comment
uses: marocchino/sticky-pull-request-comment@v2
with:
header: artifact-size-analyzer
message: |
${{ steps.compare.outputs.markdown }}
Raw JSON
```json
${{ steps.compare.outputs.json }}
```
````
### Analyze inputs
#### `artifact-name`
Type: `string`
Required: yes
Name of the GitHub artifact to upload.
#### `config-file`
Type: `string`
Required: yes
Path to the artifact configuration.
#### `output-file`
Type: `string`
Required: no
Default: `temp/artifact-size.json`
Path to the output file to be produced by the analyzer.
Can optionally specify the format as a prefix `format:filename`, where `format` is `json`, `markdown`, or `text`.
To use the `compare` action the format must be `json`.
#### `no-header`
Type: `boolean`
Required: no
Default: `false`
When set to `true`, disables the header in output for formats with headers such as Markdown.
Use this when you want to prepend your own heading or other content before the size table.
#### `version`
Type: `string`
Required: no
Optional npm package version (e.g. `1.2.3`).
When provided, the action runs `npx artifact-size-analyzer@`.
By default it uses the installed version.
#### `config-from`
Type: `string`
Required: no
Default: `head`
Which branch to use for the configuration file:
- `head`: Uses the PR head branch (default)
- `target`: Uses the PR target branch
- `local`: Uses the currently checked out branch
### Compare inputs
#### `base-artifact`
Type: `string`
Required: yes
GitHub artifact name for the base run (uploaded by `analyze`).
#### `current-artifact`
Type: `string`
Required: yes
GitHub artifact name for the current run (uploaded by `analyze`).
#### `base-name`
Type: `string`
Required: no
Default: `artifact-size.json`
File name inside the base artifact that contains the analyzer output.
This should match the filename from the `output-file` input of the analyzer action.
Note: `base-name` and `current-name` refer to the path of the analyzer file inside the uploaded artifact; they must match the path passed to `analyze`'s `--output-file`.
#### `current-name`
Type: `string`
Required: no
Default: `artifact-size.json`
File name inside the current artifact that contains the analyzer output.
This should match the filename from the `output-file` input of the analyzer action.
#### `version`
Type: `string`
Required: no
Optional npm package version (e.g. `1.2.3`).
When provided, the action runs `npx artifact-size-analyzer@`.
By default it uses the installed version.
#### `no-header`
Type: `boolean`
Required: no
Default: `false`
When set to `true`, disables the header in output for formats with headers such as Markdown.
Use this when you want to prepend your own heading or other content before the size table.
#### `unchanged`
Type: `string`
Required: no
Default: `collapse`
Controls how artifacts with unchanged sizes are handled:
- `show`: Display all artifacts
- `hide`: Hide unchanged artifacts from output
- `collapse`: Show unchanged artifacts in a collapsible `` section (default)
Use `collapse` for pull request comments to keep the main table focused while still showing all artifacts in an expandable section.
### Compare outputs
#### `json`
Type: `string`
The comparison result formatted as JSON.
#### `markdown`
Type: `string`
The comparison result formatted as Markdown.
#### `text`
Type: `string`
The comparison result formatted as plain text.
## Using with CLI
Create a baseline (on the default branch):
```bash
npx artifact-size-analyzer analyze -c example-config.json -f json -o temp/base.json
```
Analyze current artifact(s) (on the feature branch):
```bash
npx artifact-size-analyzer analyze -c example-config.json -f json -o temp/current.json
```
Compare the results:
```bash
npx artifact-size-analyzer compare --base temp/base.json --current temp/current.json
```
### Usage
```bash
npx artifact-size-analyzer [options]
```
where `command` is one of:
- `analyze`: Analyze artifacts defined in a config file.
- `compare`: Compare two previously saved analysis outputs.
### Analyze
Analyze artifacts from a config file and print results or write to a file.
```bash
npx artifact-size-analyzer analyze -c example-config.json
npx artifact-size-analyzer analyze -c example-config.json -f json -o temp/base.json
```
Options:
- `-c, --config-file `: Path to the config file (required)
- `-f, --format `: Output format (default: `text`)
- `-o, --output-file `: Write output to file instead of stdout. Can be specified multiple times. If `format` is omitted the value from `--format` is used.
### Compare
Compare two saved results and print the diff.
The files should be the JSON outputs produced by `analyze -f json`.
```bash
npx artifact-size-analyzer compare --base base.json --current current.json -f text
```
Options:
- `--base `: Baseline JSON file produced by `analyze` (required)
- `--current `: Current JSON file produced by `analyze` (required)
- `-f, --format `: Output format (default: `text`)
- `--unchanged `: Control how artifacts with unchanged sizes are handled (default: `show`)
- `show`: Display all artifacts
- `hide`: Hide unchanged artifacts from output
- `collapse`: Show unchanged artifacts in a collapsible `` section
- `-o, --output-file `: Write output to file instead of stdout
## Using with API
Programmatic usage is supported via the library exports.
To analyze an artifact:
```ts
import { analyzeArtifact } from "artifact-size-analyzer";
/* compression algorithm options */
const compression = {
gzip: false,
brotli: false,
};
/* artifact configuration (similar to the configuration file) */
const artifact = {
id: "dist",
name: "dist",
include: ["dist/**/*.js"],
exclude: [],
};
/* analyzes the configured artifact */
const result = await analyzeArtifact(artifact, { cwd: process.cwd(), compression });
console.log("Result:", result);
```
To compare two artifacts:
```ts
import fs from "node:fs/promises";
import { type ArtifactSize, compareArtifact } from "artifact-size-analyzer";
/* previously saved output from `analyzeArtifact()` */
const base = JSON.parse(await fs.readFile("base.json", "utf8")) as ArtifactSize;
const current = JSON.parse(await fs.readFile("current.json", "utf8")) as ArtifactSize;
/* compares the two artifacts */
const result = compareArtifact(base, current);
console.log("Result:", result);
```
You can format the output of `analyzeArtifact` and `compareArtifact()` using `formatArtifact()` and `formatDiff()`:
```ts
import { formatDiff } from "artifact-size-analyzer";
const output = formatDiff([result], "markdown");
console.log(output);
```
Other noteworthy functions:
- `readConfigFile()` reads, validates and normalizes a configuration file.
- `compareArtifacts()` takes two arrays of base and current artifacts and runs `compareArtifact()` on each pair (based on `id`).
## Development
Build the project locally:
```bash
npm install
npm run build
```
Run tests and linting during development:
```bash
npm test
npm run eslint
npm run prettier:check
```