From 73af57a2ae2d43f123dd7d73ae03f54a67188cbf Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Mon, 24 Aug 2026 00:12:57 -0700 Subject: [PATCH] fix(desktop): prefer the unpacked web dist over the asar-internal renderer index when packaged MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The renderer index resolver tried APP_ROOT/dist/index.html — inside app.asar when packaged — before the app.asar.unpacked copy that asarUnpack (dist/**) ships and that resolveWebDist() already prefers for the embedded dashboard. Loading the asar-internal index is how lazily imported chunks (syntax-diff-*, shiki-*, mermaid-embed-*) end up fetched from a path that cannot serve them, killing the workspace pane (#93479). Reorder the candidate ladder to prefer the unpacked web dist when packaged, following the unpackedPathFor/resolveWebDist precedent. All window loaders (main, overlay, quick) share resolveRendererIndex, so one reorder covers every surface. Dev behavior is unchanged: outside an asar both candidates collapse to APP_ROOT/dist and keep the original order. --- apps/desktop/electron/main.ts | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/apps/desktop/electron/main.ts b/apps/desktop/electron/main.ts index 2103811bcb..7cd87d8a99 100644 --- a/apps/desktop/electron/main.ts +++ b/apps/desktop/electron/main.ts @@ -4277,8 +4277,21 @@ function resolveWebDist() { } function resolveRendererIndex() { - const candidates = [path.join(APP_ROOT, 'dist', 'index.html'), path.join(resolveWebDist(), 'index.html')] - const present = candidates.filter(fileExists) + const asarIndex = path.join(APP_ROOT, 'dist', 'index.html') + const webDistIndex = path.join(resolveWebDist(), 'index.html') + + // A packaged build ships dist/ twice: inside app.asar AND — because + // asarUnpack lists dist/** — beside it in app.asar.unpacked. Prefer the + // unpacked tree, matching the resolveWebDist()/unpackedPathFor precedent: + // it is the copy the embedded dashboard serves and the copy a repair + // rewrites, while pointing the window at the asar-internal index.html is + // exactly how lazy chunks end up fetched from a path that cannot serve + // them (#93479). Every window loader shares this resolver (main, overlay, + // quick), so the ordering fix covers all of them. Dev is unchanged: + // unpackedPathFor is a no-op outside an asar, so both candidates collapse + // to APP_ROOT/dist and the original order is preserved. + const candidates = IS_PACKAGED ? [webDistIndex, asarIndex] : [asarIndex, webDistIndex] + const present = [...new Set(candidates)].filter(fileExists) // index.html and the hashed chunks it names are one generation. An update // that replaces only one of the two shipped copies (app.asar vs