@mui/internal-bundle-size-checker 1.0.4 → 1.0.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/build/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -4
- package/src/cli.js +10 -272
- package/src/fetchSnapshot.js +58 -0
- package/src/index.js +2 -9
- package/src/renderMarkdownReport.js +72 -74
- package/src/renderMarkdownReport.test.js +559 -0
- package/src/types.d.ts +1 -58
- package/src/viteBuilder.js +229 -0
- package/src/webpackBuilder.js +267 -0
- package/src/worker.js +51 -283
- package/vite.config.mts +5 -0
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import fs from 'fs/promises';
|
|
3
|
+
import { gzipSync } from 'zlib';
|
|
4
|
+
import { build, transformWithEsbuild } from 'vite';
|
|
5
|
+
import { visualizer } from 'rollup-plugin-visualizer';
|
|
6
|
+
|
|
7
|
+
const rootDir = process.cwd();
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @typedef {Object} ManifestChunk
|
|
11
|
+
* @property {string} file - Hashed filename of the chunk
|
|
12
|
+
* @property {string} [name] - Optional name of the chunk
|
|
13
|
+
* @property {string} [src] - Original source path
|
|
14
|
+
* @property {string[]} [css] - Associated CSS files
|
|
15
|
+
* @property {boolean} [isEntry] - Indicates if this is an entry point
|
|
16
|
+
* @property {boolean} [isDynamicEntry] - Indicates if this is a dynamic entry point
|
|
17
|
+
* @property {string[]} [imports] - Imported chunk keys
|
|
18
|
+
* @property {string[]} [dynamicImports] - Dynamically imported chunk keys
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @typedef {Record<string, ManifestChunk>} Manifest
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Creates vite configuration for bundle size checking
|
|
27
|
+
* @param {ObjectEntry} entry - Entry point (string or object)
|
|
28
|
+
* @param {CommandLineArgs} args
|
|
29
|
+
* @returns {Promise<{configuration: import('vite').InlineConfig, externalsArray: string[]}>}
|
|
30
|
+
*/
|
|
31
|
+
async function createViteConfig(entry, args) {
|
|
32
|
+
const entryName = entry.id;
|
|
33
|
+
let entryContent;
|
|
34
|
+
|
|
35
|
+
if (entry.code && (entry.import || entry.importedNames)) {
|
|
36
|
+
entryContent = entry.code;
|
|
37
|
+
} else if (entry.code) {
|
|
38
|
+
entryContent = entry.code;
|
|
39
|
+
} else if (entry.import) {
|
|
40
|
+
if (entry.importedNames && entry.importedNames.length > 0) {
|
|
41
|
+
// Generate named imports for each name in the importedNames array
|
|
42
|
+
const imports = entry.importedNames
|
|
43
|
+
.map((name) => `import { ${name} } from '${entry.import}';`)
|
|
44
|
+
.join('\n');
|
|
45
|
+
const logs = entry.importedNames.map((name) => `console.log(${name});`).join('\n');
|
|
46
|
+
entryContent = `${imports}\n${logs}`;
|
|
47
|
+
} else {
|
|
48
|
+
// Default to import * as if importedNames is not defined
|
|
49
|
+
entryContent = `import * as _ from '${entry.import}';\nconsole.log(_);`;
|
|
50
|
+
}
|
|
51
|
+
} else {
|
|
52
|
+
throw new Error(`Entry "${entry.id}" must have either code or import property defined`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Use externals from the entry object
|
|
56
|
+
const externalsArray = entry.externals || ['react', 'react-dom'];
|
|
57
|
+
|
|
58
|
+
// Ensure build directory exists
|
|
59
|
+
const outDir = path.join(rootDir, 'build', entryName);
|
|
60
|
+
await fs.mkdir(outDir, { recursive: true });
|
|
61
|
+
/**
|
|
62
|
+
* @type {import('vite').InlineConfig}
|
|
63
|
+
*/
|
|
64
|
+
const configuration = {
|
|
65
|
+
configFile: false,
|
|
66
|
+
root: rootDir,
|
|
67
|
+
|
|
68
|
+
build: {
|
|
69
|
+
write: true,
|
|
70
|
+
minify: true,
|
|
71
|
+
outDir,
|
|
72
|
+
emptyOutDir: true,
|
|
73
|
+
rollupOptions: {
|
|
74
|
+
input: '/index.tsx',
|
|
75
|
+
external: externalsArray,
|
|
76
|
+
plugins: [
|
|
77
|
+
...(args.analyze
|
|
78
|
+
? [
|
|
79
|
+
// File sizes are not accurate, use it only for relative comparison
|
|
80
|
+
visualizer({
|
|
81
|
+
filename: `${outDir}.html`,
|
|
82
|
+
title: `Bundle Size Analysis: ${entryName}`,
|
|
83
|
+
projectRoot: rootDir,
|
|
84
|
+
open: false,
|
|
85
|
+
gzipSize: true,
|
|
86
|
+
brotliSize: false,
|
|
87
|
+
template: 'treemap',
|
|
88
|
+
}),
|
|
89
|
+
]
|
|
90
|
+
: []),
|
|
91
|
+
],
|
|
92
|
+
},
|
|
93
|
+
manifest: true,
|
|
94
|
+
reportCompressedSize: true,
|
|
95
|
+
target: 'esnext',
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
esbuild: {
|
|
99
|
+
legalComments: 'none',
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
define: {
|
|
103
|
+
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'production'),
|
|
104
|
+
},
|
|
105
|
+
logLevel: args.verbose ? 'info' : 'silent',
|
|
106
|
+
// Add plugins to handle virtual entry points
|
|
107
|
+
plugins: [
|
|
108
|
+
{
|
|
109
|
+
name: 'virtual-entry',
|
|
110
|
+
resolveId(id) {
|
|
111
|
+
if (id === '/index.tsx') {
|
|
112
|
+
return `\0virtual:index.tsx`;
|
|
113
|
+
}
|
|
114
|
+
if (id === '/entry.tsx') {
|
|
115
|
+
return `\0virtual:entry.tsx`;
|
|
116
|
+
}
|
|
117
|
+
return null;
|
|
118
|
+
},
|
|
119
|
+
load(id) {
|
|
120
|
+
if (id === `\0virtual:index.tsx`) {
|
|
121
|
+
return transformWithEsbuild(`import('/entry.tsx').then(console.log)`, id);
|
|
122
|
+
}
|
|
123
|
+
if (id === `\0virtual:entry.tsx`) {
|
|
124
|
+
return transformWithEsbuild(entryContent, id);
|
|
125
|
+
}
|
|
126
|
+
return null;
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
return { configuration, externalsArray };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Walks the dependency tree starting from a chunk and collects all dependencies
|
|
137
|
+
* @param {string} chunkKey - The key of the chunk to start from
|
|
138
|
+
* @param {Manifest} manifest - The Vite manifest
|
|
139
|
+
* @param {Set<string>} visited - Set of already visited chunks to avoid cycles
|
|
140
|
+
* @returns {Set<string>} - Set of all chunk keys in the dependency tree
|
|
141
|
+
*/
|
|
142
|
+
function walkDependencyTree(chunkKey, manifest, visited = new Set()) {
|
|
143
|
+
if (visited.has(chunkKey)) {
|
|
144
|
+
return visited;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
visited.add(chunkKey);
|
|
148
|
+
const chunk = manifest[chunkKey];
|
|
149
|
+
|
|
150
|
+
if (!chunk) {
|
|
151
|
+
throw new Error(`Chunk not found in manifest: ${chunkKey}`);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Walk through static imports
|
|
155
|
+
if (chunk.imports) {
|
|
156
|
+
for (const importKey of chunk.imports) {
|
|
157
|
+
walkDependencyTree(importKey, manifest, visited);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Walk through dynamic imports
|
|
162
|
+
if (chunk.dynamicImports) {
|
|
163
|
+
for (const dynamicImportKey of chunk.dynamicImports) {
|
|
164
|
+
walkDependencyTree(dynamicImportKey, manifest, visited);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return visited;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Process vite output to extract bundle sizes
|
|
173
|
+
* @param {string} outDir - The output directory
|
|
174
|
+
* @param {string} entryName - The entry name
|
|
175
|
+
* @returns {Promise<Map<string, { parsed: number, gzip: number }>>} - Map of bundle names to size information
|
|
176
|
+
*/
|
|
177
|
+
async function processBundleSizes(outDir, entryName) {
|
|
178
|
+
// Read the manifest file to find the generated chunks
|
|
179
|
+
const manifestPath = path.join(outDir, '.vite/manifest.json');
|
|
180
|
+
const manifestContent = await fs.readFile(manifestPath, 'utf8');
|
|
181
|
+
/** @type {Manifest} */
|
|
182
|
+
const manifest = JSON.parse(manifestContent);
|
|
183
|
+
|
|
184
|
+
// Find the main entry point JS file in the manifest
|
|
185
|
+
const mainEntry = manifest['virtual:entry.tsx'];
|
|
186
|
+
|
|
187
|
+
if (!mainEntry) {
|
|
188
|
+
throw new Error(`No main entry found in manifest for ${entryName}`);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Walk the dependency tree to get all chunks that are part of this entry
|
|
192
|
+
const allChunks = walkDependencyTree('virtual:entry.tsx', manifest);
|
|
193
|
+
|
|
194
|
+
// Process each chunk in the dependency tree in parallel
|
|
195
|
+
const chunkPromises = Array.from(allChunks, async (chunkKey) => {
|
|
196
|
+
const chunk = manifest[chunkKey];
|
|
197
|
+
const filePath = path.join(outDir, chunk.file);
|
|
198
|
+
const fileContent = await fs.readFile(filePath, 'utf8');
|
|
199
|
+
|
|
200
|
+
// Calculate sizes
|
|
201
|
+
const parsed = Buffer.byteLength(fileContent);
|
|
202
|
+
const gzip = Buffer.byteLength(gzipSync(fileContent));
|
|
203
|
+
|
|
204
|
+
// Use chunk key as the name, or fallback to entry name for main chunk
|
|
205
|
+
const chunkName = chunkKey === 'virtual:entry.tsx' ? entryName : chunkKey;
|
|
206
|
+
return /** @type {const} */ ([chunkName, { parsed, gzip }]);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
const chunkEntries = await Promise.all(chunkPromises);
|
|
210
|
+
return new Map(chunkEntries);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Get sizes for a vite bundle
|
|
215
|
+
* @param {ObjectEntry} entry - The entry configuration
|
|
216
|
+
* @param {CommandLineArgs} args - Command line arguments
|
|
217
|
+
* @returns {Promise<Map<string, { parsed: number, gzip: number }>>}
|
|
218
|
+
*/
|
|
219
|
+
export async function getViteSizes(entry, args) {
|
|
220
|
+
// Create vite configuration
|
|
221
|
+
const { configuration } = await createViteConfig(entry, args);
|
|
222
|
+
const outDir = path.join(rootDir, 'build', entry.id);
|
|
223
|
+
|
|
224
|
+
// Run vite build
|
|
225
|
+
await build(configuration);
|
|
226
|
+
|
|
227
|
+
// Process the output to get bundle sizes
|
|
228
|
+
return processBundleSizes(outDir, entry.id);
|
|
229
|
+
}
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import { promisify } from 'util';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import webpackCallbackBased from 'webpack';
|
|
4
|
+
import CompressionPlugin from 'compression-webpack-plugin';
|
|
5
|
+
import TerserPlugin from 'terser-webpack-plugin';
|
|
6
|
+
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
|
|
7
|
+
import { createRequire } from 'node:module';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @type {(options: webpackCallbackBased.Configuration) => Promise<webpackCallbackBased.Stats>}
|
|
11
|
+
*/
|
|
12
|
+
// @ts-expect-error Can't select the right overload
|
|
13
|
+
const webpack = promisify(webpackCallbackBased);
|
|
14
|
+
const rootDir = process.cwd();
|
|
15
|
+
const require = createRequire(import.meta.url);
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Creates webpack configuration for bundle size checking
|
|
19
|
+
* @param {ObjectEntry} entry - Entry point (string or object)
|
|
20
|
+
* @param {CommandLineArgs} args
|
|
21
|
+
* @returns {Promise<{configuration: import('webpack').Configuration, externalsArray: string[]}>}
|
|
22
|
+
*/
|
|
23
|
+
async function createWebpackConfig(entry, args) {
|
|
24
|
+
const analyzerMode = args.analyze ? 'static' : 'disabled';
|
|
25
|
+
const concatenateModules = !args.accurateBundles;
|
|
26
|
+
|
|
27
|
+
const entryName = entry.id;
|
|
28
|
+
let entryContent;
|
|
29
|
+
|
|
30
|
+
if (entry.code && (entry.import || entry.importedNames)) {
|
|
31
|
+
entryContent = entry.code;
|
|
32
|
+
} else if (entry.code) {
|
|
33
|
+
entryContent = entry.code;
|
|
34
|
+
} else if (entry.import) {
|
|
35
|
+
if (entry.importedNames && entry.importedNames.length > 0) {
|
|
36
|
+
// Generate named imports for each name in the importedNames array
|
|
37
|
+
const imports = entry.importedNames
|
|
38
|
+
.map((name) => `import { ${name} } from '${entry.import}';`)
|
|
39
|
+
.join('\n');
|
|
40
|
+
const logs = entry.importedNames.map((name) => `console.log(${name});`).join('\n');
|
|
41
|
+
entryContent = `${imports}\n${logs}`;
|
|
42
|
+
} else {
|
|
43
|
+
// Default to import * as if importedNames is not defined
|
|
44
|
+
entryContent = `import * as _ from '${entry.import}';\nconsole.log(_);`;
|
|
45
|
+
}
|
|
46
|
+
} else {
|
|
47
|
+
throw new Error(`Entry "${entry.id}" must have either code or import property defined`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Generate externals function from an array of package names
|
|
52
|
+
* @param {string[]} packages - Array of package names to exclude (defaults to react and react-dom)
|
|
53
|
+
* @returns {function} - Function to determine if a request should be treated as external
|
|
54
|
+
*/
|
|
55
|
+
function createExternalsFunction(packages = ['react', 'react-dom']) {
|
|
56
|
+
/**
|
|
57
|
+
* Check if a request should be treated as external
|
|
58
|
+
* Uses the new recommended format to avoid deprecation warnings
|
|
59
|
+
* @param {{ context: string, request: string }} params - Object containing context and request
|
|
60
|
+
* @param {Function} callback - Callback to handle the result
|
|
61
|
+
*/
|
|
62
|
+
return ({ request }, callback) => {
|
|
63
|
+
// Iterate through all packages and check if request is equal to or starts with package + '/'
|
|
64
|
+
for (const pkg of packages) {
|
|
65
|
+
if (request === pkg || request.startsWith(`${pkg}/`)) {
|
|
66
|
+
return callback(null, `commonjs ${request}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return callback();
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Use externals from the entry object
|
|
75
|
+
const externalsArray = entry.externals || ['react', 'react-dom'];
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* @type {import('webpack').Configuration}
|
|
79
|
+
*/
|
|
80
|
+
const configuration = {
|
|
81
|
+
externals: [
|
|
82
|
+
// @ts-expect-error -- webpack types are not compatible with the current version
|
|
83
|
+
createExternalsFunction(externalsArray),
|
|
84
|
+
],
|
|
85
|
+
mode: 'production',
|
|
86
|
+
optimization: {
|
|
87
|
+
concatenateModules,
|
|
88
|
+
minimizer: [
|
|
89
|
+
new TerserPlugin({
|
|
90
|
+
test: /\.m?js(\?.*)?$/i,
|
|
91
|
+
// Avoid creating LICENSE.txt files for each module
|
|
92
|
+
// See https://github.com/webpack-contrib/terser-webpack-plugin#remove-comments
|
|
93
|
+
terserOptions: {
|
|
94
|
+
format: {
|
|
95
|
+
comments: false,
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
extractComments: false,
|
|
99
|
+
}),
|
|
100
|
+
],
|
|
101
|
+
},
|
|
102
|
+
module: {
|
|
103
|
+
rules: [
|
|
104
|
+
{
|
|
105
|
+
test: /\.[jt]sx?$/,
|
|
106
|
+
include: rootDir,
|
|
107
|
+
exclude: /node_modules/,
|
|
108
|
+
use: {
|
|
109
|
+
loader: require.resolve('babel-loader'),
|
|
110
|
+
options: {
|
|
111
|
+
presets: [
|
|
112
|
+
require.resolve('@babel/preset-react'),
|
|
113
|
+
require.resolve('@babel/preset-typescript'),
|
|
114
|
+
],
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
test: /\.css$/,
|
|
120
|
+
use: [require.resolve('css-loader')],
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
test: /\.(png|svg|jpg|gif)$/,
|
|
124
|
+
use: [require.resolve('file-loader')],
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
},
|
|
128
|
+
output: {
|
|
129
|
+
filename: '[name].js',
|
|
130
|
+
library: {
|
|
131
|
+
// TODO: Use `type: 'module'` once it is supported (currently incompatible with `externals`)
|
|
132
|
+
name: 'M',
|
|
133
|
+
type: 'var',
|
|
134
|
+
// type: 'module',
|
|
135
|
+
},
|
|
136
|
+
path: path.join(rootDir, 'build'),
|
|
137
|
+
},
|
|
138
|
+
plugins: [
|
|
139
|
+
new CompressionPlugin({
|
|
140
|
+
filename: '[path][base][fragment].gz',
|
|
141
|
+
}),
|
|
142
|
+
new BundleAnalyzerPlugin({
|
|
143
|
+
analyzerMode,
|
|
144
|
+
// We create a report for each bundle so around 120 reports.
|
|
145
|
+
// Opening them all is spam.
|
|
146
|
+
// If opened with `webpack --config . --analyze` it'll still open one new tab though.
|
|
147
|
+
openAnalyzer: false,
|
|
148
|
+
// '[name].html' not supported: https://github.com/webpack-contrib/webpack-bundle-analyzer/issues/12
|
|
149
|
+
reportFilename: `${entryName}.html`,
|
|
150
|
+
logLevel: 'warn',
|
|
151
|
+
}),
|
|
152
|
+
],
|
|
153
|
+
// A context to the current dir, which has a node_modules folder with workspace dependencies
|
|
154
|
+
context: rootDir,
|
|
155
|
+
entry: {
|
|
156
|
+
// This format is a data: url combined with inline matchResource to obtain a virtual entry.
|
|
157
|
+
// See https://github.com/webpack/webpack/issues/6437#issuecomment-874466638
|
|
158
|
+
// See https://webpack.js.org/api/module-methods/#import
|
|
159
|
+
// See https://webpack.js.org/api/loaders/#inline-matchresource
|
|
160
|
+
[entryName]: `./index.js!=!data:text/javascript;charset=utf-8;base64,${Buffer.from(entryContent.trim()).toString('base64')}`,
|
|
161
|
+
},
|
|
162
|
+
// TODO: 'browserslist:modern'
|
|
163
|
+
// See https://github.com/webpack/webpack/issues/14203
|
|
164
|
+
target: 'web',
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
// Return both the configuration and the externals array
|
|
168
|
+
return { configuration, externalsArray };
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Process webpack stats to extract bundle sizes
|
|
173
|
+
* @param {import('webpack').Stats} webpackStats - The webpack stats object
|
|
174
|
+
* @returns {Map<string, { parsed: number, gzip: number }>} - Map of bundle names to size information
|
|
175
|
+
*/
|
|
176
|
+
function processBundleSizes(webpackStats) {
|
|
177
|
+
/** @type {Map<string, { parsed: number, gzip: number }>} */
|
|
178
|
+
const sizeMap = new Map();
|
|
179
|
+
|
|
180
|
+
if (!webpackStats) {
|
|
181
|
+
throw new Error('No webpack stats were returned');
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (webpackStats.hasErrors()) {
|
|
185
|
+
const statsJson = webpackStats.toJson({
|
|
186
|
+
all: false,
|
|
187
|
+
entrypoints: true,
|
|
188
|
+
errors: true,
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
const entrypointKeys = statsJson.entrypoints ? Object.keys(statsJson.entrypoints) : [];
|
|
192
|
+
|
|
193
|
+
throw new Error(
|
|
194
|
+
`ERROR: The following errors occurred during bundling of ${entrypointKeys.join(', ')} with webpack: \n${(
|
|
195
|
+
statsJson.errors || []
|
|
196
|
+
)
|
|
197
|
+
.map((error) => {
|
|
198
|
+
return `${JSON.stringify(error, null, 2)}`;
|
|
199
|
+
})
|
|
200
|
+
.join('\n')}`,
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const stats = webpackStats.toJson({
|
|
205
|
+
all: false,
|
|
206
|
+
assets: true,
|
|
207
|
+
entrypoints: true,
|
|
208
|
+
relatedAssets: true,
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
if (!stats.assets) {
|
|
212
|
+
return sizeMap;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const assets = new Map(stats.assets.map((asset) => [asset.name, asset]));
|
|
216
|
+
|
|
217
|
+
if (stats.entrypoints) {
|
|
218
|
+
Object.values(stats.entrypoints).forEach((entrypoint) => {
|
|
219
|
+
let parsedSize = 0;
|
|
220
|
+
let gzipSize = 0;
|
|
221
|
+
|
|
222
|
+
if (entrypoint.assets) {
|
|
223
|
+
entrypoint.assets.forEach(({ name, size }) => {
|
|
224
|
+
const asset = assets.get(name);
|
|
225
|
+
if (asset && asset.related) {
|
|
226
|
+
const gzippedAsset = asset.related.find((relatedAsset) => {
|
|
227
|
+
return relatedAsset.type === 'gzipped';
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
if (size !== undefined) {
|
|
231
|
+
parsedSize += size;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (gzippedAsset && gzippedAsset.size !== undefined) {
|
|
235
|
+
gzipSize += gzippedAsset.size;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (!entrypoint.name) {
|
|
242
|
+
throw new Error('Entrypoint name is undefined');
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
sizeMap.set(entrypoint.name, { parsed: parsedSize, gzip: gzipSize });
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return sizeMap;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Get sizes for a webpack bundle
|
|
254
|
+
* @param {ObjectEntry} entry - The entry configuration
|
|
255
|
+
* @param {CommandLineArgs} args - Command line arguments
|
|
256
|
+
* @returns {Promise<Map<string, { parsed: number, gzip: number }>>}
|
|
257
|
+
*/
|
|
258
|
+
export async function getWebpackSizes(entry, args) {
|
|
259
|
+
// Create webpack configuration
|
|
260
|
+
const { configuration } = await createWebpackConfig(entry, args);
|
|
261
|
+
|
|
262
|
+
// Run webpack
|
|
263
|
+
const webpackStats = await webpack(configuration);
|
|
264
|
+
|
|
265
|
+
// Process the webpack stats to get bundle sizes
|
|
266
|
+
return processBundleSizes(webpackStats);
|
|
267
|
+
}
|