fix(desktop): prefer the unpacked web dist over the asar-internal renderer index when packaged

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.
This commit is contained in:
Teknium
2026-08-24 00:12:57 -07:00
parent b614e2656b
commit 73af57a2ae
+15 -2
View File
@@ -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