diff --git a/MIGRATION.md b/MIGRATION.md index 53a10ac4519..483ed0b01fc 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -3,6 +3,7 @@ - [From version 6.5.x to 7.0.0](#from-version-65x-to-700) - [7.0 breaking changes](#70-breaking-changes) - [Dropped support for Node 15 and below](#dropped-support-for-node-15-and-below) + - [ESM format in Main.js](#esm-format-in-mainjs) - [Modern browser support](#modern-browser-support) - [React peer dependencies required](#react-peer-dependencies-required) - [start-storybook / build-storybook binaries removed](#start-storybook--build-storybook-binaries-removed) @@ -290,6 +291,48 @@ For avoiding that, this change passes the mapped args instead of raw args at `re Storybook 7.0 requires **Node 16** or above. If you are using an older version of Node, you will need to upgrade or keep using Storybook 6 in the meantime. +#### ESM format in Main.js + +Storybook 7.0 supports ESM in `.storybook/main.js`, and the configurations can be part of a default export. The default export will be the recommended way going forward. + +If your main.js file looks like this: + +```js +module.exports = { + stories: ['../stories/**/*.stories.mdx', '../stories/**/*.stories.@(js|jsx|ts|tsx)'], + framework: { name: '@storybook/react-vite' }, +}; +``` + +Or like this: + +```js +export const stories = ['../stories/**/*.stories.mdx', '../stories/**/*.stories.@(js|jsx|ts|tsx)']; +export const framework = { name: '@storybook/react-vite' }; +``` + +Please migrate them to be default exported instead: + +```js +const config = { + stories: ['../stories/**/*.stories.mdx', '../stories/**/*.stories.@(js|jsx|ts|tsx)'], + framework: { name: '@storybook/react-vite' }, +}; +export default config; +``` + +For Typescript users, we introduced types for that default export, so you can import it in your main.ts file. The `StorybookConfig` type will come from the Storybook package for the framework you are using, which relates to the package in the "framework" field you have in your main.ts file. For example, if you are using React Vite, you will import it from `@storybook/react-vite`: + +```ts +import { StorybookConfig } from '@storybook/react-vite'; + +const config: StorybookConfig = { + stories: ['../stories/**/*.stories.mdx', '../stories/**/*.stories.@(js|jsx|ts|tsx)'], + framework: { name: '@storybook/react-vite' }, +}; +export default config; +``` + #### Modern browser support Starting in Storybook 7.0, Storybook will no longer support IE11, amongst other legacy browser versions. diff --git a/code/frameworks/html-vite/package.json b/code/frameworks/html-vite/package.json index 7bffe666103..7f1958a5e62 100644 --- a/code/frameworks/html-vite/package.json +++ b/code/frameworks/html-vite/package.json @@ -57,7 +57,7 @@ "@storybook/html": "7.0.0-beta.36", "@storybook/node-logger": "7.0.0-beta.36", "@storybook/preview-web": "7.0.0-beta.36", - "magic-string": "^0.26.1" + "magic-string": "^0.27.0" }, "devDependencies": { "@types/node": "^16.0.0", diff --git a/code/frameworks/react-vite/package.json b/code/frameworks/react-vite/package.json index 3bf25279400..5b0fbec8279 100644 --- a/code/frameworks/react-vite/package.json +++ b/code/frameworks/react-vite/package.json @@ -54,7 +54,7 @@ "@storybook/react": "7.0.0-beta.36", "@vitejs/plugin-react": "^3.0.1", "ast-types": "^0.14.2", - "magic-string": "^0.26.1", + "magic-string": "^0.27.0", "react-docgen": "6.0.0-alpha.3" }, "devDependencies": { diff --git a/code/frameworks/svelte-vite/package.json b/code/frameworks/svelte-vite/package.json index dd935aba664..17e9a1b49fe 100644 --- a/code/frameworks/svelte-vite/package.json +++ b/code/frameworks/svelte-vite/package.json @@ -52,7 +52,7 @@ "@storybook/node-logger": "7.0.0-beta.36", "@storybook/svelte": "7.0.0-beta.36", "@sveltejs/vite-plugin-svelte": "^2.0.0", - "magic-string": "^0.26.1", + "magic-string": "^0.27.0", "svelte": "^3.0.0", "sveltedoc-parser": "^4.2.1", "ts-dedent": "^2.2.0" diff --git a/code/frameworks/vue-vite/package.json b/code/frameworks/vue-vite/package.json index 9f462406bba..5565e490ce5 100644 --- a/code/frameworks/vue-vite/package.json +++ b/code/frameworks/vue-vite/package.json @@ -52,7 +52,7 @@ "@storybook/core-common": "7.0.0-beta.36", "@storybook/core-server": "7.0.0-beta.36", "@storybook/vue": "7.0.0-beta.36", - "magic-string": "^0.26.1", + "magic-string": "^0.27.0", "vue-docgen-api": "^4.40.0" }, "devDependencies": { diff --git a/code/frameworks/vue3-vite/package.json b/code/frameworks/vue3-vite/package.json index 386707f4872..09bd8b00d8b 100644 --- a/code/frameworks/vue3-vite/package.json +++ b/code/frameworks/vue3-vite/package.json @@ -52,7 +52,7 @@ "@storybook/core-server": "7.0.0-beta.36", "@storybook/vue3": "7.0.0-beta.36", "@vitejs/plugin-vue": "^4.0.0", - "magic-string": "^0.26.1", + "magic-string": "^0.27.0", "vue-docgen-api": "^4.40.0" }, "devDependencies": { diff --git a/code/frameworks/web-components-vite/package.json b/code/frameworks/web-components-vite/package.json index ecae9d8732f..bf01fc95af8 100644 --- a/code/frameworks/web-components-vite/package.json +++ b/code/frameworks/web-components-vite/package.json @@ -52,7 +52,7 @@ "@storybook/core-server": "7.0.0-beta.36", "@storybook/node-logger": "7.0.0-beta.36", "@storybook/web-components": "7.0.0-beta.36", - "magic-string": "^0.26.1" + "magic-string": "^0.27.0" }, "devDependencies": { "@types/node": "^16.0.0", diff --git a/code/lib/builder-vite/package.json b/code/lib/builder-vite/package.json index 0f3290bbd4a..c765e40eae6 100644 --- a/code/lib/builder-vite/package.json +++ b/code/lib/builder-vite/package.json @@ -59,7 +59,7 @@ "fs-extra": "^11.1.0", "glob": "^7.2.0", "glob-promise": "^4.2.0", - "magic-string": "^0.26.1", + "magic-string": "^0.27.0", "rollup": "^2.25.0 || ^3.3.0", "slash": "^3.0.0" }, diff --git a/code/lib/cli/src/generators/ANGULAR/index.ts b/code/lib/cli/src/generators/ANGULAR/index.ts index f23ba2c1a8f..5eeaa9f76cf 100644 --- a/code/lib/cli/src/generators/ANGULAR/index.ts +++ b/code/lib/cli/src/generators/ANGULAR/index.ts @@ -56,12 +56,15 @@ const generator: Generator<{ projectName: string }> = async ( .join(''); fs.writeFileSync( - `${storybookFolder}/main.js`, + `${storybookFolder}/main.ts`, dedent(` - const mainRoot = require('${rootReferencePathFromStorybookFolder}../.storybook/main.js'); - module.exports = { + import { StorybookConfig } from'@storybook/angular'; + import mainRoot from'${rootReferencePathFromStorybookFolder}../.storybook/main'; + + const config: StorybookConfig = { ...mainRoot }; + export default config; `) ); } diff --git a/code/lib/cli/src/generators/SVELTE/index.ts b/code/lib/cli/src/generators/SVELTE/index.ts index 9639d5b5053..136dedfb9c0 100644 --- a/code/lib/cli/src/generators/SVELTE/index.ts +++ b/code/lib/cli/src/generators/SVELTE/index.ts @@ -4,7 +4,6 @@ import type { Generator } from '../types'; const generator: Generator = async (packageManager, npmOptions, options) => { await baseGenerator(packageManager, npmOptions, options, 'svelte', { extensions: ['js', 'jsx', 'ts', 'tsx', 'svelte'], - commonJs: true, }); }; diff --git a/code/lib/cli/src/generators/baseGenerator.ts b/code/lib/cli/src/generators/baseGenerator.ts index 5a9f48b201d..d5cba7d0766 100644 --- a/code/lib/cli/src/generators/baseGenerator.ts +++ b/code/lib/cli/src/generators/baseGenerator.ts @@ -25,7 +25,6 @@ const defaultOptions: FrameworkOptions = { framework: undefined, extensions: undefined, componentsDestinationPath: undefined, - commonJs: false, storybookConfigFolder: '.storybook', }; @@ -123,13 +122,7 @@ const hasFrameworkTemplates = (framework?: SupportedFrameworks) => export async function baseGenerator( packageManager: JsPackageManager, npmOptions: NpmOptions, - { - language, - builder = CoreBuilder.Webpack5, - pnp, - commonJs, - frameworkPreviewParts, - }: GeneratorOptions, + { language, builder = CoreBuilder.Webpack5, pnp, frameworkPreviewParts }: GeneratorOptions, renderer: SupportedRenderers, options: FrameworkOptions = defaultOptions, framework?: SupportedFrameworks @@ -232,7 +225,7 @@ export async function baseGenerator( docs: { autodocs: 'tag' }, addons: pnp ? addons.map(wrapForPnp) : addons, extensions, - commonJs, + language, ...(staticDir ? { staticDirs: [path.join('..', staticDir)] } : null), ...extraMain, ...(type !== 'framework' @@ -245,7 +238,7 @@ export async function baseGenerator( }); } - await configurePreview({ frameworkPreviewParts, storybookConfigFolder }); + await configurePreview({ frameworkPreviewParts, storybookConfigFolder, language }); // FIXME: temporary workaround for https://github.com/storybookjs/storybook/issues/17516 if ( @@ -273,10 +266,12 @@ export async function baseGenerator( if (isNewFolder) { await generateStorybookBabelConfigInCWD(); } - packageManager.addDependencies({ ...npmOptions, packageJson }, [ - ...versionedPackages, - ...babelDependencies, - ]); + + const depsToInstall = [...versionedPackages, ...babelDependencies]; + + if (depsToInstall.length > 0) { + packageManager.addDependencies({ ...npmOptions, packageJson }, depsToInstall); + } if (addScripts) { packageManager.addStorybookCommandInScripts({ diff --git a/code/lib/cli/src/generators/configure.ts b/code/lib/cli/src/generators/configure.ts index b1f26922f47..8efbf7ba059 100644 --- a/code/lib/cli/src/generators/configure.ts +++ b/code/lib/cli/src/generators/configure.ts @@ -1,12 +1,13 @@ import fse from 'fs-extra'; import { dedent } from 'ts-dedent'; +import { SupportedLanguage } from '../project_types'; interface ConfigureMainOptions { addons: string[]; extensions?: string[]; - commonJs?: boolean; staticDirs?: string[]; storybookConfigFolder: string; + language: SupportedLanguage; /** * Extra values for main.js * @@ -26,46 +27,52 @@ export interface FrameworkPreviewParts { interface ConfigurePreviewOptions { frameworkPreviewParts?: FrameworkPreviewParts; storybookConfigFolder: string; + language: SupportedLanguage; } export async function configureMain({ addons, extensions = ['js', 'jsx', 'ts', 'tsx'], - commonJs = false, storybookConfigFolder, + language, ...custom }: ConfigureMainOptions) { const prefix = (await fse.pathExists('./src')) ? '../src' : '../stories'; - const config = { stories: [`${prefix}/**/*.mdx`, `${prefix}/**/*.stories.@(${extensions.join('|')})`], addons, ...custom, }; - // replace escaped values and delimiters - const stringified = `module.exports = ${JSON.stringify(config, null, 2) - .replace(/\\"/g, '"') - .replace(/['"]%%/g, '') - .replace(/%%['"]/g, '') - .replace(/\\n/g, '\r\n')}`; - // main.js isn't actually JSON, but we used JSON.stringify to convert the runtime-object into code. - // un-stringify the value for referencing packages by string - // .replaceAll(/"(path\.dirname\(require\.resolve\(path\.join\('.*\))"/g, (_, a) => a)}`; + const isTypescript = + language === SupportedLanguage.TYPESCRIPT || language === SupportedLanguage.TYPESCRIPT_LEGACY; + + const tsTemplate = dedent`<>const config<> = <>; + export default config;`; + + const jsTemplate = dedent`export default <>;`; + + const finalTemplate = isTypescript ? tsTemplate : jsTemplate; + + const mainJsContents = finalTemplate + .replace('<>', `import { StorybookConfig } from '${custom.framework.name}';\n\n`) + .replace('<>', ': StorybookConfig') + .replace('<>', JSON.stringify(config, null, 2)); await fse.writeFile( - `./${storybookConfigFolder}/main.${commonJs ? 'cjs' : 'js'}`, - dedent` - const path = require('path'); - ${stringified} - `, + `./${storybookConfigFolder}/main.${isTypescript ? 'ts' : 'js'}`, + dedent(mainJsContents), { encoding: 'utf8' } ); } export async function configurePreview(options: ConfigurePreviewOptions) { - const { prefix = '' } = options?.frameworkPreviewParts || {}; - const previewPath = `./${options.storybookConfigFolder}/preview.js`; + const { prefix = '' } = options.frameworkPreviewParts || {}; + const isTypescript = + options.language === SupportedLanguage.TYPESCRIPT || + options.language === SupportedLanguage.TYPESCRIPT_LEGACY; + + const previewPath = `./${options.storybookConfigFolder}/preview.${isTypescript ? 'ts' : 'js'}`; // If the framework template included a preview then we have nothing to do if (await fse.pathExists(previewPath)) { diff --git a/code/lib/cli/src/generators/types.ts b/code/lib/cli/src/generators/types.ts index 198123152e1..bb62010bbd5 100644 --- a/code/lib/cli/src/generators/types.ts +++ b/code/lib/cli/src/generators/types.ts @@ -8,7 +8,6 @@ export type GeneratorOptions = { builder: Builder; linkable: boolean; pnp: boolean; - commonJs: boolean; frameworkPreviewParts?: FrameworkPreviewParts; }; @@ -24,7 +23,6 @@ export interface FrameworkOptions { extraMain?: any; extensions?: string[]; framework?: Record; - commonJs?: boolean; storybookConfigFolder?: string; componentsDestinationPath?: string; } @@ -49,7 +47,6 @@ export type CommandOptions = { yes?: boolean; builder?: Builder; linkable?: boolean; - commonJs?: boolean; disableTelemetry?: boolean; enableCrashReports?: boolean; debug?: boolean; diff --git a/code/lib/cli/src/initiate.ts b/code/lib/cli/src/initiate.ts index 6419ba9b6fb..1edf244404f 100644 --- a/code/lib/cli/src/initiate.ts +++ b/code/lib/cli/src/initiate.ts @@ -61,7 +61,6 @@ const installStorybook = ( language, builder: options.builder || detectBuilder(packageManager), linkable: !!options.linkable, - commonJs: options.commonJs, pnp: options.usePnp, }; @@ -294,7 +293,6 @@ async function doInitiate(options: CommandOptions, pkg: PackageJson): Promise { + const installResult = await installStorybook( + projectType as ProjectType, + packageManager, + options + ).catch((e) => { process.exit(); }); diff --git a/code/lib/cli/templates/angular/template-csf/.storybook/tsconfig.json b/code/lib/cli/templates/angular/template-csf/.storybook/tsconfig.json index 2243e0894a8..eb06864100d 100644 --- a/code/lib/cli/templates/angular/template-csf/.storybook/tsconfig.json +++ b/code/lib/cli/templates/angular/template-csf/.storybook/tsconfig.json @@ -2,9 +2,10 @@ "extends": "../tsconfig.app.json", "compilerOptions": { "types": ["node"], - "allowSyntheticDefaultImports": true + "allowSyntheticDefaultImports": true, + "resolveJsonModule": true }, "exclude": ["../src/test.ts", "../src/**/*.spec.ts"], - "include": ["../src/**/*"], + "include": ["../src/**/*", "./preview.ts"], "files": ["./typings.d.ts"] } diff --git a/code/yarn.lock b/code/yarn.lock index 9fe3fdb85fe..654b5095cc5 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -5775,7 +5775,7 @@ __metadata: fs-extra: ^11.1.0 glob: ^7.2.0 glob-promise: ^4.2.0 - magic-string: ^0.26.1 + magic-string: ^0.27.0 rollup: ^3.0.0 slash: ^3.0.0 typescript: ~4.9.3 @@ -6287,7 +6287,7 @@ __metadata: "@storybook/node-logger": 7.0.0-beta.36 "@storybook/preview-web": 7.0.0-beta.36 "@types/node": ^16.0.0 - magic-string: ^0.26.1 + magic-string: ^0.27.0 typescript: ~4.9.3 languageName: unknown linkType: soft @@ -6838,7 +6838,7 @@ __metadata: "@types/node": ^16.0.0 "@vitejs/plugin-react": ^3.0.1 ast-types: ^0.14.2 - magic-string: ^0.26.1 + magic-string: ^0.27.0 react-docgen: 6.0.0-alpha.3 typescript: ~4.9.3 vite: ^4.0.0 @@ -7186,7 +7186,7 @@ __metadata: "@storybook/svelte": 7.0.0-beta.36 "@sveltejs/vite-plugin-svelte": ^2.0.0 "@types/node": ^16.0.0 - magic-string: ^0.26.1 + magic-string: ^0.27.0 svelte: ^3.0.0 sveltedoc-parser: ^4.2.1 ts-dedent: ^2.2.0 @@ -7334,7 +7334,7 @@ __metadata: "@storybook/core-common": 7.0.0-beta.36 "@storybook/core-server": 7.0.0-beta.36 "@storybook/vue": 7.0.0-beta.36 - magic-string: ^0.26.1 + magic-string: ^0.27.0 typescript: ~4.9.3 vite: ^4.0.0 vue: ^2.7.10 @@ -7381,7 +7381,7 @@ __metadata: "@storybook/vue3": 7.0.0-beta.36 "@types/node": ^16.0.0 "@vitejs/plugin-vue": ^4.0.0 - magic-string: ^0.26.1 + magic-string: ^0.27.0 typescript: ~4.9.3 vite: ^4.0.0 vue-docgen-api: ^4.40.0 @@ -7471,7 +7471,7 @@ __metadata: "@storybook/node-logger": 7.0.0-beta.36 "@storybook/web-components": 7.0.0-beta.36 "@types/node": ^16.0.0 - magic-string: ^0.26.1 + magic-string: ^0.27.0 typescript: ~4.9.3 peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -20109,7 +20109,7 @@ __metadata: languageName: node linkType: hard -"magic-string@npm:^0.26.1, magic-string@npm:^0.26.7": +"magic-string@npm:^0.26.7": version: 0.26.7 resolution: "magic-string@npm:0.26.7" dependencies: