xref: /expo/packages/@expo/cli/src/export/saveAssets.ts (revision edeec536)
1dc51e206SEvan Baconimport path from 'path';
2dc51e206SEvan Bacon
3*edeec536SEvan Baconimport { BundleAssetWithFileHashes } from './fork-bundleAsync';
4dc51e206SEvan Baconimport * as Log from '../log';
5dc51e206SEvan Baconimport { chunk } from '../utils/array';
6dc51e206SEvan Baconimport { copyAsync } from '../utils/dir';
7dc51e206SEvan Bacon
8474a7a4bSEvan Baconconst debug = require('debug')('expo:export:saveAssets') as typeof console.log;
9474a7a4bSEvan Bacon
10dc51e206SEvan Baconexport type ManifestAsset = { fileHashes: string[]; files: string[]; hash: string };
11dc51e206SEvan Bacon
12dc51e206SEvan Baconexport type Asset = ManifestAsset | BundleAssetWithFileHashes;
13dc51e206SEvan Bacon
14dc51e206SEvan Baconfunction logAssetTask(projectRoot: string, action: 'uploading' | 'saving', pathName: string) {
15474a7a4bSEvan Bacon  debug(`${action} ${pathName}`);
16dc51e206SEvan Bacon
17dc51e206SEvan Bacon  const relativePath = pathName.replace(projectRoot, '');
18dc51e206SEvan Bacon  Log.log(`${action} ${relativePath}`);
19dc51e206SEvan Bacon}
20dc51e206SEvan Bacon
21dc51e206SEvan Baconfunction collectAssetPaths(assets: Asset[]): Record<string, string> {
22dc51e206SEvan Bacon  // Collect paths by key, also effectively handles duplicates in the array
23dc51e206SEvan Bacon  const paths: { [fileHash: string]: string } = {};
24dc51e206SEvan Bacon  assets.forEach((asset) => {
25dc51e206SEvan Bacon    asset.files.forEach((path: string, index: number) => {
26dc51e206SEvan Bacon      paths[asset.fileHashes[index]] = path;
27dc51e206SEvan Bacon    });
28dc51e206SEvan Bacon  });
29dc51e206SEvan Bacon  return paths;
30dc51e206SEvan Bacon}
31dc51e206SEvan Bacon
32dc51e206SEvan Baconexport async function saveAssetsAsync(
33dc51e206SEvan Bacon  projectRoot: string,
34dc51e206SEvan Bacon  { assets, outputDir }: { assets: Asset[]; outputDir: string }
35dc51e206SEvan Bacon) {
36dc51e206SEvan Bacon  // Collect paths by key, also effectively handles duplicates in the array
37dc51e206SEvan Bacon  const paths = collectAssetPaths(assets);
38dc51e206SEvan Bacon
39dc51e206SEvan Bacon  // save files one chunk at a time
40dc51e206SEvan Bacon  for (const keys of chunk(Object.entries(paths), 5)) {
41dc51e206SEvan Bacon    await Promise.all(
42dc51e206SEvan Bacon      keys.map(([key, pathName]) => {
43dc51e206SEvan Bacon        logAssetTask(projectRoot, 'saving', pathName);
44dc51e206SEvan Bacon        // copy file over to assetPath
45dc51e206SEvan Bacon        return copyAsync(pathName, path.join(outputDir, 'assets', key));
46dc51e206SEvan Bacon      })
47dc51e206SEvan Bacon    );
48dc51e206SEvan Bacon  }
49dc51e206SEvan Bacon  Log.log('Files successfully saved.');
50dc51e206SEvan Bacon}
51