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