@fimbul-works/bundle-size 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +92 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +73 -0
- package/dist/index.d.ts +97 -0
- package/dist/index.js +158 -0
- package/package.json +75 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 FimbulWorks
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# @fimbul-works/bundle-size
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@fimbul-works/bundle-size)
|
|
4
|
+
[](https://github.com/microsoft/TypeScript)
|
|
5
|
+
[](https://bundlephobia.com/package/@fimbul-works/bundle-size)
|
|
6
|
+
|
|
7
|
+
A minimalistic library for calculating and reporting bundle sizes.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **Minification**: Powered by Terser.
|
|
12
|
+
- **Compression**: Gzip and Brotli support.
|
|
13
|
+
- **Grouped Reports**: Organize files into logical groups.
|
|
14
|
+
- **In-Memory Measurement**: Reports sizes without needing to write archives to disk unless requested.
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pnpm add -D @fimbul-works/bundle-size
|
|
20
|
+
|
|
21
|
+
# Use directly with npx
|
|
22
|
+
npx @fimbul-works/bundle-size
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Usage
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import { calculateBundleSizes } from '@fimbul-works/bundle-size';
|
|
29
|
+
|
|
30
|
+
calculateBundleSizes({
|
|
31
|
+
groups: [
|
|
32
|
+
{
|
|
33
|
+
name: 'Main Bundles',
|
|
34
|
+
include: 'dist/*.js',
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: 'Plugins',
|
|
38
|
+
include: 'plugins/*.js',
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
minify: {
|
|
42
|
+
toplevel: true,
|
|
43
|
+
compress: { passes: 2, ecma: 2020 },
|
|
44
|
+
mangle: { module: true },
|
|
45
|
+
module: true,
|
|
46
|
+
},
|
|
47
|
+
compression: ['gzip', 'brotli'],
|
|
48
|
+
save: ['minify'],
|
|
49
|
+
cleanup: ['gzip', 'brotli']
|
|
50
|
+
});
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Configuration
|
|
54
|
+
|
|
55
|
+
Create a configuration file (`bundle-size.config.(ts|js|mjs|cjs|json)`) in the project root for easy setup:
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"groups": [
|
|
60
|
+
{
|
|
61
|
+
"name": "Main Bundles",
|
|
62
|
+
"include": "dist/*.js",
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"name": "Plugins",
|
|
66
|
+
"include": "dist/plugins/*.js",
|
|
67
|
+
}
|
|
68
|
+
],
|
|
69
|
+
"minify": true
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### `BundleGroup`
|
|
74
|
+
- `name`: string - Display name for the group.
|
|
75
|
+
- `include`: string | string[] - Glob patterns to include.
|
|
76
|
+
- `exclude`: string | string[] - Glob patterns to exclude.
|
|
77
|
+
- `minify`: boolean | TerserOptions - Whether to minify. If `true`, uses top-level `minify` options or defaults.
|
|
78
|
+
|
|
79
|
+
### `BundleSizeOptions`
|
|
80
|
+
- `groups`: BundleGroup[] - Array of groups to process.
|
|
81
|
+
- `compression`: ('gzip' | 'brotli')[] - Compression formats to report.
|
|
82
|
+
- `minify`: boolean | TerserOptions - Default minification settings for groups.
|
|
83
|
+
- `save`: boolean | ('minify' | 'gzip' | 'brotli')[] - Which files to keep on disk.
|
|
84
|
+
- `cleanup`: boolean | ('minify' | 'gzip' | 'brotli')[] - Which files to remove after reporting.
|
|
85
|
+
|
|
86
|
+
## License
|
|
87
|
+
|
|
88
|
+
MIT License - See [LICENSE](LICENSE) file for details.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
Built with 📦 by [FimbulWorks](https://github.com/fimbul-works)
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { access, readFile } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { pathToFileURL } from "node:url";
|
|
5
|
+
import pc from "picocolors";
|
|
6
|
+
import { calculateBundleSizes } from "./index.js";
|
|
7
|
+
/**
|
|
8
|
+
* Loads a configuration file from a specific path
|
|
9
|
+
*/
|
|
10
|
+
async function loadConfigFile(fullPath) {
|
|
11
|
+
if (fullPath.endsWith(".json")) {
|
|
12
|
+
const content = await readFile(fullPath, "utf-8");
|
|
13
|
+
return JSON.parse(content);
|
|
14
|
+
}
|
|
15
|
+
const module = await import(pathToFileURL(fullPath).href);
|
|
16
|
+
return module.default || module;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Searches for a configuration file in the current directory
|
|
20
|
+
*/
|
|
21
|
+
async function findConfig() {
|
|
22
|
+
const names = [
|
|
23
|
+
"bundle-size.config.ts",
|
|
24
|
+
"bundle-size.config.js",
|
|
25
|
+
"bundle-size.config.mjs",
|
|
26
|
+
"bundle-size.config.cjs",
|
|
27
|
+
"bundle-size.config.json",
|
|
28
|
+
];
|
|
29
|
+
for (const name of names) {
|
|
30
|
+
const fullPath = path.join(process.cwd(), name);
|
|
31
|
+
try {
|
|
32
|
+
await access(fullPath);
|
|
33
|
+
return await loadConfigFile(fullPath);
|
|
34
|
+
}
|
|
35
|
+
catch { }
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
async function run() {
|
|
40
|
+
const args = process.argv.slice(2);
|
|
41
|
+
const customConfigPath = args[0];
|
|
42
|
+
let config;
|
|
43
|
+
if (customConfigPath) {
|
|
44
|
+
const fullPath = path.resolve(process.cwd(), customConfigPath);
|
|
45
|
+
try {
|
|
46
|
+
await access(fullPath);
|
|
47
|
+
config = await loadConfigFile(fullPath);
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
console.error(pc.red(`Error: Could not load configuration from "${customConfigPath}"`));
|
|
51
|
+
if (error instanceof Error) {
|
|
52
|
+
console.error(pc.dim(error.message));
|
|
53
|
+
}
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
config = await findConfig();
|
|
59
|
+
}
|
|
60
|
+
if (!config) {
|
|
61
|
+
console.error(pc.red("Error: No configuration found. Create a bundle-size.config.ts/js/json or provide a path as an argument."));
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
await calculateBundleSizes(config);
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
console.error(pc.red("Error calculating bundle sizes:"));
|
|
69
|
+
console.error(error);
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
run();
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { type MinifyOptions } from "terser";
|
|
2
|
+
/**
|
|
3
|
+
* Output type
|
|
4
|
+
*/
|
|
5
|
+
export type OutputType = "minify" | "gzip" | "brotli";
|
|
6
|
+
/**
|
|
7
|
+
* Bundle group
|
|
8
|
+
*/
|
|
9
|
+
export interface BundleGroup {
|
|
10
|
+
/**
|
|
11
|
+
* Group name
|
|
12
|
+
*/
|
|
13
|
+
name: string;
|
|
14
|
+
/**
|
|
15
|
+
* Glob patterns to include
|
|
16
|
+
*/
|
|
17
|
+
include: string | string[];
|
|
18
|
+
/**
|
|
19
|
+
* Glob patterns to exclude
|
|
20
|
+
*/
|
|
21
|
+
exclude?: string | string[];
|
|
22
|
+
/**
|
|
23
|
+
* Whether to minify
|
|
24
|
+
*/
|
|
25
|
+
minify?: boolean | MinifyOptions;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Bundle size options
|
|
29
|
+
*/
|
|
30
|
+
export interface BundleSizeOptions {
|
|
31
|
+
/**
|
|
32
|
+
* Groups of files to process
|
|
33
|
+
*/
|
|
34
|
+
groups: BundleGroup[];
|
|
35
|
+
/**
|
|
36
|
+
* Compression formats to report
|
|
37
|
+
*/
|
|
38
|
+
compression?: ("gzip" | "brotli")[];
|
|
39
|
+
/**
|
|
40
|
+
* Which files to keep on disk
|
|
41
|
+
*/
|
|
42
|
+
save?: boolean | OutputType[];
|
|
43
|
+
/**
|
|
44
|
+
* Which files to remove after reporting
|
|
45
|
+
*/
|
|
46
|
+
cleanup?: boolean | OutputType[];
|
|
47
|
+
/**
|
|
48
|
+
* Default minification settings for groups
|
|
49
|
+
*/
|
|
50
|
+
minify?: boolean | MinifyOptions;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* File size result
|
|
54
|
+
*/
|
|
55
|
+
interface FileSizeResult {
|
|
56
|
+
/**
|
|
57
|
+
* File path
|
|
58
|
+
*/
|
|
59
|
+
file: string;
|
|
60
|
+
/**
|
|
61
|
+
* Original size
|
|
62
|
+
*/
|
|
63
|
+
size: number;
|
|
64
|
+
/**
|
|
65
|
+
* Minified size
|
|
66
|
+
*/
|
|
67
|
+
minified?: number;
|
|
68
|
+
/**
|
|
69
|
+
* Gzipped size
|
|
70
|
+
*/
|
|
71
|
+
gzip?: number;
|
|
72
|
+
/**
|
|
73
|
+
* Brotli size
|
|
74
|
+
*/
|
|
75
|
+
brotli?: number;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Group result
|
|
79
|
+
*/
|
|
80
|
+
interface GroupResult {
|
|
81
|
+
/**
|
|
82
|
+
* Group name
|
|
83
|
+
*/
|
|
84
|
+
name: string;
|
|
85
|
+
/**
|
|
86
|
+
* File size results
|
|
87
|
+
*/
|
|
88
|
+
files: FileSizeResult[];
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Calculates bundle sizes.
|
|
92
|
+
*
|
|
93
|
+
* @param options Bundle size options
|
|
94
|
+
* @returns Promise that resolves to the group results
|
|
95
|
+
*/
|
|
96
|
+
export declare function calculateBundleSizes(options: BundleSizeOptions): Promise<GroupResult[]>;
|
|
97
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { readFile, stat, unlink, writeFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { brotliCompressSync, gzipSync } from "node:zlib";
|
|
4
|
+
import bytes from "bytes";
|
|
5
|
+
import glob from "fast-glob";
|
|
6
|
+
import pc from "picocolors";
|
|
7
|
+
import { minify } from "terser";
|
|
8
|
+
/**
|
|
9
|
+
* Calculates bundle sizes.
|
|
10
|
+
*
|
|
11
|
+
* @param options Bundle size options
|
|
12
|
+
* @returns Promise that resolves to the group results
|
|
13
|
+
*/
|
|
14
|
+
export async function calculateBundleSizes(options) {
|
|
15
|
+
const { groups, compression = ["gzip", "brotli"] } = options;
|
|
16
|
+
const results = [];
|
|
17
|
+
const defaultTerserOptions = {
|
|
18
|
+
toplevel: true,
|
|
19
|
+
compress: { passes: 2, ecma: 2020 },
|
|
20
|
+
mangle: { module: true },
|
|
21
|
+
module: true,
|
|
22
|
+
};
|
|
23
|
+
const isOutputRequested = (option, type) => {
|
|
24
|
+
if (typeof option === "boolean")
|
|
25
|
+
return option;
|
|
26
|
+
if (Array.isArray(option))
|
|
27
|
+
return option.includes(type);
|
|
28
|
+
return false;
|
|
29
|
+
};
|
|
30
|
+
const shouldSave = (type) => isOutputRequested(options.save, type);
|
|
31
|
+
const shouldCleanup = (type) => isOutputRequested(options.cleanup, type);
|
|
32
|
+
const safeUnlink = async (path) => {
|
|
33
|
+
try {
|
|
34
|
+
await unlink(path);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// Ignore errors if file doesn't exist
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
const getMinifyOptions = (minify, undefinedValue) => {
|
|
41
|
+
if (typeof minify === "undefined") {
|
|
42
|
+
return undefinedValue === true ? defaultTerserOptions : undefinedValue;
|
|
43
|
+
}
|
|
44
|
+
if (typeof minify === "object") {
|
|
45
|
+
return minify;
|
|
46
|
+
}
|
|
47
|
+
return defaultTerserOptions;
|
|
48
|
+
};
|
|
49
|
+
// Default minification options
|
|
50
|
+
const defaultMinifyOptions = getMinifyOptions(options.minify, true);
|
|
51
|
+
// Process each group
|
|
52
|
+
for (const group of groups) {
|
|
53
|
+
const groupResult = { name: group.name, files: [] };
|
|
54
|
+
const files = await glob(group.include, {
|
|
55
|
+
ignore: group.exclude ? (Array.isArray(group.exclude) ? group.exclude : [group.exclude]) : [],
|
|
56
|
+
});
|
|
57
|
+
for (const file of files) {
|
|
58
|
+
// Ignore already minified files
|
|
59
|
+
if (file.includes(".min.js")) {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
const minFile = file.replace(/\.js$/, ".min.js");
|
|
63
|
+
// Read the contents and size
|
|
64
|
+
const content = await readFile(file);
|
|
65
|
+
const originalSize = (await stat(file)).size;
|
|
66
|
+
const fileResult = { file, size: originalSize };
|
|
67
|
+
let currentContent = content;
|
|
68
|
+
// Minifiy if requested
|
|
69
|
+
const terserOptions = getMinifyOptions(group.minify, defaultMinifyOptions);
|
|
70
|
+
if (terserOptions) {
|
|
71
|
+
const minified = await minify(content.toString(), terserOptions);
|
|
72
|
+
if (minified.code) {
|
|
73
|
+
currentContent = Buffer.from(minified.code);
|
|
74
|
+
fileResult.minified = currentContent.length;
|
|
75
|
+
if (shouldSave("minify")) {
|
|
76
|
+
await writeFile(minFile, currentContent);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const baseFileForCompressed = terserOptions ? minFile : file;
|
|
81
|
+
// Compression
|
|
82
|
+
if (compression.includes("gzip")) {
|
|
83
|
+
const gzipped = gzipSync(currentContent);
|
|
84
|
+
fileResult.gzip = gzipped.length;
|
|
85
|
+
if (shouldSave("gzip")) {
|
|
86
|
+
await writeFile(`${baseFileForCompressed}.gz`, gzipped);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (compression.includes("brotli")) {
|
|
90
|
+
const brotlied = brotliCompressSync(currentContent);
|
|
91
|
+
fileResult.brotli = brotlied.length;
|
|
92
|
+
if (shouldSave("brotli")) {
|
|
93
|
+
await writeFile(`${baseFileForCompressed}.br`, brotlied);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
groupResult.files.push(fileResult);
|
|
97
|
+
}
|
|
98
|
+
results.push(groupResult);
|
|
99
|
+
}
|
|
100
|
+
// Print results
|
|
101
|
+
printResults(results);
|
|
102
|
+
// Cleanup
|
|
103
|
+
for (const group of results) {
|
|
104
|
+
for (const file of group.files) {
|
|
105
|
+
const minFile = file.file.replace(/\.js$/, ".min.js");
|
|
106
|
+
const baseFileForCompressed = file.minified !== undefined ? minFile : file.file;
|
|
107
|
+
if (shouldCleanup("minify") && file.minified !== undefined) {
|
|
108
|
+
await safeUnlink(minFile);
|
|
109
|
+
}
|
|
110
|
+
if (shouldCleanup("gzip") && file.gzip !== undefined) {
|
|
111
|
+
await safeUnlink(`${baseFileForCompressed}.gz`);
|
|
112
|
+
}
|
|
113
|
+
if (shouldCleanup("brotli") && file.brotli !== undefined) {
|
|
114
|
+
await safeUnlink(`${baseFileForCompressed}.br`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return results;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Print the bundle size results to the console.
|
|
122
|
+
* @param results
|
|
123
|
+
*/
|
|
124
|
+
function printResults(results) {
|
|
125
|
+
const divider = pc.bold(pc.cyan("===================================================================================="));
|
|
126
|
+
console.log(`\n${divider}`);
|
|
127
|
+
console.log(pc.bold(pc.cyan(" Bundle sizes (bytes):")));
|
|
128
|
+
console.log(`${divider}\n`);
|
|
129
|
+
for (const group of results) {
|
|
130
|
+
console.log(pc.bold(pc.yellow(` ${group.name}:`)));
|
|
131
|
+
// Sort files by size descending
|
|
132
|
+
const sortedFiles = [...group.files].sort((a, b) => b.size - a.size);
|
|
133
|
+
for (const file of sortedFiles) {
|
|
134
|
+
const fileName = path.basename(file.file);
|
|
135
|
+
let line = ` ${pc.white(fileName.padEnd(30))} ${pc.green(formatSize(file.size).padStart(10))}`;
|
|
136
|
+
if (file.minified !== undefined) {
|
|
137
|
+
line += ` ${pc.dim("min:")} ${pc.blue(formatSize(file.minified).padStart(8))}`;
|
|
138
|
+
}
|
|
139
|
+
if (file.gzip !== undefined) {
|
|
140
|
+
line += ` ${pc.dim("gz:")} ${pc.magenta(formatSize(file.gzip).padStart(8))}`;
|
|
141
|
+
}
|
|
142
|
+
if (file.brotli !== undefined) {
|
|
143
|
+
line += ` ${pc.dim("br:")} ${pc.cyan(formatSize(file.brotli).padStart(8))}`;
|
|
144
|
+
}
|
|
145
|
+
console.log(line);
|
|
146
|
+
}
|
|
147
|
+
console.log("");
|
|
148
|
+
}
|
|
149
|
+
console.log(`${divider}\n`);
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Format file size.
|
|
153
|
+
* @param size
|
|
154
|
+
* @returns
|
|
155
|
+
*/
|
|
156
|
+
function formatSize(size) {
|
|
157
|
+
return bytes(size, { decimalPlaces: 2 }) || "0 B";
|
|
158
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fimbul-works/bundle-size",
|
|
3
|
+
"description": "A micro-library for calculating bundle sizes with minification and compression support",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"private": false,
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"author": "FimbulWorks <contact@fimbul.works>",
|
|
9
|
+
"homepage": "https://github.com/fimbul-works/bundle-size#readme",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/fimbul-works/bundle-size.git"
|
|
13
|
+
},
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/fimbul-works/bundle-size/issues"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"bundle",
|
|
19
|
+
"bundle-size",
|
|
20
|
+
"bundlesize",
|
|
21
|
+
"minify",
|
|
22
|
+
"gzip",
|
|
23
|
+
"brotli",
|
|
24
|
+
"compression",
|
|
25
|
+
"size",
|
|
26
|
+
"build",
|
|
27
|
+
"cli",
|
|
28
|
+
"reporter",
|
|
29
|
+
"metrics",
|
|
30
|
+
"esbuild",
|
|
31
|
+
"rollup",
|
|
32
|
+
"vite",
|
|
33
|
+
"performance",
|
|
34
|
+
"javascript",
|
|
35
|
+
"typescript"
|
|
36
|
+
],
|
|
37
|
+
"main": "./dist/index.js",
|
|
38
|
+
"types": "./dist/index.d.ts",
|
|
39
|
+
"files": [
|
|
40
|
+
"dist",
|
|
41
|
+
"README.md",
|
|
42
|
+
"LICENSE"
|
|
43
|
+
],
|
|
44
|
+
"bin": {
|
|
45
|
+
"bundle-size": "./dist/cli.js"
|
|
46
|
+
},
|
|
47
|
+
"scripts": {
|
|
48
|
+
"build": "tsc --build --clean && tsc",
|
|
49
|
+
"format": "npx @biomejs/biome format --write src",
|
|
50
|
+
"prepublishOnly": "npm run build"
|
|
51
|
+
},
|
|
52
|
+
"exports": {
|
|
53
|
+
".": "./dist/index.js"
|
|
54
|
+
},
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"bytes": "^3.1.2",
|
|
57
|
+
"fast-glob": "^3.3.3",
|
|
58
|
+
"picocolors": "^1.1.1",
|
|
59
|
+
"terser": "^5.48.0"
|
|
60
|
+
},
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@biomejs/biome": "^2.4.16",
|
|
63
|
+
"@types/bytes": "^3.1.5",
|
|
64
|
+
"@types/node": "^25.9.1",
|
|
65
|
+
"typescript": "^6.0.3"
|
|
66
|
+
},
|
|
67
|
+
"engines": {
|
|
68
|
+
"node": ">=20.0.0"
|
|
69
|
+
},
|
|
70
|
+
"os": [
|
|
71
|
+
"darwin",
|
|
72
|
+
"linux",
|
|
73
|
+
"win32"
|
|
74
|
+
]
|
|
75
|
+
}
|