@mui/internal-bundle-size-checker 1.0.9-canary.46 → 1.0.9-canary.47
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 +2 -2
- package/src/builder.js +14 -9
- package/src/cli.js +5 -1
- package/src/strings.js +38 -0
- package/src/worker.js +2 -3
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.47",
|
|
4
4
|
"description": "Bundle size checker for MUI packages.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"@types/micromatch": "^4.0.9",
|
|
38
38
|
"@types/yargs": "^17.0.33"
|
|
39
39
|
},
|
|
40
|
-
"gitSha": "
|
|
40
|
+
"gitSha": "1e49380da7c1a731162a8815a0bc3d1c528fd360",
|
|
41
41
|
"scripts": {
|
|
42
42
|
"typescript": "tsc -p tsconfig.json",
|
|
43
43
|
"test": "pnpm -w test --project @mui/internal-bundle-size-checker"
|
package/src/builder.js
CHANGED
|
@@ -4,6 +4,7 @@ import * as zlib from 'node:zlib';
|
|
|
4
4
|
import { promisify } from 'node:util';
|
|
5
5
|
import { build, transformWithEsbuild } from 'vite';
|
|
6
6
|
import { visualizer } from 'rollup-plugin-visualizer';
|
|
7
|
+
import { escapeFilename } from './strings.js';
|
|
7
8
|
|
|
8
9
|
const gzipAsync = promisify(zlib.gzip);
|
|
9
10
|
|
|
@@ -48,7 +49,7 @@ function createReplacePlugin(replacements) {
|
|
|
48
49
|
* @param {ObjectEntry} entry - Entry point (string or object)
|
|
49
50
|
* @param {CommandLineArgs} args
|
|
50
51
|
* @param {Record<string, string>} [replacements] - String replacements to apply
|
|
51
|
-
* @returns {Promise<import('vite').InlineConfig>}
|
|
52
|
+
* @returns {Promise<{ config:import('vite').InlineConfig, treemapPath: string }>}
|
|
52
53
|
*/
|
|
53
54
|
async function createViteConfig(entry, args, replacements = {}) {
|
|
54
55
|
const entryName = entry.id;
|
|
@@ -78,13 +79,15 @@ async function createViteConfig(entry, args, replacements = {}) {
|
|
|
78
79
|
const externalsArray = entry.externals || ['react', 'react-dom'];
|
|
79
80
|
|
|
80
81
|
// Ensure build directory exists
|
|
81
|
-
const outDir = path.join(rootDir, 'build', entryName);
|
|
82
|
+
const outDir = path.join(rootDir, 'build', escapeFilename(entryName));
|
|
82
83
|
await fs.mkdir(outDir, { recursive: true });
|
|
83
84
|
|
|
85
|
+
const treemapPath = path.join(outDir, 'treemap.html');
|
|
86
|
+
|
|
84
87
|
/**
|
|
85
88
|
* @type {import('vite').InlineConfig}
|
|
86
89
|
*/
|
|
87
|
-
const
|
|
90
|
+
const config = {
|
|
88
91
|
configFile: false,
|
|
89
92
|
root: rootDir,
|
|
90
93
|
|
|
@@ -112,7 +115,7 @@ async function createViteConfig(entry, args, replacements = {}) {
|
|
|
112
115
|
? [
|
|
113
116
|
// File sizes are not accurate, use it only for relative comparison
|
|
114
117
|
visualizer({
|
|
115
|
-
filename:
|
|
118
|
+
filename: treemapPath,
|
|
116
119
|
title: `Bundle Size Analysis: ${entryName}`,
|
|
117
120
|
projectRoot: rootDir,
|
|
118
121
|
open: false,
|
|
@@ -171,7 +174,7 @@ async function createViteConfig(entry, args, replacements = {}) {
|
|
|
171
174
|
],
|
|
172
175
|
};
|
|
173
176
|
|
|
174
|
-
return
|
|
177
|
+
return { config, treemapPath };
|
|
175
178
|
}
|
|
176
179
|
|
|
177
180
|
/**
|
|
@@ -275,19 +278,21 @@ async function processBundleSizes(output, entryName) {
|
|
|
275
278
|
* @param {ObjectEntry} entry - The entry configuration
|
|
276
279
|
* @param {CommandLineArgs} args - Command line arguments
|
|
277
280
|
* @param {Record<string, string>} [replacements] - String replacements to apply
|
|
278
|
-
* @returns {Promise<Map<string, SizeSnapshotEntry
|
|
281
|
+
* @returns {Promise<{ sizes: Map<string, SizeSnapshotEntry>, treemapPath: string }>}
|
|
279
282
|
*/
|
|
280
283
|
export async function getBundleSizes(entry, args, replacements) {
|
|
281
284
|
// Create vite configuration
|
|
282
|
-
const
|
|
285
|
+
const { config, treemapPath } = await createViteConfig(entry, args, replacements);
|
|
283
286
|
|
|
284
287
|
// Run vite build
|
|
285
|
-
const { output } = /** @type {import('vite').Rollup.RollupOutput} */ (await build(
|
|
288
|
+
const { output } = /** @type {import('vite').Rollup.RollupOutput} */ (await build(config));
|
|
286
289
|
const manifestChunk = output.find((chunk) => chunk.fileName === '.vite/manifest.json');
|
|
287
290
|
if (!manifestChunk) {
|
|
288
291
|
throw new Error(`Manifest file not found in output for entry: ${entry.id}`);
|
|
289
292
|
}
|
|
290
293
|
|
|
291
294
|
// Process the output to get bundle sizes
|
|
292
|
-
|
|
295
|
+
const sizes = await processBundleSizes(output, entry.id);
|
|
296
|
+
|
|
297
|
+
return { sizes, treemapPath };
|
|
293
298
|
}
|
package/src/cli.js
CHANGED
|
@@ -7,6 +7,8 @@ import yargs from 'yargs';
|
|
|
7
7
|
import { Piscina } from 'piscina';
|
|
8
8
|
import micromatch from 'micromatch';
|
|
9
9
|
import envCi from 'env-ci';
|
|
10
|
+
import { pathToFileURL } from 'node:url';
|
|
11
|
+
import chalk from 'chalk';
|
|
10
12
|
import { loadConfig } from './configLoader.js';
|
|
11
13
|
import { uploadSnapshot } from './uploadSnapshot.js';
|
|
12
14
|
import { renderMarkdownReport } from './renderMarkdownReport.js';
|
|
@@ -229,7 +231,9 @@ async function run(argv) {
|
|
|
229
231
|
await fs.writeFile(snapshotDestPath, JSON.stringify(sortedBundleSizes, null, 2));
|
|
230
232
|
|
|
231
233
|
// eslint-disable-next-line no-console
|
|
232
|
-
console.log(
|
|
234
|
+
console.log(
|
|
235
|
+
`Bundle size snapshot written to ${chalk.underline(pathToFileURL(snapshotDestPath))}`,
|
|
236
|
+
);
|
|
233
237
|
|
|
234
238
|
// Upload the snapshot if upload configuration is provided and not null
|
|
235
239
|
if (config && config.upload) {
|
package/src/strings.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
const illegalRe = /[/?<>\\:*|"]/g;
|
|
2
|
+
// eslint-disable-next-line no-control-regex
|
|
3
|
+
const controlRe = /[\x00-\x1f\x80-\x9f]/g;
|
|
4
|
+
const reservedRe = /^\.+$/;
|
|
5
|
+
const windowsReservedRe = /^(con|prn|aux|nul|com[0-9]|lpt[0-9])(\..*)?$/i;
|
|
6
|
+
const windowsTrailingRe = /[. ]+$/;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Inspired by https://github.com/parshap/node-sanitize-filename
|
|
10
|
+
*
|
|
11
|
+
* Replaces characters in strings that are illegal/unsafe for filenames.
|
|
12
|
+
* Unsafe characters are either removed or replaced by a substitute set
|
|
13
|
+
* in the optional `options` object.
|
|
14
|
+
*
|
|
15
|
+
* Illegal Characters on Various Operating Systems
|
|
16
|
+
* / ? < > \ : * | "
|
|
17
|
+
* https://kb.acronis.com/content/39790
|
|
18
|
+
*
|
|
19
|
+
* Unicode Control codes
|
|
20
|
+
* C0 0x00-0x1f & C1 (0x80-0x9f)
|
|
21
|
+
* http://en.wikipedia.org/wiki/C0_and_C1_control_codes
|
|
22
|
+
*
|
|
23
|
+
* Reserved filenames on Unix-based systems (".", "..")
|
|
24
|
+
* Reserved filenames in Windows ("CON", "PRN", "AUX", "NUL", "COM1",
|
|
25
|
+
* "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
|
|
26
|
+
* "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", and
|
|
27
|
+
* "LPT9") case-insesitively and with or without filename extensions.
|
|
28
|
+
* @param {string} input
|
|
29
|
+
*/
|
|
30
|
+
export function escapeFilename(input, replacement = '_') {
|
|
31
|
+
const sanitized = input
|
|
32
|
+
.replace(illegalRe, replacement)
|
|
33
|
+
.replace(controlRe, replacement)
|
|
34
|
+
.replace(reservedRe, replacement)
|
|
35
|
+
.replace(windowsReservedRe, replacement)
|
|
36
|
+
.replace(windowsTrailingRe, replacement);
|
|
37
|
+
return sanitized;
|
|
38
|
+
}
|
package/src/worker.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { pathToFileURL } from 'node:url';
|
|
2
|
-
import path from 'node:path';
|
|
3
2
|
import fs from 'node:fs/promises';
|
|
4
3
|
import chalk from 'chalk';
|
|
5
4
|
import * as module from 'node:module';
|
|
@@ -83,7 +82,7 @@ export default async function getSizes({ entry, args, index, total, replace }) {
|
|
|
83
82
|
}
|
|
84
83
|
|
|
85
84
|
try {
|
|
86
|
-
const sizeMap = await getBundleSizes(entry, args, replace);
|
|
85
|
+
const { sizes: sizeMap, treemapPath } = await getBundleSizes(entry, args, replace);
|
|
87
86
|
|
|
88
87
|
// Create a concise log message showing import details
|
|
89
88
|
let entryDetails = '';
|
|
@@ -108,7 +107,7 @@ ${chalk.green('✓')} ${chalk.green.bold(`Completed ${index + 1}/${total}: [${en
|
|
|
108
107
|
${chalk.cyan('Import:')} ${entryDetails}
|
|
109
108
|
${chalk.cyan('Externals:')} ${entry.externals.join(', ')}
|
|
110
109
|
${chalk.cyan('Sizes:')} ${chalk.yellow(byteSizeFormatter.format(entrySize.parsed))} (${chalk.yellow(byteSizeFormatter.format(entrySize.gzip))} gzipped)
|
|
111
|
-
${args.analyze ? ` ${chalk.cyan('Analysis:')} ${chalk.underline(pathToFileURL(
|
|
110
|
+
${args.analyze ? ` ${chalk.cyan('Analysis:')} ${chalk.underline(pathToFileURL(treemapPath).href)}` : ''}
|
|
112
111
|
`.trim(),
|
|
113
112
|
);
|
|
114
113
|
|