@mui/internal-bundle-size-checker 1.0.9-canary.3 → 1.0.9-canary.5
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/package.json +4 -2
- package/src/cli.js +130 -46
- package/src/fetchSnapshot.js +10 -8
- package/src/github.js +7 -0
- package/src/renderMarkdownReport.js +12 -3
- package/src/renderMarkdownReport.test.js +38 -5
- package/src/types.d.ts +6 -0
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.5",
|
|
4
4
|
"description": "Bundle size checker for MUI packages.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"@aws-sdk/client-s3": "^3.515.0",
|
|
23
23
|
"@aws-sdk/credential-providers": "^3.787.0",
|
|
24
24
|
"@babel/core": "^7.27.4",
|
|
25
|
+
"@octokit/rest": "^22.0.0",
|
|
25
26
|
"@babel/preset-react": "^7.18.6",
|
|
26
27
|
"@babel/preset-typescript": "^7.27.1",
|
|
27
28
|
"babel-loader": "^10.0.0",
|
|
@@ -32,6 +33,7 @@
|
|
|
32
33
|
"execa": "^7.2.0",
|
|
33
34
|
"fast-glob": "^3.3.2",
|
|
34
35
|
"file-loader": "^6.2.0",
|
|
36
|
+
"git-url-parse": "^16.1.0",
|
|
35
37
|
"micromatch": "^4.0.8",
|
|
36
38
|
"piscina": "^4.2.1",
|
|
37
39
|
"rollup-plugin-visualizer": "^6.0.1",
|
|
@@ -48,7 +50,7 @@
|
|
|
48
50
|
"@types/webpack-bundle-analyzer": "^4.7.0",
|
|
49
51
|
"@types/yargs": "^17.0.33"
|
|
50
52
|
},
|
|
51
|
-
"gitSha": "
|
|
53
|
+
"gitSha": "8ddf4c81e7d28c0a1b0aa151d76697873870f123",
|
|
52
54
|
"scripts": {
|
|
53
55
|
"typescript": "tsc -p tsconfig.json",
|
|
54
56
|
"test": "pnpm -w test --project @mui/internal-bundle-size-checker"
|
package/src/cli.js
CHANGED
|
@@ -6,8 +6,12 @@ import fs from 'fs/promises';
|
|
|
6
6
|
import yargs from 'yargs';
|
|
7
7
|
import { Piscina } from 'piscina';
|
|
8
8
|
import micromatch from 'micromatch';
|
|
9
|
+
import { execa } from 'execa';
|
|
10
|
+
import gitUrlParse from 'git-url-parse';
|
|
9
11
|
import { loadConfig } from './configLoader.js';
|
|
10
12
|
import { uploadSnapshot } from './uploadSnapshot.js';
|
|
13
|
+
import { renderMarkdownReport } from './renderMarkdownReport.js';
|
|
14
|
+
import { octokit } from './github.js';
|
|
11
15
|
|
|
12
16
|
/**
|
|
13
17
|
* @typedef {import('./sizeDiff.js').SizeSnapshot} SizeSnapshot
|
|
@@ -18,6 +22,26 @@ const DEFAULT_CONCURRENCY = os.availableParallelism();
|
|
|
18
22
|
|
|
19
23
|
const rootDir = process.cwd();
|
|
20
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Gets the current repository owner and name from git remote
|
|
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
|
+
|
|
21
45
|
/**
|
|
22
46
|
* creates size snapshot for every bundle that built with webpack
|
|
23
47
|
* @param {CommandLineArgs} args
|
|
@@ -72,6 +96,42 @@ async function getWebpackSizes(args, config) {
|
|
|
72
96
|
return sizeArrays.flat();
|
|
73
97
|
}
|
|
74
98
|
|
|
99
|
+
/**
|
|
100
|
+
* Report command handler
|
|
101
|
+
* @param {ReportCommandArgs} argv - Command line arguments
|
|
102
|
+
*/
|
|
103
|
+
async function reportCommand(argv) {
|
|
104
|
+
const { pr, owner: argOwner, repo: argRepo } = argv;
|
|
105
|
+
|
|
106
|
+
// Get current repo info and coerce with provided arguments
|
|
107
|
+
const currentRepo = await getCurrentRepoInfo();
|
|
108
|
+
const owner = argOwner ?? currentRepo.owner;
|
|
109
|
+
const repo = argRepo ?? currentRepo.repo;
|
|
110
|
+
|
|
111
|
+
if (typeof pr !== 'number') {
|
|
112
|
+
throw new Error('Invalid pull request number. Please provide a valid --pr option.');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Validate that both owner and repo are available
|
|
116
|
+
if (!owner || !repo) {
|
|
117
|
+
throw new Error(
|
|
118
|
+
'Repository owner and name are required. Please provide --owner and --repo options, or run this command from within a git repository.',
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Fetch PR information
|
|
123
|
+
const { data: prInfo } = await octokit.pulls.get({
|
|
124
|
+
owner,
|
|
125
|
+
repo,
|
|
126
|
+
pull_number: pr,
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// Generate and print the markdown report
|
|
130
|
+
const report = await renderMarkdownReport(prInfo);
|
|
131
|
+
// eslint-disable-next-line no-console
|
|
132
|
+
console.log(report);
|
|
133
|
+
}
|
|
134
|
+
|
|
75
135
|
/**
|
|
76
136
|
* Main runner function
|
|
77
137
|
* @param {CommandLineArgs} argv - Command line arguments
|
|
@@ -113,52 +173,76 @@ async function run(argv) {
|
|
|
113
173
|
}
|
|
114
174
|
|
|
115
175
|
yargs(process.argv.slice(2))
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
176
|
+
.command(
|
|
177
|
+
/** @type {import('yargs').CommandModule<{}, CommandLineArgs>} */ ({
|
|
178
|
+
command: '$0',
|
|
179
|
+
describe: 'Saves a size snapshot in size-snapshot.json',
|
|
180
|
+
builder: (cmdYargs) => {
|
|
181
|
+
return cmdYargs
|
|
182
|
+
.option('analyze', {
|
|
183
|
+
default: false,
|
|
184
|
+
describe: 'Creates a webpack-bundle-analyzer report for each bundle.',
|
|
185
|
+
type: 'boolean',
|
|
186
|
+
})
|
|
187
|
+
.option('accurateBundles', {
|
|
188
|
+
default: false,
|
|
189
|
+
describe: 'Displays used bundles accurately at the cost of more CPU cycles.',
|
|
190
|
+
type: 'boolean',
|
|
191
|
+
})
|
|
192
|
+
.option('verbose', {
|
|
193
|
+
default: false,
|
|
194
|
+
describe: 'Show more detailed information during compilation.',
|
|
195
|
+
type: 'boolean',
|
|
196
|
+
})
|
|
197
|
+
.option('vite', {
|
|
198
|
+
default: false,
|
|
199
|
+
describe: 'Use Vite instead of webpack for bundling.',
|
|
200
|
+
type: 'boolean',
|
|
201
|
+
})
|
|
202
|
+
.option('output', {
|
|
203
|
+
alias: 'o',
|
|
204
|
+
describe:
|
|
205
|
+
'Path to output the size snapshot JSON file (defaults to size-snapshot.json in current directory).',
|
|
206
|
+
type: 'string',
|
|
207
|
+
})
|
|
208
|
+
.option('filter', {
|
|
209
|
+
alias: 'F',
|
|
210
|
+
describe: 'Filter entry points by glob pattern(s) applied to their IDs',
|
|
211
|
+
type: 'array',
|
|
212
|
+
})
|
|
213
|
+
.option('concurrency', {
|
|
214
|
+
alias: 'c',
|
|
215
|
+
describe: 'Number of workers to use for parallel processing',
|
|
216
|
+
type: 'number',
|
|
217
|
+
default: DEFAULT_CONCURRENCY,
|
|
218
|
+
});
|
|
219
|
+
},
|
|
220
|
+
handler: run,
|
|
221
|
+
}),
|
|
222
|
+
)
|
|
223
|
+
.command(
|
|
224
|
+
/** @type {import('yargs').CommandModule<{}, ReportCommandArgs>} */ ({
|
|
225
|
+
command: 'report',
|
|
226
|
+
describe: 'Generate a markdown report for a pull request',
|
|
227
|
+
builder: (cmdYargs) => {
|
|
228
|
+
return cmdYargs
|
|
229
|
+
.option('pr', {
|
|
230
|
+
describe: 'Pull request number',
|
|
231
|
+
type: 'number',
|
|
232
|
+
demandOption: true,
|
|
233
|
+
})
|
|
234
|
+
.option('owner', {
|
|
235
|
+
describe: 'Repository owner (defaults to current git repo owner)',
|
|
236
|
+
type: 'string',
|
|
237
|
+
})
|
|
238
|
+
.option('repo', {
|
|
239
|
+
describe: 'Repository name (defaults to current git repo name)',
|
|
240
|
+
type: 'string',
|
|
241
|
+
});
|
|
242
|
+
},
|
|
243
|
+
handler: reportCommand,
|
|
244
|
+
}),
|
|
245
|
+
)
|
|
162
246
|
.help()
|
|
163
247
|
.strict(true)
|
|
164
248
|
.version(false)
|
package/src/fetchSnapshot.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { octokit } from './github.js';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
*
|
|
3
5
|
* @param {string} repo - The name of the repository e.g. 'mui/material-ui'
|
|
@@ -44,15 +46,15 @@ export async function fetchSnapshot(repo, sha) {
|
|
|
44
46
|
*/
|
|
45
47
|
async function getParentCommits(repo, commit, depth = 4) {
|
|
46
48
|
try {
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
const [owner, repoName] = repo.split('/');
|
|
50
|
+
|
|
51
|
+
const { data: commits } = await octokit.repos.listCommits({
|
|
52
|
+
owner,
|
|
53
|
+
repo: repoName,
|
|
54
|
+
sha: commit,
|
|
55
|
+
per_page: depth,
|
|
56
|
+
});
|
|
53
57
|
|
|
54
|
-
/** @type {{ sha: string }[]} */
|
|
55
|
-
const commits = await response.json();
|
|
56
58
|
// Skip the first commit (which is the starting commit) and return the rest
|
|
57
59
|
return commits.slice(1).map((commitDetails) => commitDetails.sha);
|
|
58
60
|
} catch (/** @type {any} */ error) {
|
package/src/github.js
ADDED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import { calculateSizeDiff } from './sizeDiff.js';
|
|
8
8
|
import { fetchSnapshot, fetchSnapshotWithFallback } from './fetchSnapshot.js';
|
|
9
9
|
import { displayPercentFormatter, byteSizeChangeFormatter } from './formatUtils.js';
|
|
10
|
+
import { octokit } from './github.js';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Generates a symbol based on the relative change value.
|
|
@@ -224,11 +225,19 @@ function getDetailsUrl(prInfo, options = {}) {
|
|
|
224
225
|
export async function renderMarkdownReport(prInfo, circleciBuildNumber, options = {}) {
|
|
225
226
|
let markdownContent = '';
|
|
226
227
|
|
|
227
|
-
const baseCommit = prInfo.base.sha;
|
|
228
228
|
const prCommit = prInfo.head.sha;
|
|
229
229
|
const repo = prInfo.base.repo.full_name;
|
|
230
230
|
const { fallbackDepth = 3 } = options;
|
|
231
231
|
|
|
232
|
+
const [owner, repoName] = repo.split('/');
|
|
233
|
+
const { data } = await octokit.repos.compareCommits({
|
|
234
|
+
owner,
|
|
235
|
+
repo: repoName,
|
|
236
|
+
base: prInfo.base.sha,
|
|
237
|
+
head: prCommit,
|
|
238
|
+
});
|
|
239
|
+
const baseCommit = data.merge_base_commit.sha;
|
|
240
|
+
|
|
232
241
|
const [baseResult, prSnapshot] = await Promise.all([
|
|
233
242
|
fetchSnapshotWithFallback(repo, baseCommit, fallbackDepth),
|
|
234
243
|
fetchSnapshot(repo, prCommit),
|
|
@@ -237,9 +246,9 @@ export async function renderMarkdownReport(prInfo, circleciBuildNumber, options
|
|
|
237
246
|
const { snapshot: baseSnapshot, actualCommit: actualBaseCommit } = baseResult;
|
|
238
247
|
|
|
239
248
|
if (!baseSnapshot) {
|
|
240
|
-
markdownContent += `_:no_entry_sign: No bundle size snapshot found for base
|
|
249
|
+
markdownContent += `_:no_entry_sign: No bundle size snapshot found for merge base ${baseCommit} or any of its ${fallbackDepth} parent commits._\n\n`;
|
|
241
250
|
} else if (actualBaseCommit !== baseCommit) {
|
|
242
|
-
markdownContent += `_:information_source: Using snapshot from parent commit ${actualBaseCommit} (fallback from ${baseCommit})._\n\n`;
|
|
251
|
+
markdownContent += `_:information_source: Using snapshot from parent commit ${actualBaseCommit} (fallback from merge base ${baseCommit})._\n\n`;
|
|
243
252
|
}
|
|
244
253
|
|
|
245
254
|
const sizeDiff = calculateSizeDiff(baseSnapshot ?? {}, prSnapshot);
|
|
@@ -5,6 +5,18 @@ import * as fetchSnapshotModule from './fetchSnapshot.js';
|
|
|
5
5
|
|
|
6
6
|
// Mock the fetchSnapshot module
|
|
7
7
|
vi.mock('./fetchSnapshot.js');
|
|
8
|
+
// Mock the @octokit/rest module
|
|
9
|
+
vi.mock('@octokit/rest', () => ({
|
|
10
|
+
Octokit: vi.fn(() => ({
|
|
11
|
+
repos: {
|
|
12
|
+
compareCommits: vi.fn(),
|
|
13
|
+
listCommits: vi.fn(),
|
|
14
|
+
},
|
|
15
|
+
pulls: {
|
|
16
|
+
get: vi.fn(),
|
|
17
|
+
},
|
|
18
|
+
})),
|
|
19
|
+
}));
|
|
8
20
|
|
|
9
21
|
describe('renderMarkdownReport', () => {
|
|
10
22
|
const mockFetchSnapshot = vi.mocked(fetchSnapshotModule.fetchSnapshot);
|
|
@@ -24,9 +36,26 @@ describe('renderMarkdownReport', () => {
|
|
|
24
36
|
},
|
|
25
37
|
};
|
|
26
38
|
|
|
27
|
-
beforeEach(() => {
|
|
39
|
+
beforeEach(async () => {
|
|
28
40
|
mockFetchSnapshot.mockClear();
|
|
29
41
|
mockFetchSnapshotWithFallback.mockClear();
|
|
42
|
+
|
|
43
|
+
// Import and mock the octokit instance after mocking the module
|
|
44
|
+
const { octokit } = await import('./github.js');
|
|
45
|
+
|
|
46
|
+
// Set up default mock for compareCommits to return the base commit SHA
|
|
47
|
+
vi.mocked(octokit.repos.compareCommits).mockResolvedValue(
|
|
48
|
+
/** @type {any} */ ({
|
|
49
|
+
data: {
|
|
50
|
+
merge_base_commit: {
|
|
51
|
+
sha: mockPrInfo.base.sha,
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
}),
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
// Clear any previous mock calls
|
|
58
|
+
vi.mocked(octokit.repos.compareCommits).mockClear();
|
|
30
59
|
});
|
|
31
60
|
|
|
32
61
|
it('should generate markdown report with size increases', async () => {
|
|
@@ -109,7 +138,7 @@ describe('renderMarkdownReport', () => {
|
|
|
109
138
|
const result = await renderMarkdownReport(mockPrInfo);
|
|
110
139
|
|
|
111
140
|
expect(result).toContain(
|
|
112
|
-
'No bundle size snapshot found for base
|
|
141
|
+
'No bundle size snapshot found for merge base abc123 or any of its 3 parent commits.',
|
|
113
142
|
);
|
|
114
143
|
});
|
|
115
144
|
|
|
@@ -512,7 +541,9 @@ describe('renderMarkdownReport', () => {
|
|
|
512
541
|
|
|
513
542
|
const result = await renderMarkdownReport(mockPrInfo);
|
|
514
543
|
|
|
515
|
-
expect(result).toContain(
|
|
544
|
+
expect(result).toContain(
|
|
545
|
+
'Using snapshot from parent commit parent1 (fallback from merge base abc123)',
|
|
546
|
+
);
|
|
516
547
|
expect(result).toContain('baseCommit=parent1');
|
|
517
548
|
});
|
|
518
549
|
|
|
@@ -527,7 +558,7 @@ describe('renderMarkdownReport', () => {
|
|
|
527
558
|
const result = await renderMarkdownReport(mockPrInfo);
|
|
528
559
|
|
|
529
560
|
expect(result).toContain(
|
|
530
|
-
'No bundle size snapshot found for base
|
|
561
|
+
'No bundle size snapshot found for merge base abc123 or any of its 3 parent commits.',
|
|
531
562
|
);
|
|
532
563
|
});
|
|
533
564
|
|
|
@@ -548,7 +579,9 @@ describe('renderMarkdownReport', () => {
|
|
|
548
579
|
|
|
549
580
|
const result = await renderMarkdownReport(mockPrInfo, undefined, { fallbackDepth: 1 });
|
|
550
581
|
|
|
551
|
-
expect(result).toContain(
|
|
582
|
+
expect(result).toContain(
|
|
583
|
+
'Using snapshot from parent commit parent1 (fallback from merge base abc123)',
|
|
584
|
+
);
|
|
552
585
|
expect(mockFetchSnapshotWithFallback).toHaveBeenCalledWith('mui/material-ui', 'abc123', 1);
|
|
553
586
|
});
|
|
554
587
|
});
|
package/src/types.d.ts
CHANGED