diff --git a/code/lib/builder-vite/src/codegen-iframe-script.ts b/code/lib/builder-vite/src/codegen-iframe-script.ts
index 8f986e9ca26a..a5818c1a170b 100644
--- a/code/lib/builder-vite/src/codegen-iframe-script.ts
+++ b/code/lib/builder-vite/src/codegen-iframe-script.ts
@@ -30,7 +30,7 @@ export async function generateIframeScriptCode(options: ExtendedOptions) {
import { configure } from '${rendererName}';
import { logger } from '@storybook/client-logger';
- import * as clientApi from "@storybook/preview-api";
+ import * as previewApi from "@storybook/preview-api";
${filesToImport(configEntries, 'config')}
import * as preview from '${virtualPreviewFile}';
diff --git a/code/lib/preview-api/src/modules/client-api/ClientApi.ts b/code/lib/preview-api/src/modules/client-api/ClientApi.ts
index f2d8eb358748..0f7510d8e0f8 100644
--- a/code/lib/preview-api/src/modules/client-api/ClientApi.ts
+++ b/code/lib/preview-api/src/modules/client-api/ClientApi.ts
@@ -1,4 +1,4 @@
-///
+/* eslint-disable no-underscore-dangle */
import { dedent } from 'ts-dedent';
import global from 'global';
@@ -29,10 +29,6 @@ import { combineParameters, composeStepRunners, normalizeInputTypes } from '../.
import { StoryStoreFacade } from './StoryStoreFacade';
-// ClientApi (and StoreStore) are really singletons. However they are not created until the
-// relevant framework instanciates them via `start.js`. The good news is this happens right away.
-let singleton: ClientApi;
-
const warningAlternatives = {
addDecorator: `Instead, use \`export const decorators = [];\` in your \`preview.js\`.`,
addParameters: `Instead, use \`export const parameters = {};\` in your \`preview.js\`.`,
@@ -55,61 +51,61 @@ const checkMethod = (method: keyof typeof warningAlternatives) => {
);
}
- if (!singleton) {
+ if (!global.__STORYBOOK_CLIENT_API__) {
throw new Error(`Singleton client API not yet initialized, cannot call \`${method}\`.`);
}
};
export const addDecorator = (decorator: DecoratorFunction) => {
checkMethod('addDecorator');
- singleton.addDecorator(decorator);
+ global.__STORYBOOK_CLIENT_API__?.addDecorator(decorator);
};
export const addParameters = (parameters: Parameters) => {
checkMethod('addParameters');
- singleton.addParameters(parameters);
+ global.__STORYBOOK_CLIENT_API__?.addParameters(parameters);
};
export const addLoader = (loader: LoaderFunction) => {
checkMethod('addLoader');
- singleton.addLoader(loader);
+ global.__STORYBOOK_CLIENT_API__?.addLoader(loader);
};
export const addArgs = (args: Args) => {
checkMethod('addArgs');
- singleton.addArgs(args);
+ global.__STORYBOOK_CLIENT_API__?.addArgs(args);
};
export const addArgTypes = (argTypes: ArgTypes) => {
checkMethod('addArgTypes');
- singleton.addArgTypes(argTypes);
+ global.__STORYBOOK_CLIENT_API__?.addArgTypes(argTypes);
};
export const addArgsEnhancer = (enhancer: ArgsEnhancer) => {
checkMethod('addArgsEnhancer');
- singleton.addArgsEnhancer(enhancer);
+ global.__STORYBOOK_CLIENT_API__?.addArgsEnhancer(enhancer);
};
export const addArgTypesEnhancer = (enhancer: ArgTypesEnhancer) => {
checkMethod('addArgTypesEnhancer');
- singleton.addArgTypesEnhancer(enhancer);
+ global.__STORYBOOK_CLIENT_API__?.addArgTypesEnhancer(enhancer);
};
export const addStepRunner = (stepRunner: StepRunner) => {
checkMethod('addStepRunner');
- singleton.addStepRunner(stepRunner);
+ global.__STORYBOOK_CLIENT_API__?.addStepRunner(stepRunner);
};
export const getGlobalRender = () => {
checkMethod('getGlobalRender');
- return singleton.facade.projectAnnotations.render;
+ return global.__STORYBOOK_CLIENT_API__?.facade.projectAnnotations.render;
};
-export const setGlobalRender = (
- render: typeof singleton['facade']['projectAnnotations']['render']
-) => {
+export const setGlobalRender = (render: StoryStoreFacade['projectAnnotations']['render']) => {
checkMethod('setGlobalRender');
- singleton.facade.projectAnnotations.render = render;
+ if (global.__STORYBOOK_CLIENT_API__) {
+ global.__STORYBOOK_CLIENT_API__.facade.projectAnnotations.render = render;
+ }
};
const invalidStoryTypes = new Set(['string', 'number', 'boolean', 'symbol']);
@@ -132,8 +128,6 @@ export class ClientApi {
this.addons = {};
this.storyStore = storyStore;
-
- singleton = this as any;
}
importFn(path: Path) {
@@ -213,7 +207,6 @@ export class ClientApi {
_addedExports = {} as Record;
_loadAddedExports() {
- // eslint-disable-next-line no-underscore-dangle
Object.entries(this._addedExports).forEach(([fileName, fileExports]) =>
this.facade.addStoriesFromExports(fileName, fileExports)
);
@@ -247,7 +240,7 @@ export class ClientApi {
let i = 1;
// Deal with `storiesOf()` being called twice in the same file.
// On HMR, we clear _addedExports[fileName] below.
- // eslint-disable-next-line no-underscore-dangle
+
while (this._addedExports[fileName]) {
i += 1;
fileName = `${baseFilename}-${i}`;
@@ -259,7 +252,7 @@ export class ClientApi {
m.hot.accept();
m.hot.dispose(() => {
this.facade.clearFilenameExports(fileName);
- // eslint-disable-next-line no-underscore-dangle
+
delete this._addedExports[fileName];
// We need to update the importFn as soon as the module re-evaluates
@@ -268,7 +261,6 @@ export class ClientApi {
// debounce it somehow for initial startup. Instead, we'll take advantage of
// the fact that the evaluation of the module happens immediately in the same tick
setTimeout(() => {
- // eslint-disable-next-line no-underscore-dangle
this._loadAddedExports();
this.onImportFnChanged?.({ importFn: this.importFn.bind(this) });
}, 0);
@@ -301,7 +293,7 @@ export class ClientApi {
parameters: {},
};
// We map these back to a simple default export, even though we have type guarantees at this point
- // eslint-disable-next-line no-underscore-dangle
+
this._addedExports[fileName] = { default: meta };
let counter = 0;
@@ -320,10 +312,8 @@ export class ClientApi {
const { decorators, loaders, component, args, argTypes, ...storyParameters } = parameters;
- // eslint-disable-next-line no-underscore-dangle
const storyId = parameters.__id || toId(kind, storyName);
- // eslint-disable-next-line no-underscore-dangle
const csfExports = this._addedExports[fileName];
// Whack a _ on the front incase it is "default"
csfExports[`story${counter}`] = {