storybook/code/lib/builder-vite/src/codegen-iframe-script.ts
2022-09-22 17:52:00 -04:00

114 lines
3.7 KiB
TypeScript

import { isAbsolute, resolve } from 'path';
import { getFrameworkName } from '@storybook/core-common';
import { virtualPreviewFile, virtualStoriesFile } from './virtual-file-names';
import { transformAbsPath } from './utils/transform-abs-path';
import type { ExtendedOptions } from './types';
export async function generateIframeScriptCode(options: ExtendedOptions) {
const { presets } = options;
const frameworkName = await getFrameworkName(options);
const previewAnnotations = await presets.apply('previewAnnotations', [], options);
const resolvedPreviewAnnotations = previewAnnotations.map((entry) =>
isAbsolute(entry) ? entry : resolve(entry)
);
const configEntries = [...resolvedPreviewAnnotations].filter(Boolean);
const absoluteFilesToImport = (files: string[], name: string) =>
files
.map((el, i) => `import ${name ? `* as ${name}_${i} from ` : ''}'${transformAbsPath(el)}'`)
.join('\n');
const importArray = (name: string, length: number) =>
new Array(length).fill(0).map((_, i) => `${name}_${i}`);
// noinspection UnnecessaryLocalVariableJS
/** @todo Inline variable and remove `noinspection` */
// language=JavaScript
const code = `
// Ensure that the client API is initialized by the framework before any other iframe code
// is loaded. That way our client-apis can assume the existence of the API+store
import { configure } from '${frameworkName}';
import * as clientApi from "@storybook/client-api";
import { logger } from '@storybook/client-logger';
${absoluteFilesToImport(configEntries, 'config')}
import * as preview from '${virtualPreviewFile}';
import { configStories } from '${virtualStoriesFile}';
const {
addDecorator,
addParameters,
addLoader,
addArgs,
addArgTypes,
addStepRunner,
addArgTypesEnhancer,
addArgsEnhancer,
setGlobalRender,
} = clientApi;
const configs = [${importArray('config', configEntries.length)
.concat('preview.default')
.join(',')}].filter(Boolean)
configs.forEach(config => {
Object.keys(config).forEach((key) => {
const value = config[key];
switch (key) {
case 'args': {
return addArgs(value);
}
case 'argTypes': {
return addArgTypes(value);
}
case 'decorators': {
return value.forEach((decorator) => addDecorator(decorator, false));
}
case 'loaders': {
return value.forEach((loader) => addLoader(loader, false));
}
case 'parameters': {
return addParameters({ ...value }, false);
}
case 'argTypesEnhancers': {
return value.forEach((enhancer) => addArgTypesEnhancer(enhancer));
}
case 'argsEnhancers': {
return value.forEach((enhancer) => addArgsEnhancer(enhancer))
}
case 'render': {
return setGlobalRender(value)
}
case 'globals':
case 'globalTypes': {
const v = {};
v[key] = value;
return addParameters(v, false);
}
case 'decorateStory':
case 'applyDecorators':
case 'renderToDOM': {
return null; // This key is not handled directly in v6 mode.
}
case 'runStep': {
return addStepRunner(value);
}
default: {
// eslint-disable-next-line prefer-template
return console.log(key + ' was not supported :( !');
}
}
});
})
/* TODO: not quite sure what to do with this, to fix HMR
if (import.meta.hot) {
import.meta.hot.accept();
}
*/
configStories(configure);
`.trim();
return code;
}