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