@mui/internal-bundle-size-checker 1.0.9-canary.4 → 1.0.9-canary.40
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 +5 -2
- package/package.json +11 -24
- package/src/{viteBuilder.js → builder.js} +51 -26
- package/src/cli.js +146 -41
- package/src/configLoader.js +121 -43
- package/src/fetchSnapshot.js +3 -61
- package/src/fetchSnapshotWithFallback.js +34 -0
- package/src/git.js +50 -0
- package/src/github.js +4 -1
- package/src/index.js +3 -9
- package/src/notifyPr.js +81 -0
- package/src/renderMarkdownReport.js +16 -23
- package/src/renderMarkdownReport.test.js +97 -80
- package/src/sizeDiff.js +1 -5
- package/src/types.d.ts +10 -23
- package/src/uploadSnapshot.js +2 -2
- package/src/worker.js +7 -14
- package/tsconfig.json +2 -2
- package/src/webpackBuilder.js +0 -267
package/README.md
CHANGED
|
@@ -19,9 +19,12 @@ bundle-size-checker [options]
|
|
|
19
19
|
|
|
20
20
|
Options:
|
|
21
21
|
|
|
22
|
-
- `--analyze`: Creates a
|
|
23
|
-
- `--
|
|
22
|
+
- `--analyze`: Creates a report for each bundle (using rollup-plugin-visualizer)
|
|
23
|
+
- `--debug`: Build with readable output (no name mangling or whitespace collapse, but still tree-shake)
|
|
24
|
+
- `--verbose`: Show more detailed information during compilation
|
|
24
25
|
- `--output`, `-o`: Path to output the size snapshot JSON file
|
|
26
|
+
- `--filter`, `-F`: Filter entry points by glob pattern(s) applied to their IDs
|
|
27
|
+
- `--concurrency`, `-c`: Number of workers to use for parallel processing
|
|
25
28
|
|
|
26
29
|
### Configuration
|
|
27
30
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mui/internal-bundle-size-checker",
|
|
3
|
-
"version": "1.0.9-canary.
|
|
3
|
+
"version": "1.0.9-canary.40",
|
|
4
4
|
"description": "Bundle size checker for MUI packages.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -19,38 +19,25 @@
|
|
|
19
19
|
"./browser": "./src/browser.js"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@aws-sdk/client-s3": "^3.
|
|
23
|
-
"@aws-sdk/credential-providers": "^3.
|
|
24
|
-
"@babel/core": "^7.27.4",
|
|
22
|
+
"@aws-sdk/client-s3": "^3.883.0",
|
|
23
|
+
"@aws-sdk/credential-providers": "^3.883.0",
|
|
25
24
|
"@octokit/rest": "^22.0.0",
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"chalk": "^5.4.1",
|
|
30
|
-
"compression-webpack-plugin": "^10.0.0",
|
|
31
|
-
"css-loader": "^7.1.2",
|
|
32
|
-
"env-ci": "^11.1.0",
|
|
33
|
-
"execa": "^7.2.0",
|
|
34
|
-
"fast-glob": "^3.3.2",
|
|
35
|
-
"file-loader": "^6.2.0",
|
|
25
|
+
"chalk": "^5.6.0",
|
|
26
|
+
"env-ci": "^11.2.0",
|
|
27
|
+
"execa": "^9.6.0",
|
|
36
28
|
"git-url-parse": "^16.1.0",
|
|
37
29
|
"micromatch": "^4.0.8",
|
|
38
|
-
"piscina": "^
|
|
39
|
-
"rollup-plugin-visualizer": "^6.0.
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"webpack": "^5.90.3",
|
|
43
|
-
"webpack-bundle-analyzer": "^4.10.1",
|
|
44
|
-
"yargs": "^17.7.2"
|
|
30
|
+
"piscina": "^5.1.3",
|
|
31
|
+
"rollup-plugin-visualizer": "^6.0.3",
|
|
32
|
+
"vite": "^7.1.4",
|
|
33
|
+
"yargs": "^18.0.0"
|
|
45
34
|
},
|
|
46
35
|
"devDependencies": {
|
|
47
36
|
"@types/env-ci": "^3.1.4",
|
|
48
37
|
"@types/micromatch": "^4.0.9",
|
|
49
|
-
"@types/webpack": "^5.28.5",
|
|
50
|
-
"@types/webpack-bundle-analyzer": "^4.7.0",
|
|
51
38
|
"@types/yargs": "^17.0.33"
|
|
52
39
|
},
|
|
53
|
-
"gitSha": "
|
|
40
|
+
"gitSha": "f9fb2233d5f6d847f6205b345bb829a712eea199",
|
|
54
41
|
"scripts": {
|
|
55
42
|
"typescript": "tsc -p tsconfig.json",
|
|
56
43
|
"test": "pnpm -w test --project @mui/internal-bundle-size-checker"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import path from 'path';
|
|
2
|
-
import fs from 'fs/promises';
|
|
3
|
-
import * as zlib from 'zlib';
|
|
4
|
-
import { promisify } from 'util';
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import * as zlib from 'node:zlib';
|
|
4
|
+
import { promisify } from 'node:util';
|
|
5
5
|
import { build, transformWithEsbuild } from 'vite';
|
|
6
6
|
import { visualizer } from 'rollup-plugin-visualizer';
|
|
7
7
|
|
|
@@ -29,7 +29,7 @@ const rootDir = process.cwd();
|
|
|
29
29
|
* Creates vite configuration for bundle size checking
|
|
30
30
|
* @param {ObjectEntry} entry - Entry point (string or object)
|
|
31
31
|
* @param {CommandLineArgs} args
|
|
32
|
-
* @returns {Promise<
|
|
32
|
+
* @returns {Promise<import('vite').InlineConfig>}
|
|
33
33
|
*/
|
|
34
34
|
async function createViteConfig(entry, args) {
|
|
35
35
|
const entryName = entry.id;
|
|
@@ -70,12 +70,12 @@ async function createViteConfig(entry, args) {
|
|
|
70
70
|
|
|
71
71
|
build: {
|
|
72
72
|
write: true,
|
|
73
|
-
minify: true,
|
|
73
|
+
minify: args.debug ? 'esbuild' : true,
|
|
74
74
|
outDir,
|
|
75
75
|
emptyOutDir: true,
|
|
76
76
|
rollupOptions: {
|
|
77
77
|
input: '/index.tsx',
|
|
78
|
-
external: externalsArray,
|
|
78
|
+
external: (id) => externalsArray.some((ext) => id === ext || id.startsWith(`${ext}/`)),
|
|
79
79
|
plugins: [
|
|
80
80
|
...(args.analyze
|
|
81
81
|
? [
|
|
@@ -100,10 +100,15 @@ async function createViteConfig(entry, args) {
|
|
|
100
100
|
|
|
101
101
|
esbuild: {
|
|
102
102
|
legalComments: 'none',
|
|
103
|
+
...(args.debug && {
|
|
104
|
+
minifyIdentifiers: false,
|
|
105
|
+
minifyWhitespace: false,
|
|
106
|
+
minifySyntax: true, // This enables tree-shaking and other safe optimizations
|
|
107
|
+
}),
|
|
103
108
|
},
|
|
104
109
|
|
|
105
110
|
define: {
|
|
106
|
-
'process.env.NODE_ENV': JSON.stringify(
|
|
111
|
+
'process.env.NODE_ENV': JSON.stringify('production'),
|
|
107
112
|
},
|
|
108
113
|
logLevel: args.verbose ? 'info' : 'silent',
|
|
109
114
|
// Add plugins to handle virtual entry points
|
|
@@ -132,7 +137,7 @@ async function createViteConfig(entry, args) {
|
|
|
132
137
|
],
|
|
133
138
|
};
|
|
134
139
|
|
|
135
|
-
return
|
|
140
|
+
return configuration;
|
|
136
141
|
}
|
|
137
142
|
|
|
138
143
|
/**
|
|
@@ -173,61 +178,81 @@ function walkDependencyTree(chunkKey, manifest, visited = new Set()) {
|
|
|
173
178
|
|
|
174
179
|
/**
|
|
175
180
|
* Process vite output to extract bundle sizes
|
|
176
|
-
* @param {
|
|
181
|
+
* @param {import('vite').Rollup.RollupOutput['output']} output - The Vite output
|
|
177
182
|
* @param {string} entryName - The entry name
|
|
178
|
-
* @returns {Promise<Map<string,
|
|
183
|
+
* @returns {Promise<Map<string, SizeSnapshotEntry>>} - Map of bundle names to size information
|
|
179
184
|
*/
|
|
180
|
-
async function processBundleSizes(
|
|
185
|
+
async function processBundleSizes(output, entryName) {
|
|
186
|
+
const chunksByFileName = new Map(output.map((chunk) => [chunk.fileName, chunk]));
|
|
187
|
+
|
|
181
188
|
// Read the manifest file to find the generated chunks
|
|
182
|
-
const
|
|
183
|
-
|
|
189
|
+
const manifestChunk = chunksByFileName.get('.vite/manifest.json');
|
|
190
|
+
if (manifestChunk?.type !== 'asset') {
|
|
191
|
+
throw new Error(`Manifest file not found in output for entry: ${entryName}`);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const manifestContent =
|
|
195
|
+
typeof manifestChunk.source === 'string'
|
|
196
|
+
? manifestChunk.source
|
|
197
|
+
: new TextDecoder().decode(manifestChunk.source);
|
|
198
|
+
|
|
184
199
|
/** @type {Manifest} */
|
|
185
200
|
const manifest = JSON.parse(manifestContent);
|
|
186
201
|
|
|
187
202
|
// Find the main entry point JS file in the manifest
|
|
188
|
-
const mainEntry = manifest[
|
|
203
|
+
const mainEntry = Object.entries(manifest).find(([_, entry]) => entry.name === '_virtual_entry');
|
|
189
204
|
|
|
190
205
|
if (!mainEntry) {
|
|
191
206
|
throw new Error(`No main entry found in manifest for ${entryName}`);
|
|
192
207
|
}
|
|
193
208
|
|
|
194
209
|
// Walk the dependency tree to get all chunks that are part of this entry
|
|
195
|
-
const allChunks = walkDependencyTree(
|
|
210
|
+
const allChunks = walkDependencyTree(mainEntry[0], manifest);
|
|
196
211
|
|
|
197
212
|
// Process each chunk in the dependency tree in parallel
|
|
198
213
|
const chunkPromises = Array.from(allChunks, async (chunkKey) => {
|
|
199
214
|
const chunk = manifest[chunkKey];
|
|
200
|
-
const
|
|
201
|
-
|
|
215
|
+
const outputChunk = chunksByFileName.get(chunk.file);
|
|
216
|
+
if (outputChunk?.type !== 'chunk') {
|
|
217
|
+
throw new Error(`Output chunk not found for ${chunk.file}`);
|
|
218
|
+
}
|
|
219
|
+
const fileContent = outputChunk.code;
|
|
202
220
|
|
|
203
221
|
// Calculate sizes
|
|
204
222
|
const parsed = Buffer.byteLength(fileContent);
|
|
205
223
|
const gzipBuffer = await gzipAsync(fileContent, { level: zlib.constants.Z_BEST_COMPRESSION });
|
|
206
224
|
const gzipSize = Buffer.byteLength(gzipBuffer);
|
|
207
225
|
|
|
226
|
+
if (chunk.isEntry) {
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
|
|
208
230
|
// Use chunk key as the name, or fallback to entry name for main chunk
|
|
209
|
-
const chunkName =
|
|
231
|
+
const chunkName = chunk.name === '_virtual_entry' ? entryName : chunk.name || chunkKey;
|
|
210
232
|
return /** @type {const} */ ([chunkName, { parsed, gzip: gzipSize }]);
|
|
211
233
|
});
|
|
212
234
|
|
|
213
235
|
const chunkEntries = await Promise.all(chunkPromises);
|
|
214
|
-
return new Map(chunkEntries);
|
|
236
|
+
return new Map(/** @type {[string, SizeSnapshotEntry][]} */ (chunkEntries.filter(Boolean)));
|
|
215
237
|
}
|
|
216
238
|
|
|
217
239
|
/**
|
|
218
240
|
* Get sizes for a vite bundle
|
|
219
241
|
* @param {ObjectEntry} entry - The entry configuration
|
|
220
242
|
* @param {CommandLineArgs} args - Command line arguments
|
|
221
|
-
* @returns {Promise<Map<string,
|
|
243
|
+
* @returns {Promise<Map<string, SizeSnapshotEntry>>}
|
|
222
244
|
*/
|
|
223
|
-
export async function
|
|
245
|
+
export async function getBundleSizes(entry, args) {
|
|
224
246
|
// Create vite configuration
|
|
225
|
-
const
|
|
226
|
-
const outDir = path.join(rootDir, 'build', entry.id);
|
|
247
|
+
const configuration = await createViteConfig(entry, args);
|
|
227
248
|
|
|
228
249
|
// Run vite build
|
|
229
|
-
await build(configuration);
|
|
250
|
+
const { output } = /** @type {import('vite').Rollup.RollupOutput} */ (await build(configuration));
|
|
251
|
+
const manifestChunk = output.find((chunk) => chunk.fileName === '.vite/manifest.json');
|
|
252
|
+
if (!manifestChunk) {
|
|
253
|
+
throw new Error(`Manifest file not found in output for entry: ${entry.id}`);
|
|
254
|
+
}
|
|
230
255
|
|
|
231
256
|
// Process the output to get bundle sizes
|
|
232
|
-
return processBundleSizes(
|
|
257
|
+
return processBundleSizes(output, entry.id);
|
|
233
258
|
}
|
package/src/cli.js
CHANGED
|
@@ -1,17 +1,33 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import os from 'os';
|
|
5
|
-
import fs from 'fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import fs from 'node:fs/promises';
|
|
6
6
|
import yargs from 'yargs';
|
|
7
7
|
import { Piscina } from 'piscina';
|
|
8
8
|
import micromatch from 'micromatch';
|
|
9
|
-
import
|
|
10
|
-
import gitUrlParse from 'git-url-parse';
|
|
9
|
+
import envCi from 'env-ci';
|
|
11
10
|
import { loadConfig } from './configLoader.js';
|
|
12
11
|
import { uploadSnapshot } from './uploadSnapshot.js';
|
|
13
12
|
import { renderMarkdownReport } from './renderMarkdownReport.js';
|
|
14
13
|
import { octokit } from './github.js';
|
|
14
|
+
import { getCurrentRepoInfo } from './git.js';
|
|
15
|
+
import { notifyPr } from './notifyPr.js';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
*/
|
|
19
|
+
function getCiInfo() {
|
|
20
|
+
const ciInfo = envCi();
|
|
21
|
+
if (!ciInfo.isCi) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
switch (ciInfo.name) {
|
|
25
|
+
case 'CircleCI':
|
|
26
|
+
return ciInfo;
|
|
27
|
+
default:
|
|
28
|
+
throw new Error(`Unsupported CI environment: ${ciInfo.name}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
15
31
|
|
|
16
32
|
/**
|
|
17
33
|
* @typedef {import('./sizeDiff.js').SizeSnapshot} SizeSnapshot
|
|
@@ -23,32 +39,12 @@ const DEFAULT_CONCURRENCY = os.availableParallelism();
|
|
|
23
39
|
const rootDir = process.cwd();
|
|
24
40
|
|
|
25
41
|
/**
|
|
26
|
-
*
|
|
27
|
-
* @returns {Promise<{owner: string | null, repo: string | null}>}
|
|
28
|
-
*/
|
|
29
|
-
async function getCurrentRepoInfo() {
|
|
30
|
-
try {
|
|
31
|
-
const { stdout } = await execa('git', ['remote', 'get-url', 'origin']);
|
|
32
|
-
const parsed = gitUrlParse(stdout.trim());
|
|
33
|
-
return {
|
|
34
|
-
owner: parsed.owner,
|
|
35
|
-
repo: parsed.name,
|
|
36
|
-
};
|
|
37
|
-
} catch (error) {
|
|
38
|
-
return {
|
|
39
|
-
owner: null,
|
|
40
|
-
repo: null,
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* creates size snapshot for every bundle that built with webpack
|
|
42
|
+
* creates size snapshot for every bundle
|
|
47
43
|
* @param {CommandLineArgs} args
|
|
48
44
|
* @param {NormalizedBundleSizeCheckerConfig} config - The loaded configuration
|
|
49
|
-
* @returns {Promise<Array<[string,
|
|
45
|
+
* @returns {Promise<Array<[string, SizeSnapshotEntry]>>}
|
|
50
46
|
*/
|
|
51
|
-
async function
|
|
47
|
+
async function getBundleSizes(args, config) {
|
|
52
48
|
const worker = new Piscina({
|
|
53
49
|
filename: new URL('./worker.js', import.meta.url).href,
|
|
54
50
|
maxThreads: args.concurrency || DEFAULT_CONCURRENCY,
|
|
@@ -96,6 +92,51 @@ async function getWebpackSizes(args, config) {
|
|
|
96
92
|
return sizeArrays.flat();
|
|
97
93
|
}
|
|
98
94
|
|
|
95
|
+
/**
|
|
96
|
+
* Posts initial "in progress" PR comment with CircleCI build information
|
|
97
|
+
* @returns {Promise<void>}
|
|
98
|
+
*/
|
|
99
|
+
async function postInitialPrComment() {
|
|
100
|
+
// /** @type {envCi.CircleCiEnv} */
|
|
101
|
+
const ciInfo = getCiInfo();
|
|
102
|
+
|
|
103
|
+
if (!ciInfo || !ciInfo.isPr) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// In CI PR builds, all required info must be present
|
|
108
|
+
if (!ciInfo.slug || !ciInfo.pr) {
|
|
109
|
+
throw new Error('PR commenting enabled but repository information missing in CI PR build');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const prNumber = Number(ciInfo.pr);
|
|
113
|
+
const circleBuildNum = process.env.CIRCLE_BUILD_NUM;
|
|
114
|
+
const circleBuildUrl = process.env.CIRCLE_BUILD_URL;
|
|
115
|
+
|
|
116
|
+
if (!circleBuildNum || !circleBuildUrl) {
|
|
117
|
+
throw new Error(
|
|
118
|
+
'PR commenting enabled but CircleCI environment variables missing in CI PR build',
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
try {
|
|
123
|
+
// eslint-disable-next-line no-console
|
|
124
|
+
console.log('Posting initial PR comment...');
|
|
125
|
+
|
|
126
|
+
const initialComment = `## Bundle size report
|
|
127
|
+
|
|
128
|
+
Bundle size will be reported once [CircleCI build #${circleBuildNum}](${circleBuildUrl}) finishes.`;
|
|
129
|
+
|
|
130
|
+
await notifyPr(ciInfo.slug, prNumber, 'bundle-size-report', initialComment);
|
|
131
|
+
|
|
132
|
+
// eslint-disable-next-line no-console
|
|
133
|
+
console.log(`Initial PR comment posted for PR #${prNumber}`);
|
|
134
|
+
} catch (/** @type {any} */ error) {
|
|
135
|
+
console.error('Failed to post initial PR comment:', error.message);
|
|
136
|
+
// Don't fail the build for comment failures
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
99
140
|
/**
|
|
100
141
|
* Report command handler
|
|
101
142
|
* @param {ReportCommandArgs} argv - Command line arguments
|
|
@@ -106,7 +147,7 @@ async function reportCommand(argv) {
|
|
|
106
147
|
// Get current repo info and coerce with provided arguments
|
|
107
148
|
const currentRepo = await getCurrentRepoInfo();
|
|
108
149
|
const owner = argOwner ?? currentRepo.owner;
|
|
109
|
-
const repo = argRepo ?? currentRepo.
|
|
150
|
+
const repo = argRepo ?? currentRepo.name;
|
|
110
151
|
|
|
111
152
|
if (typeof pr !== 'number') {
|
|
112
153
|
throw new Error('Invalid pull request number. Please provide a valid --pr option.');
|
|
@@ -126,8 +167,18 @@ async function reportCommand(argv) {
|
|
|
126
167
|
pull_number: pr,
|
|
127
168
|
});
|
|
128
169
|
|
|
170
|
+
const getMergeBaseFromGithubApi = async (
|
|
171
|
+
/** @type {string} */ base,
|
|
172
|
+
/** @type {string} */ head,
|
|
173
|
+
) => {
|
|
174
|
+
const { data } = await octokit.repos.compareCommits({ owner, repo, base, head });
|
|
175
|
+
return data.merge_base_commit.sha;
|
|
176
|
+
};
|
|
177
|
+
|
|
129
178
|
// Generate and print the markdown report
|
|
130
|
-
const report = await renderMarkdownReport(prInfo
|
|
179
|
+
const report = await renderMarkdownReport(prInfo, {
|
|
180
|
+
getMergeBase: getMergeBaseFromGithubApi,
|
|
181
|
+
});
|
|
131
182
|
// eslint-disable-next-line no-console
|
|
132
183
|
console.log(report);
|
|
133
184
|
}
|
|
@@ -143,15 +194,22 @@ async function run(argv) {
|
|
|
143
194
|
|
|
144
195
|
const config = await loadConfig(rootDir);
|
|
145
196
|
|
|
197
|
+
// Post initial PR comment if enabled and in CI environment
|
|
198
|
+
if (config && config.comment) {
|
|
199
|
+
await postInitialPrComment();
|
|
200
|
+
}
|
|
201
|
+
|
|
146
202
|
// eslint-disable-next-line no-console
|
|
147
203
|
console.log(`Starting bundle size snapshot creation with ${concurrency} workers...`);
|
|
148
204
|
|
|
149
|
-
const
|
|
150
|
-
const
|
|
205
|
+
const bundleSizes = await getBundleSizes(argv, config);
|
|
206
|
+
const sortedBundleSizes = Object.fromEntries(
|
|
207
|
+
bundleSizes.sort((a, b) => a[0].localeCompare(b[0])),
|
|
208
|
+
);
|
|
151
209
|
|
|
152
210
|
// Ensure output directory exists
|
|
153
211
|
await fs.mkdir(path.dirname(snapshotDestPath), { recursive: true });
|
|
154
|
-
await fs.writeFile(snapshotDestPath, JSON.stringify(
|
|
212
|
+
await fs.writeFile(snapshotDestPath, JSON.stringify(sortedBundleSizes, null, 2));
|
|
155
213
|
|
|
156
214
|
// eslint-disable-next-line no-console
|
|
157
215
|
console.log(`Bundle size snapshot written to ${snapshotDestPath}`);
|
|
@@ -169,6 +227,57 @@ async function run(argv) {
|
|
|
169
227
|
// Exit with error code to indicate failure
|
|
170
228
|
process.exit(1);
|
|
171
229
|
}
|
|
230
|
+
} else {
|
|
231
|
+
// eslint-disable-next-line no-console
|
|
232
|
+
console.log('No upload configuration provided, skipping upload.');
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Post PR comment if enabled and in CI environment
|
|
236
|
+
if (config && config.comment) {
|
|
237
|
+
const ciInfo = getCiInfo();
|
|
238
|
+
|
|
239
|
+
// Skip silently if not in CI or not a PR
|
|
240
|
+
if (!ciInfo || !ciInfo.isPr) {
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// In CI PR builds, all required info must be present
|
|
245
|
+
if (!ciInfo.slug || !ciInfo.pr) {
|
|
246
|
+
throw new Error('PR commenting enabled but repository information missing in CI PR build');
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const prNumber = Number(ciInfo.pr);
|
|
250
|
+
|
|
251
|
+
// eslint-disable-next-line no-console
|
|
252
|
+
console.log('Generating PR comment with bundle size changes...');
|
|
253
|
+
|
|
254
|
+
// Get tracked bundles from config
|
|
255
|
+
const trackedBundles = config.entrypoints
|
|
256
|
+
.filter((entry) => entry.track === true)
|
|
257
|
+
.map((entry) => entry.id);
|
|
258
|
+
|
|
259
|
+
// Get PR info for renderMarkdownReport
|
|
260
|
+
const { data: prInfo } = await octokit.pulls.get({
|
|
261
|
+
owner: ciInfo.slug.split('/')[0],
|
|
262
|
+
repo: ciInfo.slug.split('/')[1],
|
|
263
|
+
pull_number: prNumber,
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
// Generate markdown report
|
|
267
|
+
const report = await renderMarkdownReport(prInfo, {
|
|
268
|
+
track: trackedBundles.length > 0 ? trackedBundles : undefined,
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
// Post or update PR comment
|
|
272
|
+
await notifyPr(
|
|
273
|
+
ciInfo.slug,
|
|
274
|
+
prNumber,
|
|
275
|
+
'bundle-size-report',
|
|
276
|
+
`## Bundle size report\n\n${report}`,
|
|
277
|
+
);
|
|
278
|
+
|
|
279
|
+
// eslint-disable-next-line no-console
|
|
280
|
+
console.log(`PR comment posted/updated for PR #${prNumber}`);
|
|
172
281
|
}
|
|
173
282
|
}
|
|
174
283
|
|
|
@@ -181,12 +290,7 @@ yargs(process.argv.slice(2))
|
|
|
181
290
|
return cmdYargs
|
|
182
291
|
.option('analyze', {
|
|
183
292
|
default: false,
|
|
184
|
-
describe: 'Creates a
|
|
185
|
-
type: 'boolean',
|
|
186
|
-
})
|
|
187
|
-
.option('accurateBundles', {
|
|
188
|
-
default: false,
|
|
189
|
-
describe: 'Displays used bundles accurately at the cost of more CPU cycles.',
|
|
293
|
+
describe: 'Creates a report for each bundle.',
|
|
190
294
|
type: 'boolean',
|
|
191
295
|
})
|
|
192
296
|
.option('verbose', {
|
|
@@ -194,9 +298,10 @@ yargs(process.argv.slice(2))
|
|
|
194
298
|
describe: 'Show more detailed information during compilation.',
|
|
195
299
|
type: 'boolean',
|
|
196
300
|
})
|
|
197
|
-
.option('
|
|
301
|
+
.option('debug', {
|
|
198
302
|
default: false,
|
|
199
|
-
describe:
|
|
303
|
+
describe:
|
|
304
|
+
'Build with readable output (no name mangling or whitespace collapse, but still tree-shake).',
|
|
200
305
|
type: 'boolean',
|
|
201
306
|
})
|
|
202
307
|
.option('output', {
|