1import path from 'path'; 2 3import { BundleAssetWithFileHashes } from './fork-bundleAsync'; 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