From 94124357df3dcae84bc969e0b3b393108b101063 Mon Sep 17 00:00:00 2001 From: Michael Shilman Date: Fri, 27 Aug 2021 19:56:26 +0800 Subject: [PATCH 01/14] Node-logger: Add once to match client-logger --- lib/node-logger/src/index.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/node-logger/src/index.ts b/lib/node-logger/src/index.ts index 07beaa620bbb..aa5c0769c00f 100644 --- a/lib/node-logger/src/index.ts +++ b/lib/node-logger/src/index.ts @@ -27,3 +27,15 @@ export const logger = { }; export { npmLog as instance }; + +const logged = new Set(); +export const once = (type: 'info' | 'warn' | 'error') => (message: string) => { + if (logged.has(message)) return undefined; + logged.add(message); + return logger[type](message); +}; + +once.clear = () => logged.clear(); +once.info = once('info'); +once.warn = once('warn'); +once.error = once('error'); From 712a7036f5351f020def8697f76633566036fe24 Mon Sep 17 00:00:00 2001 From: Michael Shilman Date: Fri, 27 Aug 2021 19:58:23 +0800 Subject: [PATCH 02/14] Core: Add babelModeV7 feature flag for improved babel config --- .../server/framework-preset-web-components.ts | 6 +- examples/react-ts/main.ts | 1 + .../src/preview/base-webpack.config.ts | 2 +- lib/core-common/src/types.ts | 5 + lib/core-common/src/utils/babel.ts | 2 +- lib/core-common/src/utils/es6Transpiler.ts | 4 +- lib/core-server/src/presets/common-preset.ts | 9 +- lib/manager-webpack4/src/manager-config.ts | 4 +- .../src/manager-webpack.config.ts | 195 ----------------- .../src/{ => presets}/babel-loader-manager.ts | 6 +- .../src/presets/manager-preset.ts | 199 +++++++++++++++++- lib/manager-webpack5/src/manager-config.ts | 4 +- .../src/manager-webpack.config.ts | 188 ----------------- .../src/{ => presets}/babel-loader-manager.ts | 6 +- .../src/presets/manager-preset.ts | 192 ++++++++++++++++- 15 files changed, 412 insertions(+), 411 deletions(-) delete mode 100644 lib/manager-webpack4/src/manager-webpack.config.ts rename lib/manager-webpack4/src/{ => presets}/babel-loader-manager.ts (77%) delete mode 100644 lib/manager-webpack5/src/manager-webpack.config.ts rename lib/manager-webpack5/src/{ => presets}/babel-loader-manager.ts (77%) diff --git a/app/web-components/src/server/framework-preset-web-components.ts b/app/web-components/src/server/framework-preset-web-components.ts index 8e14b519defe..6e17cad29f5a 100644 --- a/app/web-components/src/server/framework-preset-web-components.ts +++ b/app/web-components/src/server/framework-preset-web-components.ts @@ -1,7 +1,9 @@ // eslint-disable-next-line import/no-extraneous-dependencies import { Configuration } from 'webpack'; +import type { Options } from '@storybook/core-common'; -export function webpack(config: Configuration) { +export function webpack(config: Configuration, options: Options) { + const babelrcOptions = options.features?.babelModeV7 ? null : { babelrc: false }; config.module.rules.push({ test: [ new RegExp(`src(.*)\\.js$`), @@ -30,7 +32,7 @@ export function webpack(config: Configuration) { }, ], ], - babelrc: false, + ...babelrcOptions, }, }, }); diff --git a/examples/react-ts/main.ts b/examples/react-ts/main.ts index 9460c8989714..bf60ccabbd75 100644 --- a/examples/react-ts/main.ts +++ b/examples/react-ts/main.ts @@ -22,6 +22,7 @@ const config: StorybookConfig = { postcss: false, previewCsfV3: true, buildStoriesJson: true, + babelModeV7: true, }, }; diff --git a/lib/builder-webpack4/src/preview/base-webpack.config.ts b/lib/builder-webpack4/src/preview/base-webpack.config.ts index bb37afd9b10d..996978f58f58 100644 --- a/lib/builder-webpack4/src/preview/base-webpack.config.ts +++ b/lib/builder-webpack4/src/preview/base-webpack.config.ts @@ -4,7 +4,7 @@ import path from 'path'; import { logger } from '@storybook/node-logger'; import deprecate from 'util-deprecate'; import dedent from 'ts-dedent'; -import type { BuilderOptions, LoadedPreset, Options } from '@storybook/core-common'; +import type { LoadedPreset, Options } from '@storybook/core-common'; const warnImplicitPostcssPlugins = deprecate( () => ({ diff --git a/lib/core-common/src/types.ts b/lib/core-common/src/types.ts index ed34b1c21f2a..d9054b9cb57a 100644 --- a/lib/core-common/src/types.ts +++ b/lib/core-common/src/types.ts @@ -265,6 +265,11 @@ export interface StorybookConfig { * Activate preview of CSF v3.0 */ previewCsfV3?: boolean; + + /** + * Use Storybook 7.0 babel config scheme + */ + babelModeV7?: boolean; }; /** * Tells Storybook where to find stories. diff --git a/lib/core-common/src/utils/babel.ts b/lib/core-common/src/utils/babel.ts index c7af63107681..287b5092b435 100644 --- a/lib/core-common/src/utils/babel.ts +++ b/lib/core-common/src/utils/babel.ts @@ -47,7 +47,7 @@ const presets = [ require.resolve('@babel/preset-typescript'), ]; -export const babelConfig: () => TransformOptions = () => { +export const getStorybookBabelConfig: () => TransformOptions = () => { return { sourceType: 'unambiguous', presets: [...presets], diff --git a/lib/core-common/src/utils/es6Transpiler.ts b/lib/core-common/src/utils/es6Transpiler.ts index 07f9337a7997..5404e76bdc31 100644 --- a/lib/core-common/src/utils/es6Transpiler.ts +++ b/lib/core-common/src/utils/es6Transpiler.ts @@ -1,7 +1,7 @@ import { RuleSetRule } from 'webpack'; -import { babelConfig } from './babel'; +import { getStorybookBabelConfig } from './babel'; -const { plugins } = babelConfig(); +const { plugins } = getStorybookBabelConfig(); const nodeModulesThatNeedToBeParsedBecauseTheyExposeES6 = [ '@storybook[\\\\/]node_logger', diff --git a/lib/core-server/src/presets/common-preset.ts b/lib/core-server/src/presets/common-preset.ts index 4382b106b6a0..b8408309e968 100644 --- a/lib/core-server/src/presets/common-preset.ts +++ b/lib/core-server/src/presets/common-preset.ts @@ -1,20 +1,25 @@ +import dedent from 'ts-dedent'; import { getPreviewBodyTemplate, getPreviewHeadTemplate, getManagerMainTemplate, getPreviewMainTemplate, loadCustomBabelConfig, - babelConfig, + getStorybookBabelConfig, loadEnvs, Options, } from '@storybook/core-common'; +import { once } from '@storybook/node-logger'; export const babel = async (_: unknown, options: Options) => { const { configDir, presets } = options; + if (options.features?.babelModeV7) { + return presets.apply('babelDefault', {}, options); + } return loadCustomBabelConfig( configDir, - () => presets.apply('babelDefault', babelConfig(), options) as any + () => presets.apply('babelDefault', getStorybookBabelConfig(), options) as any ); }; diff --git a/lib/manager-webpack4/src/manager-config.ts b/lib/manager-webpack4/src/manager-config.ts index 0fa322e05a53..dd42e9bb3064 100644 --- a/lib/manager-webpack4/src/manager-config.ts +++ b/lib/manager-webpack4/src/manager-config.ts @@ -70,8 +70,6 @@ const deprecatedDefinedRefDisabled = deprecate( export async function getManagerWebpackConfig(options: Options): Promise { const { presets } = options; - const typescriptOptions = await presets.apply('typescript', {}, options); - const babelOptions = await presets.apply('babel', {}, { ...options, typescriptOptions }); const definedRefs: Record | undefined = await presets.apply( 'refs', @@ -145,5 +143,5 @@ export async function getManagerWebpackConfig(options: Options): Promise => { - const envs = await presets.apply>('env'); - const logLevel = await presets.apply('logLevel', undefined); - const template = await presets.apply('managerMainTemplate', getManagerMainTemplate()); - - const headHtmlSnippet = await presets.apply( - 'managerHead', - getManagerHeadTemplate(configDir, process.env) - ); - const isProd = configType === 'PRODUCTION'; - const refsTemplate = fse.readFileSync(path.join(__dirname, 'virtualModuleRef.template.js'), { - encoding: 'utf8', - }); - const { - packageJson: { version }, - } = await readPackage({ cwd: __dirname }); - - // @ts-ignore - // const { BundleAnalyzerPlugin } = await import('webpack-bundle-analyzer').catch(() => ({})); - - return { - name: 'manager', - mode: isProd ? 'production' : 'development', - bail: isProd, - devtool: false, - entry: entries, - output: { - path: outputDir, - filename: isProd ? '[name].[contenthash].manager.bundle.js' : '[name].manager.bundle.js', - publicPath: '', - }, - watchOptions: { - ignored: /node_modules/, - }, - plugins: [ - refs - ? ((new VirtualModulePlugin({ - [path.resolve(path.join(configDir, `generated-refs.js`))]: refsTemplate.replace( - `'{{refs}}'`, - JSON.stringify(refs) - ), - }) as any) as WebpackPluginInstance) - : null, - (new HtmlWebpackPlugin({ - filename: `index.html`, - // FIXME: `none` isn't a known option - chunksSortMode: 'none' as any, - alwaysWriteToDisk: true, - inject: false, - templateParameters: (compilation, files, options) => ({ - compilation, - files, - options, - version, - globals: { - CONFIG_TYPE: configType, - LOGLEVEL: logLevel, - VERSIONCHECK: JSON.stringify(versionCheck), - RELEASE_NOTES_DATA: JSON.stringify(releaseNotesData), - DOCS_MODE: docsMode, // global docs mode - PREVIEW_URL: previewUrl, // global preview URL - }, - headHtmlSnippet, - }), - template, - }) as any) as WebpackPluginInstance, - (new CaseSensitivePathsPlugin() as any) as WebpackPluginInstance, - (new Dotenv({ silent: true }) as any) as WebpackPluginInstance, - // graphql sources check process variable - new DefinePlugin({ - 'process.env': stringifyEnvs(envs), - NODE_ENV: JSON.stringify(envs.NODE_ENV), - }) as WebpackPluginInstance, - // isProd && - // BundleAnalyzerPlugin && - // new BundleAnalyzerPlugin({ analyzerMode: 'static', openAnalyzer: false }), - ].filter(Boolean), - module: { - rules: [ - babelLoader(), - es6Transpiler() as any, - { - test: /\.css$/, - use: [ - require.resolve('style-loader'), - { - loader: require.resolve('css-loader'), - options: { - importLoaders: 1, - }, - }, - ], - }, - { - test: /\.(svg|ico|jpg|jpeg|png|apng|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/, - loader: require.resolve('file-loader'), - options: { - name: isProd - ? 'static/media/[name].[contenthash:8].[ext]' - : 'static/media/[path][name].[ext]', - }, - }, - { - test: /\.(mp4|webm|wav|mp3|m4a|aac|oga)(\?.*)?$/, - loader: require.resolve('url-loader'), - options: { - limit: 10000, - name: isProd - ? 'static/media/[name].[contenthash:8].[ext]' - : 'static/media/[path][name].[ext]', - }, - }, - ], - }, - resolve: { - extensions: ['.mjs', '.js', '.jsx', '.json', '.cjs', '.ts', '.tsx'], - modules: ['node_modules'].concat(envs.NODE_PATH || []), - mainFields: [modern ? 'sbmodern' : null, 'browser', 'module', 'main'].filter(Boolean), - alias: { - ...themingPaths, - ...uiPaths, - }, - plugins: [ - // Transparently resolve packages via PnP when needed; noop otherwise - PnpWebpackPlugin, - ], - }, - resolveLoader: { - plugins: [PnpWebpackPlugin.moduleLoader(module)], - }, - recordsPath: resolvePathInStorybookCache('public/records.json'), - performance: { - hints: false, - }, - optimization: { - splitChunks: { - chunks: 'all', - }, - runtimeChunk: true, - sideEffects: true, - usedExports: true, - concatenateModules: true, - minimizer: isProd - ? [ - new TerserWebpackPlugin({ - parallel: true, - terserOptions: { - mangle: false, - sourceMap: true, - keep_fnames: true, - }, - }), - ] - : [], - }, - }; -}; diff --git a/lib/manager-webpack4/src/babel-loader-manager.ts b/lib/manager-webpack4/src/presets/babel-loader-manager.ts similarity index 77% rename from lib/manager-webpack4/src/babel-loader-manager.ts rename to lib/manager-webpack4/src/presets/babel-loader-manager.ts index d5837ce29092..d67252740306 100644 --- a/lib/manager-webpack4/src/babel-loader-manager.ts +++ b/lib/manager-webpack4/src/presets/babel-loader-manager.ts @@ -1,7 +1,7 @@ import { RuleSetRule } from 'webpack'; -import { getProjectRoot, babelConfig } from '@storybook/core-common'; +import { getProjectRoot, getStorybookBabelConfig } from '@storybook/core-common'; -const { plugins, presets } = babelConfig(); +const { plugins, presets } = getStorybookBabelConfig(); export const babelLoader: () => RuleSetRule = () => ({ test: /\.(mjs|tsx?|jsx?)$/, @@ -17,6 +17,8 @@ export const babelLoader: () => RuleSetRule = () => ({ // transformed for frameworks like ember require.resolve('@babel/plugin-transform-template-literals'), ], + babelrc: false, + babelConfig: false, }, }, ], diff --git a/lib/manager-webpack4/src/presets/manager-preset.ts b/lib/manager-webpack4/src/presets/manager-preset.ts index bb31b2f08554..725a8650de48 100644 --- a/lib/manager-webpack4/src/presets/manager-preset.ts +++ b/lib/manager-webpack4/src/presets/manager-preset.ts @@ -1,12 +1,201 @@ -import { Configuration } from 'webpack'; -import { loadManagerOrAddonsFile, ManagerWebpackOptions, Options } from '@storybook/core-common'; -import createDevConfig from '../manager-webpack.config'; +import path from 'path'; +import fse from 'fs-extra'; +import { DefinePlugin, Configuration, WebpackPluginInstance } from 'webpack'; +import Dotenv from 'dotenv-webpack'; +import HtmlWebpackPlugin from 'html-webpack-plugin'; +import CaseSensitivePathsPlugin from 'case-sensitive-paths-webpack-plugin'; +import PnpWebpackPlugin from 'pnp-webpack-plugin'; +import VirtualModulePlugin from 'webpack-virtual-modules'; +import TerserWebpackPlugin from 'terser-webpack-plugin'; + +import themingPaths from '@storybook/theming/paths'; +import uiPaths from '@storybook/ui/paths'; + +import readPackage from 'read-pkg-up'; +import { + loadManagerOrAddonsFile, + resolvePathInStorybookCache, + stringifyEnvs, + es6Transpiler, + getManagerHeadTemplate, + getManagerMainTemplate, + Options, + ManagerWebpackOptions, +} from '@storybook/core-common'; + +import { babelLoader } from './babel-loader-manager'; export async function managerWebpack( _: Configuration, - options: Options & ManagerWebpackOptions + { + configDir, + configType, + docsMode, + entries, + refs, + outputDir, + previewUrl, + versionCheck, + releaseNotesData, + presets, + modern, + }: Options & ManagerWebpackOptions ): Promise { - return createDevConfig(options); + const envs = await presets.apply>('env'); + const logLevel = await presets.apply('logLevel', undefined); + const template = await presets.apply('managerMainTemplate', getManagerMainTemplate()); + + const headHtmlSnippet = await presets.apply( + 'managerHead', + getManagerHeadTemplate(configDir, process.env) + ); + const isProd = configType === 'PRODUCTION'; + const refsTemplate = fse.readFileSync(path.join(__dirname, 'virtualModuleRef.template.js'), { + encoding: 'utf8', + }); + const { + packageJson: { version }, + } = await readPackage({ cwd: __dirname }); + + // @ts-ignore + // const { BundleAnalyzerPlugin } = await import('webpack-bundle-analyzer').catch(() => ({})); + + return { + name: 'manager', + mode: isProd ? 'production' : 'development', + bail: isProd, + devtool: false, + entry: entries, + output: { + path: outputDir, + filename: isProd ? '[name].[contenthash].manager.bundle.js' : '[name].manager.bundle.js', + publicPath: '', + }, + watchOptions: { + ignored: /node_modules/, + }, + plugins: [ + refs + ? ((new VirtualModulePlugin({ + [path.resolve(path.join(configDir, `generated-refs.js`))]: refsTemplate.replace( + `'{{refs}}'`, + JSON.stringify(refs) + ), + }) as any) as WebpackPluginInstance) + : null, + (new HtmlWebpackPlugin({ + filename: `index.html`, + // FIXME: `none` isn't a known option + chunksSortMode: 'none' as any, + alwaysWriteToDisk: true, + inject: false, + templateParameters: (compilation, files, options) => ({ + compilation, + files, + options, + version, + globals: { + CONFIG_TYPE: configType, + LOGLEVEL: logLevel, + VERSIONCHECK: JSON.stringify(versionCheck), + RELEASE_NOTES_DATA: JSON.stringify(releaseNotesData), + DOCS_MODE: docsMode, // global docs mode + PREVIEW_URL: previewUrl, // global preview URL + }, + headHtmlSnippet, + }), + template, + }) as any) as WebpackPluginInstance, + (new CaseSensitivePathsPlugin() as any) as WebpackPluginInstance, + (new Dotenv({ silent: true }) as any) as WebpackPluginInstance, + // graphql sources check process variable + new DefinePlugin({ + 'process.env': stringifyEnvs(envs), + NODE_ENV: JSON.stringify(envs.NODE_ENV), + }) as WebpackPluginInstance, + // isProd && + // BundleAnalyzerPlugin && + // new BundleAnalyzerPlugin({ analyzerMode: 'static', openAnalyzer: false }), + ].filter(Boolean), + module: { + rules: [ + babelLoader(), + es6Transpiler() as any, + { + test: /\.css$/, + use: [ + require.resolve('style-loader'), + { + loader: require.resolve('css-loader'), + options: { + importLoaders: 1, + }, + }, + ], + }, + { + test: /\.(svg|ico|jpg|jpeg|png|apng|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/, + loader: require.resolve('file-loader'), + options: { + name: isProd + ? 'static/media/[name].[contenthash:8].[ext]' + : 'static/media/[path][name].[ext]', + }, + }, + { + test: /\.(mp4|webm|wav|mp3|m4a|aac|oga)(\?.*)?$/, + loader: require.resolve('url-loader'), + options: { + limit: 10000, + name: isProd + ? 'static/media/[name].[contenthash:8].[ext]' + : 'static/media/[path][name].[ext]', + }, + }, + ], + }, + resolve: { + extensions: ['.mjs', '.js', '.jsx', '.json', '.cjs', '.ts', '.tsx'], + modules: ['node_modules'].concat(envs.NODE_PATH || []), + mainFields: [modern ? 'sbmodern' : null, 'browser', 'module', 'main'].filter(Boolean), + alias: { + ...themingPaths, + ...uiPaths, + }, + plugins: [ + // Transparently resolve packages via PnP when needed; noop otherwise + PnpWebpackPlugin, + ], + }, + resolveLoader: { + plugins: [PnpWebpackPlugin.moduleLoader(module)], + }, + recordsPath: resolvePathInStorybookCache('public/records.json'), + performance: { + hints: false, + }, + optimization: { + splitChunks: { + chunks: 'all', + }, + runtimeChunk: true, + sideEffects: true, + usedExports: true, + concatenateModules: true, + minimizer: isProd + ? [ + new TerserWebpackPlugin({ + parallel: true, + terserOptions: { + mangle: false, + sourceMap: true, + keep_fnames: true, + }, + }), + ] + : [], + }, + }; } export async function managerEntries( diff --git a/lib/manager-webpack5/src/manager-config.ts b/lib/manager-webpack5/src/manager-config.ts index 0fa322e05a53..dd42e9bb3064 100644 --- a/lib/manager-webpack5/src/manager-config.ts +++ b/lib/manager-webpack5/src/manager-config.ts @@ -70,8 +70,6 @@ const deprecatedDefinedRefDisabled = deprecate( export async function getManagerWebpackConfig(options: Options): Promise { const { presets } = options; - const typescriptOptions = await presets.apply('typescript', {}, options); - const babelOptions = await presets.apply('babel', {}, { ...options, typescriptOptions }); const definedRefs: Record | undefined = await presets.apply( 'refs', @@ -145,5 +143,5 @@ export async function getManagerWebpackConfig(options: Options): Promise => { - const envs = await presets.apply>('env'); - const logLevel = await presets.apply('logLevel', undefined); - const template = await presets.apply('managerMainTemplate', getManagerMainTemplate()); - - const headHtmlSnippet = await presets.apply( - 'managerHead', - getManagerHeadTemplate(configDir, process.env) - ); - const isProd = configType === 'PRODUCTION'; - const refsTemplate = fse.readFileSync(path.join(__dirname, 'virtualModuleRef.template.js'), { - encoding: 'utf8', - }); - const { - packageJson: { version }, - } = await readPackage({ cwd: __dirname }); - - // @ts-ignore - // const { BundleAnalyzerPlugin } = await import('webpack-bundle-analyzer').catch(() => ({})); - - return { - name: 'manager', - mode: isProd ? 'production' : 'development', - bail: isProd, - devtool: false, - entry: entries, - output: { - path: outputDir, - filename: isProd ? '[name].[contenthash].manager.bundle.js' : '[name].manager.bundle.js', - publicPath: '', - }, - watchOptions: { - ignored: /node_modules/, - }, - plugins: [ - refs - ? ((new VirtualModulePlugin({ - [path.resolve(path.join(configDir, `generated-refs.js`))]: refsTemplate.replace( - `'{{refs}}'`, - JSON.stringify(refs) - ), - }) as any) as WebpackPluginInstance) - : null, - (new HtmlWebpackPlugin({ - filename: `index.html`, - // FIXME: `none` isn't a known option - chunksSortMode: 'none' as any, - alwaysWriteToDisk: true, - inject: false, - templateParameters: (compilation, files, options) => ({ - compilation, - files, - options, - version, - globals: { - CONFIG_TYPE: configType, - LOGLEVEL: logLevel, - VERSIONCHECK: JSON.stringify(versionCheck), - RELEASE_NOTES_DATA: JSON.stringify(releaseNotesData), - DOCS_MODE: docsMode, // global docs mode - PREVIEW_URL: previewUrl, // global preview URL - }, - headHtmlSnippet, - }), - template, - }) as any) as WebpackPluginInstance, - (new CaseSensitivePathsPlugin() as any) as WebpackPluginInstance, - hasDotenv() ? new Dotenv({ silent: true }) : null, - // graphql sources check process variable - new DefinePlugin({ - 'process.env': stringifyEnvs(envs), - NODE_ENV: JSON.stringify(envs.NODE_ENV), - }) as WebpackPluginInstance, - // isProd && - // BundleAnalyzerPlugin && - // new BundleAnalyzerPlugin({ analyzerMode: 'static', openAnalyzer: false }), - ].filter(Boolean), - module: { - rules: [ - babelLoader(), - es6Transpiler() as any, - { - test: /\.css$/, - use: [ - require.resolve('style-loader'), - { - loader: require.resolve('css-loader'), - options: { - importLoaders: 1, - }, - }, - ], - }, - { - test: /\.(svg|ico|jpg|jpeg|png|apng|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/, - loader: require.resolve('file-loader'), - options: { - name: isProd - ? 'static/media/[name].[contenthash:8].[ext]' - : 'static/media/[path][name].[ext]', - }, - }, - { - test: /\.(mp4|webm|wav|mp3|m4a|aac|oga)(\?.*)?$/, - loader: require.resolve('url-loader'), - options: { - limit: 10000, - name: isProd - ? 'static/media/[name].[contenthash:8].[ext]' - : 'static/media/[path][name].[ext]', - }, - }, - ], - }, - resolve: { - extensions: ['.mjs', '.js', '.jsx', '.json', '.cjs', '.ts', '.tsx'], - modules: ['node_modules'].concat(envs.NODE_PATH || []), - mainFields: [modern ? 'sbmodern' : null, 'browser', 'module', 'main'].filter(Boolean), - alias: { - ...themingPaths, - ...uiPaths, - }, - }, - recordsPath: resolvePathInStorybookCache('public/records.json'), - performance: { - hints: false, - }, - optimization: { - splitChunks: { - chunks: 'all', - }, - runtimeChunk: true, - sideEffects: true, - usedExports: true, - concatenateModules: true, - minimizer: isProd - ? [ - new TerserWebpackPlugin({ - parallel: true, - terserOptions: { - mangle: false, - sourceMap: true, - keep_fnames: true, - }, - }), - ] - : [], - }, - }; -}; diff --git a/lib/manager-webpack5/src/babel-loader-manager.ts b/lib/manager-webpack5/src/presets/babel-loader-manager.ts similarity index 77% rename from lib/manager-webpack5/src/babel-loader-manager.ts rename to lib/manager-webpack5/src/presets/babel-loader-manager.ts index d5837ce29092..d67252740306 100644 --- a/lib/manager-webpack5/src/babel-loader-manager.ts +++ b/lib/manager-webpack5/src/presets/babel-loader-manager.ts @@ -1,7 +1,7 @@ import { RuleSetRule } from 'webpack'; -import { getProjectRoot, babelConfig } from '@storybook/core-common'; +import { getProjectRoot, getStorybookBabelConfig } from '@storybook/core-common'; -const { plugins, presets } = babelConfig(); +const { plugins, presets } = getStorybookBabelConfig(); export const babelLoader: () => RuleSetRule = () => ({ test: /\.(mjs|tsx?|jsx?)$/, @@ -17,6 +17,8 @@ export const babelLoader: () => RuleSetRule = () => ({ // transformed for frameworks like ember require.resolve('@babel/plugin-transform-template-literals'), ], + babelrc: false, + babelConfig: false, }, }, ], diff --git a/lib/manager-webpack5/src/presets/manager-preset.ts b/lib/manager-webpack5/src/presets/manager-preset.ts index bb31b2f08554..a6d4bf84ebe2 100644 --- a/lib/manager-webpack5/src/presets/manager-preset.ts +++ b/lib/manager-webpack5/src/presets/manager-preset.ts @@ -1,12 +1,194 @@ -import { Configuration } from 'webpack'; -import { loadManagerOrAddonsFile, ManagerWebpackOptions, Options } from '@storybook/core-common'; -import createDevConfig from '../manager-webpack.config'; +import path from 'path'; +import fse from 'fs-extra'; +import { DefinePlugin, Configuration, WebpackPluginInstance } from 'webpack'; +import Dotenv from 'dotenv-webpack'; +import HtmlWebpackPlugin from 'html-webpack-plugin'; +import CaseSensitivePathsPlugin from 'case-sensitive-paths-webpack-plugin'; +import VirtualModulePlugin from 'webpack-virtual-modules'; +import TerserWebpackPlugin from 'terser-webpack-plugin'; + +import themingPaths from '@storybook/theming/paths'; +import uiPaths from '@storybook/ui/paths'; + +import readPackage from 'read-pkg-up'; +import { + loadManagerOrAddonsFile, + resolvePathInStorybookCache, + stringifyEnvs, + es6Transpiler, + getManagerHeadTemplate, + getManagerMainTemplate, + Options, + ManagerWebpackOptions, + hasDotenv, +} from '@storybook/core-common'; + +import { babelLoader } from './babel-loader-manager'; export async function managerWebpack( _: Configuration, - options: Options & ManagerWebpackOptions + { + configDir, + configType, + docsMode, + entries, + refs, + outputDir, + previewUrl, + versionCheck, + releaseNotesData, + presets, + modern, + }: Options & ManagerWebpackOptions ): Promise { - return createDevConfig(options); + const envs = await presets.apply>('env'); + const logLevel = await presets.apply('logLevel', undefined); + const template = await presets.apply('managerMainTemplate', getManagerMainTemplate()); + + const headHtmlSnippet = await presets.apply( + 'managerHead', + getManagerHeadTemplate(configDir, process.env) + ); + const isProd = configType === 'PRODUCTION'; + const refsTemplate = fse.readFileSync(path.join(__dirname, 'virtualModuleRef.template.js'), { + encoding: 'utf8', + }); + const { + packageJson: { version }, + } = await readPackage({ cwd: __dirname }); + + // @ts-ignore + // const { BundleAnalyzerPlugin } = await import('webpack-bundle-analyzer').catch(() => ({})); + + return { + name: 'manager', + mode: isProd ? 'production' : 'development', + bail: isProd, + devtool: false, + entry: entries, + output: { + path: outputDir, + filename: isProd ? '[name].[contenthash].manager.bundle.js' : '[name].manager.bundle.js', + publicPath: '', + }, + watchOptions: { + ignored: /node_modules/, + }, + plugins: [ + refs + ? ((new VirtualModulePlugin({ + [path.resolve(path.join(configDir, `generated-refs.js`))]: refsTemplate.replace( + `'{{refs}}'`, + JSON.stringify(refs) + ), + }) as any) as WebpackPluginInstance) + : null, + (new HtmlWebpackPlugin({ + filename: `index.html`, + // FIXME: `none` isn't a known option + chunksSortMode: 'none' as any, + alwaysWriteToDisk: true, + inject: false, + templateParameters: (compilation, files, options) => ({ + compilation, + files, + options, + version, + globals: { + CONFIG_TYPE: configType, + LOGLEVEL: logLevel, + VERSIONCHECK: JSON.stringify(versionCheck), + RELEASE_NOTES_DATA: JSON.stringify(releaseNotesData), + DOCS_MODE: docsMode, // global docs mode + PREVIEW_URL: previewUrl, // global preview URL + }, + headHtmlSnippet, + }), + template, + }) as any) as WebpackPluginInstance, + (new CaseSensitivePathsPlugin() as any) as WebpackPluginInstance, + hasDotenv() ? new Dotenv({ silent: true }) : null, + // graphql sources check process variable + new DefinePlugin({ + 'process.env': stringifyEnvs(envs), + NODE_ENV: JSON.stringify(envs.NODE_ENV), + }) as WebpackPluginInstance, + // isProd && + // BundleAnalyzerPlugin && + // new BundleAnalyzerPlugin({ analyzerMode: 'static', openAnalyzer: false }), + ].filter(Boolean), + module: { + rules: [ + babelLoader(), + es6Transpiler() as any, + { + test: /\.css$/, + use: [ + require.resolve('style-loader'), + { + loader: require.resolve('css-loader'), + options: { + importLoaders: 1, + }, + }, + ], + }, + { + test: /\.(svg|ico|jpg|jpeg|png|apng|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/, + loader: require.resolve('file-loader'), + options: { + name: isProd + ? 'static/media/[name].[contenthash:8].[ext]' + : 'static/media/[path][name].[ext]', + }, + }, + { + test: /\.(mp4|webm|wav|mp3|m4a|aac|oga)(\?.*)?$/, + loader: require.resolve('url-loader'), + options: { + limit: 10000, + name: isProd + ? 'static/media/[name].[contenthash:8].[ext]' + : 'static/media/[path][name].[ext]', + }, + }, + ], + }, + resolve: { + extensions: ['.mjs', '.js', '.jsx', '.json', '.cjs', '.ts', '.tsx'], + modules: ['node_modules'].concat(envs.NODE_PATH || []), + mainFields: [modern ? 'sbmodern' : null, 'browser', 'module', 'main'].filter(Boolean), + alias: { + ...themingPaths, + ...uiPaths, + }, + }, + recordsPath: resolvePathInStorybookCache('public/records.json'), + performance: { + hints: false, + }, + optimization: { + splitChunks: { + chunks: 'all', + }, + runtimeChunk: true, + sideEffects: true, + usedExports: true, + concatenateModules: true, + minimizer: isProd + ? [ + new TerserWebpackPlugin({ + parallel: true, + terserOptions: { + mangle: false, + sourceMap: true, + keep_fnames: true, + }, + }), + ] + : [], + }, + }; } export async function managerEntries( From 4372cf8618311f6c3b5a154891e6d3f1d76395c0 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Fri, 27 Aug 2021 14:22:17 +0200 Subject: [PATCH 03/14] small corrections --- lib/manager-webpack4/src/presets/babel-loader-manager.ts | 2 +- lib/manager-webpack4/src/presets/manager-preset.ts | 9 ++++++--- lib/manager-webpack5/src/presets/babel-loader-manager.ts | 2 +- lib/manager-webpack5/src/presets/manager-preset.ts | 9 ++++++--- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/lib/manager-webpack4/src/presets/babel-loader-manager.ts b/lib/manager-webpack4/src/presets/babel-loader-manager.ts index d67252740306..5e47b9adcaee 100644 --- a/lib/manager-webpack4/src/presets/babel-loader-manager.ts +++ b/lib/manager-webpack4/src/presets/babel-loader-manager.ts @@ -18,7 +18,7 @@ export const babelLoader: () => RuleSetRule = () => ({ require.resolve('@babel/plugin-transform-template-literals'), ], babelrc: false, - babelConfig: false, + configFile: false, }, }, ], diff --git a/lib/manager-webpack4/src/presets/manager-preset.ts b/lib/manager-webpack4/src/presets/manager-preset.ts index 725a8650de48..5da0e64a9a3c 100644 --- a/lib/manager-webpack4/src/presets/manager-preset.ts +++ b/lib/manager-webpack4/src/presets/manager-preset.ts @@ -50,9 +50,12 @@ export async function managerWebpack( getManagerHeadTemplate(configDir, process.env) ); const isProd = configType === 'PRODUCTION'; - const refsTemplate = fse.readFileSync(path.join(__dirname, 'virtualModuleRef.template.js'), { - encoding: 'utf8', - }); + const refsTemplate = fse.readFileSync( + path.join(__dirname, '..', 'virtualModuleRef.template.js'), + { + encoding: 'utf8', + } + ); const { packageJson: { version }, } = await readPackage({ cwd: __dirname }); diff --git a/lib/manager-webpack5/src/presets/babel-loader-manager.ts b/lib/manager-webpack5/src/presets/babel-loader-manager.ts index d67252740306..5e47b9adcaee 100644 --- a/lib/manager-webpack5/src/presets/babel-loader-manager.ts +++ b/lib/manager-webpack5/src/presets/babel-loader-manager.ts @@ -18,7 +18,7 @@ export const babelLoader: () => RuleSetRule = () => ({ require.resolve('@babel/plugin-transform-template-literals'), ], babelrc: false, - babelConfig: false, + configFile: false, }, }, ], diff --git a/lib/manager-webpack5/src/presets/manager-preset.ts b/lib/manager-webpack5/src/presets/manager-preset.ts index a6d4bf84ebe2..a4e6dafa40e0 100644 --- a/lib/manager-webpack5/src/presets/manager-preset.ts +++ b/lib/manager-webpack5/src/presets/manager-preset.ts @@ -50,9 +50,12 @@ export async function managerWebpack( getManagerHeadTemplate(configDir, process.env) ); const isProd = configType === 'PRODUCTION'; - const refsTemplate = fse.readFileSync(path.join(__dirname, 'virtualModuleRef.template.js'), { - encoding: 'utf8', - }); + const refsTemplate = fse.readFileSync( + path.join(__dirname, '..', 'virtualModuleRef.template.js'), + { + encoding: 'utf8', + } + ); const { packageJson: { version }, } = await readPackage({ cwd: __dirname }); From 090c0269ec661bf80ba3f59fbe7c44e4b274bbd8 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Fri, 27 Aug 2021 14:33:42 +0200 Subject: [PATCH 04/14] add a babelrc command --- lib/cli/src/babal-config.ts | 6 ++++++ lib/cli/src/generate.ts | 6 ++++++ 2 files changed, 12 insertions(+) create mode 100644 lib/cli/src/babal-config.ts diff --git a/lib/cli/src/babal-config.ts b/lib/cli/src/babal-config.ts new file mode 100644 index 000000000000..84d159f08d68 --- /dev/null +++ b/lib/cli/src/babal-config.ts @@ -0,0 +1,6 @@ +import { logger } from '@storybook/node-logger'; + +export const generateStorybookBabelConfig = async () => { + const cwd = process.cwd(); + logger.info(`Generating the storybook default babel config at ${cwd}`); +}; diff --git a/lib/cli/src/generate.ts b/lib/cli/src/generate.ts index 01209a82f6fd..a6533bf0189a 100644 --- a/lib/cli/src/generate.ts +++ b/lib/cli/src/generate.ts @@ -11,6 +11,7 @@ import { extract } from './extract'; import { upgrade } from './upgrade'; import { repro } from './repro'; import { link } from './link'; +import { generateStorybookBabelConfig } from './babal-config'; const pkg = sync({ cwd: __dirname }).packageJson; @@ -37,6 +38,11 @@ program .option('-s --skip-postinstall', 'Skip package specific postinstall config modifications') .action((addonName, options) => add(addonName, options)); +program + .command('babelrc') + .description('generate the default storybook babel config into your current working directory') + .action(() => generateStorybookBabelConfig()); + program .command('upgrade') .description('Upgrade your Storybook packages to the latest') From 4c09e018e1ab133922a5b16ee4c6de6e7a6ad433 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Fri, 27 Aug 2021 14:38:24 +0200 Subject: [PATCH 05/14] fix non-spreadable properties on now non-existing default babel config --- .../src/server/framework-preset-react.ts | 4 +- .../src/presets/babel-loader-manager.ts | 46 ++++++++++--------- 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/app/react/src/server/framework-preset-react.ts b/app/react/src/server/framework-preset-react.ts index 2e8b75682e4b..71d6816a366b 100644 --- a/app/react/src/server/framework-preset-react.ts +++ b/app/react/src/server/framework-preset-react.ts @@ -50,11 +50,11 @@ export async function babelDefault(config: TransformOptions) { return { ...config, presets: [ - ...config.presets, + ...(config?.presets || []), [require.resolve('@babel/preset-react'), presetReactOptions], require.resolve('@babel/preset-flow'), ], - plugins: [...(config.plugins || []), require.resolve('babel-plugin-add-react-displayname')], + plugins: [...(config?.plugins || []), require.resolve('babel-plugin-add-react-displayname')], }; } diff --git a/lib/manager-webpack5/src/presets/babel-loader-manager.ts b/lib/manager-webpack5/src/presets/babel-loader-manager.ts index 5e47b9adcaee..4a8aafd5af51 100644 --- a/lib/manager-webpack5/src/presets/babel-loader-manager.ts +++ b/lib/manager-webpack5/src/presets/babel-loader-manager.ts @@ -1,27 +1,29 @@ import { RuleSetRule } from 'webpack'; import { getProjectRoot, getStorybookBabelConfig } from '@storybook/core-common'; -const { plugins, presets } = getStorybookBabelConfig(); +export const babelLoader: () => RuleSetRule = () => { + const { plugins, presets } = getStorybookBabelConfig(); -export const babelLoader: () => RuleSetRule = () => ({ - test: /\.(mjs|tsx?|jsx?)$/, - use: [ - { - loader: require.resolve('babel-loader'), - options: { - sourceType: 'unambiguous', - presets: [...presets, require.resolve('@babel/preset-react')], - plugins: [ - ...plugins, - // Should only be done on manager. Template literals are not meant to be - // transformed for frameworks like ember - require.resolve('@babel/plugin-transform-template-literals'), - ], - babelrc: false, - configFile: false, + return { + test: /\.(mjs|tsx?|jsx?)$/, + use: [ + { + loader: require.resolve('babel-loader'), + options: { + sourceType: 'unambiguous', + presets: [...presets, require.resolve('@babel/preset-react')], + plugins: [ + ...plugins, + // Should only be done on manager. Template literals are not meant to be + // transformed for frameworks like ember + require.resolve('@babel/plugin-transform-template-literals'), + ], + babelrc: false, + configFile: false, + }, }, - }, - ], - include: [getProjectRoot()], - exclude: [/node_modules/, /dist/], -}); + ], + include: [getProjectRoot()], + exclude: [/node_modules/, /dist/], + }; +}; From b40cd6a72280ddb8bfd6b0b1f0748a234d3fa4bc Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Fri, 27 Aug 2021 15:30:01 +0200 Subject: [PATCH 06/14] make the babel cli command functional --- lib/cli/package.json | 1 + lib/cli/src/babal-config.ts | 41 ++++++++++++- lib/cli/src/generate.ts | 4 +- lib/core-common/src/utils/babel.ts | 98 ++++++++++++++---------------- yarn.lock | 1 + 5 files changed, 89 insertions(+), 56 deletions(-) diff --git a/lib/cli/package.json b/lib/cli/package.json index b51f3aabcefc..16eade2f6997 100644 --- a/lib/cli/package.json +++ b/lib/cli/package.json @@ -49,6 +49,7 @@ "@babel/core": "^7.12.10", "@babel/preset-env": "^7.12.11", "@storybook/codemod": "6.4.0-alpha.32", + "@storybook/core-common": "6.4.0-alpha.32", "@storybook/node-logger": "6.4.0-alpha.32", "@storybook/semver": "^7.3.2", "boxen": "^4.2.0", diff --git a/lib/cli/src/babal-config.ts b/lib/cli/src/babal-config.ts index 84d159f08d68..2d6fe8aaa443 100644 --- a/lib/cli/src/babal-config.ts +++ b/lib/cli/src/babal-config.ts @@ -1,6 +1,41 @@ +import { writeFile, access } from 'fs-extra'; import { logger } from '@storybook/node-logger'; +import { getStorybookBabelConfig } from '@storybook/core-common'; +import path from 'path'; +import prompts from 'prompts'; -export const generateStorybookBabelConfig = async () => { - const cwd = process.cwd(); - logger.info(`Generating the storybook default babel config at ${cwd}`); +export const generateStorybookBabelConfigInCWD = async () => { + const target = process.cwd(); + return generateStorybookBabelConfig({ target }); +}; +export const generateStorybookBabelConfig = async ({ target }: { target: string }) => { + logger.info(`Generating the storybook default babel config at ${target}`); + + const config = getStorybookBabelConfig(); + const contents = JSON.stringify(config, null, 2); + + const fileName = '.babelrc.json'; + const location = path.join(target, fileName); + + const exists = await access(location).then( + () => true, + () => false + ); + + if (exists) { + const { overwrite } = await prompts({ + type: 'confirm', + initial: true, + name: 'overwrite', + message: `${fileName} already exists. Would you like overwrite it?`, + }); + + if (overwrite === false) { + logger.warn(`Cancelled, babel config file was NOT written to file-system.`); + return; + } + } + + logger.info(`Writing file to ${location}`); + await writeFile(location, contents); }; diff --git a/lib/cli/src/generate.ts b/lib/cli/src/generate.ts index a6533bf0189a..e67cba9164bb 100644 --- a/lib/cli/src/generate.ts +++ b/lib/cli/src/generate.ts @@ -11,7 +11,7 @@ import { extract } from './extract'; import { upgrade } from './upgrade'; import { repro } from './repro'; import { link } from './link'; -import { generateStorybookBabelConfig } from './babal-config'; +import { generateStorybookBabelConfigInCWD } from './babal-config'; const pkg = sync({ cwd: __dirname }).packageJson; @@ -41,7 +41,7 @@ program program .command('babelrc') .description('generate the default storybook babel config into your current working directory') - .action(() => generateStorybookBabelConfig()); + .action(() => generateStorybookBabelConfigInCWD()); program .command('upgrade') diff --git a/lib/core-common/src/utils/babel.ts b/lib/core-common/src/utils/babel.ts index 287b5092b435..b146dccd9ab2 100644 --- a/lib/core-common/src/utils/babel.ts +++ b/lib/core-common/src/utils/babel.ts @@ -1,56 +1,52 @@ import { TransformOptions } from '@babel/core'; -const plugins = [ - require.resolve('@babel/plugin-transform-shorthand-properties'), - require.resolve('@babel/plugin-transform-block-scoping'), - /* - * Added for TypeScript experimental decorator support - * https://babeljs.io/docs/en/babel-plugin-transform-typescript#typescript-compiler-options - */ - [require.resolve('@babel/plugin-proposal-decorators'), { legacy: true }], - [require.resolve('@babel/plugin-proposal-class-properties'), { loose: true }], - [require.resolve('@babel/plugin-proposal-private-methods'), { loose: true }], - require.resolve('@babel/plugin-proposal-export-default-from'), - require.resolve('@babel/plugin-syntax-dynamic-import'), - [ - require.resolve('@babel/plugin-proposal-object-rest-spread'), - { loose: true, useBuiltIns: true }, - ], - require.resolve('@babel/plugin-transform-classes'), - require.resolve('@babel/plugin-transform-arrow-functions'), - require.resolve('@babel/plugin-transform-parameters'), - require.resolve('@babel/plugin-transform-destructuring'), - require.resolve('@babel/plugin-transform-spread'), - require.resolve('@babel/plugin-transform-for-of'), - require.resolve('babel-plugin-macros'), - /* - * Optional chaining and nullish coalescing are supported in - * @babel/preset-env, but not yet supported in Webpack due to support - * missing from acorn. These can be removed once Webpack has support. - * See https://github.com/facebook/create-react-app/issues/8445#issuecomment-588512250 - */ - require.resolve('@babel/plugin-proposal-optional-chaining'), - require.resolve('@babel/plugin-proposal-nullish-coalescing-operator'), - [ - require.resolve('babel-plugin-polyfill-corejs3'), - { - method: 'usage-global', - absoluteImports: require.resolve('core-js'), - // eslint-disable-next-line global-require - version: require('core-js/package.json').version, - }, - ], -]; - -const presets = [ - [require.resolve('@babel/preset-env'), { shippedProposals: true, loose: true }], - require.resolve('@babel/preset-typescript'), -]; - -export const getStorybookBabelConfig: () => TransformOptions = () => { +export const getStorybookBabelConfig = () => { return { sourceType: 'unambiguous', - presets: [...presets], - plugins: [...plugins], - }; + presets: [ + [require.resolve('@babel/preset-env'), { shippedProposals: true, loose: true }], + require.resolve('@babel/preset-typescript'), + ], + plugins: [ + require.resolve('@babel/plugin-transform-shorthand-properties'), + require.resolve('@babel/plugin-transform-block-scoping'), + /* + * Added for TypeScript experimental decorator support + * https://babeljs.io/docs/en/babel-plugin-transform-typescript#typescript-compiler-options + */ + [require.resolve('@babel/plugin-proposal-decorators'), { legacy: true }], + [require.resolve('@babel/plugin-proposal-class-properties'), { loose: true }], + [require.resolve('@babel/plugin-proposal-private-methods'), { loose: true }], + require.resolve('@babel/plugin-proposal-export-default-from'), + require.resolve('@babel/plugin-syntax-dynamic-import'), + [ + require.resolve('@babel/plugin-proposal-object-rest-spread'), + { loose: true, useBuiltIns: true }, + ], + require.resolve('@babel/plugin-transform-classes'), + require.resolve('@babel/plugin-transform-arrow-functions'), + require.resolve('@babel/plugin-transform-parameters'), + require.resolve('@babel/plugin-transform-destructuring'), + require.resolve('@babel/plugin-transform-spread'), + require.resolve('@babel/plugin-transform-for-of'), + require.resolve('babel-plugin-macros'), + /* + * Optional chaining and nullish coalescing are supported in + * @babel/preset-env, but not yet supported in Webpack due to support + * missing from acorn. These can be removed once Webpack has support. + * See https://github.com/facebook/create-react-app/issues/8445#issuecomment-588512250 + */ + require.resolve('@babel/plugin-proposal-optional-chaining'), + require.resolve('@babel/plugin-proposal-nullish-coalescing-operator'), + [ + require.resolve('babel-plugin-polyfill-corejs3'), + { + method: 'usage-global', + absoluteImports: require.resolve('core-js'), + // eslint-disable-next-line global-require + version: require('core-js/package.json').version, + }, + ], + ], + } as TransformOptions; }; diff --git a/yarn.lock b/yarn.lock index 3c96867ce639..735a000450e0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7775,6 +7775,7 @@ __metadata: "@babel/preset-env": ^7.12.11 "@storybook/client-api": 6.4.0-alpha.32 "@storybook/codemod": 6.4.0-alpha.32 + "@storybook/core-common": 6.4.0-alpha.32 "@storybook/node-logger": 6.4.0-alpha.32 "@storybook/semver": ^7.3.2 "@types/cross-spawn": ^6.0.2 From 82c2fd882f65b5fa79f7d11171b597d4a8a6afb7 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Fri, 27 Aug 2021 16:00:32 +0200 Subject: [PATCH 07/14] generate with local (no require.resolve'd) paths --- lib/cli/src/babal-config.ts | 2 +- lib/cli/src/generate.ts | 2 +- lib/cli/src/initiate.ts | 2 +- lib/core-common/src/utils/babel.ts | 51 ++++++++++--------- .../src/presets/babel-loader-manager.ts | 46 +++++++++-------- .../src/presets/babel-loader-manager.ts | 4 +- 6 files changed, 55 insertions(+), 52 deletions(-) diff --git a/lib/cli/src/babal-config.ts b/lib/cli/src/babal-config.ts index 2d6fe8aaa443..ff5dd2b6261b 100644 --- a/lib/cli/src/babal-config.ts +++ b/lib/cli/src/babal-config.ts @@ -11,7 +11,7 @@ export const generateStorybookBabelConfigInCWD = async () => { export const generateStorybookBabelConfig = async ({ target }: { target: string }) => { logger.info(`Generating the storybook default babel config at ${target}`); - const config = getStorybookBabelConfig(); + const config = getStorybookBabelConfig({ local: true }); const contents = JSON.stringify(config, null, 2); const fileName = '.babelrc.json'; diff --git a/lib/cli/src/generate.ts b/lib/cli/src/generate.ts index e67cba9164bb..8336509521c5 100644 --- a/lib/cli/src/generate.ts +++ b/lib/cli/src/generate.ts @@ -4,7 +4,7 @@ import chalk from 'chalk'; import envinfo from 'envinfo'; import leven from 'leven'; import { sync } from 'read-pkg-up'; -import initiate from './initiate'; +import { initiate } from './initiate'; import { add } from './add'; import { migrate } from './migrate'; import { extract } from './extract'; diff --git a/lib/cli/src/initiate.ts b/lib/cli/src/initiate.ts index 95bcb5a11c5a..dce515f83bb0 100644 --- a/lib/cli/src/initiate.ts +++ b/lib/cli/src/initiate.ts @@ -298,7 +298,7 @@ const projectTypeInquirer = async (options: { yes?: boolean }) => { return Promise.resolve(); }; -export default function (options: CommandOptions, pkg: Package): Promise { +export function initiate(options: CommandOptions, pkg: Package): Promise { const welcomeMessage = 'sb init - the simplest way to add a Storybook to your project.'; logger.log(chalk.inverse(`\n ${welcomeMessage} \n`)); diff --git a/lib/core-common/src/utils/babel.ts b/lib/core-common/src/utils/babel.ts index b146dccd9ab2..e105cec3d189 100644 --- a/lib/core-common/src/utils/babel.ts +++ b/lib/core-common/src/utils/babel.ts @@ -1,48 +1,49 @@ import { TransformOptions } from '@babel/core'; -export const getStorybookBabelConfig = () => { +const r = (s: string, local: boolean) => { + return local ? s : require.resolve(s); +}; + +export const getStorybookBabelConfig = ({ local = false }: { local?: boolean } = {}) => { return { sourceType: 'unambiguous', presets: [ - [require.resolve('@babel/preset-env'), { shippedProposals: true, loose: true }], - require.resolve('@babel/preset-typescript'), + [r('@babel/preset-env', local), { shippedProposals: true, loose: true }], + r('@babel/preset-typescript', local), ], plugins: [ - require.resolve('@babel/plugin-transform-shorthand-properties'), - require.resolve('@babel/plugin-transform-block-scoping'), + r('@babel/plugin-transform-shorthand-properties', local), + r('@babel/plugin-transform-block-scoping', local), /* * Added for TypeScript experimental decorator support * https://babeljs.io/docs/en/babel-plugin-transform-typescript#typescript-compiler-options */ - [require.resolve('@babel/plugin-proposal-decorators'), { legacy: true }], - [require.resolve('@babel/plugin-proposal-class-properties'), { loose: true }], - [require.resolve('@babel/plugin-proposal-private-methods'), { loose: true }], - require.resolve('@babel/plugin-proposal-export-default-from'), - require.resolve('@babel/plugin-syntax-dynamic-import'), - [ - require.resolve('@babel/plugin-proposal-object-rest-spread'), - { loose: true, useBuiltIns: true }, - ], - require.resolve('@babel/plugin-transform-classes'), - require.resolve('@babel/plugin-transform-arrow-functions'), - require.resolve('@babel/plugin-transform-parameters'), - require.resolve('@babel/plugin-transform-destructuring'), - require.resolve('@babel/plugin-transform-spread'), - require.resolve('@babel/plugin-transform-for-of'), - require.resolve('babel-plugin-macros'), + [r('@babel/plugin-proposal-decorators', local), { legacy: true }], + [r('@babel/plugin-proposal-class-properties', local), { loose: true }], + [r('@babel/plugin-proposal-private-methods', local), { loose: true }], + r('@babel/plugin-proposal-export-default-from', local), + r('@babel/plugin-syntax-dynamic-import', local), + [r('@babel/plugin-proposal-object-rest-spread', local), { loose: true, useBuiltIns: true }], + r('@babel/plugin-transform-classes', local), + r('@babel/plugin-transform-arrow-functions', local), + r('@babel/plugin-transform-parameters', local), + r('@babel/plugin-transform-destructuring', local), + r('@babel/plugin-transform-spread', local), + r('@babel/plugin-transform-for-of', local), + r('babel-plugin-macros', local), /* * Optional chaining and nullish coalescing are supported in * @babel/preset-env, but not yet supported in Webpack due to support * missing from acorn. These can be removed once Webpack has support. * See https://github.com/facebook/create-react-app/issues/8445#issuecomment-588512250 */ - require.resolve('@babel/plugin-proposal-optional-chaining'), - require.resolve('@babel/plugin-proposal-nullish-coalescing-operator'), + r('@babel/plugin-proposal-optional-chaining', local), + r('@babel/plugin-proposal-nullish-coalescing-operator', local), [ - require.resolve('babel-plugin-polyfill-corejs3'), + r('babel-plugin-polyfill-corejs3', local), { method: 'usage-global', - absoluteImports: require.resolve('core-js'), + absoluteImports: r('core-js', local), // eslint-disable-next-line global-require version: require('core-js/package.json').version, }, diff --git a/lib/manager-webpack4/src/presets/babel-loader-manager.ts b/lib/manager-webpack4/src/presets/babel-loader-manager.ts index 5e47b9adcaee..07f9f43118ec 100644 --- a/lib/manager-webpack4/src/presets/babel-loader-manager.ts +++ b/lib/manager-webpack4/src/presets/babel-loader-manager.ts @@ -1,27 +1,29 @@ import { RuleSetRule } from 'webpack'; import { getProjectRoot, getStorybookBabelConfig } from '@storybook/core-common'; -const { plugins, presets } = getStorybookBabelConfig(); +export const babelLoader = () => { + const { plugins, presets } = getStorybookBabelConfig(); -export const babelLoader: () => RuleSetRule = () => ({ - test: /\.(mjs|tsx?|jsx?)$/, - use: [ - { - loader: require.resolve('babel-loader'), - options: { - sourceType: 'unambiguous', - presets: [...presets, require.resolve('@babel/preset-react')], - plugins: [ - ...plugins, - // Should only be done on manager. Template literals are not meant to be - // transformed for frameworks like ember - require.resolve('@babel/plugin-transform-template-literals'), - ], - babelrc: false, - configFile: false, + return { + test: /\.(mjs|tsx?|jsx?)$/, + use: [ + { + loader: require.resolve('babel-loader'), + options: { + sourceType: 'unambiguous', + presets: [...presets, require.resolve('@babel/preset-react')], + plugins: [ + ...plugins, + // Should only be done on manager. Template literals are not meant to be + // transformed for frameworks like ember + require.resolve('@babel/plugin-transform-template-literals'), + ], + babelrc: false, + configFile: false, + }, }, - }, - ], - include: [getProjectRoot()], - exclude: [/node_modules/, /dist/], -}); + ], + include: [getProjectRoot()], + exclude: [/node_modules/, /dist/], + } as RuleSetRule; +}; diff --git a/lib/manager-webpack5/src/presets/babel-loader-manager.ts b/lib/manager-webpack5/src/presets/babel-loader-manager.ts index 4a8aafd5af51..07f9f43118ec 100644 --- a/lib/manager-webpack5/src/presets/babel-loader-manager.ts +++ b/lib/manager-webpack5/src/presets/babel-loader-manager.ts @@ -1,7 +1,7 @@ import { RuleSetRule } from 'webpack'; import { getProjectRoot, getStorybookBabelConfig } from '@storybook/core-common'; -export const babelLoader: () => RuleSetRule = () => { +export const babelLoader = () => { const { plugins, presets } = getStorybookBabelConfig(); return { @@ -25,5 +25,5 @@ export const babelLoader: () => RuleSetRule = () => { ], include: [getProjectRoot()], exclude: [/node_modules/, /dist/], - }; + } as RuleSetRule; }; From e1606a548d9d7cc0581a48d9443ef2f98e1e028f Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Fri, 27 Aug 2021 16:19:04 +0200 Subject: [PATCH 08/14] cleanup --- lib/core-server/src/presets/common-preset.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/core-server/src/presets/common-preset.ts b/lib/core-server/src/presets/common-preset.ts index b8408309e968..4ddfcf914598 100644 --- a/lib/core-server/src/presets/common-preset.ts +++ b/lib/core-server/src/presets/common-preset.ts @@ -1,4 +1,3 @@ -import dedent from 'ts-dedent'; import { getPreviewBodyTemplate, getPreviewHeadTemplate, @@ -9,7 +8,6 @@ import { loadEnvs, Options, } from '@storybook/core-common'; -import { once } from '@storybook/node-logger'; export const babel = async (_: unknown, options: Options) => { const { configDir, presets } = options; From 2b5aa745bd8e7578fe5088bc21c82ebeb4025d23 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Fri, 27 Aug 2021 16:25:53 +0200 Subject: [PATCH 09/14] new and improved snapshots --- lib/core-server/src/__snapshots__/cra-ts-essentials_manager-dev | 2 ++ .../src/__snapshots__/cra-ts-essentials_manager-prod | 2 ++ lib/core-server/src/__snapshots__/html-kitchen-sink_manager-dev | 2 ++ .../src/__snapshots__/html-kitchen-sink_manager-prod | 2 ++ lib/core-server/src/__snapshots__/vue-3-cli_manager-dev | 2 ++ lib/core-server/src/__snapshots__/vue-3-cli_manager-prod | 2 ++ .../src/__snapshots__/web-components-kitchen-sink_manager-dev | 2 ++ .../src/__snapshots__/web-components-kitchen-sink_manager-prod | 2 ++ 8 files changed, 16 insertions(+) diff --git a/lib/core-server/src/__snapshots__/cra-ts-essentials_manager-dev b/lib/core-server/src/__snapshots__/cra-ts-essentials_manager-dev index 4e178a11ece1..08a97245e468 100644 --- a/lib/core-server/src/__snapshots__/cra-ts-essentials_manager-dev +++ b/lib/core-server/src/__snapshots__/cra-ts-essentials_manager-dev @@ -44,6 +44,8 @@ Object { Object { "loader": "NODE_MODULES/babel-loader/lib/index.js", "options": Object { + "babelrc": false, + "configFile": false, "plugins": Array [ "NODE_MODULES/@babel/plugin-transform-shorthand-properties/lib/index.js", "NODE_MODULES/@babel/plugin-transform-block-scoping/lib/index.js", diff --git a/lib/core-server/src/__snapshots__/cra-ts-essentials_manager-prod b/lib/core-server/src/__snapshots__/cra-ts-essentials_manager-prod index db6851a6b30e..91c113945e6c 100644 --- a/lib/core-server/src/__snapshots__/cra-ts-essentials_manager-prod +++ b/lib/core-server/src/__snapshots__/cra-ts-essentials_manager-prod @@ -44,6 +44,8 @@ Object { Object { "loader": "NODE_MODULES/babel-loader/lib/index.js", "options": Object { + "babelrc": false, + "configFile": false, "plugins": Array [ "NODE_MODULES/@babel/plugin-transform-shorthand-properties/lib/index.js", "NODE_MODULES/@babel/plugin-transform-block-scoping/lib/index.js", diff --git a/lib/core-server/src/__snapshots__/html-kitchen-sink_manager-dev b/lib/core-server/src/__snapshots__/html-kitchen-sink_manager-dev index 4658aa09a26c..766eb604b77c 100644 --- a/lib/core-server/src/__snapshots__/html-kitchen-sink_manager-dev +++ b/lib/core-server/src/__snapshots__/html-kitchen-sink_manager-dev @@ -46,6 +46,8 @@ Object { Object { "loader": "NODE_MODULES/babel-loader/lib/index.js", "options": Object { + "babelrc": false, + "configFile": false, "plugins": Array [ "NODE_MODULES/@babel/plugin-transform-shorthand-properties/lib/index.js", "NODE_MODULES/@babel/plugin-transform-block-scoping/lib/index.js", diff --git a/lib/core-server/src/__snapshots__/html-kitchen-sink_manager-prod b/lib/core-server/src/__snapshots__/html-kitchen-sink_manager-prod index 22bd1485f828..41b8889625aa 100644 --- a/lib/core-server/src/__snapshots__/html-kitchen-sink_manager-prod +++ b/lib/core-server/src/__snapshots__/html-kitchen-sink_manager-prod @@ -46,6 +46,8 @@ Object { Object { "loader": "NODE_MODULES/babel-loader/lib/index.js", "options": Object { + "babelrc": false, + "configFile": false, "plugins": Array [ "NODE_MODULES/@babel/plugin-transform-shorthand-properties/lib/index.js", "NODE_MODULES/@babel/plugin-transform-block-scoping/lib/index.js", diff --git a/lib/core-server/src/__snapshots__/vue-3-cli_manager-dev b/lib/core-server/src/__snapshots__/vue-3-cli_manager-dev index be6c5b62a0d3..0c04036fe091 100644 --- a/lib/core-server/src/__snapshots__/vue-3-cli_manager-dev +++ b/lib/core-server/src/__snapshots__/vue-3-cli_manager-dev @@ -46,6 +46,8 @@ Object { Object { "loader": "NODE_MODULES/babel-loader/lib/index.js", "options": Object { + "babelrc": false, + "configFile": false, "plugins": Array [ "NODE_MODULES/@babel/plugin-transform-shorthand-properties/lib/index.js", "NODE_MODULES/@babel/plugin-transform-block-scoping/lib/index.js", diff --git a/lib/core-server/src/__snapshots__/vue-3-cli_manager-prod b/lib/core-server/src/__snapshots__/vue-3-cli_manager-prod index b86aeecbfb37..9e196e4220fb 100644 --- a/lib/core-server/src/__snapshots__/vue-3-cli_manager-prod +++ b/lib/core-server/src/__snapshots__/vue-3-cli_manager-prod @@ -46,6 +46,8 @@ Object { Object { "loader": "NODE_MODULES/babel-loader/lib/index.js", "options": Object { + "babelrc": false, + "configFile": false, "plugins": Array [ "NODE_MODULES/@babel/plugin-transform-shorthand-properties/lib/index.js", "NODE_MODULES/@babel/plugin-transform-block-scoping/lib/index.js", diff --git a/lib/core-server/src/__snapshots__/web-components-kitchen-sink_manager-dev b/lib/core-server/src/__snapshots__/web-components-kitchen-sink_manager-dev index a34185d641e1..f7b97a41cabc 100644 --- a/lib/core-server/src/__snapshots__/web-components-kitchen-sink_manager-dev +++ b/lib/core-server/src/__snapshots__/web-components-kitchen-sink_manager-dev @@ -46,6 +46,8 @@ Object { Object { "loader": "NODE_MODULES/babel-loader/lib/index.js", "options": Object { + "babelrc": false, + "configFile": false, "plugins": Array [ "NODE_MODULES/@babel/plugin-transform-shorthand-properties/lib/index.js", "NODE_MODULES/@babel/plugin-transform-block-scoping/lib/index.js", diff --git a/lib/core-server/src/__snapshots__/web-components-kitchen-sink_manager-prod b/lib/core-server/src/__snapshots__/web-components-kitchen-sink_manager-prod index 99029c68161c..bad2f198819b 100644 --- a/lib/core-server/src/__snapshots__/web-components-kitchen-sink_manager-prod +++ b/lib/core-server/src/__snapshots__/web-components-kitchen-sink_manager-prod @@ -46,6 +46,8 @@ Object { Object { "loader": "NODE_MODULES/babel-loader/lib/index.js", "options": Object { + "babelrc": false, + "configFile": false, "plugins": Array [ "NODE_MODULES/@babel/plugin-transform-shorthand-properties/lib/index.js", "NODE_MODULES/@babel/plugin-transform-block-scoping/lib/index.js", From 5a988b02b4abbcf4237824106bbe5f02c981c153 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Fri, 27 Aug 2021 17:03:24 +0200 Subject: [PATCH 10/14] expose the list of dependencies we'll need in the CLI --- lib/core-common/src/utils/babel.ts | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/lib/core-common/src/utils/babel.ts b/lib/core-common/src/utils/babel.ts index e105cec3d189..8d0416274fb5 100644 --- a/lib/core-common/src/utils/babel.ts +++ b/lib/core-common/src/utils/babel.ts @@ -51,3 +51,28 @@ export const getStorybookBabelConfig = ({ local = false }: { local?: boolean } = ], } as TransformOptions; }; + +export const getStorybookBabelDependencies = () => [ + '@babel/preset-env', + '@babel/preset-typescript', + '@babel/plugin-transform-shorthand-properties', + '@babel/plugin-transform-block-scoping', + '@babel/plugin-proposal-decorators', + '@babel/plugin-proposal-class-properties', + '@babel/plugin-proposal-private-methods', + '@babel/plugin-proposal-export-default-from', + '@babel/plugin-syntax-dynamic-import', + '@babel/plugin-proposal-object-rest-spread', + '@babel/plugin-transform-classes', + '@babel/plugin-transform-arrow-functions', + '@babel/plugin-transform-parameters', + '@babel/plugin-transform-destructuring', + '@babel/plugin-transform-spread', + '@babel/plugin-transform-for-of', + 'babel-plugin-macros', + '@babel/plugin-proposal-optional-chaining', + '@babel/plugin-proposal-nullish-coalescing-operator', + 'babel-plugin-polyfill-corejs3', + 'babel-loader', + 'core-js', +]; From 863a561c1915f7a8fe55ff4812c3b187da99f86b Mon Sep 17 00:00:00 2001 From: Michael Shilman Date: Sat, 28 Aug 2021 00:12:52 +0800 Subject: [PATCH 11/14] CLI: Automatically generate babel config file in empty projects --- lib/cli/src/{babal-config.ts => babel-config.ts} | 0 lib/cli/src/generate.ts | 2 +- lib/cli/src/generators/baseGenerator.ts | 12 ++++++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) rename lib/cli/src/{babal-config.ts => babel-config.ts} (100%) diff --git a/lib/cli/src/babal-config.ts b/lib/cli/src/babel-config.ts similarity index 100% rename from lib/cli/src/babal-config.ts rename to lib/cli/src/babel-config.ts diff --git a/lib/cli/src/generate.ts b/lib/cli/src/generate.ts index 8336509521c5..b514be300d9b 100644 --- a/lib/cli/src/generate.ts +++ b/lib/cli/src/generate.ts @@ -11,7 +11,7 @@ import { extract } from './extract'; import { upgrade } from './upgrade'; import { repro } from './repro'; import { link } from './link'; -import { generateStorybookBabelConfigInCWD } from './babal-config'; +import { generateStorybookBabelConfigInCWD } from './babel-config'; const pkg = sync({ cwd: __dirname }).packageJson; diff --git a/lib/cli/src/generators/baseGenerator.ts b/lib/cli/src/generators/baseGenerator.ts index 6f3634a7333d..b3a7395d30c0 100644 --- a/lib/cli/src/generators/baseGenerator.ts +++ b/lib/cli/src/generators/baseGenerator.ts @@ -1,3 +1,5 @@ +import fse from 'fs-extra'; +import { getStorybookBabelDependencies } from '@storybook/core-common'; import { NpmOptions } from '../NpmOptions'; import { StoryFormat, @@ -9,6 +11,7 @@ import { import { getBabelDependencies, copyComponents } from '../helpers'; import { configure } from './configure'; import { getPackageDetails, JsPackageManager } from '../js-package-manager'; +import { generateStorybookBabelConfigInCWD } from '../babel-config'; export type GeneratorOptions = { language: SupportedLanguage; @@ -91,6 +94,11 @@ export async function baseGenerator( const yarn2Dependencies = packageManager.type === 'yarn2' ? ['@storybook/addon-docs', '@mdx-js/react'] : []; + const files = await fse.readdir(process.cwd()); + const isNewFolder = !files.some( + (fname) => fname.startsWith('.babel') || fname.startsWith('babel') || fname === 'package.json' + ); + const packageJson = packageManager.retrievePackageJson(); const installedDependencies = new Set(Object.keys(packageJson.dependencies)); @@ -129,6 +137,10 @@ export async function baseGenerator( } const babelDependencies = addBabel ? await getBabelDependencies(packageManager, packageJson) : []; + if (isNewFolder) { + babelDependencies.push(...getStorybookBabelDependencies()); + await generateStorybookBabelConfigInCWD(); + } packageManager.addDependencies({ ...npmOptions, packageJson }, [ ...versionedPackages, ...babelDependencies, From 492a1fe6857cfd4fb494ed8ca3a9f2250139bcc9 Mon Sep 17 00:00:00 2001 From: Michael Shilman Date: Mon, 30 Aug 2021 19:29:53 +0800 Subject: [PATCH 12/14] Add babelModeV7 migration instructions --- MIGRATION.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/MIGRATION.md b/MIGRATION.md index e5dd732ef7b6..6e2de30ab53c 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -1,5 +1,7 @@

