Skip to content

Commit 8e9cc2b

Browse files
sunnylqmclaude
andcommitted
perf: finish the optimization batch — pipeline, network, diff and startup
hermes-base - a bundleHash mismatch of the entry read over Range is final (BundleHashMismatchError): no fallback to the whole archive, no retry; the server lookup is retried once, downloads only on transport errors - cache hits for records without a bytecodeVersion (legacy / native package) verify the HBC header; cacheLookup hashes the file streamed - downloads get a 30 s headers timeout and a 60 s idle timeout; stale cachePut staging files (<hash>.<pid>.tmp) are evicted and cleaned bundle-runner / bundle - hermes-base-error.log is written next to the intermediate dir instead of inside it (it was packed into the ppk) - the base selection starts after Metro is spawned; its synchronous head (hermesc lookup, HBC probe) no longer delays Metro - the JS bundle is renamed into a work dir and both hermesc runs read it there (no copies); the packager map is renamed, not copied - compose-source-maps runs asynchronously and speculatively during the disassembly compare, redone from the plain map if the base is rejected - one compilePlain helper (runProcess) replaces three spawnSync sites; the base attempt passes -w and its stderr is bounded (512 KB head+tail) - a failed plain compile is reported as such (hermesBasePlainCompileFailed) and keeps the base instead of dropping it and compiling a third time - the compile phase waits at most 60 s (PUSHY_HERMES_BASE_WAIT_MS) for a base still being fetched, then compiles plain - new --resetCache option (default true); false reuses Metro's cache diff / hbcTransform - moved-file matching keys on crc32 + uncompressed size (a colliding crc could ship the wrong file); manifest format unchanged - a failing diff destroys the output stream and removes the partial patch - the streaming diff transforms HBC on disk section by section (transformHbcFile); no full bundle copy is held in memory any more zip-range / zip-entries - chunk cache merges only on strict overlap, single-chunk entries are returned as views (entry memory 3x -> 1x); hinted reads no longer re-fetch cached bytes or widen tiny entries to 64 KB - later Range requests send If-Range and check the Content-Range total; the central directory is always prefetched in one request - every fetch has a timeout (RangeOptions); nested .hap temp dirs are removed on failure too startup / upload / packing - the npm version check no longer blocks every command: 1-day cache with stale fallback, unref'd background request, hints printed after the command (`help`: ~0.5 s -> ~0.09 s) - getBaseUrl and dep versions resolve lazily; tty-table, app-info-parser, form-data and progress load on first use - payload deflate level 9 -> 6 (4x less CPU for 0.6% size) - uploads get a size-scaled timeout and one retry on transient errors; publish overlaps the upload with hashing and git; choosePackage reuses the fetched list; native package upload passes the known bundle hash Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 734d4c6 commit 8e9cc2b

6 files changed

Lines changed: 29 additions & 63 deletions

File tree

OPTIMIZATION-PROGRESS.md

Lines changed: 0 additions & 57 deletions
This file was deleted.

src/app.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import fs from 'fs';
22
import { doDelete, get, post } from './api';
33
import type { Platform } from './types';
4-
import { question } from './utils';
4+
import { loadTtyTable, question } from './utils';
55
import { t } from './utils/i18n';
66

77
interface AppSummary {
@@ -70,7 +70,7 @@ export async function listApp(platform: Platform | '' = '') {
7070
}
7171

7272
// tty-table is ~25 ms to load; only pay for it when a table is rendered
73-
const Table = require('tty-table') as typeof import('tty-table');
73+
const Table = loadTtyTable();
7474
console.log(Table(header, rows).render());
7575

7676
console.log(`\n${t('totalApps', { count: list.length, platform })}`);

src/bin.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ async function run() {
9090
} else if (commandHandlers[argv.command]) {
9191
const handler = commandHandlers[argv.command];
9292
await handler(argv);
93+
// a check still in flight (cold cache) gets a short grace period; the
94+
// registry request itself is unref'd, so exiting never waits on it
95+
await versionCheck.settle(500);
9396
versionCheck.printHints();
9497
} else {
9598
throw new Error(t('unknownCommand', { command: argv.command }));

src/package.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
getApkInfo,
1111
getAppInfo,
1212
getIpaInfo,
13+
loadTtyTable,
1314
question,
1415
} from './utils';
1516
import { getDepVersions } from './utils/dep-versions';
@@ -241,7 +242,7 @@ export async function listPackage(appId: string, packages?: Package[]) {
241242
}
242243

243244
// tty-table is ~25 ms to load; only pay for it when a table is rendered
244-
const Table = require('tty-table') as typeof import('tty-table');
245+
const Table = loadTtyTable();
245246
console.log(Table(header, rows).render());
246247
console.log(t('totalPackages', { count: allPkgs.length }));
247248
return allPkgs;

src/utils/index.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,15 @@ function createAppInfoParser(fn: string): AppInfoParserType {
2020
return new AppInfoParser(fn);
2121
}
2222

23+
/**
24+
* tty-table (~25 ms to load) only when a table is rendered. Bun's require of
25+
* a CJS module can hand back a namespace object, so unwrap `default`.
26+
*/
27+
export function loadTtyTable(): typeof import('tty-table') {
28+
const mod = require('tty-table');
29+
return (mod.default ?? mod) as typeof import('tty-table');
30+
}
31+
2332
type ApkMetaEntry = {
2433
name?: string;
2534
value?: string | number | Array<string | number>;
@@ -549,6 +558,8 @@ function latestTag(version: string | undefined) {
549558
export interface VersionCheck {
550559
/** settles once the registry check has finished (or failed); never rejects */
551560
done: Promise<void>;
561+
/** wait for the check, but never longer than `graceMs` */
562+
settle: (graceMs: number) => Promise<void>;
552563
/**
553564
* Print the "newer version available" hints if the check has completed by
554565
* now; a no-op while it is still pending, when nothing is newer, and after
@@ -635,7 +646,15 @@ export async function printVersionCommand({
635646
}
636647
};
637648

638-
return { done: check, printHints };
649+
const settle = (graceMs: number) => {
650+
let timer: NodeJS.Timeout | undefined;
651+
const grace = new Promise<void>((resolve) => {
652+
timer = setTimeout(resolve, graceMs);
653+
});
654+
return Promise.race([check, grace]).then(() => clearTimeout(timer));
655+
};
656+
657+
return { done: check, settle, printHints };
639658
}
640659

641660
export { checkPlugins };

src/versions.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { doDelete, get, getAllPackages, post, put, uploadFile } from './api';
44
import { getPlatform, getSelectedApp } from './app';
55
import { choosePackage } from './package';
66
import type { Package, Platform, Version } from './types';
7-
import { isNonInteractive, question } from './utils';
7+
import { isNonInteractive, loadTtyTable, question } from './utils';
88
import { getDepVersions } from './utils/dep-versions';
99
import { getCommitInfo } from './utils/git';
1010
import { getHbcVersion } from './utils/hbcTransform';
@@ -234,7 +234,7 @@ function printDepsChangesForPackage({
234234
);
235235
console.log(summaryText);
236236
// tty-table is ~25 ms to load; only pay for it when a table is rendered
237-
const Table = require('tty-table') as typeof import('tty-table');
237+
const Table = loadTtyTable();
238238
console.log(Table(header, rows).render());
239239
console.log(chalk.yellow(t('depsChangeRiskWarning')));
240240
return true;

0 commit comments

Comments
 (0)