1import fs from 'fs';
2import Server from 'metro/src/Server';
3import output from 'metro/src/shared/output/bundle';
4import type { BundleOptions } from 'metro/src/shared/types';
5import path from 'path';
6
7import { Options } from './resolveOptions';
8import { Log } from '../../log';
9import { loadMetroConfigAsync } from '../../start/server/metro/instantiateMetro';
10import { importCliSaveAssetsFromProject } from '../../start/server/metro/resolveFromProject';
11import { setNodeEnv } from '../../utils/nodeEnv';
12import { getAssets } from '../fork-bundleAsync';
13
14export async function exportEmbedAsync(projectRoot: string, options: Options) {
15  setNodeEnv(options.dev ? 'development' : 'production');
16  require('@expo/env').load(projectRoot);
17
18  const { config } = await loadMetroConfigAsync(
19    projectRoot,
20    {
21      maxWorkers: options.maxWorkers,
22      resetCache: options.resetCache,
23      config: options.config,
24    },
25    {
26      isExporting: true,
27    }
28  );
29
30  const saveAssets = importCliSaveAssetsFromProject(projectRoot);
31
32  let sourceMapUrl = options.sourcemapOutput;
33  if (sourceMapUrl && !options.sourcemapUseAbsolutePath) {
34    sourceMapUrl = path.basename(sourceMapUrl);
35  }
36
37  const bundleRequest = {
38    ...Server.DEFAULT_BUNDLE_OPTIONS,
39    entryFile: options.entryFile,
40    sourceMapUrl,
41    dev: options.dev,
42    minify: !!options.minify,
43    platform: options.platform,
44    unstable_transformProfile:
45      options.unstableTransformProfile as BundleOptions['unstable_transformProfile'],
46  };
47
48  const server = new Server(config, {
49    watch: false,
50  });
51
52  try {
53    const bundle = await server.build({
54      ...bundleRequest,
55      bundleType: 'bundle',
56    });
57
58    fs.mkdirSync(path.dirname(options.bundleOutput), { recursive: true, mode: 0o755 });
59
60    // Persist bundle and source maps.
61    await output.save(bundle, options, Log.log);
62
63    // Save the assets of the bundle
64    const outputAssets = await getAssets(server, {
65      ...bundleRequest,
66      bundleType: 'todo',
67    });
68
69    await saveAssets(outputAssets, options.platform, options.assetsDest, options.assetCatalogDest);
70  } finally {
71    server.end();
72  }
73}
74