Skip to content

Commit fc47ed4

Browse files
feat(Sky): Add checkpoint logging and sequential dynamic imports for Electron workbench
Improve Electron workbench debugging and loading with three additions: 1. Workbench.js checkpoints (WB1-WB5): Add console.log checkpoints at key stages of load() to trace where initialization hangs: resolveWindowConfiguration, setupNLS, import(workbenchUrl), return, and main(). 2. Profile URI fix: Fix reviveProfile() failures when Wind's ResolveConfiguration returns undefined location due to Vite cache. Injects code to ensure profiles have required URI properties (location, promptsHome, extensionsResource, mcpResource). 3. Step 9 (desktop.main.js): When Electron=true, patch desktop.main.js with checkpoint logging (CP1-CP6) to trace where initServices() hangs - MainProcessService, EnvironmentService, SharedProcessService, FileService, Promise.all, and Workbench creation. 4. Step 10 (workbench.desktop.main.js): Replace 3385 static side-effect imports with sequential dynamic imports. Static imports overwhelm WKWebView's module loader; sequential loading logs progress every 10 modules and recovers from individual failures.
1 parent 5d5810c commit fc47ed4

6 files changed

Lines changed: 155 additions & 4 deletions

File tree

.astro/collections/collections.json

100755100644
File mode changed.

.astro/content-assets.mjs

Lines changed: 0 additions & 1 deletion
This file was deleted.

.astro/content-modules.mjs

Lines changed: 0 additions & 1 deletion
This file was deleted.

.astro/content.d.ts

100755100644
File mode changed.

.astro/types.d.ts

100755100644
File mode changed.

astro.config.ts

Lines changed: 155 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -309,10 +309,43 @@ export default defineConfig({
309309

310310
Content = ErrorListeners + "\n" + Content;
311311

312-
// 8b: Wrap result.main(configuration) with try/catch + await
312+
// 8b: Add checkpoints inside load() to trace the hang
313+
Content = Content.replace(
314+
"const configuration2 = await resolveWindowConfiguration()",
315+
`console.log("[workbench.js] WB1: calling resolveWindowConfiguration");const configuration2 = await resolveWindowConfiguration()`,
316+
);
317+
// 8b-fix: Ensure profile URIs exist for reviveProfile().
318+
// Wind's ResolveConfiguration may have location:undefined
319+
// due to Vite cache. Fix the configuration in-place here.
320+
Content = Content.replace(
321+
"setupNLS(configuration2)",
322+
[
323+
`if(configuration2.profiles){`,
324+
`const _S="vscode-userdata";`,
325+
`const _fix=(p)=>{if(!p)return;`,
326+
`if(!p.location)p.location={scheme:_S,path:"/User/profiles/"+(p.id||"default")};`,
327+
`if(!p.promptsHome)p.promptsHome={scheme:_S,path:"/User/prompts"};`,
328+
`if(!p.extensionsResource)p.extensionsResource={scheme:_S,path:"/User/extensions.json"};`,
329+
`if(!p.mcpResource)p.mcpResource={scheme:_S,path:"/User/mcp.json"};`,
330+
`};`,
331+
`_fix(configuration2.profiles.profile);`,
332+
`if(Array.isArray(configuration2.profiles.all))configuration2.profiles.all.forEach(_fix);`,
333+
`}`,
334+
`console.log("[workbench.js] WB2: config resolved, calling setupNLS");setupNLS(configuration2)`,
335+
].join(""),
336+
);
337+
Content = Content.replace(
338+
"const result2 = await import(workbenchUrl)",
339+
`console.log("[workbench.js] WB3: importing workbench module:",workbenchUrl);const result2 = await import(workbenchUrl)`,
340+
);
341+
Content = Content.replace(
342+
"return { result: result2, configuration: configuration2 }",
343+
`console.log("[workbench.js] WB4: import done");return { result: result2, configuration: configuration2 }`,
344+
);
345+
// 8c: Wrap result.main(configuration) with try/catch + await
313346
Content = Content.replace(
314347
"result.main(configuration)",
315-
`try{await result.main(configuration)}catch(_e){console.error("[workbench.js] main() failed:",_e);if(_e&&_e.stack)console.error(_e.stack)}`,
348+
`console.log("[workbench.js] WB5: calling main()");try{await result.main(configuration)}catch(_e){console.error("[workbench.js] main() failed:",_e);if(_e&&_e.stack)console.error(_e.stack)}`,
316349
);
317350

318351
await writeFile(WorkbenchJS, Content, "utf-8");
@@ -328,6 +361,126 @@ export default defineConfig({
328361
}
329362
}
330363

364+
// Step 9: When Electron=true, patch desktop.main.js with
365+
// checkpoint logging to trace where initServices() hangs.
366+
if (process.env["Electron"] === "true") {
367+
const DesktopMainJS = join(
368+
Destination,
369+
"workbench",
370+
"electron-browser",
371+
"desktop.main.js",
372+
);
373+
try {
374+
let Content = await readFile(
375+
DesktopMainJS,
376+
"utf-8",
377+
);
378+
// Patches use IIFE wrappers (()=>{log;return expr})() for
379+
// expression contexts, and statement prepends for statement contexts.
380+
// CP5-7 are inside Promise.all([...]) so we log BEFORE the array.
381+
const Patches: [string, string][] = [
382+
[
383+
"new ElectronIPCMainProcessService(this.configuration.windowId)",
384+
`(()=>{console.log("[desktop.main] CP1: creating MainProcessService");return new ElectronIPCMainProcessService(this.configuration.windowId)})()`,
385+
],
386+
[
387+
"new NativeWorkbenchEnvironmentService(this.configuration, productService)",
388+
`(()=>{console.log("[desktop.main] CP2: creating EnvironmentService");return new NativeWorkbenchEnvironmentService(this.configuration, productService)})()`,
389+
],
390+
[
391+
"new SharedProcessService(this.configuration.windowId, logService)",
392+
`(()=>{console.log("[desktop.main] CP3: creating SharedProcessService");return new SharedProcessService(this.configuration.windowId, logService)})()`,
393+
],
394+
[
395+
"new FileService(logService)",
396+
`(()=>{console.log("[desktop.main] CP4: creating FileService");return new FileService(logService)})()`,
397+
],
398+
[
399+
"const [configurationService, storageService] = await Promise.all([",
400+
`console.log("[desktop.main] CP5: entering Promise.all (workspace+storage+keyboard)");const [configurationService, storageService] = await Promise.all([`,
401+
],
402+
[
403+
"const workbench = new Workbench(",
404+
`console.log("[desktop.main] CP6: initServices DONE, creating Workbench");const workbench = new Workbench(`,
405+
],
406+
];
407+
for (const [Search, Replace] of Patches) {
408+
if (Content.includes(Search)) {
409+
Content = Content.replace(Search, Replace);
410+
}
411+
}
412+
await writeFile(DesktopMainJS, Content, "utf-8");
413+
console.log(
414+
"[CopyVSCode] Step 9: Patched desktop.main.js with checkpoint logging",
415+
);
416+
} catch (Error) {
417+
console.warn(
418+
"[CopyVSCode] Step 9: desktop.main.js checkpoint patching failed:",
419+
Error,
420+
);
421+
}
422+
}
423+
424+
// Step 10: When Electron=true, replace workbench.desktop.main.js
425+
// static imports with sequential dynamic imports that log progress.
426+
// Static imports of 3385 modules overwhelm WKWebView's module loader.
427+
if (process.env["Electron"] === "true") {
428+
const DesktopBarrelJS = join(
429+
Destination,
430+
"workbench",
431+
"workbench.desktop.main.js",
432+
);
433+
try {
434+
const Content = await readFile(
435+
DesktopBarrelJS,
436+
"utf-8",
437+
);
438+
// Extract side-effect import paths: import './foo.js';
439+
const SideEffectImports: string[] = [];
440+
const SideEffectRE =
441+
/^import\s+['"]([^'"]+)['"]\s*;?\s*$/gm;
442+
let Match;
443+
while (
444+
(Match = SideEffectRE.exec(Content)) !== null
445+
) {
446+
SideEffectImports.push(Match[1]);
447+
}
448+
// Build: static named imports at top, then dynamic side-effect
449+
// imports, then registerSingleton + export at bottom.
450+
const Lines = [
451+
`// Sequential dynamic import loader (Step 10)`,
452+
`import { registerSingleton } from '../platform/instantiation/common/extensions.js';`,
453+
`import { IUserDataInitializationService, UserDataInitializationService } from './services/userData/browser/userDataInit.js';`,
454+
`import { SyncDescriptor } from '../platform/instantiation/common/descriptors.js';`,
455+
``,
456+
`console.log("[workbench.desktop.main] Loading ${SideEffectImports.length} modules sequentially...");`,
457+
`const _t0 = performance.now();`,
458+
`let _n = 0;`,
459+
...SideEffectImports.map(
460+
(Path: string, I: number) =>
461+
`try{await import('${Path}');_n++;${I % 10 === 0 ? `console.log("[workbench.desktop.main] "+_n+"/${SideEffectImports.length}: ${Path}");` : ""}}catch(_e){console.error("[workbench.desktop.main] FAILED #${I}: ${Path}",_e)}`,
462+
),
463+
`console.log("[workbench.desktop.main] Done: "+_n+"/${SideEffectImports.length} in "+(performance.now()-_t0).toFixed(0)+"ms");`,
464+
``,
465+
`registerSingleton(IUserDataInitializationService, new SyncDescriptor(UserDataInitializationService, [[]], true));`,
466+
`export { main } from './electron-browser/desktop.main.js';`,
467+
];
468+
await writeFile(
469+
DesktopBarrelJS,
470+
Lines.join("\n"),
471+
"utf-8",
472+
);
473+
console.log(
474+
`[CopyVSCode] Step 10: Replaced ${SideEffectImports.length} static imports with sequential dynamic imports`,
475+
);
476+
} catch (Error) {
477+
console.warn(
478+
"[CopyVSCode] Step 10: dynamic import replacement failed:",
479+
Error,
480+
);
481+
}
482+
}
483+
331484
console.log("[CopyVSCode] ✓ Assets ready in Target/");
332485
},
333486
},

0 commit comments

Comments
 (0)