mirror of
https://github.com/zoriya/v10.git
synced 2026-08-05 13:48:14 +00:00
fix(ci): report lazy bundle chunks separately (#1710)
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor Agent
parent
edfec1c93e
commit
17d6ebfc30
@@ -7,8 +7,8 @@
|
||||
* When --base is omitted, generates a local report showing current sizes.
|
||||
* When --base is provided, generates a comparison report with diffs.
|
||||
*
|
||||
* Reads JSON arrays of { name, size, type, category?, format, standaloneSize? }
|
||||
* entries produced by bundle-size.js.
|
||||
* Reads JSON arrays of { name, size, type, category?, format, standaloneSize?,
|
||||
* lazySize?, totalSize? } entries produced by bundle-size.js.
|
||||
*/
|
||||
|
||||
import { readFileSync } from 'node:fs';
|
||||
@@ -44,6 +44,56 @@ function statusIcon(current, previous) {
|
||||
return pct > 10 ? '🔴' : '🔺';
|
||||
}
|
||||
|
||||
function entryStatusIcon(current, previous) {
|
||||
if (!previous) return '🆕';
|
||||
const currentSize = comparisonSize(current);
|
||||
const previousSize = comparisonSize(previous);
|
||||
if (Math.abs(currentSize - previousSize) > 300) {
|
||||
return statusIcon(currentSize, previousSize);
|
||||
}
|
||||
const currentLazy = comparisonLazySize(current);
|
||||
const previousLazy = comparisonLazySize(previous);
|
||||
if (currentLazy !== previousLazy) {
|
||||
return statusIcon(currentLazy, previousLazy);
|
||||
}
|
||||
return statusIcon(currentLazy, previousLazy);
|
||||
}
|
||||
|
||||
function lazySize(entry) {
|
||||
if (!entry) return 0;
|
||||
return (
|
||||
entry.lazySize ??
|
||||
Math.max(0, (entry.totalSize ?? entry.size) - entry.size)
|
||||
);
|
||||
}
|
||||
|
||||
function lazyLabel(entry) {
|
||||
const lazy = lazySize(entry);
|
||||
return lazy > 0 ? formatBytes(lazy) : '—';
|
||||
}
|
||||
|
||||
function lazyDelta(current, previous) {
|
||||
const currentLazy = lazySize(current);
|
||||
const previousLazy = lazySize(previous);
|
||||
if (currentLazy === 0 && previousLazy === 0) return '—';
|
||||
return formatDelta(currentLazy, previousLazy).bytes;
|
||||
}
|
||||
|
||||
function comparisonSize(entry) {
|
||||
return entry?.standaloneSize ?? entry?.size ?? 0;
|
||||
}
|
||||
|
||||
function comparisonLazySize(entry) {
|
||||
return entry?.standaloneLazySize ?? lazySize(entry);
|
||||
}
|
||||
|
||||
function comparisonLazyDelta(current, previous) {
|
||||
const currentLazy = comparisonLazySize(current);
|
||||
const previousLazy = comparisonLazySize(previous);
|
||||
if (currentLazy === 0 && previousLazy === 0) return '—';
|
||||
return formatDelta(currentLazy, previousLazy).bytes;
|
||||
}
|
||||
|
||||
/** Preferred display order for packages. Unlisted packages sort to the end. */
|
||||
const PACKAGE_ORDER = ['html', 'react', 'core', 'element', 'store', 'utils'];
|
||||
|
||||
@@ -112,26 +162,37 @@ function generateCategoryBreakdowns(entries, pkg) {
|
||||
|
||||
const label = CATEGORY_LABELS[cat] ?? cat;
|
||||
const isSkin = cat === 'skin';
|
||||
const hasLazy = catEntries.some((entry) => lazySize(entry) > 0);
|
||||
|
||||
lines.push('<details>');
|
||||
lines.push(`<summary><b>${label} (${catEntries.length})</b></summary>`);
|
||||
lines.push('');
|
||||
|
||||
if (isSkin) {
|
||||
lines.push('| Entry | Type | Size |');
|
||||
lines.push('|---|---|--:|');
|
||||
lines.push(
|
||||
hasLazy
|
||||
? '| Entry | Type | Initial | Lazy |'
|
||||
: '| Entry | Type | Initial |',
|
||||
);
|
||||
lines.push(hasLazy ? '|---|---|--:|--:|' : '|---|---|--:|');
|
||||
} else {
|
||||
lines.push('| Entry | Size |');
|
||||
lines.push('|---|--:|');
|
||||
lines.push(
|
||||
hasLazy ? '| Entry | Initial | Lazy |' : '| Entry | Initial |',
|
||||
);
|
||||
lines.push(hasLazy ? '|---|--:|--:|' : '|---|--:|');
|
||||
}
|
||||
|
||||
for (const entry of catEntries) {
|
||||
const el = entryLabel(entry.name, pkg);
|
||||
const fmt = entry.format ?? 'js';
|
||||
if (isSkin) {
|
||||
lines.push(`| ${el} | ${fmt} | ${formatBytes(entry.size)} |`);
|
||||
const cells = [`${el}`, fmt, formatBytes(entry.size)];
|
||||
if (hasLazy) cells.push(lazyLabel(entry));
|
||||
lines.push(`| ${cells.join(' | ')} |`);
|
||||
} else {
|
||||
lines.push(`| ${el} | ${formatBytes(entry.size)} |`);
|
||||
const cells = [`${el}`, formatBytes(entry.size)];
|
||||
if (hasLazy) cells.push(lazyLabel(entry));
|
||||
lines.push(`| ${cells.join(' | ')} |`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,12 +215,15 @@ function generateFlatBreakdown(entries, pkg) {
|
||||
lines.push('<details>');
|
||||
lines.push(`<summary><b>Entries (${entries.length})</b></summary>`);
|
||||
lines.push('');
|
||||
lines.push('| Entry | Size |');
|
||||
lines.push('|---|--:|');
|
||||
const hasLazy = entries.some((entry) => lazySize(entry) > 0);
|
||||
lines.push(hasLazy ? '| Entry | Initial | Lazy |' : '| Entry | Initial |');
|
||||
lines.push(hasLazy ? '|---|--:|--:|' : '|---|--:|');
|
||||
|
||||
for (const entry of entries) {
|
||||
const el = entryLabel(entry.name, pkg);
|
||||
lines.push(`| ${el} | ${formatBytes(entry.size)} |`);
|
||||
const cells = [`${el}`, formatBytes(entry.size)];
|
||||
if (hasLazy) cells.push(lazyLabel(entry));
|
||||
lines.push(`| ${cells.join(' | ')} |`);
|
||||
}
|
||||
|
||||
lines.push('');
|
||||
@@ -174,8 +238,8 @@ function generateFlatBreakdown(entries, pkg) {
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function generateComparisonReport(current, base) {
|
||||
const baseMap = Object.fromEntries(base.map((e) => [e.name, e.size]));
|
||||
const currentMap = Object.fromEntries(current.map((e) => [e.name, e.size]));
|
||||
const baseEntryMap = Object.fromEntries(base.map((e) => [e.name, e]));
|
||||
|
||||
// Standalone size lookups — used to gate UI component diffs.
|
||||
// UI marginal sizes shift when root content changes (brotli compression is
|
||||
@@ -230,7 +294,12 @@ function generateComparisonReport(current, base) {
|
||||
// New entry — always surface
|
||||
if (prevStandalone === undefined) return true;
|
||||
const curStandalone = currentStandaloneMap[e.name];
|
||||
return Math.abs(curStandalone - prevStandalone) > 300;
|
||||
const initialChanged = Math.abs(curStandalone - prevStandalone) > 300;
|
||||
const currentLazy = comparisonLazySize(e);
|
||||
const previousEntry = baseEntryMap[e.name];
|
||||
const previousLazy = comparisonLazySize(previousEntry);
|
||||
const lazyChanged = Math.abs(currentLazy - previousLazy) > 300;
|
||||
return initialChanged || lazyChanged;
|
||||
});
|
||||
|
||||
// Entries that existed in base but are missing in PR (removed)
|
||||
@@ -250,24 +319,27 @@ function generateComparisonReport(current, base) {
|
||||
lines.push(`## ${pkgIcon} @videojs/${pkg}`);
|
||||
lines.push('');
|
||||
|
||||
lines.push('| Path | Base | PR | Diff | % | |');
|
||||
lines.push('|---|--:|--:|--:|--:|:-:|');
|
||||
lines.push('| Path | Base initial | PR initial | Diff | % | Lazy | |');
|
||||
lines.push('|---|--:|--:|--:|--:|--:|:-:|');
|
||||
|
||||
for (const entry of changed) {
|
||||
const el = entryLabel(entry.name, pkg);
|
||||
const prev = baseMap[entry.name];
|
||||
const d = formatDelta(entry.size, prev);
|
||||
const status = statusIcon(entry.size, prev);
|
||||
const baseSize = prev !== undefined ? formatBytes(prev) : '—';
|
||||
const previousEntry = baseEntryMap[entry.name];
|
||||
const prevInitial = previousEntry ? comparisonSize(previousEntry) : undefined;
|
||||
const currentInitial = comparisonSize(entry);
|
||||
const d = formatDelta(currentInitial, prevInitial);
|
||||
const status = entryStatusIcon(entry, previousEntry);
|
||||
const baseSize = prevInitial !== undefined ? formatBytes(prevInitial) : '—';
|
||||
lines.push(
|
||||
`| ${el} | ${baseSize} | ${formatBytes(entry.size)} | ${d.bytes} | ${d.pct} | ${status} |`,
|
||||
`| ${el} | ${baseSize} | ${formatBytes(currentInitial)} | ${d.bytes} | ${d.pct} | ${comparisonLazyDelta(entry, previousEntry)} | ${status} |`,
|
||||
);
|
||||
}
|
||||
|
||||
for (const entry of removed) {
|
||||
const el = entryLabel(entry.name, pkg);
|
||||
const previousInitial = comparisonSize(entry);
|
||||
lines.push(
|
||||
`| ${el} | ${formatBytes(entry.size)} | — | −${formatBytes(entry.size)} | −100% | 🗑️ |`,
|
||||
`| ${el} | ${formatBytes(previousInitial)} | — | −${formatBytes(previousInitial)} | −100% | ${comparisonLazyDelta(undefined, entry)} | 🗑️ |`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -289,7 +361,9 @@ function generateComparisonReport(current, base) {
|
||||
lines.push('<details>');
|
||||
lines.push('<summary>ℹ️ How to interpret</summary>');
|
||||
lines.push('');
|
||||
lines.push('All sizes are standalone totals (minified + brotli).');
|
||||
lines.push(
|
||||
'JS sizes are initial static graph totals (minified + brotli). Lazy dynamic chunks are shown separately when present.',
|
||||
);
|
||||
lines.push('');
|
||||
lines.push('| Icon | Meaning |');
|
||||
lines.push('|---|---|');
|
||||
@@ -299,7 +373,7 @@ function generateComparisonReport(current, base) {
|
||||
lines.push('| 🔽 | Decreased |');
|
||||
lines.push('| 🆕 | New (no baseline) |');
|
||||
lines.push('');
|
||||
lines.push('Run `pnpm size` locally to check current sizes.');
|
||||
lines.push('Run `pnpm size` locally to check current initial sizes.');
|
||||
lines.push('</details>');
|
||||
|
||||
return lines.join('\n');
|
||||
@@ -392,13 +466,18 @@ function generateLocalReport(current) {
|
||||
|
||||
const label = CATEGORY_LABELS[cat] ?? cat;
|
||||
const isSkin = cat === 'skin';
|
||||
const hasLazy = catEntries.some((entry) => lazySize(entry) > 0);
|
||||
|
||||
lines.push('');
|
||||
lines.push(` ${ansi.dim(label)}`);
|
||||
|
||||
const header = isSkin
|
||||
? ['Entry', 'Type', 'Size']
|
||||
: ['Entry', 'Size'];
|
||||
? hasLazy
|
||||
? ['Entry', 'Type', 'Initial', 'Lazy']
|
||||
: ['Entry', 'Type', 'Initial']
|
||||
: hasLazy
|
||||
? ['Entry', 'Initial', 'Lazy']
|
||||
: ['Entry', 'Initial'];
|
||||
const rows = [header];
|
||||
|
||||
for (const entry of catEntries) {
|
||||
@@ -406,37 +485,50 @@ function generateLocalReport(current) {
|
||||
entry.name.replace(`@videojs/${pkg}`, '') || '.';
|
||||
const fmt = entry.format ?? 'js';
|
||||
if (isSkin) {
|
||||
rows.push([
|
||||
const row = [
|
||||
{ text: subpath, style: ansi.cyan },
|
||||
{ text: fmt, style: ansi.dim },
|
||||
colorSize(entry.size),
|
||||
]);
|
||||
];
|
||||
if (hasLazy) row.push(colorSize(lazySize(entry)));
|
||||
rows.push(row);
|
||||
} else {
|
||||
rows.push([
|
||||
const row = [
|
||||
{ text: subpath, style: ansi.cyan },
|
||||
colorSize(entry.size),
|
||||
]);
|
||||
];
|
||||
if (hasLazy) row.push(colorSize(lazySize(entry)));
|
||||
rows.push(row);
|
||||
}
|
||||
}
|
||||
|
||||
lines.push(printTable(rows));
|
||||
}
|
||||
} else {
|
||||
const rows = [['Entry', 'Size']];
|
||||
const hasLazy = entries.some((entry) => lazySize(entry) > 0);
|
||||
const rows = [
|
||||
hasLazy ? ['Entry', 'Initial', 'Lazy'] : ['Entry', 'Initial'],
|
||||
];
|
||||
for (const entry of entries) {
|
||||
const subpath =
|
||||
entry.name.replace(`@videojs/${pkg}`, '') || '.';
|
||||
rows.push([
|
||||
const row = [
|
||||
{ text: subpath, style: ansi.cyan },
|
||||
colorSize(entry.size),
|
||||
]);
|
||||
];
|
||||
if (hasLazy) row.push(colorSize(lazySize(entry)));
|
||||
rows.push(row);
|
||||
}
|
||||
lines.push(printTable(rows));
|
||||
}
|
||||
}
|
||||
|
||||
lines.push('');
|
||||
lines.push(ansi.dim('Sizes are minified + brotli.'));
|
||||
lines.push(
|
||||
ansi.dim(
|
||||
'Initial sizes are minified + brotli; lazy chunks are shown separately.',
|
||||
),
|
||||
);
|
||||
lines.push('');
|
||||
|
||||
return lines.join('\n');
|
||||
|
||||
+154
-33
@@ -4,7 +4,9 @@
|
||||
* Auto-discovers packages from `packages/`, reads their `exports` field to find
|
||||
* entry points, and externalizes `peerDependencies`.
|
||||
*
|
||||
* All sizes are standalone totals (minified + brotli).
|
||||
* JS sizes are initial static graph totals (minified + brotli). Lazy dynamic
|
||||
* chunks are measured separately so they stay visible without counting as
|
||||
* eager entry cost.
|
||||
*
|
||||
* Wildcard exports (e.g., `./ui/*`, `./media/⁕/index.js`) are resolved to
|
||||
* actual files on disk. Supports both file-level (`*.js`) and directory-level
|
||||
@@ -15,7 +17,7 @@
|
||||
* Each entry includes a `category` field for grouped reporting in html/react:
|
||||
* preset, media, player, skin, ui, or feature.
|
||||
*
|
||||
* Usage: node .github/scripts/bundle-size.js [--json output.json]
|
||||
* Usage: node .github/scripts/bundle-size.js [--root repo-root] [--json output.json]
|
||||
*/
|
||||
|
||||
import { build, transform } from 'esbuild';
|
||||
@@ -26,11 +28,15 @@ import {
|
||||
writeFileSync,
|
||||
existsSync,
|
||||
} from 'node:fs';
|
||||
import { resolve, dirname, join, basename } from 'node:path';
|
||||
import { resolve, dirname, join, basename, relative } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const ROOT = resolve(__dirname, '../..');
|
||||
const rootIndex = process.argv.indexOf('--root');
|
||||
const ROOT =
|
||||
rootIndex !== -1
|
||||
? resolve(process.argv[rootIndex + 1])
|
||||
: resolve(__dirname, '../..');
|
||||
const PACKAGES_DIR = join(ROOT, 'packages');
|
||||
|
||||
const SKIP_PACKAGES = new Set([
|
||||
@@ -150,9 +156,70 @@ function buildPresetEntry(pkgShortName, config, distDir) {
|
||||
* @property {string} [category] - preset, media, player, skin, ui, feature (only for html/react)
|
||||
* @property {'js' | 'css'} format
|
||||
* @property {number} [standaloneSize] - For UI components: standalone size used for stable diff gating
|
||||
* @property {number} [totalSize] - Initial + lazy dynamic chunk size
|
||||
* @property {number} [lazySize] - Lazy dynamic chunk size
|
||||
* @property {number} [chunkCount] - Number of dynamic chunks
|
||||
* @property {number} [standaloneTotalSize] - Standalone initial + lazy dynamic chunk size
|
||||
* @property {number} [standaloneLazySize] - Standalone lazy dynamic chunk size
|
||||
*/
|
||||
|
||||
/** Bundle entry points with esbuild and return the minified + brotli size. */
|
||||
function compressSize(code) {
|
||||
return brotliCompressSync(Buffer.from(code), {
|
||||
params: {
|
||||
[constants.BROTLI_PARAM_QUALITY]: constants.BROTLI_MAX_QUALITY,
|
||||
},
|
||||
}).length;
|
||||
}
|
||||
|
||||
function outputPath(path) {
|
||||
return resolve(ROOT, path);
|
||||
}
|
||||
|
||||
function entryKey(path) {
|
||||
return relative(ROOT, path).replaceAll('\\', '/');
|
||||
}
|
||||
|
||||
function staticOutputs(metafile, entryPoints) {
|
||||
const entryPointsSet = entryPoints
|
||||
? new Set(entryPoints.map((entry) => entryKey(entry)))
|
||||
: null;
|
||||
const outputs = new Set();
|
||||
const queue = Object.entries(metafile.outputs)
|
||||
.filter(([, output]) =>
|
||||
entryPointsSet
|
||||
? entryPointsSet.has(output.entryPoint)
|
||||
: output.entryPoint === '<stdin>',
|
||||
)
|
||||
.map(([path]) => path);
|
||||
|
||||
for (const path of queue) {
|
||||
if (outputs.has(path)) continue;
|
||||
outputs.add(path);
|
||||
|
||||
const output = metafile.outputs[path];
|
||||
for (const link of output.imports ?? []) {
|
||||
if (link.kind === 'dynamic-import') continue;
|
||||
if (metafile.outputs[link.path]) queue.push(link.path);
|
||||
}
|
||||
}
|
||||
|
||||
return outputs;
|
||||
}
|
||||
|
||||
function sizeFields(measurement) {
|
||||
return {
|
||||
size: measurement.size,
|
||||
...(measurement.lazySize > 0
|
||||
? {
|
||||
totalSize: measurement.totalSize,
|
||||
lazySize: measurement.lazySize,
|
||||
chunkCount: measurement.chunkCount,
|
||||
}
|
||||
: {}),
|
||||
};
|
||||
}
|
||||
|
||||
/** Bundle entry points with esbuild and return initial and lazy sizes. */
|
||||
async function measure(entryPoints, external = []) {
|
||||
const result = await build({
|
||||
entryPoints,
|
||||
@@ -160,35 +227,44 @@ async function measure(entryPoints, external = []) {
|
||||
minify: true,
|
||||
treeShaking: true,
|
||||
format: 'esm',
|
||||
splitting: true,
|
||||
absWorkingDir: ROOT,
|
||||
write: false,
|
||||
outdir: '/tmp/bundle-size-out',
|
||||
external,
|
||||
metafile: true,
|
||||
logLevel: 'silent',
|
||||
});
|
||||
|
||||
const code = result.outputFiles.map((f) => f.text).join('');
|
||||
const compressed = brotliCompressSync(Buffer.from(code), {
|
||||
params: {
|
||||
[constants.BROTLI_PARAM_QUALITY]: constants.BROTLI_MAX_QUALITY,
|
||||
},
|
||||
});
|
||||
const sizeByPath = new Map(
|
||||
result.outputFiles.map((file) => [file.path, compressSize(file.text)]),
|
||||
);
|
||||
const staticPaths = staticOutputs(result.metafile, entryPoints);
|
||||
let size = 0;
|
||||
let totalSize = 0;
|
||||
|
||||
return compressed.length;
|
||||
for (const [path] of Object.entries(result.metafile.outputs)) {
|
||||
const bytes = sizeByPath.get(outputPath(path)) ?? 0;
|
||||
totalSize += bytes;
|
||||
if (staticPaths.has(path)) size += bytes;
|
||||
}
|
||||
|
||||
return {
|
||||
size,
|
||||
totalSize,
|
||||
lazySize: Math.max(0, totalSize - size),
|
||||
chunkCount: Math.max(0, result.outputFiles.length - staticPaths.size),
|
||||
};
|
||||
}
|
||||
|
||||
/** Minify a CSS file with esbuild then brotli-compress it. */
|
||||
async function measureCSS(filePath) {
|
||||
const content = readFileSync(filePath, 'utf8');
|
||||
const result = await transform(content, { loader: 'css', minify: true });
|
||||
const compressed = brotliCompressSync(Buffer.from(result.code), {
|
||||
params: {
|
||||
[constants.BROTLI_PARAM_QUALITY]: constants.BROTLI_MAX_QUALITY,
|
||||
},
|
||||
});
|
||||
return compressed.length;
|
||||
return compressSize(result.code);
|
||||
}
|
||||
|
||||
/** Bundle a virtual entry (source string) with esbuild and return the minified + brotli size. */
|
||||
/** Bundle a virtual entry (source string) with esbuild and return initial and lazy sizes. */
|
||||
async function measureVirtual(code, resolveDir, external = []) {
|
||||
const result = await build({
|
||||
stdin: { contents: code, resolveDir, loader: 'js' },
|
||||
@@ -196,20 +272,34 @@ async function measureVirtual(code, resolveDir, external = []) {
|
||||
minify: true,
|
||||
treeShaking: true,
|
||||
format: 'esm',
|
||||
splitting: true,
|
||||
absWorkingDir: ROOT,
|
||||
write: false,
|
||||
outdir: '/tmp/bundle-size-out',
|
||||
external,
|
||||
metafile: true,
|
||||
logLevel: 'silent',
|
||||
});
|
||||
|
||||
const output = result.outputFiles.map((f) => f.text).join('');
|
||||
const compressed = brotliCompressSync(Buffer.from(output), {
|
||||
params: {
|
||||
[constants.BROTLI_PARAM_QUALITY]: constants.BROTLI_MAX_QUALITY,
|
||||
},
|
||||
});
|
||||
const sizeByPath = new Map(
|
||||
result.outputFiles.map((file) => [file.path, compressSize(file.text)]),
|
||||
);
|
||||
const staticPaths = staticOutputs(result.metafile);
|
||||
let size = 0;
|
||||
let totalSize = 0;
|
||||
|
||||
return compressed.length;
|
||||
for (const [path] of Object.entries(result.metafile.outputs)) {
|
||||
const bytes = sizeByPath.get(outputPath(path)) ?? 0;
|
||||
totalSize += bytes;
|
||||
if (staticPaths.has(path)) size += bytes;
|
||||
}
|
||||
|
||||
return {
|
||||
size,
|
||||
totalSize,
|
||||
lazySize: Math.max(0, totalSize - size),
|
||||
chunkCount: Math.max(0, result.outputFiles.length - staticPaths.size),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -447,12 +537,13 @@ async function main() {
|
||||
// Always measure root — needed for UI marginal calculations even when
|
||||
// the root itself is excluded from results (categorized packages skip
|
||||
// root because presets are measured as virtual bundles instead).
|
||||
const rootSize = await measure([pkg.rootPath], pkg.external);
|
||||
const rootMeasurement = await measure([pkg.rootPath], pkg.external);
|
||||
const rootSize = rootMeasurement.size;
|
||||
|
||||
if (rootCat !== '_skip') {
|
||||
results.push({
|
||||
name: pkg.name,
|
||||
size: rootSize,
|
||||
...sizeFields(rootMeasurement),
|
||||
type: 'root',
|
||||
...(rootCat ? { category: rootCat } : {}),
|
||||
format: 'js',
|
||||
@@ -480,12 +571,29 @@ async function main() {
|
||||
// compression non-linearity, so diffs must gate on standalone.
|
||||
let size;
|
||||
let standaloneSize;
|
||||
let measurement;
|
||||
let standaloneMeasurement;
|
||||
if (cat === 'ui') {
|
||||
const combined = await measure([pkg.rootPath, sub.path], pkg.external);
|
||||
size = Math.max(0, combined - rootSize);
|
||||
standaloneSize = await measure([sub.path], pkg.external);
|
||||
standaloneMeasurement = await measure([sub.path], pkg.external);
|
||||
size = Math.max(0, combined.size - rootSize);
|
||||
const lazySize = Math.max(
|
||||
0,
|
||||
combined.lazySize - rootMeasurement.lazySize,
|
||||
);
|
||||
measurement = {
|
||||
size,
|
||||
totalSize: size + lazySize,
|
||||
lazySize,
|
||||
chunkCount: Math.max(
|
||||
0,
|
||||
combined.chunkCount - rootMeasurement.chunkCount,
|
||||
),
|
||||
};
|
||||
standaloneSize = standaloneMeasurement.size;
|
||||
} else {
|
||||
size = await measure([sub.path], pkg.external);
|
||||
measurement = await measure([sub.path], pkg.external);
|
||||
size = measurement.size;
|
||||
}
|
||||
|
||||
results.push({
|
||||
@@ -494,7 +602,20 @@ async function main() {
|
||||
type: 'subpath',
|
||||
...(cat ? { category: cat } : {}),
|
||||
format: 'js',
|
||||
...(measurement && measurement.lazySize > 0
|
||||
? {
|
||||
totalSize: measurement.totalSize,
|
||||
lazySize: measurement.lazySize,
|
||||
chunkCount: measurement.chunkCount,
|
||||
}
|
||||
: {}),
|
||||
...(standaloneSize !== undefined ? { standaloneSize } : {}),
|
||||
...(standaloneMeasurement && standaloneMeasurement.lazySize > 0
|
||||
? {
|
||||
standaloneTotalSize: standaloneMeasurement.totalSize,
|
||||
standaloneLazySize: standaloneMeasurement.lazySize,
|
||||
}
|
||||
: {}),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -507,10 +628,10 @@ async function main() {
|
||||
const code = buildPresetEntry(pkgShortName, config, distDir);
|
||||
if (!code) continue;
|
||||
|
||||
const size = await measureVirtual(code, distDir, pkg.external);
|
||||
const measurement = await measureVirtual(code, distDir, pkg.external);
|
||||
results.push({
|
||||
name: `${pkg.name}${config.label}`,
|
||||
size,
|
||||
...sizeFields(measurement),
|
||||
type: 'subpath',
|
||||
category: 'preset',
|
||||
format: 'js',
|
||||
|
||||
@@ -54,6 +54,13 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.base_ref }}
|
||||
|
||||
- name: Checkout PR scripts
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
repository: ${{ github.event.pull_request.head.repo.full_name }}
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
path: .bundle-size-pr
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
|
||||
@@ -75,9 +82,9 @@ jobs:
|
||||
run: |
|
||||
pnpm install
|
||||
|
||||
if [ -f .github/scripts/bundle-size.js ]; then
|
||||
if [ -f .bundle-size-pr/.github/scripts/bundle-size.js ]; then
|
||||
pnpm build:packages
|
||||
node .github/scripts/bundle-size.js --json base-size.json
|
||||
node .bundle-size-pr/.github/scripts/bundle-size.js --root . --json base-size.json
|
||||
else
|
||||
echo '[]' > base-size.json
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user