Migration

+- [From version 6.3.x to 6.4.0](#from-version-63x-to-640) + - [Babel mode v7](#babel-mode-v7) - [From version 6.2.x to 6.3.0](#from-version-62x-to-630) - [Webpack 5 manager build](#webpack-5-manager-build) - [Angular 12 upgrade](#angular-12-upgrade) @@ -162,6 +164,39 @@ - [Packages renaming](#packages-renaming) - [Deprecated embedded addons](#deprecated-embedded-addons) +## From version 6.3.x to 6.4.0 + +### Babel mode v7 + +SB6.4 introduces an opt-in feature flag, `features.babelModeV7`, that reworks the way Babel is configured in Storybook to make it more consistent with the Babel is configured in your app. This breaking change will become the default in SB 7.0, but we encourage you to migrate today. + +> NOTE: CRA apps using `@storybook/preset-create-react-app` use CRA's handling, so the new flag has no effect on CRA apps. + +In SB6.x and earlier, Storybook provided its own default configuration and inconsistently handled configurations from the user's babelrc file. This resulted in a final configuration that differs from your application's configuration AND is difficult to debug. + +In `babelModeV7`, Storybook no longer provides its own default configuration and is primarily configured via babelrc file, with small, incremental updates from Storybook addons. + +In 6.x, Storybook supported a `.storybook/babelrc` configuration option. This is no longer supported and it's up to you to reconcile this with your project babelrc. + +To activate the v7 mode set the feature flag in your `.storybook/main.js` config: + +```js +module.exports = { + // ... your existing config + features: { + babelModeV7: true, + }, +}; +``` + +In the new mode, Storybook expects you to provide a configuration file. If you want a configuration file that's equivalent to the 6.x default, you can run the following command in your project directory: + +```sh +npx sb@next babelrc +``` + +This will create a `.babelrc.json` file. You may need to add package dependencies. + ## From version 6.2.x to 6.3.0 ### Webpack 5 manager build From 5fe2295067e8d8fcc2ffd4c660edff2f80b6347d Mon Sep 17 00:00:00 2001 From: Michael Shilman Date: Mon, 30 Aug 2021 19:30:12 +0800 Subject: [PATCH 13/14] Add babelModeV7 documentation --- docs/configure/babel.md | 67 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/docs/configure/babel.md b/docs/configure/babel.md index 7e3b2dd07926..b102819c277a 100644 --- a/docs/configure/babel.md +++ b/docs/configure/babel.md @@ -2,7 +2,21 @@ title: 'Babel' --- -Storybook’s webpack config by [default](#default-configuration) sets up [Babel](https://babeljs.io/) for ES6 transpiling. Storybook works with evergreen browsers by default. +Storybook’s webpack config by [default](#default-configuration) sets up [Babel](https://babeljs.io/) for ES6 transpiling. + +It has three different modes: + +- **CRA** - the mode for Create React App apps specifically +- **V6** - the default mode for version 6.x and below +- **V7** - a new mode slated to become the default in SB7.x + +## CRA mode + +CRA apps configured with `@storybook/preset-create-react-app` use CRA's babel handling to behave as close as possible to your actual application. None of the other documentation on this page applies. + +## V6 mode + +Storybook works with evergreen browsers by default. If you want to run Storybook in IE11, make sure to [disable](../essentials/introduction#disabling-addons) the docs-addon that is part of `@storybook/addon-essentials`, as this currently [causes issues in IE11](https://github.com/storybookjs/storybook/issues/8884). @@ -37,3 +51,54 @@ module.exports = { }), }; ``` + +## V7 Mode + +V7 mode is a new option available in Storybook 6.4+ behind a feature flag. + +Its goal is to make Babel configuration simpler, less buggy, easier to troubleshoot, and more consistent with the rest of the JS ecosystem. + +In V7 mode, you are responsible for configuring Babel using your `.babelrc` file and Storybook does not provide any default. Storybook's frameworks and addons may provide small programmatic modifications to the babel configuration. + +### Activating + +To activate V7 mode, set the feature flag in your `.storybook/main.js` config: + +```js +module.exports = { + // ... your existing config + features: { + babelModeV7: true, + }, +}; +``` + +### Migrating from V6 + +For detailed instructions on how to migrate from `V6` mode please see [MIGRATION.md](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#babel-mode-v7). + +### Generate a babelrc + +If your app does not use a babelrc and you need one, you can generate a babelrc file by running the following command in your project directory: + +```sh +npx sb@next babelrc +``` + +This will create a `.babelrc.json` file. You may need to add package dependencies. + +### Troubleshooting + +To troubleshoot your babel configuration, set the `BABEL_SHOW_CONFIG_FOR` environment variable. + +For example, to see how Storybook is transpiling your `.storybook/preview.js` config: + +```sh +BABEL_SHOW_CONFIG_FOR=.storybook/preview.js yarn storybook +``` + +This will print out the babel configuration for `.storybook/preview.js`, which can be used to debug when files fail to transpile or transpile incorrectly. + +> NOTE: Due to what appears to be a Babel bug, setting this flag causes Babel transpilation to fail on the file provided. Thus you cannot actually _RUN_ storybook using this command. However, it will print out the configuration information as advertised and thus you can use this to debug your Storybook. You'll need to remove the flag to actually run your Storybook. + +For more info, please refer to the [Babel documentation](https://babeljs.io/docs/en/configuration#print-effective-configs). From e3e0248fc9bdf79bb7e7187e3de179e66df092f1 Mon Sep 17 00:00:00 2001 From: Michael Shilman Date: Tue, 31 Aug 2021 12:34:19 +0800 Subject: [PATCH 14/14] Update MIGRATION.md --- MIGRATION.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MIGRATION.md b/MIGRATION.md index 6e2de30ab53c..76c01e2cf7e2 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -195,7 +195,7 @@ In the new mode, Storybook expects you to provide a configuration file. If you w npx sb@next babelrc ``` -This will create a `.babelrc.json` file. You may need to add package dependencies. +This will create a `.babelrc.json` file. This file includes a bunch of babel plugins, so you may need to add new package devDependencies accordingly. ## From version 6.2.x to 6.3.0