xref: /expo/packages/@expo/cli/src/export/exportApp.ts (revision aa3bb5e3)
1import path from 'path';
2
3import * as Log from '../log';
4import { ensureDirectoryAsync } from '../utils/dir';
5import { createBundlesAsync } from './createBundles';
6import { exportAssetsAsync } from './exportAssets';
7import { getPublicExpoManifestAsync } from './getPublicExpoManifest';
8import { printBundleSizes } from './printBundleSizes';
9import { Options } from './resolveOptions';
10import {
11  writeAssetMapAsync,
12  writeBundlesAsync,
13  writeDebugHtmlAsync,
14  writeMetadataJsonAsync,
15  writeSourceMapsAsync,
16} from './writeContents';
17
18/**
19 * The structure of the outputDir will be:
20 *
21 * ```
22 * ├── assets
23 * │   └── *
24 * ├── bundles
25 * │   ├── android-01ee6e3ab3e8c16a4d926c91808d5320.js
26 * │   └── ios-ee8206cc754d3f7aa9123b7f909d94ea.js
27 * └── metadata.json
28 * ```
29 */
30export async function exportAppAsync(
31  projectRoot: string,
32  {
33    platforms,
34    outputDir,
35    clear,
36    dev,
37    dumpAssetmap,
38    dumpSourcemap,
39  }: Pick<Options, 'dumpAssetmap' | 'dumpSourcemap' | 'dev' | 'clear' | 'outputDir' | 'platforms'>
40): Promise<void> {
41  const exp = await getPublicExpoManifestAsync(projectRoot);
42
43  const outputPath = path.resolve(projectRoot, outputDir);
44  const assetsPath = path.join(outputPath, 'assets');
45  const bundlesPath = path.join(outputPath, 'bundles');
46
47  await Promise.all([assetsPath, bundlesPath].map(ensureDirectoryAsync));
48
49  // Run metro bundler and create the JS bundles/source maps.
50  const bundles = await createBundlesAsync(
51    projectRoot,
52    { resetCache: !!clear },
53    {
54      platforms,
55      dev,
56      useDevServer: true,
57      // TODO: Disable source map generation if we aren't outputting them.
58    }
59  );
60
61  // Log bundle size info to the user
62  printBundleSizes(bundles);
63
64  // Write the JS bundles to disk, and get the bundle file names (this could change with async chunk loading support).
65  const { hashes, fileNames } = await writeBundlesAsync({ bundles, outputDir: bundlesPath });
66
67  Log.log('Finished saving JS Bundles');
68
69  const { assets } = await exportAssetsAsync(projectRoot, {
70    exp,
71    outputDir: outputPath,
72    bundles,
73  });
74
75  if (dumpAssetmap) {
76    Log.log('Dumping asset map');
77    await writeAssetMapAsync({ outputDir: outputPath, assets });
78  }
79
80  // build source maps
81  if (dumpSourcemap) {
82    Log.log('Dumping source maps');
83    await writeSourceMapsAsync({
84      bundles,
85      hashes,
86      outputDir: bundlesPath,
87      fileNames,
88    });
89
90    Log.log('Preparing additional debugging files');
91    // If we output source maps, then add a debug HTML file which the user can open in
92    // the web browser to inspect the output like web.
93    await writeDebugHtmlAsync({
94      outputDir: outputPath,
95      fileNames,
96    });
97  }
98
99  // Generate a `metadata.json` and the export is complete.
100  await writeMetadataJsonAsync({ outputDir, bundles, fileNames });
101}
102