From 7134b221fdfbe8151ca50384b16e3106024c6aea Mon Sep 17 00:00:00 2001 From: cale bradbury Date: Fri, 6 Dec 2024 00:17:10 -0500 Subject: [PATCH 1/3] Add try catch when initializing user code --- packages/engine/src/HedronEngine.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/engine/src/HedronEngine.ts b/packages/engine/src/HedronEngine.ts index 975084cd..c6886d40 100644 --- a/packages/engine/src/HedronEngine.ts +++ b/packages/engine/src/HedronEngine.ts @@ -36,7 +36,11 @@ export class HedronEngine { public async initiateSketchModules(moduleIds: string[]) { for (const moduleId of moduleIds) { - await this.addSketchModule(moduleId) + try { + await this.addSketchModule(moduleId) + } catch (error) { + console.error('Init error in: ' + moduleId, error) + } } this.store.setState({ isSketchModulesReady: true }) From 02f4d93070cd020db628c65cbf1e70d202795a29 Mon Sep 17 00:00:00 2001 From: Alex Kempton Date: Fri, 6 Dec 2024 11:50:51 +0100 Subject: [PATCH 2/3] refactor error handling --- packages/engine/src/HedronEngine.ts | 32 ++++++--- packages/engine/src/importSketchModule.ts | 81 ++++++++++++++--------- packages/engine/src/types.ts | 3 + 3 files changed, 72 insertions(+), 44 deletions(-) create mode 100644 packages/engine/src/types.ts diff --git a/packages/engine/src/HedronEngine.ts b/packages/engine/src/HedronEngine.ts index c6886d40..f43314cd 100644 --- a/packages/engine/src/HedronEngine.ts +++ b/packages/engine/src/HedronEngine.ts @@ -1,10 +1,11 @@ import { listenToStore } from './storeListener' import { importSketchModule } from './importSketchModule' +import { Result } from './types' import { stripForSave } from '@utils/stripForSave' import { Renderer } from '@world/Renderer' import { SketchManager } from '@world/SketchManager' import { createDebugScene } from '@world/debugScene' -import { EngineData } from '@store/types' +import { EngineData, SketchModuleItem } from '@store/types' import { getSketchesOfModuleId } from '@store/selectors/getSketchesOfModuleId' import { createEngineStore, EngineStore } from '@store/engineStore' @@ -36,31 +37,40 @@ export class HedronEngine { public async initiateSketchModules(moduleIds: string[]) { for (const moduleId of moduleIds) { - try { - await this.addSketchModule(moduleId) - } catch (error) { - console.error('Init error in: ' + moduleId, error) - } + await this.addSketchModule(moduleId) } this.store.setState({ isSketchModulesReady: true }) } - public async addSketchModule(moduleId: string) { + public async addSketchModule(moduleId: string): Promise> { if (!this.sketchesUrl) throw new Error('Sketches URL not ready') - const moduleItem = await importSketchModule(this.sketchesUrl, moduleId) + const result = await importSketchModule(this.sketchesUrl, moduleId) + + if (!result.success) { + // TODO: check for errors and show UI error + return result + } + + const moduleItem = result.data this.store.getState().setSketchModuleItem(moduleItem) - return moduleItem + return result } public removeSketchModule = async (moduleId: string): Promise => { this.store.getState().deleteSketchModule(moduleId) } - public async reimportSketchModuleAndReloadSketches(moduleId: string) { - const moduleItem = await this.addSketchModule(moduleId) + public async reimportSketchModuleAndReloadSketches(moduleId: string): Promise { + const result = await this.addSketchModule(moduleId) + + if (!result.success) { + return + } + + const moduleItem = result.data const sketchesToRefresh = getSketchesOfModuleId(this.store.getState(), moduleId) diff --git a/packages/engine/src/importSketchModule.ts b/packages/engine/src/importSketchModule.ts index ec10aa8e..f0fe821f 100644 --- a/packages/engine/src/importSketchModule.ts +++ b/packages/engine/src/importSketchModule.ts @@ -1,46 +1,61 @@ +import { Result } from './types' import { SketchConfig, SketchModule, SketchModuleItem } from '@store/types' import { createUniqueId } from '@utils/createUniqueId' export const importSketchModule = async ( baseUrl: string, moduleId: string, -): Promise => { - const cacheBust = createUniqueId() +): Promise> => { + try { + const cacheBust = createUniqueId() - // Get the sketch module - const sketchPath = `${baseUrl}/${moduleId}/index.js?${cacheBust}` - if ((await fetch(sketchPath)).status !== 200) { - return Promise.reject(`Sketch module not found: ${sketchPath}`) - } - const sketchModule = await import(/* @vite-ignore */ sketchPath) - const module: SketchModule = sketchModule.default + // Get the sketch module + const sketchPath = `${baseUrl}/${moduleId}/index.js?${cacheBust}` + if ((await fetch(sketchPath)).status !== 200) { + return Promise.reject(`Sketch module not found: ${sketchPath}`) + } + const sketchModule = await import(/* @vite-ignore */ sketchPath) + const module: SketchModule = sketchModule.default - // Get the sketch config - const configPath = `${baseUrl}/${moduleId}/config.js?${cacheBust}` - let config: SketchConfig - if ((await fetch(configPath)).status !== 200) { - // No config file found - // Try instancing the sketch, and call getConfig() on it - const tempModule = new module() - config = tempModule.getConfig?.() - if (!config) { - return Promise.reject( - `Sketch config not found: ${configPath} and no valid getConfig() function found in sketch`, - ) + // Get the sketch config + const configPath = `${baseUrl}/${moduleId}/config.js?${cacheBust}` + let config: SketchConfig + if ((await fetch(configPath)).status !== 200) { + // No config file found + // Try instancing the sketch, and call getConfig() on it + const tempModule = new module() + config = tempModule.getConfig?.() + if (!config) { + return Promise.reject( + `Sketch config not found: ${configPath} and no valid getConfig() function found in sketch`, + ) + } + } else { + const configModule = await import(/* @vite-ignore */ configPath) + config = configModule.default } - } else { - const configModule = await import(/* @vite-ignore */ configPath) - config = configModule.default - } - // A config could be missing a title, but it is a required parameter - if (!config.title) { - config.title = moduleId - } + // A config could be missing a title, but it is a required parameter + if (!config.title) { + config.title = moduleId + } + + return { + success: true, + error: undefined, + data: { + moduleId, + config, + module, + }, + } + } catch (error) { + console.error(error) - return { - moduleId, - config, - module, + return { + data: undefined, + success: false, + error: `[HEDRON] Sketch module failed to import: ${moduleId}`, + } } } diff --git a/packages/engine/src/types.ts b/packages/engine/src/types.ts new file mode 100644 index 00000000..5a29ba95 --- /dev/null +++ b/packages/engine/src/types.ts @@ -0,0 +1,3 @@ +export type Result = + | { success: true; data: T; error: undefined } + | { success: false; error: string; data: undefined } From 68f1e7604d961836f27f1b4ff2b199ec0c797b46 Mon Sep 17 00:00:00 2001 From: Alex Kempton Date: Fri, 6 Dec 2024 11:57:57 +0100 Subject: [PATCH 3/3] update comment --- packages/engine/src/HedronEngine.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/engine/src/HedronEngine.ts b/packages/engine/src/HedronEngine.ts index f43314cd..410fac43 100644 --- a/packages/engine/src/HedronEngine.ts +++ b/packages/engine/src/HedronEngine.ts @@ -49,7 +49,7 @@ export class HedronEngine { const result = await importSketchModule(this.sketchesUrl, moduleId) if (!result.success) { - // TODO: check for errors and show UI error + // TODO: Show UI error here (engine needs to have some "error" state slice) return result }