Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
202 changes: 202 additions & 0 deletions packages/bundlecheck/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ A CLI tool to check the bundle size of npm packages, similar to [bundlephobia.co
- Custom npm registry support (for private registries)
- Fast bundling using esbuild (with pnpm support)
- **Local caching** for faster repeated lookups (SQLite-based, max 100 entries)
- **Library API** for programmatic usage in Node.js applications

## Installation

Expand Down Expand Up @@ -152,6 +153,207 @@ bundlecheck express # auto-detects "node" from package.json engines
bundlecheck lodash --force
```

## Programmatic Usage (Library API)

In addition to the CLI, `@node-cli/bundlecheck` can be used as a library in your Node.js code.

### Installation

```bash
npm install @node-cli/bundlecheck
```

### Basic Usage

```js
import { getBundleStats, getBundleTrend, getPackageVersions } from "@node-cli/bundlecheck";

// Get bundle stats for a single package
const stats = await getBundleStats({
package: "@mantine/core@7.0.0",
});
console.log(stats);
// {
// packageName: "@mantine/core",
// packageVersion: "7.0.0",
// rawSize: 234567,
// gzipSize: 45678,
// rawSizeFormatted: "229.07 kB",
// gzipSizeFormatted: "44.61 kB",
// exports: [],
// externals: ["react", "react-dom"],
// dependencies: ["@floating-ui/react", ...],
// platform: "browser",
// gzipLevel: 5,
// fromCache: false
// }

// Check specific exports (tree-shaking)
const buttonStats = await getBundleStats({
package: "@mantine/core",
exports: ["Button", "Input"],
});
console.log(buttonStats.gzipSizeFormatted); // "12.3 kB"

// Get bundle size trend across versions
const trend = await getBundleTrend({
package: "@mantine/core",
versionCount: 5,
});
console.log(trend);
// {
// packageName: "@mantine/core",
// versions: [
// { version: "7.0.0", rawSize: 234567, gzipSize: 45678, rawSizeFormatted: "229.07 kB", ... },
// { version: "6.0.0", rawSize: 220000, gzipSize: 42000, ... },
// ...
// ],
// change: {
// fromVersion: "5.0.0",
// toVersion: "7.0.0",
// rawDiff: 14567,
// rawPercent: 6.6,
// rawDiffFormatted: "+14.23 kB",
// gzipDiff: 3678,
// gzipPercent: 8.7,
// gzipDiffFormatted: "+3.59 kB"
// }
// }

// Get available versions for a package
const versions = await getPackageVersions({
package: "@mantine/core",
});
console.log(versions.tags.latest); // "7.0.0"
console.log(versions.versions.slice(0, 5)); // ["7.0.0", "6.0.21", "6.0.20", ...]
```

### API Reference

#### `getBundleStats(options)`

Get bundle size statistics for a single package.

**Options:**

| Option | Type | Default | Description |
| ------------ | ----------------------------- | ---------- | -------------------------------------------------------- |
| `package` | `string` | (required) | Package name with optional version (e.g., `lodash@4.17.0`) |
| `exports` | `string[]` | `undefined`| Specific exports to measure (tree-shaking) |
| `external` | `string[]` | `undefined`| Additional packages to mark as external |
| `noExternal` | `boolean` | `false` | Bundle everything including default externals |
| `gzipLevel` | `number` | `5` | Gzip compression level (1-9) |
| `registry` | `string` | `undefined`| Custom npm registry URL |
| `platform` | `"browser" \| "node" \| "auto"` | `"auto"` | Target platform |
| `force` | `boolean` | `false` | Bypass cache |

**Returns:** `Promise<BundleStats>`

```ts
type BundleStats = {
packageName: string; // Display name (may include subpath)
packageVersion: string; // Resolved version
exports: string[]; // Exports analyzed
rawSize: number; // Raw size in bytes
gzipSize: number | null; // Gzip size in bytes (null for node platform)
gzipLevel: number; // Compression level used
externals: string[]; // External packages
dependencies: string[]; // Package dependencies
platform: "browser" | "node";
rawSizeFormatted: string; // Human-readable (e.g., "45.2 kB")
gzipSizeFormatted: string | null;
fromCache: boolean; // Whether result was from cache
};
```

#### `getBundleTrend(options)`

Get bundle size trend across multiple versions.

**Options:**

| Option | Type | Default | Description |
| -------------- | ----------------------------- | ---------- | -------------------------------------------------------- |
| `package` | `string` | (required) | Package name (version ignored if provided) |
| `versionCount` | `number` | `5` | Number of versions to analyze |
| `exports` | `string[]` | `undefined`| Specific exports to measure |
| `external` | `string[]` | `undefined`| Additional packages to mark as external |
| `noExternal` | `boolean` | `false` | Bundle everything including default externals |
| `gzipLevel` | `number` | `5` | Gzip compression level (1-9) |
| `registry` | `string` | `undefined`| Custom npm registry URL |
| `platform` | `"browser" \| "node" \| "auto"` | `"auto"` | Target platform |
| `force` | `boolean` | `false` | Bypass cache |

**Returns:** `Promise<BundleTrend>`

```ts
type BundleTrend = {
packageName: string;
versions: TrendVersionResult[]; // Results for each version (newest first)
change: TrendChange | null; // Change between oldest and newest
};

type TrendVersionResult = {
version: string;
rawSize: number;
gzipSize: number | null;
rawSizeFormatted: string;
gzipSizeFormatted: string | null;
};

type TrendChange = {
fromVersion: string;
toVersion: string;
rawDiff: number; // Positive = increase, negative = decrease
rawPercent: number | null; // null if oldest size was 0
rawDiffFormatted: string; // e.g., "+5.2 kB" or "-1.3 kB"
gzipDiff: number | null;
gzipPercent: number | null; // null if not applicable or oldest size was 0
gzipDiffFormatted: string | null;
};
```

#### `getPackageVersions(options)`

Get available versions for an npm package.

**Options:**

| Option | Type | Default | Description |
| ---------- | -------- | ---------- | ---------------------------- |
| `package` | `string` | (required) | Package name |
| `registry` | `string` | `undefined`| Custom npm registry URL |

**Returns:** `Promise<PackageVersions>`

```ts
type PackageVersions = {
versions: string[]; // All versions (newest first)
tags: Record<string, string>; // Dist tags (e.g., { latest: "7.0.0" })
};
```

### Utility Functions

```js
import { formatBytes, parsePackageSpecifier, clearCache, getCacheCount } from "@node-cli/bundlecheck";

// Format bytes to human-readable string
formatBytes(1024); // "1 kB"
formatBytes(1536); // "1.5 kB"

// Parse a package specifier
parsePackageSpecifier("@scope/name@1.0.0");
// { name: "@scope/name", version: "1.0.0" }

parsePackageSpecifier("@scope/name/subpath@2.0.0");
// { name: "@scope/name", version: "2.0.0", subpath: "subpath" }

// Cache management
getCacheCount(); // Returns number of cached entries
clearCache(); // Clears all cached results
```

## How It Works

1. Creates a temporary directory
Expand Down
3 changes: 2 additions & 1 deletion packages/bundlecheck/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
"description": "CLI tool to check the bundle size of npm packages (like bundlephobia)",
"type": "module",
"types": "./dist/index.d.ts",
"main": "./dist/index.js",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/bundler.js"
"import": "./dist/index.js"
}
},
"bin": "dist/bundlecheck.js",
Expand Down
Loading