Skip to content

Commit ec7a3b6

Browse files
committed
Add --analyze flag to enable bundle analyzer to CLI
1 parent 9898fcd commit ec7a3b6

File tree

11 files changed

+756
-13
lines changed

11 files changed

+756
-13
lines changed

packages/snaps-cli/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@
112112
"util": "^0.12.5",
113113
"vm-browserify": "^1.1.2",
114114
"webpack": "^5.88.0",
115+
"webpack-bundle-analyzer": "^4.10.2",
115116
"webpack-merge": "^5.9.0",
116117
"yargs": "^17.7.1"
117118
},
@@ -128,6 +129,7 @@
128129
"@types/jest": "^27.5.1",
129130
"@types/node": "18.14.2",
130131
"@types/serve-handler": "^6.1.0",
132+
"@types/webpack-bundle-analyzer": "^4.7.0",
131133
"@types/yargs": "^17.0.24",
132134
"@typescript-eslint/eslint-plugin": "^5.42.1",
133135
"@typescript-eslint/parser": "^6.21.0",

packages/snaps-cli/src/builders.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,12 @@ export enum TranspilationModes {
66
None = 'none',
77
}
88

9-
const builders: Record<string, Readonly<Options>> = {
10-
// eslint-disable-next-line @typescript-eslint/naming-convention
9+
const builders = {
10+
analyze: {
11+
describe: 'Analyze the Snap bundle',
12+
type: 'boolean',
13+
},
14+
1115
config: {
1216
alias: 'c',
1317
describe: 'Path to config file',
@@ -146,6 +150,6 @@ const builders: Record<string, Readonly<Options>> = {
146150
type: 'boolean',
147151
deprecated: true,
148152
},
149-
};
153+
} as const satisfies Record<string, Readonly<Options>>;
150154

151155
export default builders;

packages/snaps-cli/src/commands/build/build.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ describe('buildHandler', () => {
2727

2828
expect(process.exitCode).not.toBe(1);
2929
expect(build).toHaveBeenCalledWith(config, {
30+
analyze: false,
3031
evaluate: false,
3132
spinner: expect.any(Object),
3233
});

packages/snaps-cli/src/commands/build/build.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { evaluate } from '../eval';
99
import { build } from './implementation';
1010

1111
type BuildContext = {
12+
analyze: boolean;
1213
config: ProcessedWebpackConfig;
1314
};
1415

@@ -27,10 +28,10 @@ const steps: Steps<BuildContext> = [
2728
},
2829
{
2930
name: 'Building the snap bundle.',
30-
task: async ({ config, spinner }) => {
31+
task: async ({ analyze, config, spinner }) => {
3132
// We don't evaluate the bundle here, because it's done in a separate
3233
// step.
33-
return await build(config, { evaluate: false, spinner });
34+
return await build(config, { analyze, evaluate: false, spinner });
3435
},
3536
},
3637
{
@@ -57,10 +58,15 @@ const steps: Steps<BuildContext> = [
5758
* This creates the destination directory if it doesn't exist.
5859
*
5960
* @param config - The config object.
61+
* @param analyze - Whether to analyze the bundle.
6062
* @returns Nothing.
6163
*/
62-
export async function buildHandler(config: ProcessedConfig): Promise<void> {
64+
export async function buildHandler(
65+
config: ProcessedConfig,
66+
analyze = false,
67+
): Promise<void> {
6368
return await executeSteps(steps, {
6469
config,
70+
analyze,
6571
});
6672
}

packages/snaps-cli/src/commands/build/index.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ describe('build command', () => {
1010
const config = getMockConfig('webpack');
1111

1212
// @ts-expect-error - Partial `YargsArgs` is fine for testing.
13-
await command.handler({ context: { config } });
13+
await command.handler({ analyze: false, context: { config } });
1414

15-
expect(buildHandler).toHaveBeenCalledWith(config);
15+
expect(buildHandler).toHaveBeenCalledWith(config, false);
1616
});
1717
});

packages/snaps-cli/src/commands/build/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const command = {
99
desc: 'Build snap from source',
1010
builder: (yarg: yargs.Argv) => {
1111
yarg
12+
.option('analyze', builders.analyze)
1213
.option('dist', builders.dist)
1314
.option('eval', builders.eval)
1415
.option('manifest', builders.manifest)
@@ -22,7 +23,8 @@ const command = {
2223
.implies('writeManifest', 'manifest')
2324
.implies('depsToTranspile', 'transpilationMode');
2425
},
25-
handler: async (argv: YargsArgs) => buildHandler(argv.context.config),
26+
handler: async (argv: YargsArgs) =>
27+
buildHandler(argv.context.config, argv.analyze),
2628
};
2729

2830
export * from './implementation';

packages/snaps-cli/src/types/yargs.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ type YargsArgs = {
2020
config: ProcessedConfig;
2121
};
2222

23+
analyze?: boolean;
2324
fix?: boolean;
2425
input?: string;
2526

packages/snaps-cli/src/webpack/__snapshots__/config.test.ts.snap

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3440,3 +3440,202 @@ exports[`getDefaultConfiguration returns the default Webpack configuration for t
34403440
"target": "browserslist:/foo/bar/.browserslistrc",
34413441
}
34423442
`;
3443+
3444+
exports[`getDefaultConfiguration returns the default Webpack configuration when \`analyze\` is \`true\` 1`] = `
3445+
{
3446+
"devtool": false,
3447+
"entry": "/foo/bar/src/index.js",
3448+
"infrastructureLogging": {
3449+
"level": "none",
3450+
},
3451+
"mode": "production",
3452+
"module": {
3453+
"rules": [
3454+
{
3455+
"exclude": /node_modules/u,
3456+
"test": /\\\\\\.\\(js\\|jsx\\|mjs\\|cjs\\|ts\\|tsx\\)\\$/u,
3457+
"use": {
3458+
"loader": "/foo/bar/node_modules/swc-loader/index.js",
3459+
"options": {
3460+
"env": {
3461+
"targets": "chrome >= 90, firefox >= 91",
3462+
},
3463+
"jsc": {
3464+
"parser": {
3465+
"syntax": "typescript",
3466+
"tsx": true,
3467+
},
3468+
"transform": {
3469+
"react": {
3470+
"importSource": "@metamask/snaps-sdk",
3471+
"runtime": "automatic",
3472+
"useBuiltins": true,
3473+
},
3474+
},
3475+
},
3476+
"module": {
3477+
"type": "es6",
3478+
},
3479+
"sourceMaps": false,
3480+
"sync": false,
3481+
},
3482+
},
3483+
},
3484+
{
3485+
"resolve": {
3486+
"fullySpecified": false,
3487+
},
3488+
"test": /\\\\\\.m\\?js\\$/u,
3489+
},
3490+
{
3491+
"test": /\\\\\\.svg\\$/u,
3492+
"type": "asset/source",
3493+
},
3494+
{
3495+
"generator": {
3496+
"dataUrl": [Function],
3497+
},
3498+
"test": /\\\\\\.png\\$/u,
3499+
"type": "asset/inline",
3500+
},
3501+
{
3502+
"generator": {
3503+
"dataUrl": [Function],
3504+
},
3505+
"test": /\\\\\\.jpe\\?g\\$/u,
3506+
"type": "asset/inline",
3507+
},
3508+
false,
3509+
],
3510+
},
3511+
"optimization": {
3512+
"minimize": true,
3513+
"minimizer": [
3514+
TerserPlugin {
3515+
"options": {
3516+
"exclude": undefined,
3517+
"extractComments": true,
3518+
"include": undefined,
3519+
"minimizer": {
3520+
"implementation": [Function],
3521+
"options": {},
3522+
},
3523+
"parallel": true,
3524+
"test": /\\\\\\.\\[cm\\]\\?js\\(\\\\\\?\\.\\*\\)\\?\\$/i,
3525+
},
3526+
},
3527+
],
3528+
"nodeEnv": false,
3529+
},
3530+
"output": {
3531+
"chunkFormat": "commonjs",
3532+
"clean": false,
3533+
"filename": "bundle.js",
3534+
"library": {
3535+
"name": "module.exports",
3536+
"type": "assign",
3537+
},
3538+
"path": "/foo/bar/dist",
3539+
"publicPath": "/",
3540+
},
3541+
"performance": {
3542+
"hints": false,
3543+
},
3544+
"plugins": [
3545+
BundleAnalyzerPlugin {
3546+
"logger": Logger {
3547+
"activeLevels": Set {
3548+
"info",
3549+
"warn",
3550+
"error",
3551+
"silent",
3552+
},
3553+
},
3554+
"opts": {
3555+
"analyzerHost": "127.0.0.1",
3556+
"analyzerMode": "server",
3557+
"analyzerPort": 8888,
3558+
"analyzerUrl": [Function],
3559+
"defaultSizes": "parsed",
3560+
"excludeAssets": null,
3561+
"generateStatsFile": false,
3562+
"logLevel": "info",
3563+
"openAnalyzer": true,
3564+
"reportFilename": null,
3565+
"reportTitle": [Function],
3566+
"startAnalyzer": true,
3567+
"statsFilename": "stats.json",
3568+
"statsOptions": null,
3569+
},
3570+
"server": null,
3571+
},
3572+
SnapsWebpackPlugin {
3573+
"options": {
3574+
"eval": undefined,
3575+
"manifestPath": "/foo/bar/snap.manifest.json",
3576+
"writeManifest": true,
3577+
},
3578+
},
3579+
SnapsStatsPlugin {
3580+
"options": {
3581+
"verbose": false,
3582+
},
3583+
},
3584+
DefinePlugin {
3585+
"definitions": {
3586+
"process.env.DEBUG": ""false"",
3587+
"process.env.NODE_DEBUG": ""false"",
3588+
"process.env.NODE_ENV": ""production"",
3589+
},
3590+
},
3591+
ProgressPlugin {
3592+
"dependenciesCount": 10000,
3593+
"handler": [Function],
3594+
"modulesCount": 5000,
3595+
"percentBy": undefined,
3596+
"profile": false,
3597+
"showActiveModules": false,
3598+
"showDependencies": true,
3599+
"showEntries": true,
3600+
"showModules": true,
3601+
},
3602+
SnapsBundleWarningsPlugin {
3603+
"options": {
3604+
"buffer": true,
3605+
"builtInResolver": SnapsBuiltInResolver {
3606+
"options": {
3607+
"ignore": [],
3608+
},
3609+
"unresolvedModules": Set {},
3610+
},
3611+
"builtIns": true,
3612+
},
3613+
},
3614+
],
3615+
"resolve": {
3616+
"extensions": [
3617+
".js",
3618+
".jsx",
3619+
".mjs",
3620+
".cjs",
3621+
".ts",
3622+
".tsx",
3623+
],
3624+
"fallback": {
3625+
"buffer": false,
3626+
"fs": false,
3627+
"path": false,
3628+
},
3629+
"plugins": [
3630+
SnapsBuiltInResolver {
3631+
"options": {
3632+
"ignore": [],
3633+
},
3634+
"unresolvedModules": Set {},
3635+
},
3636+
],
3637+
},
3638+
"stats": "none",
3639+
"target": "browserslist:/foo/bar/.browserslistrc",
3640+
}
3641+
`;

packages/snaps-cli/src/webpack/config.test.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,25 @@ describe('getDefaultConfiguration', () => {
200200
},
201201
);
202202

203+
it('returns the default Webpack configuration when `analyze` is `true`', async () => {
204+
const config = getMockConfig('webpack', {
205+
input: 'src/index.js',
206+
output: {
207+
path: 'dist',
208+
},
209+
manifest: {
210+
path: 'snap.manifest.json',
211+
},
212+
});
213+
214+
jest.spyOn(process, 'cwd').mockReturnValue('/foo/bar');
215+
216+
const output = await getDefaultConfiguration(config, { analyze: true });
217+
218+
// eslint-disable-next-line jest/no-restricted-matchers
219+
expect(normalizeConfig(output)).toMatchSnapshot();
220+
});
221+
203222
it.each([
204223
getMockConfig('browserify', {
205224
cliOptions: {

packages/snaps-cli/src/webpack/config.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';
33
import type { Ora } from 'ora';
44
import { resolve } from 'path';
55
import TerserPlugin from 'terser-webpack-plugin';
6-
import type { Configuration } from 'webpack';
6+
import type { Configuration, WebpackPluginInstance } from 'webpack';
77
import { DefinePlugin, ProgressPlugin, ProvidePlugin } from 'webpack';
8+
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
89

910
import type { ProcessedWebpackConfig } from '../config';
1011
import { getFunctionLoader, wasm } from './loaders';
@@ -25,6 +26,11 @@ import {
2526
} from './utils';
2627

2728
export type WebpackOptions = {
29+
/**
30+
* Whether to analyze the bundle.
31+
*/
32+
analyze?: boolean;
33+
2834
/**
2935
* Whether to watch for changes.
3036
*/
@@ -282,6 +288,9 @@ export async function getDefaultConfiguration(
282288
* @see https://webpack.js.org/configuration/plugins/
283289
*/
284290
plugins: [
291+
options.analyze &&
292+
(new BundleAnalyzerPlugin() as unknown as WebpackPluginInstance),
293+
285294
/**
286295
* The `ForkTsCheckerWebpackPlugin` is a Webpack plugin that checks
287296
* Typescript type definitions, it does this in a separate process for speed.

0 commit comments

Comments
 (0)