diff --git a/code/lib/preview-api/src/modules/preview-web/Preview.tsx b/code/lib/preview-api/src/modules/preview-web/Preview.tsx index ee4524c32ecf..f3185734078b 100644 --- a/code/lib/preview-api/src/modules/preview-web/Preview.tsx +++ b/code/lib/preview-api/src/modules/preview-web/Preview.tsx @@ -72,6 +72,8 @@ export class Preview { // project annotations. Once the index loads, it is stored on the store and this will get unset. private projectAnnotationsBeforeInitialization?: ProjectAnnotations; + private beforeAllCleanup?: (() => MaybePromise) | void; + protected storeInitializationPromise: Promise; protected resolveStoreInitializationPromise!: () => void; @@ -160,9 +162,23 @@ export class Preview { } // If initialization gets as far as project annotations, this function runs. - async initializeWithProjectAnnotations(projectAnnotations: ProjectAnnotations) { - this.projectAnnotationsBeforeInitialization = projectAnnotations; + async initializeWithProjectAnnotations( + projectAnnotations: ProjectAnnotations, + storyStore?: StoryStore + ) { try { + await this.beforeAllCleanup?.(); + this.beforeAllCleanup = await projectAnnotations.beforeAll?.(); + } catch (err) { + this.renderPreviewEntryError('Error in beforeAll hook:', err as Error); + throw err; + } + + // Don't reinitialize story store if it's already been set. + if (storyStore) return; + + try { + this.projectAnnotationsBeforeInitialization = projectAnnotations; const storyIndex = await this.getStoryIndexFromServer(); return this.initializeWithStoryIndex(storyIndex); } catch (err) { @@ -226,13 +242,12 @@ export class Preview { this.getProjectAnnotations = getProjectAnnotations; const projectAnnotations = await this.getProjectAnnotationsOrRenderError(); - if (!this.storyStoreValue) { - await this.initializeWithProjectAnnotations(projectAnnotations); - return; - } + await this.initializeWithProjectAnnotations(projectAnnotations, this.storyStoreValue); - this.storyStoreValue.setProjectAnnotations(projectAnnotations); - this.emitGlobals(); + if (this.storyStoreValue) { + this.storyStoreValue.setProjectAnnotations(projectAnnotations); + this.emitGlobals(); + } } async onStoryIndexChanged() { diff --git a/code/lib/preview-api/src/modules/store/csf/composeConfigs.ts b/code/lib/preview-api/src/modules/store/csf/composeConfigs.ts index b6ed3ecd7551..5eb1734093e8 100644 --- a/code/lib/preview-api/src/modules/store/csf/composeConfigs.ts +++ b/code/lib/preview-api/src/modules/store/csf/composeConfigs.ts @@ -59,6 +59,7 @@ export function composeConfigs( initialGlobals: getObjectField(moduleExportList, 'initialGlobals'), globalTypes: getObjectField(moduleExportList, 'globalTypes'), loaders: getArrayField(moduleExportList, 'loaders'), + beforeAll: getSingletonField(moduleExportList, 'beforeAll'), beforeEach: getArrayField(moduleExportList, 'beforeEach'), render: getSingletonField(moduleExportList, 'render'), renderToCanvas: getSingletonField(moduleExportList, 'renderToCanvas'), diff --git a/code/lib/types/src/modules/story.ts b/code/lib/types/src/modules/story.ts index 041aaed2e709..4bbfce1cf4f4 100644 --- a/code/lib/types/src/modules/story.ts +++ b/code/lib/types/src/modules/story.ts @@ -46,6 +46,8 @@ export type ProjectAnnotations = CsfProjectAnnotatio /* @deprecated use renderToCanvas */ renderToDOM?: RenderToCanvas; + + beforeAll?: () => MaybePromise MaybePromise)>; }; type NamedExportsOrDefault = TExport | { default: TExport };