From 775f3ae5429bf4889b17b4db2a5513ee6ba39ea1 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Tue, 13 Dec 2022 12:18:34 +0100 Subject: [PATCH] ensure exports using singleton always reference the global --- .../builder-vite/src/codegen-iframe-script.ts | 2 +- .../src/modules/client-api/ClientApi.ts | 46 ++++++++----------- 2 files changed, 19 insertions(+), 29 deletions(-) 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}`] = {