Skip to content

Commit

Permalink
Consolidate loader, play and render context and add a self referencin…
Browse files Browse the repository at this point in the history
…g context property
  • Loading branch information
kasperpeulen committed Jun 25, 2024
1 parent 77c3c8a commit e944cc5
Show file tree
Hide file tree
Showing 18 changed files with 86 additions and 102 deletions.
2 changes: 1 addition & 1 deletion code/addons/links/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
"prep": "node --loader ../../../scripts/node_modules/esbuild-register/loader.js -r ../../../scripts/node_modules/esbuild-register/register.js ../../../scripts/prepare/addon-bundle.ts"
},
"dependencies": {
"@storybook/csf": "^0.1.8",
"@storybook/csf": "0.1.10--canary.d841bb4.0",
"@storybook/global": "^5.0.0",
"ts-dedent": "^2.0.0"
},
Expand Down
2 changes: 1 addition & 1 deletion code/lib/codemod/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
"@babel/core": "^7.24.4",
"@babel/preset-env": "^7.24.4",
"@babel/types": "^7.24.0",
"@storybook/csf": "^0.1.8",
"@storybook/csf": "0.1.10--canary.d841bb4.0",
"@storybook/csf-tools": "workspace:*",
"@storybook/node-logger": "workspace:*",
"@storybook/types": "workspace:*",
Expand Down
2 changes: 1 addition & 1 deletion code/lib/core-events/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
"prep": "node --loader ../../../scripts/node_modules/esbuild-register/loader.js -r ../../../scripts/node_modules/esbuild-register/register.js ../../../scripts/prepare/bundle.ts"
},
"dependencies": {
"@storybook/csf": "^0.1.8",
"@storybook/csf": "0.1.10--canary.d841bb4.0",
"ts-dedent": "^2.0.0"
},
"devDependencies": {
Expand Down
2 changes: 1 addition & 1 deletion code/lib/core-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
"@storybook/channels": "workspace:*",
"@storybook/core-common": "workspace:*",
"@storybook/core-events": "workspace:*",
"@storybook/csf": "^0.1.8",
"@storybook/csf": "0.1.10--canary.d841bb4.0",
"@storybook/csf-tools": "workspace:*",
"@storybook/docs-mdx": "3.1.0-next.0",
"@storybook/global": "^5.0.0",
Expand Down
2 changes: 1 addition & 1 deletion code/lib/csf-tools/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
"@babel/parser": "^7.24.4",
"@babel/traverse": "^7.24.1",
"@babel/types": "^7.24.0",
"@storybook/csf": "^0.1.8",
"@storybook/csf": "0.1.10--canary.d841bb4.0",
"@storybook/types": "workspace:*",
"fs-extra": "^11.1.0",
"recast": "^0.23.5",
Expand Down
9 changes: 6 additions & 3 deletions code/lib/instrumenter/src/instrumenter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -412,12 +412,14 @@ export class Instrumenter {
const { callRefsByResult, renderPhase } = this.getState(call.storyId);

// Map complex values to a JSON-serializable representation.
const serializeValues = (value: any): any => {
// We use a depth, to avoid infinite recursion of self referencing values.
const serializeValues = (value: any, depth = 0): any => {
if (callRefsByResult.has(value)) {
return callRefsByResult.get(value);
}
if (value instanceof Array) {
return value.map(serializeValues);
if (depth > 10) return [];
return value.map((it) => serializeValues(it, ++depth));
}
if (value instanceof Date) {
return { __date__: { value: value.toISOString() } };
Expand Down Expand Up @@ -451,8 +453,9 @@ export class Instrumenter {
return { __class__: { name: value.constructor.name } };
}
if (Object.prototype.toString.call(value) === '[object Object]') {
if (depth > 10) return {};
return Object.fromEntries(
Object.entries(value).map(([key, val]) => [key, serializeValues(val)])
Object.entries(value).map(([key, val]) => [key, serializeValues(val, ++depth)])
);
}
return value;
Expand Down
2 changes: 1 addition & 1 deletion code/lib/manager-api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"@storybook/channels": "workspace:*",
"@storybook/client-logger": "workspace:*",
"@storybook/core-events": "workspace:*",
"@storybook/csf": "^0.1.8",
"@storybook/csf": "0.1.10--canary.d841bb4.0",
"@storybook/global": "^5.0.0",
"@storybook/icons": "^1.2.5",
"@storybook/router": "workspace:*",
Expand Down
2 changes: 1 addition & 1 deletion code/lib/preview-api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"@storybook/channels": "workspace:*",
"@storybook/client-logger": "workspace:*",
"@storybook/core-events": "workspace:*",
"@storybook/csf": "^0.1.8",
"@storybook/csf": "0.1.10--canary.d841bb4.0",
"@storybook/global": "^5.0.0",
"@storybook/types": "workspace:*",
"@types/qs": "^6.9.5",
Expand Down
53 changes: 24 additions & 29 deletions code/lib/preview-api/src/modules/preview-web/render/StoryRender.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import type {
StoryContextForLoaders,
StoryId,
StoryRenderOptions,
ViewMode,
} from '@storybook/types';
import type { Channel } from '@storybook/channels';
import {
Expand Down Expand Up @@ -71,7 +70,7 @@ export class StoryRender<TRenderer extends Renderer> implements Render<TRenderer
private renderToScreen: RenderToCanvas<TRenderer>,
private callbacks: RenderContextCallbacks<TRenderer>,
public id: StoryId,
public viewMode: ViewMode,
public viewMode: StoryContext['viewMode'],
public renderOptions: StoryRenderOptions = { autoplay: true, forceInitialArgs: false },
story?: PreparedStory<TRenderer>
) {
Expand Down Expand Up @@ -165,6 +164,7 @@ export class StoryRender<TRenderer extends Renderer> implements Render<TRenderer
applyBeforeEach,
unboundStoryFn,
playFunction,
runStep,
} = story;

if (forceRemount && !initial) {
Expand All @@ -180,33 +180,16 @@ export class StoryRender<TRenderer extends Renderer> implements Render<TRenderer
const abortSignal = (this.abortController as AbortController).signal;

try {
let loadedContext: Awaited<ReturnType<typeof applyLoaders>>;
await this.runPhase(abortSignal, 'loading', async () => {
loadedContext = await applyLoaders({
...this.storyContext(),
viewMode: this.viewMode,
// TODO add this to CSF
canvasElement,
} as unknown as StoryContextForLoaders<TRenderer>);
});
if (abortSignal.aborted) return;

const renderStoryContext: StoryContext<TRenderer> = {
...loadedContext!,
// By this stage, it is possible that new args/globals have been received for this story
// and we need to ensure we render it with the new values
...this.storyContext(),
const context: StoryContext<TRenderer> = {
...(this.storyContext() as StoryContextForLoaders<TRenderer>),
viewMode: this.viewMode,
abortSignal,
// We should consider parameterizing the story types with TRenderer['canvasElement'] in the future
canvasElement: canvasElement as any,
canvasElement,
loaded: {},
step: (label, play) => runStep(label, play, context),
};

await this.runPhase(abortSignal, 'beforeEach', async () => {
const cleanupCallbacks = await applyBeforeEach(renderStoryContext);
this.store.addCleanupCallbacks(story, cleanupCallbacks);
});

if (abortSignal.aborted) return;
context.context = context;

const renderContext: RenderContext<TRenderer> = {
componentId,
Expand All @@ -226,10 +209,22 @@ export class StoryRender<TRenderer extends Renderer> implements Render<TRenderer
return this.callbacks.showException(error);
},
forceRemount: forceRemount || this.notYetRendered,
storyContext: renderStoryContext,
storyFn: () => unboundStoryFn(renderStoryContext),
storyContext: context,
storyFn: () => unboundStoryFn(context),
unboundStoryFn,
};
await this.runPhase(abortSignal, 'loading', async () => {
context.loaded = await applyLoaders(context);
});

if (abortSignal.aborted) return;

await this.runPhase(abortSignal, 'beforeEach', async () => {
const cleanupCallbacks = await applyBeforeEach(context);
this.store.addCleanupCallbacks(story, cleanupCallbacks);
});

if (abortSignal.aborted) return;

await this.runPhase(abortSignal, 'rendering', async () => {
const teardown = await this.renderToScreen(renderContext, canvasElement);
Expand All @@ -253,7 +248,7 @@ export class StoryRender<TRenderer extends Renderer> implements Render<TRenderer
this.disableKeyListeners = true;
try {
await this.runPhase(abortSignal, 'playing', async () => {
await playFunction(renderContext.storyContext);
await playFunction(context);
});
if (!ignoreUnhandledErrors && unhandledErrors.size > 0) {
await this.runPhase(abortSignal, 'errored');
Expand Down
37 changes: 11 additions & 26 deletions code/lib/preview-api/src/modules/store/csf/prepareStory.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* eslint-disable @typescript-eslint/no-loop-func,no-underscore-dangle */
/* eslint-disable no-underscore-dangle */
import { global } from '@storybook/global';
import type {
Args,
Expand All @@ -8,12 +8,9 @@ import type {
NormalizedProjectAnnotations,
NormalizedStoryAnnotations,
Parameters,
PlayFunction,
PlayFunctionContext,
PreparedMeta,
PreparedStory,
Renderer,
StepLabel,
StoryContext,
StoryContextForEnhancers,
StoryContextForLoaders,
Expand Down Expand Up @@ -50,9 +47,9 @@ export function prepareStory<TRenderer extends Renderer>(
);

const applyLoaders = async (
context: StoryContextForLoaders<TRenderer>
): Promise<StoryContextForLoaders<TRenderer> & { loaded: StoryContext<TRenderer>['loaded'] }> => {
let updatedContext = { ...context, loaded: {} };
context: StoryContext<TRenderer>
): Promise<StoryContext<TRenderer>['loaded']> => {
const loaded = {};
for (const loaders of [
...('__STORYBOOK_TEST_LOADERS__' in global && Array.isArray(global.__STORYBOOK_TEST_LOADERS__)
? [global.__STORYBOOK_TEST_LOADERS__]
Expand All @@ -61,12 +58,11 @@ export function prepareStory<TRenderer extends Renderer>(
normalizeArrays(componentAnnotations.loaders),
normalizeArrays(storyAnnotations.loaders),
]) {
const loadResults = await Promise.all(loaders.map((loader) => loader(updatedContext)));
const loaded: Record<string, any> = Object.assign({}, ...loadResults);
updatedContext = { ...updatedContext, loaded: { ...updatedContext.loaded, ...loaded } };
if (context.abortSignal.aborted) return loaded;
const loadResults = await Promise.all(loaders.map((loader) => loader(context)));
Object.assign(loaded, ...loadResults);
}

return updatedContext;
return loaded;
};

const applyBeforeEach = async (context: StoryContext<TRenderer>): Promise<CleanupCallback[]> => {
Expand All @@ -76,6 +72,7 @@ export function prepareStory<TRenderer extends Renderer>(
...normalizeArrays(componentAnnotations.beforeEach),
...normalizeArrays(storyAnnotations.beforeEach),
]) {
if (context.abortSignal.aborted) return cleanupCallbacks;
const cleanup = await beforeEach(context);
if (cleanup) cleanupCallbacks.push(cleanup);
}
Expand Down Expand Up @@ -106,20 +103,7 @@ export function prepareStory<TRenderer extends Renderer>(
const decoratedStoryFn = applyHooks<TRenderer>(applyDecorators)(undecoratedStoryFn, decorators);
const unboundStoryFn = (context: StoryContext<TRenderer>) => decoratedStoryFn(context);

const play = storyAnnotations?.play || componentAnnotations.play;

const playFunction =
play &&
(async (storyContext: StoryContext<TRenderer>) => {
const playFunctionContext: PlayFunctionContext<TRenderer> = {
...storyContext,
// eslint-disable-next-line @typescript-eslint/no-shadow
step: (label: StepLabel, play: PlayFunction<TRenderer>) =>
// TODO: We know runStep is defined, we need a proper normalized annotations type
runStep!(label, play, playFunctionContext),
};
return play(playFunctionContext);
});
const playFunction = storyAnnotations?.play ?? componentAnnotations?.play;

return {
...partialAnnotations,
Expand All @@ -133,6 +117,7 @@ export function prepareStory<TRenderer extends Renderer>(
applyLoaders,
applyBeforeEach,
playFunction,
runStep,
};
}
export function prepareMeta<TRenderer extends Renderer>(
Expand Down
2 changes: 1 addition & 1 deletion code/lib/source-loader/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"prep": "node --loader ../../../scripts/node_modules/esbuild-register/loader.js -r ../../../scripts/node_modules/esbuild-register/register.js ../../../scripts/prepare/bundle.ts"
},
"dependencies": {
"@storybook/csf": "^0.1.8",
"@storybook/csf": "0.1.10--canary.d841bb4.0",
"@storybook/types": "workspace:*",
"estraverse": "^5.2.0",
"lodash": "^4.17.21",
Expand Down
2 changes: 1 addition & 1 deletion code/lib/types/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
"file-system-cache": "2.3.0"
},
"devDependencies": {
"@storybook/csf": "^0.1.8",
"@storybook/csf": "0.1.10--canary.d841bb4.0",
"@types/fs-extra": "^11.0.1",
"@types/node": "^18.0.0",
"typescript": "^5.3.2"
Expand Down
16 changes: 8 additions & 8 deletions code/lib/types/src/modules/story.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type {
DecoratorFunction,
LoaderFunction,
CleanupCallback,
StepRunner,
} from '@storybook/csf';

import type {
Expand All @@ -16,7 +17,6 @@ import type {
StoryAnnotations,
StoryContext,
StoryContextForEnhancers,
StoryContextForLoaders,
StoryFn,
StoryId,
StoryIdentifier,
Expand All @@ -41,12 +41,12 @@ export type RenderToCanvas<TRenderer extends Renderer> = (
element: TRenderer['canvasElement']
) => MaybePromise<void | TeardownRenderToCanvas>;

export type ProjectAnnotations<TRenderer extends Renderer> = CsfProjectAnnotations<TRenderer> & {
export interface ProjectAnnotations<TRenderer extends Renderer>
extends CsfProjectAnnotations<TRenderer> {
renderToCanvas?: RenderToCanvas<TRenderer>;

/* @deprecated use renderToCanvas */
renderToDOM?: RenderToCanvas<TRenderer>;
};
}

type NamedExportsOrDefault<TExport> = TExport | { default: TExport };

Expand All @@ -55,12 +55,13 @@ export type NamedOrDefaultProjectAnnotations<TRenderer extends Renderer = Render

export type NormalizedProjectAnnotations<TRenderer extends Renderer = Renderer> = Omit<
ProjectAnnotations<TRenderer>,
'decorators' | 'loaders'
'decorators' | 'loaders' | 'runStep'
> & {
argTypes?: StrictArgTypes;
globalTypes?: StrictGlobalTypes;
decorators?: DecoratorFunction<TRenderer>[];
loaders?: LoaderFunction<TRenderer>[];
runStep: StepRunner<TRenderer>;
};

export type NormalizedComponentAnnotations<TRenderer extends Renderer = Renderer> = Omit<
Expand Down Expand Up @@ -101,11 +102,10 @@ export type PreparedStory<TRenderer extends Renderer = Renderer> =
originalStoryFn: StoryFn<TRenderer>;
undecoratedStoryFn: LegacyStoryFn<TRenderer>;
unboundStoryFn: LegacyStoryFn<TRenderer>;
applyLoaders: (
context: StoryContextForLoaders<TRenderer>
) => Promise<StoryContextForLoaders<TRenderer> & { loaded: StoryContext<TRenderer>['loaded'] }>;
applyLoaders: (context: StoryContext<TRenderer>) => Promise<StoryContext<TRenderer>['loaded']>;
applyBeforeEach: (context: StoryContext<TRenderer>) => Promise<CleanupCallback[]>;
playFunction?: (context: StoryContext<TRenderer>) => Promise<void> | void;
runStep: StepRunner<TRenderer>;
};

export type PreparedMeta<TRenderer extends Renderer = Renderer> = Omit<
Expand Down
5 changes: 3 additions & 2 deletions code/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@
"@storybook/core-events": "workspace:*",
"@storybook/core-server": "workspace:*",
"@storybook/core-webpack": "workspace:*",
"@storybook/csf": "^0.1.8",
"@storybook/csf": "0.1.10--canary.d841bb4.0",
"@storybook/csf-plugin": "workspace:*",
"@storybook/csf-tools": "workspace:*",
"@storybook/docs-tools": "workspace:*",
Expand Down Expand Up @@ -293,5 +293,6 @@
"Dependency Upgrades"
]
]
}
},
"packageManager": "yarn@4.3.1"

This comment has been minimized.

Copy link
@ndelangen

ndelangen Jul 1, 2024

Member

We should NOT add this line.

}
2 changes: 1 addition & 1 deletion code/renderers/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
"prep": "node --loader ../../../scripts/node_modules/esbuild-register/loader.js -r ../../../scripts/node_modules/esbuild-register/register.js ../../../scripts/prepare/bundle.ts"
},
"dependencies": {
"@storybook/csf": "^0.1.8",
"@storybook/csf": "0.1.10--canary.d841bb4.0",
"@storybook/csf-tools": "workspace:*",
"@storybook/global": "^5.0.0",
"@storybook/preview-api": "workspace:*",
Expand Down
2 changes: 1 addition & 1 deletion code/ui/blocks/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
"@storybook/client-logger": "workspace:*",
"@storybook/components": "workspace:*",
"@storybook/core-events": "workspace:*",
"@storybook/csf": "^0.1.8",
"@storybook/csf": "0.1.10--canary.d841bb4.0",
"@storybook/docs-tools": "workspace:*",
"@storybook/global": "^5.0.0",
"@storybook/icons": "^1.2.5",
Expand Down
Loading

0 comments on commit e944cc5

Please sign in to comment.