@node-cli/bundlecheck 1.1.1 → 1.1.2
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/dist/trend.js +37 -19
- package/dist/trend.js.map +1 -1
- package/package.json +2 -2
package/dist/trend.js
CHANGED
|
@@ -54,27 +54,41 @@ import { TREND_VERSION_COUNT } from "./defaults.js";
|
|
|
54
54
|
const lines = [];
|
|
55
55
|
// Color helper (respects boring flag)
|
|
56
56
|
const blue = (text)=>boring ? text : kleur.blue(text);
|
|
57
|
-
//
|
|
58
|
-
|
|
59
|
-
const
|
|
60
|
-
const
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
57
|
+
// Create maps from formatted string to representative value
|
|
58
|
+
// This ensures values that display the same get the same bar length
|
|
59
|
+
const gzipFormattedToValue = new Map();
|
|
60
|
+
const rawFormattedToValue = new Map();
|
|
61
|
+
for (const result of results){
|
|
62
|
+
const gzipFormatted = formatBytes(result.gzipSize);
|
|
63
|
+
const rawFormatted = formatBytes(result.rawSize);
|
|
64
|
+
// Use first occurrence as representative value for each formatted string
|
|
65
|
+
if (!gzipFormattedToValue.has(gzipFormatted)) {
|
|
66
|
+
gzipFormattedToValue.set(gzipFormatted, result.gzipSize);
|
|
67
|
+
}
|
|
68
|
+
if (!rawFormattedToValue.has(rawFormatted)) {
|
|
69
|
+
rawFormattedToValue.set(rawFormatted, result.rawSize);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Get unique representative values for min/max calculation
|
|
73
|
+
const uniqueGzipValues = [
|
|
74
|
+
...gzipFormattedToValue.values()
|
|
75
|
+
];
|
|
76
|
+
const uniqueRawValues = [
|
|
77
|
+
...rawFormattedToValue.values()
|
|
78
|
+
];
|
|
79
|
+
const minGzipSize = Math.min(...uniqueGzipValues);
|
|
80
|
+
const maxGzipSize = Math.max(...uniqueGzipValues);
|
|
81
|
+
const minRawSize = Math.min(...uniqueRawValues);
|
|
82
|
+
const maxRawSize = Math.max(...uniqueRawValues);
|
|
69
83
|
// Find max version length for alignment
|
|
70
84
|
const maxVersionLen = Math.max(...results.map((r)=>r.version.length));
|
|
71
85
|
// Bar width (characters)
|
|
72
86
|
const barWidth = 30;
|
|
73
87
|
const minBarWidth = 10; // Minimum bar length for smallest value
|
|
74
88
|
// Helper to calculate bar length with min-max scaling
|
|
75
|
-
const calcBarLength = (value, min, max
|
|
76
|
-
if (max === min
|
|
77
|
-
return barWidth; // All values are
|
|
89
|
+
const calcBarLength = (value, min, max)=>{
|
|
90
|
+
if (max === min) {
|
|
91
|
+
return barWidth; // All values are the same
|
|
78
92
|
}
|
|
79
93
|
// Scale from minBarWidth to barWidth based on position between min and max
|
|
80
94
|
const ratio = (value - min) / (max - min);
|
|
@@ -88,20 +102,24 @@ import { TREND_VERSION_COUNT } from "./defaults.js";
|
|
|
88
102
|
// Gzip size bars
|
|
89
103
|
lines.push(blue("Gzip Size:"));
|
|
90
104
|
for (const result of results){
|
|
91
|
-
const
|
|
105
|
+
const sizeStr = formatBytes(result.gzipSize);
|
|
106
|
+
// Use representative value for this formatted string to ensure consistent bar length
|
|
107
|
+
const representativeValue = gzipFormattedToValue.get(sizeStr);
|
|
108
|
+
const barLength = calcBarLength(representativeValue, minGzipSize, maxGzipSize);
|
|
92
109
|
const bar = "▇".repeat(barLength);
|
|
93
110
|
const padding = " ".repeat(maxVersionLen - result.version.length);
|
|
94
|
-
const sizeStr = formatBytes(result.gzipSize);
|
|
95
111
|
lines.push(` ${result.version}${padding} ${bar} ${sizeStr}`);
|
|
96
112
|
}
|
|
97
113
|
lines.push("");
|
|
98
114
|
// Raw size bars
|
|
99
115
|
lines.push(blue("Raw Size:"));
|
|
100
116
|
for (const result of results){
|
|
101
|
-
const
|
|
117
|
+
const sizeStr = formatBytes(result.rawSize);
|
|
118
|
+
// Use representative value for this formatted string to ensure consistent bar length
|
|
119
|
+
const representativeValue = rawFormattedToValue.get(sizeStr);
|
|
120
|
+
const barLength = calcBarLength(representativeValue, minRawSize, maxRawSize);
|
|
102
121
|
const bar = "▇".repeat(barLength);
|
|
103
122
|
const padding = " ".repeat(maxVersionLen - result.version.length);
|
|
104
|
-
const sizeStr = formatBytes(result.rawSize);
|
|
105
123
|
lines.push(` ${result.version}${padding} ${bar} ${sizeStr}`);
|
|
106
124
|
}
|
|
107
125
|
lines.push("");
|
package/dist/trend.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/trend.ts"],"sourcesContent":["import { Logger } from \"@node-cli/logger\";\nimport kleur from \"kleur\";\nimport { prerelease } from \"semver\";\nimport { checkBundleSize, formatBytes } from \"./bundler.js\";\nimport { TREND_VERSION_COUNT } from \"./defaults.js\";\n\nexport type TrendResult = {\n\tversion: string;\n\trawSize: number;\n\tgzipSize: number;\n};\n\nexport type TrendOptions = {\n\tpackageName: string;\n\tversions: string[];\n\texports?: string[];\n\tadditionalExternals?: string[];\n\tnoExternal?: boolean;\n\tgzipLevel?: number;\n\tboring?: boolean;\n};\n\n/**\n * Select versions for trend analysis\n * Returns the most recent stable versions (newest first)\n * Filters out prerelease versions (canary, alpha, beta, rc, etc.)\n */\nexport function selectTrendVersions(\n\tallVersions: string[],\n\tcount: number = TREND_VERSION_COUNT,\n): string[] {\n\t// Filter out prerelease versions (canary, alpha, beta, rc, etc.)\n\tconst stableVersions = allVersions.filter((v) => !prerelease(v));\n\treturn stableVersions.slice(0, count);\n}\n\n/**\n * Analyze bundle size trend across multiple versions\n */\nexport async function analyzeTrend(\n\toptions: TrendOptions,\n): Promise<TrendResult[]> {\n\tconst {\n\t\tpackageName,\n\t\tversions,\n\t\texports,\n\t\tadditionalExternals,\n\t\tnoExternal,\n\t\tgzipLevel,\n\t\tboring,\n\t} = options;\n\n\tconst log = new Logger({ boring });\n\tconst results: TrendResult[] = [];\n\n\tfor (const version of versions) {\n\t\tconst versionedPackage = `${packageName}@${version}`;\n\t\tlog.info(` Checking ${version}...`);\n\n\t\ttry {\n\t\t\tconst result = await checkBundleSize({\n\t\t\t\tpackageName: versionedPackage,\n\t\t\t\texports,\n\t\t\t\tadditionalExternals,\n\t\t\t\tnoExternal,\n\t\t\t\tgzipLevel,\n\t\t\t});\n\n\t\t\tresults.push({\n\t\t\t\tversion,\n\t\t\t\trawSize: result.rawSize,\n\t\t\t\tgzipSize: result.gzipSize,\n\t\t\t});\n\t\t} catch {\n\t\t\t// Skip versions that fail to analyze\n\t\t\tlog.info(` Skipping ${version} (failed to analyze)`);\n\t\t}\n\t}\n\n\treturn results;\n}\n\n/**\n * Render a bar graph showing bundle size trend\n */\nexport function renderTrendGraph(\n\tpackageName: string,\n\tresults: TrendResult[],\n\tboring: boolean = false,\n): string[] {\n\tif (results.length === 0) {\n\t\treturn [\"No data to display\"];\n\t}\n\n\tconst lines: string[] = [];\n\n\t// Color helper (respects boring flag)\n\tconst blue = (text: string) => (boring ? text : kleur.blue(text));\n\n\t// Find min/max sizes for scaling (use min-max scaling to show differences)\n\tconst gzipSizes = results.map((r) => r.gzipSize);\n\tconst rawSizes = results.map((r) => r.rawSize);\n\n\tconst minGzipSize = Math.min(...gzipSizes);\n\tconst maxGzipSize = Math.max(...gzipSizes);\n\tconst minRawSize = Math.min(...rawSizes);\n\tconst maxRawSize = Math.max(...rawSizes);\n\n\t// Check if all formatted values are the same (to avoid misleading bar differences)\n\tconst formattedGzipSizes = results.map((r) => formatBytes(r.gzipSize));\n\tconst formattedRawSizes = results.map((r) => formatBytes(r.rawSize));\n\tconst allGzipSame = new Set(formattedGzipSizes).size === 1;\n\tconst allRawSame = new Set(formattedRawSizes).size === 1;\n\n\t// Find max version length for alignment\n\tconst maxVersionLen = Math.max(...results.map((r) => r.version.length));\n\n\t// Bar width (characters)\n\tconst barWidth = 30;\n\tconst minBarWidth = 10; // Minimum bar length for smallest value\n\n\t// Helper to calculate bar length with min-max scaling\n\tconst calcBarLength = (\n\t\tvalue: number,\n\t\tmin: number,\n\t\tmax: number,\n\t\tallSame: boolean,\n\t): number => {\n\t\tif (max === min || allSame) {\n\t\t\treturn barWidth; // All values are effectively the same\n\t\t}\n\t\t// Scale from minBarWidth to barWidth based on position between min and max\n\t\tconst ratio = (value - min) / (max - min);\n\t\treturn Math.round(minBarWidth + ratio * (barWidth - minBarWidth));\n\t};\n\n\t// Header\n\tlines.push(\"\");\n\tlines.push(`${blue(\"Bundle Size:\")} ${packageName}`);\n\tlines.push(\"─\".repeat(60));\n\tlines.push(\"\");\n\n\t// Gzip size bars\n\tlines.push(blue(\"Gzip Size:\"));\n\tfor (const result of results) {\n\t\tconst barLength = calcBarLength(\n\t\t\tresult.gzipSize,\n\t\t\tminGzipSize,\n\t\t\tmaxGzipSize,\n\t\t\tallGzipSame,\n\t\t);\n\t\tconst bar = \"▇\".repeat(barLength);\n\t\tconst padding = \" \".repeat(maxVersionLen - result.version.length);\n\t\tconst sizeStr = formatBytes(result.gzipSize);\n\t\tlines.push(` ${result.version}${padding} ${bar} ${sizeStr}`);\n\t}\n\n\tlines.push(\"\");\n\n\t// Raw size bars\n\tlines.push(blue(\"Raw Size:\"));\n\tfor (const result of results) {\n\t\tconst barLength = calcBarLength(\n\t\t\tresult.rawSize,\n\t\t\tminRawSize,\n\t\t\tmaxRawSize,\n\t\t\tallRawSame,\n\t\t);\n\t\tconst bar = \"▇\".repeat(barLength);\n\t\tconst padding = \" \".repeat(maxVersionLen - result.version.length);\n\t\tconst sizeStr = formatBytes(result.rawSize);\n\t\tlines.push(` ${result.version}${padding} ${bar} ${sizeStr}`);\n\t}\n\n\tlines.push(\"\");\n\n\t// Summary\n\tconst oldestResult = results[results.length - 1];\n\tconst newestResult = results[0];\n\n\tif (results.length > 1) {\n\t\tconst gzipDiff = newestResult.gzipSize - oldestResult.gzipSize;\n\t\tconst gzipPercent = ((gzipDiff / oldestResult.gzipSize) * 100).toFixed(1);\n\t\tconst rawDiff = newestResult.rawSize - oldestResult.rawSize;\n\t\tconst rawPercent = ((rawDiff / oldestResult.rawSize) * 100).toFixed(1);\n\n\t\tconst gzipTrend =\n\t\t\tgzipDiff >= 0\n\t\t\t\t? `+${formatBytes(gzipDiff)}`\n\t\t\t\t: `-${formatBytes(Math.abs(gzipDiff))}`;\n\t\tconst rawTrend =\n\t\t\trawDiff >= 0\n\t\t\t\t? `+${formatBytes(rawDiff)}`\n\t\t\t\t: `-${formatBytes(Math.abs(rawDiff))}`;\n\n\t\tlines.push(\"─\".repeat(60));\n\t\tlines.push(\n\t\t\t`Change from ${oldestResult.version} to ${newestResult.version}:`,\n\t\t);\n\t\tlines.push(\n\t\t\t` ${blue(\"Gzip:\")} ${gzipTrend} (${gzipDiff >= 0 ? \"+\" : \"\"}${gzipPercent}%)`,\n\t\t);\n\t\tlines.push(\n\t\t\t` ${blue(\"Raw:\")} ${rawTrend} (${rawDiff >= 0 ? \"+\" : \"\"}${rawPercent}%)`,\n\t\t);\n\t}\n\n\tlines.push(\"\");\n\n\treturn lines;\n}\n"],"names":["Logger","kleur","prerelease","checkBundleSize","formatBytes","TREND_VERSION_COUNT","selectTrendVersions","allVersions","count","stableVersions","filter","v","slice","analyzeTrend","options","packageName","versions","exports","additionalExternals","noExternal","gzipLevel","boring","log","results","version","versionedPackage","info","result","push","rawSize","gzipSize","renderTrendGraph","length","lines","blue","text","gzipSizes","map","r","rawSizes","minGzipSize","Math","min","maxGzipSize","max","minRawSize","maxRawSize","formattedGzipSizes","formattedRawSizes","allGzipSame","Set","size","allRawSame","maxVersionLen","barWidth","minBarWidth","calcBarLength","value","allSame","ratio","round","repeat","barLength","bar","padding","sizeStr","oldestResult","newestResult","gzipDiff","gzipPercent","toFixed","rawDiff","rawPercent","gzipTrend","abs","rawTrend"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../src/trend.ts"],"sourcesContent":["import { Logger } from \"@node-cli/logger\";\nimport kleur from \"kleur\";\nimport { prerelease } from \"semver\";\nimport { checkBundleSize, formatBytes } from \"./bundler.js\";\nimport { TREND_VERSION_COUNT } from \"./defaults.js\";\n\nexport type TrendResult = {\n\tversion: string;\n\trawSize: number;\n\tgzipSize: number;\n};\n\nexport type TrendOptions = {\n\tpackageName: string;\n\tversions: string[];\n\texports?: string[];\n\tadditionalExternals?: string[];\n\tnoExternal?: boolean;\n\tgzipLevel?: number;\n\tboring?: boolean;\n};\n\n/**\n * Select versions for trend analysis\n * Returns the most recent stable versions (newest first)\n * Filters out prerelease versions (canary, alpha, beta, rc, etc.)\n */\nexport function selectTrendVersions(\n\tallVersions: string[],\n\tcount: number = TREND_VERSION_COUNT,\n): string[] {\n\t// Filter out prerelease versions (canary, alpha, beta, rc, etc.)\n\tconst stableVersions = allVersions.filter((v) => !prerelease(v));\n\treturn stableVersions.slice(0, count);\n}\n\n/**\n * Analyze bundle size trend across multiple versions\n */\nexport async function analyzeTrend(\n\toptions: TrendOptions,\n): Promise<TrendResult[]> {\n\tconst {\n\t\tpackageName,\n\t\tversions,\n\t\texports,\n\t\tadditionalExternals,\n\t\tnoExternal,\n\t\tgzipLevel,\n\t\tboring,\n\t} = options;\n\n\tconst log = new Logger({ boring });\n\tconst results: TrendResult[] = [];\n\n\tfor (const version of versions) {\n\t\tconst versionedPackage = `${packageName}@${version}`;\n\t\tlog.info(` Checking ${version}...`);\n\n\t\ttry {\n\t\t\tconst result = await checkBundleSize({\n\t\t\t\tpackageName: versionedPackage,\n\t\t\t\texports,\n\t\t\t\tadditionalExternals,\n\t\t\t\tnoExternal,\n\t\t\t\tgzipLevel,\n\t\t\t});\n\n\t\t\tresults.push({\n\t\t\t\tversion,\n\t\t\t\trawSize: result.rawSize,\n\t\t\t\tgzipSize: result.gzipSize,\n\t\t\t});\n\t\t} catch {\n\t\t\t// Skip versions that fail to analyze\n\t\t\tlog.info(` Skipping ${version} (failed to analyze)`);\n\t\t}\n\t}\n\n\treturn results;\n}\n\n/**\n * Render a bar graph showing bundle size trend\n */\nexport function renderTrendGraph(\n\tpackageName: string,\n\tresults: TrendResult[],\n\tboring: boolean = false,\n): string[] {\n\tif (results.length === 0) {\n\t\treturn [\"No data to display\"];\n\t}\n\n\tconst lines: string[] = [];\n\n\t// Color helper (respects boring flag)\n\tconst blue = (text: string) => (boring ? text : kleur.blue(text));\n\n\t// Create maps from formatted string to representative value\n\t// This ensures values that display the same get the same bar length\n\tconst gzipFormattedToValue = new Map<string, number>();\n\tconst rawFormattedToValue = new Map<string, number>();\n\n\tfor (const result of results) {\n\t\tconst gzipFormatted = formatBytes(result.gzipSize);\n\t\tconst rawFormatted = formatBytes(result.rawSize);\n\t\t// Use first occurrence as representative value for each formatted string\n\t\tif (!gzipFormattedToValue.has(gzipFormatted)) {\n\t\t\tgzipFormattedToValue.set(gzipFormatted, result.gzipSize);\n\t\t}\n\t\tif (!rawFormattedToValue.has(rawFormatted)) {\n\t\t\trawFormattedToValue.set(rawFormatted, result.rawSize);\n\t\t}\n\t}\n\n\t// Get unique representative values for min/max calculation\n\tconst uniqueGzipValues = [...gzipFormattedToValue.values()];\n\tconst uniqueRawValues = [...rawFormattedToValue.values()];\n\n\tconst minGzipSize = Math.min(...uniqueGzipValues);\n\tconst maxGzipSize = Math.max(...uniqueGzipValues);\n\tconst minRawSize = Math.min(...uniqueRawValues);\n\tconst maxRawSize = Math.max(...uniqueRawValues);\n\n\t// Find max version length for alignment\n\tconst maxVersionLen = Math.max(...results.map((r) => r.version.length));\n\n\t// Bar width (characters)\n\tconst barWidth = 30;\n\tconst minBarWidth = 10; // Minimum bar length for smallest value\n\n\t// Helper to calculate bar length with min-max scaling\n\tconst calcBarLength = (value: number, min: number, max: number): number => {\n\t\tif (max === min) {\n\t\t\treturn barWidth; // All values are the same\n\t\t}\n\t\t// Scale from minBarWidth to barWidth based on position between min and max\n\t\tconst ratio = (value - min) / (max - min);\n\t\treturn Math.round(minBarWidth + ratio * (barWidth - minBarWidth));\n\t};\n\n\t// Header\n\tlines.push(\"\");\n\tlines.push(`${blue(\"Bundle Size:\")} ${packageName}`);\n\tlines.push(\"─\".repeat(60));\n\tlines.push(\"\");\n\n\t// Gzip size bars\n\tlines.push(blue(\"Gzip Size:\"));\n\tfor (const result of results) {\n\t\tconst sizeStr = formatBytes(result.gzipSize);\n\t\t// Use representative value for this formatted string to ensure consistent bar length\n\t\tconst representativeValue = gzipFormattedToValue.get(sizeStr) as number;\n\t\tconst barLength = calcBarLength(\n\t\t\trepresentativeValue,\n\t\t\tminGzipSize,\n\t\t\tmaxGzipSize,\n\t\t);\n\t\tconst bar = \"▇\".repeat(barLength);\n\t\tconst padding = \" \".repeat(maxVersionLen - result.version.length);\n\t\tlines.push(` ${result.version}${padding} ${bar} ${sizeStr}`);\n\t}\n\n\tlines.push(\"\");\n\n\t// Raw size bars\n\tlines.push(blue(\"Raw Size:\"));\n\tfor (const result of results) {\n\t\tconst sizeStr = formatBytes(result.rawSize);\n\t\t// Use representative value for this formatted string to ensure consistent bar length\n\t\tconst representativeValue = rawFormattedToValue.get(sizeStr) as number;\n\t\tconst barLength = calcBarLength(\n\t\t\trepresentativeValue,\n\t\t\tminRawSize,\n\t\t\tmaxRawSize,\n\t\t);\n\t\tconst bar = \"▇\".repeat(barLength);\n\t\tconst padding = \" \".repeat(maxVersionLen - result.version.length);\n\t\tlines.push(` ${result.version}${padding} ${bar} ${sizeStr}`);\n\t}\n\n\tlines.push(\"\");\n\n\t// Summary\n\tconst oldestResult = results[results.length - 1];\n\tconst newestResult = results[0];\n\n\tif (results.length > 1) {\n\t\tconst gzipDiff = newestResult.gzipSize - oldestResult.gzipSize;\n\t\tconst gzipPercent = ((gzipDiff / oldestResult.gzipSize) * 100).toFixed(1);\n\t\tconst rawDiff = newestResult.rawSize - oldestResult.rawSize;\n\t\tconst rawPercent = ((rawDiff / oldestResult.rawSize) * 100).toFixed(1);\n\n\t\tconst gzipTrend =\n\t\t\tgzipDiff >= 0\n\t\t\t\t? `+${formatBytes(gzipDiff)}`\n\t\t\t\t: `-${formatBytes(Math.abs(gzipDiff))}`;\n\t\tconst rawTrend =\n\t\t\trawDiff >= 0\n\t\t\t\t? `+${formatBytes(rawDiff)}`\n\t\t\t\t: `-${formatBytes(Math.abs(rawDiff))}`;\n\n\t\tlines.push(\"─\".repeat(60));\n\t\tlines.push(\n\t\t\t`Change from ${oldestResult.version} to ${newestResult.version}:`,\n\t\t);\n\t\tlines.push(\n\t\t\t` ${blue(\"Gzip:\")} ${gzipTrend} (${gzipDiff >= 0 ? \"+\" : \"\"}${gzipPercent}%)`,\n\t\t);\n\t\tlines.push(\n\t\t\t` ${blue(\"Raw:\")} ${rawTrend} (${rawDiff >= 0 ? \"+\" : \"\"}${rawPercent}%)`,\n\t\t);\n\t}\n\n\tlines.push(\"\");\n\n\treturn lines;\n}\n"],"names":["Logger","kleur","prerelease","checkBundleSize","formatBytes","TREND_VERSION_COUNT","selectTrendVersions","allVersions","count","stableVersions","filter","v","slice","analyzeTrend","options","packageName","versions","exports","additionalExternals","noExternal","gzipLevel","boring","log","results","version","versionedPackage","info","result","push","rawSize","gzipSize","renderTrendGraph","length","lines","blue","text","gzipFormattedToValue","Map","rawFormattedToValue","gzipFormatted","rawFormatted","has","set","uniqueGzipValues","values","uniqueRawValues","minGzipSize","Math","min","maxGzipSize","max","minRawSize","maxRawSize","maxVersionLen","map","r","barWidth","minBarWidth","calcBarLength","value","ratio","round","repeat","sizeStr","representativeValue","get","barLength","bar","padding","oldestResult","newestResult","gzipDiff","gzipPercent","toFixed","rawDiff","rawPercent","gzipTrend","abs","rawTrend"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@node-cli/bundlecheck",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Arno Versini",
|
|
6
6
|
"description": "CLI tool to check the bundle size of npm packages (like bundlephobia)",
|
|
@@ -48,5 +48,5 @@
|
|
|
48
48
|
"@vitest/coverage-v8": "4.0.18",
|
|
49
49
|
"vitest": "4.0.18"
|
|
50
50
|
},
|
|
51
|
-
"gitHead": "
|
|
51
|
+
"gitHead": "9a5656abbda863cba86bdf6e3fb2f6d959515a54"
|
|
52
52
|
}
|