@node-cli/bundlesize 4.3.0 → 4.5.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/README.md +50 -0
- package/dist/defaults.d.ts +1 -0
- package/dist/defaults.js +1 -0
- package/dist/defaults.js.map +1 -1
- package/dist/reportStats.js +14 -2
- package/dist/reportStats.js.map +1 -1
- package/package.json +3 -2
- package/schemas/bundlesize.config.schema.json +151 -0
package/README.md
CHANGED
|
@@ -14,6 +14,39 @@
|
|
|
14
14
|
|
|
15
15
|
A configuration file must be provided via the `-c` parameter.
|
|
16
16
|
|
|
17
|
+
### JSON Schema Support
|
|
18
|
+
|
|
19
|
+
For IDE autocompletion and validation, you can add a `$schema` property to your configuration file:
|
|
20
|
+
|
|
21
|
+
```js
|
|
22
|
+
export default {
|
|
23
|
+
$schema:
|
|
24
|
+
"https://cdn.jsdelivr.net/npm/@node-cli/bundlesize/schemas/bundlesize.config.schema.json",
|
|
25
|
+
sizes: [
|
|
26
|
+
{
|
|
27
|
+
path: "dist/bundle.js",
|
|
28
|
+
limit: "10 kB"
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
};
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
This provides:
|
|
35
|
+
|
|
36
|
+
- Autocompletion for configuration options
|
|
37
|
+
- Inline documentation for each property
|
|
38
|
+
- Validation of configuration values
|
|
39
|
+
|
|
40
|
+
**Note**: For a specific version of the schema, use:
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
https://cdn.jsdelivr.net/npm/@node-cli/bundlesize@VERSION/schemas/bundlesize.config.schema.json
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Configuration Options
|
|
47
|
+
|
|
48
|
+
### Configuration Options
|
|
49
|
+
|
|
17
50
|
For the size option, it must export an object named "size" which is an array of objects with the following properties:
|
|
18
51
|
|
|
19
52
|
- `path`: the path to the file to check
|
|
@@ -26,6 +59,7 @@ For the report option, it must export an object named "report" which is an objec
|
|
|
26
59
|
- `previous`: the previous path to the report to compare against (required, string)
|
|
27
60
|
- `current`: the current path to the report to compare against (required, string)
|
|
28
61
|
- `columns`: the columns to display (optional, array of objects)
|
|
62
|
+
- `threshold`: the minimum gzip size change in bytes to consider as a change (optional, number, defaults to 0). Changes below this threshold are treated as no change.
|
|
29
63
|
|
|
30
64
|
## Examples
|
|
31
65
|
|
|
@@ -184,6 +218,22 @@ export default {
|
|
|
184
218
|
};
|
|
185
219
|
```
|
|
186
220
|
|
|
221
|
+
#### Simple report with custom threshold
|
|
222
|
+
|
|
223
|
+
By default, all gzip size changes are reported. You can set a threshold to ignore small changes:
|
|
224
|
+
|
|
225
|
+
```js
|
|
226
|
+
export default {
|
|
227
|
+
report: {
|
|
228
|
+
threshold: 10, // ignore changes smaller than 10 bytes
|
|
229
|
+
prev: "stats/previous.json",
|
|
230
|
+
current: "stats/current.json"
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
**Note on threshold with subgroups**: When using subgroup headers, the threshold is applied consistently. If individual file changes are below the threshold (and thus treated as zero), the sub-bundle total will also reflect this. For example, if file A changes by +3 bytes and file B changes by +4 bytes with a threshold of 5, both individual changes are ignored, and the sub-bundle will show no change (even though the raw total would be +7 bytes).
|
|
236
|
+
|
|
187
237
|
#### Report with subgroup headers (multiple tables)
|
|
188
238
|
|
|
189
239
|
You can interleave header objects inside the `sizes` array to break the report output into multiple markdown tables. Each header object must contain a `header` property (any markdown heading is allowed). A sub-bundle total line will be printed after each group along with its diff to previous stats (if available), followed by the overall bundle size and status at the end.
|
package/dist/defaults.d.ts
CHANGED
package/dist/defaults.js
CHANGED
package/dist/defaults.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/defaults.ts"],"sourcesContent":["/* istanbul ignore file */\n\nexport const defaultFlags = {\n\tboring: false,\n\tconfiguration: \"\",\n\tsilent: false,\n\ttype: \"size\",\n\tforce: false,\n};\n"],"names":["defaultFlags","boring","configuration","silent","type","force"],"mappings":"AAAA,wBAAwB,GAExB,OAAO,MAAMA,eAAe;IAC3BC,QAAQ;IACRC,eAAe;IACfC,QAAQ;IACRC,MAAM;IACNC,OAAO;AACR,EAAE"}
|
|
1
|
+
{"version":3,"sources":["../src/defaults.ts"],"sourcesContent":["/* istanbul ignore file */\n\nexport const defaultFlags = {\n\tboring: false,\n\tconfiguration: \"\",\n\tsilent: false,\n\ttype: \"size\",\n\tforce: false,\n};\n\nexport const DEFAULT_THRESHOLD = 0;\n"],"names":["defaultFlags","boring","configuration","silent","type","force","DEFAULT_THRESHOLD"],"mappings":"AAAA,wBAAwB,GAExB,OAAO,MAAMA,eAAe;IAC3BC,QAAQ;IACRC,eAAe;IACfC,QAAQ;IACRC,MAAM;IACNC,OAAO;AACR,EAAE;AAEF,OAAO,MAAMC,oBAAoB,EAAE"}
|
package/dist/reportStats.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { basename, dirname, join } from "node:path";
|
|
2
2
|
import bytes from "bytes";
|
|
3
|
+
import { DEFAULT_THRESHOLD } from "./defaults.js";
|
|
3
4
|
import { addMDrow, formatFooter, getMostRecentVersion, getOutputFile, percentFormatter, readJSONFile, validateConfigurationFile } from "./utilities.js";
|
|
4
5
|
const isHeaderEntry = (entry)=>"header" in entry;
|
|
5
6
|
export const reportStats = async ({ flags })=>{
|
|
@@ -44,6 +45,7 @@ export const reportStats = async ({ flags })=>{
|
|
|
44
45
|
let limitReached = false;
|
|
45
46
|
let overallDiff = 0;
|
|
46
47
|
let totalGzipSize = 0;
|
|
48
|
+
const threshold = configuration.report.threshold ?? DEFAULT_THRESHOLD;
|
|
47
49
|
const headerString = configuration.report.header || "## Bundle Size";
|
|
48
50
|
const footerFormatter = configuration.report.footer || formatFooter;
|
|
49
51
|
const columns = configuration.report.columns || [
|
|
@@ -103,13 +105,15 @@ export const reportStats = async ({ flags })=>{
|
|
|
103
105
|
}
|
|
104
106
|
}
|
|
105
107
|
let subGroupAccumulatedSize = 0;
|
|
108
|
+
let subGroupAccumulatedDiff = 0;
|
|
106
109
|
let subGroupAccumulatedPrevSize = 0;
|
|
107
110
|
let hasSubGroup = false;
|
|
108
111
|
const flushSubGroup = ()=>{
|
|
109
112
|
if (!hasSubGroup) {
|
|
110
113
|
return;
|
|
111
114
|
}
|
|
112
|
-
|
|
115
|
+
// Use the accumulated thresholded diff directly
|
|
116
|
+
const diff = subGroupAccumulatedDiff;
|
|
113
117
|
let diffString = "";
|
|
114
118
|
if (diff !== 0 && subGroupAccumulatedPrevSize !== 0) {
|
|
115
119
|
const sign = diff > 0 ? "+" : "-";
|
|
@@ -123,6 +127,7 @@ export const reportStats = async ({ flags })=>{
|
|
|
123
127
|
})}${diffString}`, "");
|
|
124
128
|
}
|
|
125
129
|
subGroupAccumulatedSize = 0;
|
|
130
|
+
subGroupAccumulatedDiff = 0;
|
|
126
131
|
subGroupAccumulatedPrevSize = 0;
|
|
127
132
|
hasSubGroup = false;
|
|
128
133
|
};
|
|
@@ -147,10 +152,16 @@ export const reportStats = async ({ flags })=>{
|
|
|
147
152
|
}
|
|
148
153
|
let diffString = "";
|
|
149
154
|
let previousFileSizeGzip = 0;
|
|
155
|
+
let thresholdedDiff = 0;
|
|
150
156
|
if (previousStats && previousVersion) {
|
|
151
157
|
const previousFileStats = previousStats.data[previousVersion] && previousStats.data[previousVersion][key];
|
|
152
158
|
previousFileSizeGzip = previousFileStats?.fileSizeGzip || 0;
|
|
153
|
-
|
|
159
|
+
let diff = item.fileSizeGzip - previousFileSizeGzip;
|
|
160
|
+
// Apply threshold: if the absolute diff is below threshold, treat as no change
|
|
161
|
+
if (Math.abs(diff) < threshold) {
|
|
162
|
+
diff = 0;
|
|
163
|
+
}
|
|
164
|
+
thresholdedDiff = diff;
|
|
154
165
|
overallDiff += diff;
|
|
155
166
|
diffString = diff === 0 || diff === item.fileSizeGzip ? "" : ` (${diff > 0 ? "+" : "-"}${bytes(Math.abs(diff), {
|
|
156
167
|
unitSeparator: " "
|
|
@@ -158,6 +169,7 @@ export const reportStats = async ({ flags })=>{
|
|
|
158
169
|
}
|
|
159
170
|
totalGzipSize += item.fileSizeGzip;
|
|
160
171
|
subGroupAccumulatedSize += item.fileSizeGzip;
|
|
172
|
+
subGroupAccumulatedDiff += thresholdedDiff;
|
|
161
173
|
subGroupAccumulatedPrevSize += previousFileSizeGzip;
|
|
162
174
|
hasSubGroup = true;
|
|
163
175
|
rowsMD.push(addMDrow({
|
package/dist/reportStats.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/reportStats.ts"],"sourcesContent":["import { basename, dirname, join } from \"node:path\";\nimport bytes from \"bytes\";\nimport type { FooterProperties } from \"./utilities.js\";\nimport {\n\taddMDrow,\n\tformatFooter,\n\tgetMostRecentVersion,\n\tgetOutputFile,\n\tpercentFormatter,\n\treadJSONFile,\n\tvalidateConfigurationFile,\n} from \"./utilities.js\";\n\ntype ReportConfiguration = {\n\tcurrent: string;\n\tprevious: string;\n\theader?: string;\n\tfooter?: (arguments_: FooterProperties) => string;\n\tcolumns?: { [key: string]: string }[];\n};\n\ninterface HeaderSizeEntry {\n\theader: string;\n}\ninterface FileSizeEntry {\n\tpath: string;\n\tlimit: string;\n\talias?: string;\n}\ntype SizesConfiguration = Array<HeaderSizeEntry | FileSizeEntry>;\n\nconst isHeaderEntry = (\n\tentry: HeaderSizeEntry | FileSizeEntry,\n): entry is HeaderSizeEntry => \"header\" in entry;\n\ntype ReportCompare = {\n\tdata: string;\n\texitCode: number;\n\texitMessage: string;\n\toutputFile: string;\n};\n\nexport const reportStats = async ({ flags }): Promise<ReportCompare> => {\n\tconst result: ReportCompare = {\n\t\texitCode: 0,\n\t\texitMessage: \"\",\n\t\toutputFile: \"\",\n\t\tdata: \"\",\n\t};\n\n\tlet previousStats, previousVersion: string;\n\tconst isValidConfigResult = validateConfigurationFile(flags.configuration);\n\tif (isValidConfigResult.exitMessage !== \"\") {\n\t\treturn { ...result, ...isValidConfigResult };\n\t}\n\n\tconst configurationFile = isValidConfigResult.data;\n\tconst outputFile = getOutputFile(flags.output);\n\tresult.outputFile = outputFile;\n\n\tconst configuration: {\n\t\treport: ReportConfiguration;\n\t\tsizes?: SizesConfiguration;\n\t} = await import(configurationFile).then((m) => m.default);\n\n\tconst currentStats = readJSONFile(\n\t\tjoin(dirname(configurationFile), configuration.report.current),\n\t);\n\tif (currentStats.exitMessage !== \"\") {\n\t\treturn { ...result, ...currentStats };\n\t}\n\n\ttry {\n\t\tpreviousStats = readJSONFile(\n\t\t\tjoin(dirname(configurationFile), configuration.report.previous),\n\t\t);\n\t\tif (previousStats.exitMessage !== \"\") {\n\t\t\treturn { ...result, ...previousStats };\n\t\t}\n\t\tpreviousVersion = getMostRecentVersion(previousStats.data);\n\t} catch {\n\t\t// no previous stats available.\n\t}\n\n\tconst currentVersion = getMostRecentVersion(currentStats.data);\n\n\tlet limitReached = false;\n\tlet overallDiff = 0;\n\tlet totalGzipSize = 0;\n\n\tconst headerString = configuration.report.header || \"## Bundle Size\";\n\tconst footerFormatter = configuration.report.footer || formatFooter;\n\tconst columns = configuration.report.columns || [\n\t\t{ status: \"Status\" },\n\t\t{ file: \"File\" },\n\t\t{ size: \"Size (Gzip)\" },\n\t\t{ limits: \"Limits\" },\n\t];\n\n\tconst rowsMD: string[] = [];\n\tconst hasGroupHeaders = Boolean(configuration.sizes?.some(isHeaderEntry));\n\tif (!hasGroupHeaders) {\n\t\trowsMD.push(addMDrow({ type: \"header\", columns }));\n\t}\n\n\t// Build ordered keys based on configuration.sizes if present.\n\tconst orderedKeys: Array<{\n\t\ttype: \"header\" | \"item\";\n\t\tvalue: string;\n\t\theader?: string;\n\t}> = [];\n\tif (configuration.sizes && Array.isArray(configuration.sizes)) {\n\t\tfor (const entry of configuration.sizes) {\n\t\t\tif (isHeaderEntry(entry)) {\n\t\t\t\torderedKeys.push({ type: \"header\", value: \"\", header: entry.header });\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// entry is FileSizeEntry here.\n\t\t\tif (entry.alias && currentStats.data[currentVersion][entry.alias]) {\n\t\t\t\torderedKeys.push({ type: \"item\", value: entry.alias });\n\t\t\t} else if (currentStats.data[currentVersion][entry.path]) {\n\t\t\t\torderedKeys.push({ type: \"item\", value: entry.path });\n\t\t\t}\n\t\t}\n\t}\n\n\tif (orderedKeys.length === 0) {\n\t\tfor (const key of Object.keys(currentStats.data[currentVersion])) {\n\t\t\torderedKeys.push({ type: \"item\", value: key });\n\t\t}\n\t}\n\n\tlet subGroupAccumulatedSize = 0;\n\tlet subGroupAccumulatedPrevSize = 0;\n\tlet hasSubGroup = false;\n\tconst flushSubGroup = () => {\n\t\tif (!hasSubGroup) {\n\t\t\treturn;\n\t\t}\n\t\tconst diff = subGroupAccumulatedSize - subGroupAccumulatedPrevSize;\n\t\tlet diffString = \"\";\n\t\tif (diff !== 0 && subGroupAccumulatedPrevSize !== 0) {\n\t\t\tconst sign = diff > 0 ? \"+\" : \"-\";\n\t\t\tdiffString = ` (${sign}${bytes(Math.abs(diff), { unitSeparator: \" \" })} ${percentFormatter(\n\t\t\t\tdiff / subGroupAccumulatedPrevSize,\n\t\t\t)})`;\n\t\t}\n\t\tif (hasGroupHeaders) {\n\t\t\trowsMD.push(\n\t\t\t\t`\\nSub-bundle size: ${bytes(subGroupAccumulatedSize, {\n\t\t\t\t\tunitSeparator: \" \",\n\t\t\t\t})}${diffString}`,\n\t\t\t\t\"\",\n\t\t\t);\n\t\t}\n\t\tsubGroupAccumulatedSize = 0;\n\t\tsubGroupAccumulatedPrevSize = 0;\n\t\thasSubGroup = false;\n\t};\n\n\tfor (const entry of orderedKeys) {\n\t\tif (entry.type === \"header\") {\n\t\t\tflushSubGroup();\n\t\t\trowsMD.push(\"\", entry.header as string, \"\");\n\t\t\trowsMD.push(addMDrow({ type: \"header\", columns }));\n\t\t\tcontinue;\n\t\t}\n\t\tconst key = entry.value;\n\t\tconst item = currentStats.data[currentVersion][key];\n\t\tif (!item) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst name = basename(key);\n\t\tif (!item.passed) {\n\t\t\tlimitReached = true;\n\t\t}\n\n\t\tlet diffString = \"\";\n\t\tlet previousFileSizeGzip = 0;\n\t\tif (previousStats && previousVersion) {\n\t\t\tconst previousFileStats =\n\t\t\t\tpreviousStats.data[previousVersion] &&\n\t\t\t\tpreviousStats.data[previousVersion][key];\n\t\t\tpreviousFileSizeGzip = previousFileStats?.fileSizeGzip || 0;\n\t\t\tconst diff = item.fileSizeGzip - previousFileSizeGzip;\n\t\t\toverallDiff += diff;\n\t\t\tdiffString =\n\t\t\t\tdiff === 0 || diff === item.fileSizeGzip\n\t\t\t\t\t? \"\"\n\t\t\t\t\t: ` (${diff > 0 ? \"+\" : \"-\"}${bytes(Math.abs(diff), { unitSeparator: \" \" })} ${percentFormatter(\n\t\t\t\t\t\t\tpreviousFileSizeGzip === 0 ? 0 : diff / previousFileSizeGzip,\n\t\t\t\t\t\t)})`;\n\t\t}\n\n\t\ttotalGzipSize += item.fileSizeGzip;\n\t\tsubGroupAccumulatedSize += item.fileSizeGzip;\n\t\tsubGroupAccumulatedPrevSize += previousFileSizeGzip;\n\t\thasSubGroup = true;\n\n\t\trowsMD.push(\n\t\t\taddMDrow({\n\t\t\t\ttype: \"row\",\n\t\t\t\tpassed: item.passed,\n\t\t\t\tname: name,\n\t\t\t\tsize: item.fileSizeGzip,\n\t\t\t\tdiff: diffString,\n\t\t\t\tlimit: item.limit,\n\t\t\t\tcolumns,\n\t\t\t}),\n\t\t);\n\t}\n\n\tflushSubGroup();\n\n\tconst template = `\n${headerString}\n${rowsMD.join(\"\\n\")}\n\n${footerFormatter({ limitReached, overallDiff, totalGzipSize })}\n`;\n\n\tif (limitReached) {\n\t\tresult.exitCode = 1;\n\t}\n\tresult.data = template;\n\treturn result;\n};\n"],"names":["basename","dirname","join","bytes","addMDrow","formatFooter","getMostRecentVersion","getOutputFile","percentFormatter","readJSONFile","validateConfigurationFile","isHeaderEntry","entry","reportStats","flags","result","exitCode","exitMessage","outputFile","data","previousStats","previousVersion","isValidConfigResult","configuration","configurationFile","output","then","m","default","currentStats","report","current","previous","currentVersion","limitReached","overallDiff","totalGzipSize","headerString","header","footerFormatter","footer","columns","status","file","size","limits","rowsMD","hasGroupHeaders","Boolean","sizes","some","push","type","orderedKeys","Array","isArray","value","alias","path","length","key","Object","keys","subGroupAccumulatedSize","subGroupAccumulatedPrevSize","hasSubGroup","flushSubGroup","diff","diffString","sign","Math","abs","unitSeparator","item","name","passed","previousFileSizeGzip","previousFileStats","fileSizeGzip","limit","template"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../src/reportStats.ts"],"sourcesContent":["import { basename, dirname, join } from \"node:path\";\nimport bytes from \"bytes\";\nimport { DEFAULT_THRESHOLD } from \"./defaults.js\";\nimport type { FooterProperties } from \"./utilities.js\";\nimport {\n\taddMDrow,\n\tformatFooter,\n\tgetMostRecentVersion,\n\tgetOutputFile,\n\tpercentFormatter,\n\treadJSONFile,\n\tvalidateConfigurationFile,\n} from \"./utilities.js\";\n\ntype ReportConfiguration = {\n\tcurrent: string;\n\tprevious: string;\n\theader?: string;\n\tfooter?: (arguments_: FooterProperties) => string;\n\tcolumns?: { [key: string]: string }[];\n\tthreshold?: number;\n};\n\ninterface HeaderSizeEntry {\n\theader: string;\n}\ninterface FileSizeEntry {\n\tpath: string;\n\tlimit: string;\n\talias?: string;\n}\ntype SizesConfiguration = Array<HeaderSizeEntry | FileSizeEntry>;\n\nconst isHeaderEntry = (\n\tentry: HeaderSizeEntry | FileSizeEntry,\n): entry is HeaderSizeEntry => \"header\" in entry;\n\ntype ReportCompare = {\n\tdata: string;\n\texitCode: number;\n\texitMessage: string;\n\toutputFile: string;\n};\n\nexport const reportStats = async ({ flags }): Promise<ReportCompare> => {\n\tconst result: ReportCompare = {\n\t\texitCode: 0,\n\t\texitMessage: \"\",\n\t\toutputFile: \"\",\n\t\tdata: \"\",\n\t};\n\n\tlet previousStats, previousVersion: string;\n\tconst isValidConfigResult = validateConfigurationFile(flags.configuration);\n\tif (isValidConfigResult.exitMessage !== \"\") {\n\t\treturn { ...result, ...isValidConfigResult };\n\t}\n\n\tconst configurationFile = isValidConfigResult.data;\n\tconst outputFile = getOutputFile(flags.output);\n\tresult.outputFile = outputFile;\n\n\tconst configuration: {\n\t\treport: ReportConfiguration;\n\t\tsizes?: SizesConfiguration;\n\t} = await import(configurationFile).then((m) => m.default);\n\n\tconst currentStats = readJSONFile(\n\t\tjoin(dirname(configurationFile), configuration.report.current),\n\t);\n\tif (currentStats.exitMessage !== \"\") {\n\t\treturn { ...result, ...currentStats };\n\t}\n\n\ttry {\n\t\tpreviousStats = readJSONFile(\n\t\t\tjoin(dirname(configurationFile), configuration.report.previous),\n\t\t);\n\t\tif (previousStats.exitMessage !== \"\") {\n\t\t\treturn { ...result, ...previousStats };\n\t\t}\n\t\tpreviousVersion = getMostRecentVersion(previousStats.data);\n\t} catch {\n\t\t// no previous stats available.\n\t}\n\n\tconst currentVersion = getMostRecentVersion(currentStats.data);\n\n\tlet limitReached = false;\n\tlet overallDiff = 0;\n\tlet totalGzipSize = 0;\n\n\tconst threshold = configuration.report.threshold ?? DEFAULT_THRESHOLD;\n\tconst headerString = configuration.report.header || \"## Bundle Size\";\n\tconst footerFormatter = configuration.report.footer || formatFooter;\n\tconst columns = configuration.report.columns || [\n\t\t{ status: \"Status\" },\n\t\t{ file: \"File\" },\n\t\t{ size: \"Size (Gzip)\" },\n\t\t{ limits: \"Limits\" },\n\t];\n\n\tconst rowsMD: string[] = [];\n\tconst hasGroupHeaders = Boolean(configuration.sizes?.some(isHeaderEntry));\n\tif (!hasGroupHeaders) {\n\t\trowsMD.push(addMDrow({ type: \"header\", columns }));\n\t}\n\n\t// Build ordered keys based on configuration.sizes if present.\n\tconst orderedKeys: Array<{\n\t\ttype: \"header\" | \"item\";\n\t\tvalue: string;\n\t\theader?: string;\n\t}> = [];\n\tif (configuration.sizes && Array.isArray(configuration.sizes)) {\n\t\tfor (const entry of configuration.sizes) {\n\t\t\tif (isHeaderEntry(entry)) {\n\t\t\t\torderedKeys.push({ type: \"header\", value: \"\", header: entry.header });\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// entry is FileSizeEntry here.\n\t\t\tif (entry.alias && currentStats.data[currentVersion][entry.alias]) {\n\t\t\t\torderedKeys.push({ type: \"item\", value: entry.alias });\n\t\t\t} else if (currentStats.data[currentVersion][entry.path]) {\n\t\t\t\torderedKeys.push({ type: \"item\", value: entry.path });\n\t\t\t}\n\t\t}\n\t}\n\n\tif (orderedKeys.length === 0) {\n\t\tfor (const key of Object.keys(currentStats.data[currentVersion])) {\n\t\t\torderedKeys.push({ type: \"item\", value: key });\n\t\t}\n\t}\n\n\tlet subGroupAccumulatedSize = 0;\n\tlet subGroupAccumulatedDiff = 0;\n\tlet subGroupAccumulatedPrevSize = 0;\n\tlet hasSubGroup = false;\n\tconst flushSubGroup = () => {\n\t\tif (!hasSubGroup) {\n\t\t\treturn;\n\t\t}\n\t\t// Use the accumulated thresholded diff directly\n\t\tconst diff = subGroupAccumulatedDiff;\n\t\tlet diffString = \"\";\n\t\tif (diff !== 0 && subGroupAccumulatedPrevSize !== 0) {\n\t\t\tconst sign = diff > 0 ? \"+\" : \"-\";\n\t\t\tdiffString = ` (${sign}${bytes(Math.abs(diff), { unitSeparator: \" \" })} ${percentFormatter(\n\t\t\t\tdiff / subGroupAccumulatedPrevSize,\n\t\t\t)})`;\n\t\t}\n\t\tif (hasGroupHeaders) {\n\t\t\trowsMD.push(\n\t\t\t\t`\\nSub-bundle size: ${bytes(subGroupAccumulatedSize, {\n\t\t\t\t\tunitSeparator: \" \",\n\t\t\t\t})}${diffString}`,\n\t\t\t\t\"\",\n\t\t\t);\n\t\t}\n\t\tsubGroupAccumulatedSize = 0;\n\t\tsubGroupAccumulatedDiff = 0;\n\t\tsubGroupAccumulatedPrevSize = 0;\n\t\thasSubGroup = false;\n\t};\n\n\tfor (const entry of orderedKeys) {\n\t\tif (entry.type === \"header\") {\n\t\t\tflushSubGroup();\n\t\t\trowsMD.push(\"\", entry.header as string, \"\");\n\t\t\trowsMD.push(addMDrow({ type: \"header\", columns }));\n\t\t\tcontinue;\n\t\t}\n\t\tconst key = entry.value;\n\t\tconst item = currentStats.data[currentVersion][key];\n\t\tif (!item) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst name = basename(key);\n\t\tif (!item.passed) {\n\t\t\tlimitReached = true;\n\t\t}\n\n\t\tlet diffString = \"\";\n\t\tlet previousFileSizeGzip = 0;\n\t\tlet thresholdedDiff = 0;\n\t\tif (previousStats && previousVersion) {\n\t\t\tconst previousFileStats =\n\t\t\t\tpreviousStats.data[previousVersion] &&\n\t\t\t\tpreviousStats.data[previousVersion][key];\n\t\t\tpreviousFileSizeGzip = previousFileStats?.fileSizeGzip || 0;\n\t\t\tlet diff = item.fileSizeGzip - previousFileSizeGzip;\n\t\t\t// Apply threshold: if the absolute diff is below threshold, treat as no change\n\t\t\tif (Math.abs(diff) < threshold) {\n\t\t\t\tdiff = 0;\n\t\t\t}\n\t\t\tthresholdedDiff = diff;\n\t\t\toverallDiff += diff;\n\t\t\tdiffString =\n\t\t\t\tdiff === 0 || diff === item.fileSizeGzip\n\t\t\t\t\t? \"\"\n\t\t\t\t\t: ` (${diff > 0 ? \"+\" : \"-\"}${bytes(Math.abs(diff), { unitSeparator: \" \" })} ${percentFormatter(\n\t\t\t\t\t\t\tpreviousFileSizeGzip === 0 ? 0 : diff / previousFileSizeGzip,\n\t\t\t\t\t\t)})`;\n\t\t}\n\n\t\ttotalGzipSize += item.fileSizeGzip;\n\t\tsubGroupAccumulatedSize += item.fileSizeGzip;\n\t\tsubGroupAccumulatedDiff += thresholdedDiff;\n\t\tsubGroupAccumulatedPrevSize += previousFileSizeGzip;\n\t\thasSubGroup = true;\n\n\t\trowsMD.push(\n\t\t\taddMDrow({\n\t\t\t\ttype: \"row\",\n\t\t\t\tpassed: item.passed,\n\t\t\t\tname: name,\n\t\t\t\tsize: item.fileSizeGzip,\n\t\t\t\tdiff: diffString,\n\t\t\t\tlimit: item.limit,\n\t\t\t\tcolumns,\n\t\t\t}),\n\t\t);\n\t}\n\n\tflushSubGroup();\n\n\tconst template = `\n${headerString}\n${rowsMD.join(\"\\n\")}\n\n${footerFormatter({ limitReached, overallDiff, totalGzipSize })}\n`;\n\n\tif (limitReached) {\n\t\tresult.exitCode = 1;\n\t}\n\tresult.data = template;\n\treturn result;\n};\n"],"names":["basename","dirname","join","bytes","DEFAULT_THRESHOLD","addMDrow","formatFooter","getMostRecentVersion","getOutputFile","percentFormatter","readJSONFile","validateConfigurationFile","isHeaderEntry","entry","reportStats","flags","result","exitCode","exitMessage","outputFile","data","previousStats","previousVersion","isValidConfigResult","configuration","configurationFile","output","then","m","default","currentStats","report","current","previous","currentVersion","limitReached","overallDiff","totalGzipSize","threshold","headerString","header","footerFormatter","footer","columns","status","file","size","limits","rowsMD","hasGroupHeaders","Boolean","sizes","some","push","type","orderedKeys","Array","isArray","value","alias","path","length","key","Object","keys","subGroupAccumulatedSize","subGroupAccumulatedDiff","subGroupAccumulatedPrevSize","hasSubGroup","flushSubGroup","diff","diffString","sign","Math","abs","unitSeparator","item","name","passed","previousFileSizeGzip","thresholdedDiff","previousFileStats","fileSizeGzip","limit","template"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@node-cli/bundlesize",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.5.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Arno Versini",
|
|
6
6
|
"description": "Simple CLI tool that checks file(s) size and report if limits have been reached",
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"bin": "dist/bundlesize.js",
|
|
11
11
|
"files": [
|
|
12
12
|
"dist",
|
|
13
|
+
"schemas",
|
|
13
14
|
"README.md"
|
|
14
15
|
],
|
|
15
16
|
"node": ">=18",
|
|
@@ -45,5 +46,5 @@
|
|
|
45
46
|
"@vitest/coverage-v8": "3.2.4",
|
|
46
47
|
"vitest": "3.2.4"
|
|
47
48
|
},
|
|
48
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "b2f3d976bb47479d29242c68e36dcc85df41f7b9"
|
|
49
50
|
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://cdn.jsdelivr.net/npm/@node-cli/bundlesize/schemas/bundlesize.config.schema.json",
|
|
4
|
+
"title": "Bundlesize Configuration",
|
|
5
|
+
"description": "Configuration schema for @node-cli/bundlesize - a CLI tool that checks file(s) size and reports if limits have been reached",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"$schema": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"description": "Path to the JSON Schema for this configuration file"
|
|
11
|
+
},
|
|
12
|
+
"sizes": {
|
|
13
|
+
"type": "array",
|
|
14
|
+
"description": "Array of file size entries to check",
|
|
15
|
+
"items": {
|
|
16
|
+
"oneOf": [
|
|
17
|
+
{
|
|
18
|
+
"$ref": "#/$defs/SizeEntry"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"$ref": "#/$defs/HeaderEntry"
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"report": {
|
|
27
|
+
"$ref": "#/$defs/ReportConfiguration"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"additionalProperties": false,
|
|
31
|
+
"$defs": {
|
|
32
|
+
"SizeEntry": {
|
|
33
|
+
"type": "object",
|
|
34
|
+
"description": "A file size entry to check",
|
|
35
|
+
"properties": {
|
|
36
|
+
"path": {
|
|
37
|
+
"type": "string",
|
|
38
|
+
"description": "Path to the file to check. Supports glob patterns and special placeholders: <hash> for content hashes, <semver> for semantic versions"
|
|
39
|
+
},
|
|
40
|
+
"limit": {
|
|
41
|
+
"type": "string",
|
|
42
|
+
"description": "Maximum allowed size for the file (gzipped). Examples: '1.5 kB', '500 B', '2 MB'",
|
|
43
|
+
"pattern": "^[0-9]+(\\.[0-9]+)?\\s*(B|kB|KB|MB|GB|TB|PB)$"
|
|
44
|
+
},
|
|
45
|
+
"alias": {
|
|
46
|
+
"type": "string",
|
|
47
|
+
"description": "Optional alias for the file in reports. Useful when using dynamic path patterns"
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"required": ["path", "limit"],
|
|
51
|
+
"additionalProperties": false
|
|
52
|
+
},
|
|
53
|
+
"HeaderEntry": {
|
|
54
|
+
"type": "object",
|
|
55
|
+
"description": "A header entry for grouping files in reports",
|
|
56
|
+
"properties": {
|
|
57
|
+
"header": {
|
|
58
|
+
"type": "string",
|
|
59
|
+
"description": "Header text for a group of files in the report (e.g., '### Main Bundle')"
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"required": ["header"],
|
|
63
|
+
"additionalProperties": false
|
|
64
|
+
},
|
|
65
|
+
"ColumnDefinition": {
|
|
66
|
+
"type": "object",
|
|
67
|
+
"description": "A column definition for the report table",
|
|
68
|
+
"minProperties": 1,
|
|
69
|
+
"maxProperties": 1,
|
|
70
|
+
"additionalProperties": {
|
|
71
|
+
"type": "string",
|
|
72
|
+
"description": "Column header text"
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
"ReportConfiguration": {
|
|
76
|
+
"type": "object",
|
|
77
|
+
"description": "Configuration for generating size comparison reports",
|
|
78
|
+
"properties": {
|
|
79
|
+
"current": {
|
|
80
|
+
"type": "string",
|
|
81
|
+
"description": "Path to the current stats JSON file (relative to config file)"
|
|
82
|
+
},
|
|
83
|
+
"previous": {
|
|
84
|
+
"type": "string",
|
|
85
|
+
"description": "Path to the previous stats JSON file for comparison (relative to config file)"
|
|
86
|
+
},
|
|
87
|
+
"header": {
|
|
88
|
+
"type": "string",
|
|
89
|
+
"description": "Custom header for the report. Defaults to '## Bundle Size'"
|
|
90
|
+
},
|
|
91
|
+
"threshold": {
|
|
92
|
+
"type": "number",
|
|
93
|
+
"description": "Minimum byte difference to report as a change. Differences below this threshold are treated as no change. Defaults to 0",
|
|
94
|
+
"minimum": 0
|
|
95
|
+
},
|
|
96
|
+
"columns": {
|
|
97
|
+
"type": "array",
|
|
98
|
+
"description": "Custom column definitions for the report table. Default columns: status, file, size, limits",
|
|
99
|
+
"items": {
|
|
100
|
+
"$ref": "#/$defs/ColumnDefinition"
|
|
101
|
+
},
|
|
102
|
+
"examples": [
|
|
103
|
+
[
|
|
104
|
+
{ "status": "Status" },
|
|
105
|
+
{ "file": "File" },
|
|
106
|
+
{ "size": "Size (Gzip)" },
|
|
107
|
+
{ "limits": "Limits" }
|
|
108
|
+
]
|
|
109
|
+
]
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
"required": ["current", "previous"],
|
|
113
|
+
"additionalProperties": true
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
"examples": [
|
|
117
|
+
{
|
|
118
|
+
"sizes": [
|
|
119
|
+
{
|
|
120
|
+
"path": "dist/index.js",
|
|
121
|
+
"limit": "10 kB"
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"path": "dist/vendor.<hash>.js",
|
|
125
|
+
"limit": "50 kB",
|
|
126
|
+
"alias": "vendor"
|
|
127
|
+
}
|
|
128
|
+
]
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
"sizes": [
|
|
132
|
+
{ "header": "### Core" },
|
|
133
|
+
{
|
|
134
|
+
"path": "dist/core.js",
|
|
135
|
+
"limit": "5 kB"
|
|
136
|
+
},
|
|
137
|
+
{ "header": "### Plugins" },
|
|
138
|
+
{
|
|
139
|
+
"path": "dist/plugins/*.js",
|
|
140
|
+
"limit": "2 kB"
|
|
141
|
+
}
|
|
142
|
+
],
|
|
143
|
+
"report": {
|
|
144
|
+
"current": "stats/current.json",
|
|
145
|
+
"previous": "stats/previous.json",
|
|
146
|
+
"header": "## Bundle Size Report",
|
|
147
|
+
"threshold": 100
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
]
|
|
151
|
+
}
|