1import { Platform } from '@expo/config';
2import { BundleOutput } from '@expo/dev-server';
3import chalk from 'chalk';
4import prettyBytes from 'pretty-bytes';
5import table from 'text-table';
6
7import * as Log from '../log';
8import { stripAnsi } from '../utils/ansi';
9import { learnMore } from '../utils/link';
10
11export function printBundleSizes(bundles: Partial<Record<Platform, BundleOutput>>) {
12  const files: [string, string | Uint8Array][] = [];
13
14  if (bundles.ios?.hermesBytecodeBundle) {
15    files.push(['index.ios.js (Hermes)', bundles.ios.hermesBytecodeBundle]);
16  } else if (bundles.ios?.code) {
17    files.push(['index.ios.js', bundles.ios.code]);
18  }
19  if (bundles.android?.hermesBytecodeBundle) {
20    files.push(['index.android.js (Hermes)', bundles.android.hermesBytecodeBundle]);
21  } else if (bundles.android?.code) {
22    files.push(['index.android.js', bundles.android.code]);
23  }
24
25  // Account for inline source maps
26  if (bundles.ios?.hermesSourcemap) {
27    files.push([chalk.dim('index.ios.js.map (Hermes)'), bundles.ios.hermesSourcemap]);
28  } else if (bundles.ios?.map) {
29    files.push([chalk.dim('index.ios.js.map'), bundles.ios.map]);
30  }
31  if (bundles.android?.hermesSourcemap) {
32    files.push([chalk.dim('index.android.js.map (Hermes)'), bundles.android.hermesSourcemap]);
33  } else if (bundles.android?.map) {
34    files.push([chalk.dim('index.android.js.map'), bundles.android.map]);
35  }
36
37  Log.log();
38  Log.log(createFilesTable(files));
39  Log.log();
40  Log.log(
41    chalk`�� JavaScript bundle sizes affect startup time. {dim ${learnMore(
42      `https://expo.fyi/javascript-bundle-sizes`
43    )}}`
44  );
45  Log.log();
46
47  return files;
48}
49
50export function createFilesTable(files: [string, string | Uint8Array][]): string {
51  const tableData = files.map((item, index) => {
52    const fileBranch = index === 0 ? '┌' : index === files.length - 1 ? '└' : '├';
53
54    return [`${fileBranch} ${item[0]}`, prettyBytes(Buffer.byteLength(item[1], 'utf8'))];
55  });
56  return table([['Bundle', 'Size'].map((v) => chalk.underline(v)), ...tableData], {
57    align: ['l', 'r'],
58    stringLength: (str) => stripAnsi(str)?.length ?? 0,
59  });
60}
61