perf: faster app startup - #2934
bajrangCoder wants to merge 7 commits into
Conversation
This reverts commit 5a7cc93. The startup work is being consolidated into a single PR for review. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Remove the fixed 500ms delay before hiding the splash; reveal after the app has rendered a frame. - Run independent native startup calls (encodings, storage dirs, installer, Android version) in parallel. - Run the Play Billing purchase check alongside startup. Non-Pro users still wait for it before the UI is usable so paid themes are never treated as locked; ads and the login check still wait for it. - Load the terminal manager (xterm and addons) on demand instead of in main.js; keep xterm.css in main.css and have it loaded before plugins so the synchronous plugin terminal APIs behave as before. - Target WebView 67+ instead of ES2015 and let swc reduce the core-js entry import to the polyfills that WebView needs. - Shorten the native splash fade to 150ms. - Fix disabledMap being out of scope in the owned plugins list and an unhandled rejection when the sponsor form is cancelled. - Add temporary startup timing marks (src/lib/startupPerf.js). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On free builds, a cached acode_pro value no longer waited for the Play Billing check, so plugins (including theme plugins) could initialize before a downgrade was applied. Wait for the check before loading any plugin, as before the check ran in parallel. Paid builds are always Pro and do not wait. Also remove the temporary startup timing marks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Load lib/run (markdown-it, its plugins and the markdown preview) on first run/preview instead of in main.js. - Load mime-types and its MIME database on demand at each lookup site. - Skip load-time validation for bundled editor themes; they are still validated when applied, and plugin themes are still validated when registered. - Cache the Android charset list per app build, OS version and device model instead of rebuilding it natively on every launch. - Fetch the sidebar app chunks in parallel while adding them in their original order. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each command registration (including every plugin addCommand) rebuilt the whole keymap, re-parsing both key strings for every pairwise conflict check, and immediately reconfigured every editor pane. Profiling on a device showed ~1.8s of main-thread CPU spent here while plugins loaded. - Cache canonicalized key strings; the result depends only on the input. - Find the first conflicting claim without copying the claimed-keys map for every candidate. - Rebuild the keymap lazily: registration marks it dirty and every reader rebuilds first, so reads stay current. The returned command still has its final key and description immediately. - Apply keymap refreshes once per burst in a microtask, which always runs before the next key event. - Drop the module-load rebuild that setKeyBindings immediately repeated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- runLazily captures the active file before loading the runner chunk and passes it to run(), so switching tabs during the first load cannot run or preview a different file. - Cap the canonical key binding cache so repeated registrations with new keys cannot grow it without limit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Comments Outside DiffThese findings sit on lines the diff does not cover, so they could not be posted inline. Each one leaves this list once its file changes.
|
Replaces #2930 and #2931, which merged early and are reverted in #2933. This PR is based on
revert-startup-perfso the diff shows all of the startup work. Merge #2933 first; this PR then retargets tomain.Summary
Startup work that keeps app and plugin behaviour unchanged. Measured on a Moto Edge 40 Neo, production build:
main.js: 3,313 KB → 1,997 KB (−40%), so there's less to parse before anything runs.Changes
Startup sequence (
src/main.js)devicereadyinstead of blocking it.restoreTheme()resets and saves a paid theme when a dialog closes whileHAS_PROis false.config.xml).Smaller
main.jscomponents/terminal/loader.js.xterm.cssstays inmain.css.lib/run) loads on first use. It pulls in markdown-it, its plugins and the markdown preview.runLazilycaptures the requested file first.mime-typesloads on demand at each lookup site (utils/mimeTypes.js).core-jsuses swcentrymode, so it includes only the polyfills that WebView needs, and every global a plugin could rely on is still present.Native startup
Command registration (found by profiling on the device)
Every command registration, including each plugin
addCommand, rebuilt the whole keymap. Each rebuild compared every binding with every other one and re-parsed both key strings on each comparison, then reconfigured every editor pane. That was ~1.8 s of main-thread CPU while plugins loaded.registerExternalCommandreturns still has its final key and description immediately.Existing bugs fixed along the way
disabledMapwas out of scope in the owned plugins list and crashed it when billing is available.Review feedback from #2930 and #2931
Not included
main.js, but it's wired synchronously into editor creation. Left for a separate change.Testing
vitest run: 728/728 passing. New tests:commandRegistryKeymap.test.js(batched keymap updates, current reads, removal, conflicts) andrunLazily.test.js(runs the requested file after a tab switch).main.js, and its styles are still inmain.css.🤖 Generated with Claude Code