Skip to content

Commit

Permalink
Merge pull request #23874 from storybookjs/yann/improve-empty-dir-ini…
Browse files Browse the repository at this point in the history
…t-message

CLI: Provide guidance for users who try to initialize Storybook on an empty dir
  • Loading branch information
yannbf authored Aug 24, 2023
2 parents 0d1960e + 937473b commit 86e342c
Show file tree
Hide file tree
Showing 13 changed files with 207 additions and 76 deletions.
28 changes: 18 additions & 10 deletions code/lib/cli/src/detect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
} from './project_types';
import { commandLog, isNxProject } from './helpers';
import type { JsPackageManager, PackageJsonWithMaybeDeps } from './js-package-manager';
import { HandledError } from './HandledError';

const viteConfigFiles = ['vite.config.ts', 'vite.config.js', 'vite.config.mjs'];
const webpackConfigFiles = ['webpack.config.js'];
Expand Down Expand Up @@ -135,16 +136,23 @@ export async function detectBuilder(packageManager: JsPackageManager, projectTyp
return CoreBuilder.Webpack5;
default:
// eslint-disable-next-line no-case-declarations
const { builder } = await prompts({
type: 'select',
name: 'builder',
message:
'We were not able to detect the right builder for your project. Please select one:',
choices: [
{ title: 'Vite', value: CoreBuilder.Vite },
{ title: 'Webpack 5', value: CoreBuilder.Webpack5 },
],
});
const { builder } = await prompts(
{
type: 'select',
name: 'builder',
message:
'\nWe were not able to detect the right builder for your project. Please select one:',
choices: [
{ title: 'Vite', value: CoreBuilder.Vite },
{ title: 'Webpack 5', value: CoreBuilder.Webpack5 },
],
},
{
onCancel: () => {
throw new HandledError('Canceled by the user');
},
}
);

return builder;
}
Expand Down
25 changes: 16 additions & 9 deletions code/lib/cli/src/generators/EMBER/index.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
import { CoreBuilder } from '../../project_types';
import { baseGenerator } from '../baseGenerator';
import type { Generator } from '../types';

const generator: Generator = async (packageManager, npmOptions, options) => {
await baseGenerator(packageManager, npmOptions, options, 'ember', {
extraPackages: [
// babel-plugin-ember-modules-api-polyfill is a peerDep of @storybook/ember
'babel-plugin-ember-modules-api-polyfill',
// babel-plugin-htmlbars-inline-precompile is a peerDep of @storybook/ember
'babel-plugin-htmlbars-inline-precompile',
],
staticDir: 'dist',
});
await baseGenerator(
packageManager,
npmOptions,
{ ...options, builder: CoreBuilder.Webpack5 },
'ember',
{
extraPackages: [
// babel-plugin-ember-modules-api-polyfill is a peerDep of @storybook/ember
'babel-plugin-ember-modules-api-polyfill',
// babel-plugin-htmlbars-inline-precompile is a peerDep of @storybook/ember
'babel-plugin-htmlbars-inline-precompile',
],
staticDir: 'dist',
}
);
};

export default generator;
3 changes: 2 additions & 1 deletion code/lib/cli/src/generators/NEXTJS/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { CoreBuilder } from '../../project_types';
import { baseGenerator } from '../baseGenerator';
import type { Generator } from '../types';

const generator: Generator = async (packageManager, npmOptions, options) => {
await baseGenerator(
packageManager,
npmOptions,
options,
{ ...options, builder: CoreBuilder.Webpack5 },
'react',
{
extraAddons: ['@storybook/addon-onboarding'],
Expand Down
55 changes: 32 additions & 23 deletions code/lib/cli/src/generators/REACT_SCRIPTS/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,39 +26,48 @@ const generator: Generator = async (packageManager, npmOptions, options) => {
: {};

const craVersion = await packageManager.getPackageVersion('react-scripts');
const isCra5OrHigher = craVersion && semver.gte(craVersion, '5.0.0');
const updatedOptions = isCra5OrHigher ? { ...options, builder: CoreBuilder.Webpack5 } : options;

const extraPackages = [];
if (isCra5OrHigher) {
extraPackages.push('webpack');
// Miscellaneous dependency used in `babel-preset-react-app` but not listed as dep there
extraPackages.push('babel-plugin-named-exports-order');
// Miscellaneous dependency to add to be sure Storybook + CRA is working fine with Yarn PnP mode
extraPackages.push('prop-types');
if (craVersion === null) {
throw new Error(dedent`
It looks like you're trying to initialize Storybook in a CRA project that does not have react-scripts installed.
Please install it and make sure it's of version 5 or higher, which are the versions supported by Storybook 7.0+.
`);
}

const version = versions['@storybook/preset-create-react-app'];
const extraAddons = [
`@storybook/preset-create-react-app@${version}`,
'@storybook/addon-onboarding',
];

if (!isCra5OrHigher) {
if (!craVersion && semver.gte(craVersion, '5.0.0')) {
throw new Error(dedent`
Storybook 7.0+ doesn't support react-scripts@<5.0.0.
https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#create-react-app-dropped-cra4-support
`);
}

await baseGenerator(packageManager, npmOptions, updatedOptions, 'react', {
extraAddons,
extraPackages,
staticDir: fs.existsSync(path.resolve('./public')) ? 'public' : undefined,
skipBabel: true,
extraMain,
});
const extraPackages = [];
extraPackages.push('webpack');
// Miscellaneous dependency used in `babel-preset-react-app` but not listed as dep there
extraPackages.push('babel-plugin-named-exports-order');
// Miscellaneous dependency to add to be sure Storybook + CRA is working fine with Yarn PnP mode
extraPackages.push('prop-types');

const version = versions['@storybook/preset-create-react-app'];
const extraAddons = [
`@storybook/preset-create-react-app@${version}`,
'@storybook/addon-onboarding',
];

await baseGenerator(
packageManager,
npmOptions,
{ ...options, builder: CoreBuilder.Webpack5 },
'react',
{
extraAddons,
extraPackages,
staticDir: fs.existsSync(path.resolve('./public')) ? 'public' : undefined,
skipBabel: true,
extraMain,
}
);
};

export default generator;
13 changes: 10 additions & 3 deletions code/lib/cli/src/generators/SERVER/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import { CoreBuilder } from '../../project_types';
import { baseGenerator } from '../baseGenerator';
import type { Generator } from '../types';

const generator: Generator = async (packageManager, npmOptions, options) => {
await baseGenerator(packageManager, npmOptions, options, 'server', {
extensions: ['json', 'yaml', 'yml'],
});
await baseGenerator(
packageManager,
npmOptions,
{ ...options, builder: CoreBuilder.Vite },
'server',
{
extensions: ['json', 'yaml', 'yml'],
}
);
};

export default generator;
10 changes: 9 additions & 1 deletion code/lib/cli/src/generators/SOLID/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
import { CoreBuilder } from '../../project_types';
import { baseGenerator } from '../baseGenerator';
import type { Generator } from '../types';

const generator: Generator = async (packageManager, npmOptions, options) => {
await baseGenerator(packageManager, npmOptions, options, 'solid', {}, 'solid');
await baseGenerator(
packageManager,
npmOptions,
{ ...options, builder: CoreBuilder.Vite },
'solid',
{},
'solid'
);
};

export default generator;
10 changes: 9 additions & 1 deletion code/lib/cli/src/generators/SVELTEKIT/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
import { CoreBuilder } from '../../project_types';
import { baseGenerator } from '../baseGenerator';
import type { Generator } from '../types';

const generator: Generator = async (packageManager, npmOptions, options) => {
await baseGenerator(packageManager, npmOptions, options, 'svelte', undefined, 'sveltekit');
await baseGenerator(
packageManager,
npmOptions,
{ ...options, builder: CoreBuilder.Vite },
'svelte',
undefined,
'sveltekit'
);
};

export default generator;
5 changes: 3 additions & 2 deletions code/lib/cli/src/generators/VUE/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ import { baseGenerator } from '../baseGenerator';
import type { Generator } from '../types';

const generator: Generator = async (packageManager, npmOptions, options) => {
const extraPackages = options.builder === CoreBuilder.Webpack5 ? ['vue-loader@^15.7.0'] : [];
await baseGenerator(packageManager, npmOptions, options, 'vue', {
extraPackages,
extraPackages: async ({ builder }) => {
return builder === CoreBuilder.Webpack5 ? ['vue-loader@^15.7.0'] : [];
},
});
};

Expand Down
10 changes: 5 additions & 5 deletions code/lib/cli/src/generators/VUE3/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import { baseGenerator } from '../baseGenerator';
import type { Generator } from '../types';

const generator: Generator = async (packageManager, npmOptions, options) => {
const extraPackages =
options.builder === CoreBuilder.Webpack5
? ['vue-loader@^17.0.0', '@vue/compiler-sfc@^3.2.0']
: [];
await baseGenerator(packageManager, npmOptions, options, 'vue3', {
extraPackages,
extraPackages: async ({ builder }) => {
return builder === CoreBuilder.Webpack5
? ['vue-loader@^17.0.0', '@vue/compiler-sfc@^3.2.0']
: [];
},
});
};

Expand Down
36 changes: 30 additions & 6 deletions code/lib/cli/src/generators/baseGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
extractEslintInfo,
suggestESLintPlugin,
} from '../automigrate/helpers/eslintPlugin';
import { detectBuilder } from '../detect';

const logger = console;

Expand Down Expand Up @@ -175,10 +176,11 @@ export async function baseGenerator(
npmOptions: NpmOptions,
{
language,
builder = CoreBuilder.Webpack5,
builder,
pnp,
frameworkPreviewParts,
yes: skipPrompts,
projectType,
}: GeneratorOptions,
renderer: SupportedRenderers,
options: FrameworkOptions = defaultOptions,
Expand All @@ -187,6 +189,11 @@ export async function baseGenerator(
const isStorybookInMonorepository = packageManager.isStorybookInMonorepo();
const shouldApplyRequireWrapperOnPackageNames = isStorybookInMonorepository || pnp;

if (!builder) {
// eslint-disable-next-line no-param-reassign
builder = await detectBuilder(packageManager, projectType);
}

const {
extraAddons: extraAddonPackages,
extraPackages,
Expand Down Expand Up @@ -219,19 +226,28 @@ export async function baseGenerator(
shouldApplyRequireWrapperOnPackageNames
);

const extraAddonsToInstall =
typeof extraAddonPackages === 'function'
? await extraAddonPackages({
builder: builder || builderInclude,
framework: framework || frameworkInclude,
})
: extraAddonPackages;

// added to main.js
const addons = [
'@storybook/addon-links',
'@storybook/addon-essentials',
...stripVersions(extraAddonPackages),
];
...stripVersions(extraAddonsToInstall),
].filter(Boolean);

// added to package.json
const addonPackages = [
'@storybook/addon-links',
'@storybook/addon-essentials',
'@storybook/blocks',
...extraAddonPackages,
];
...extraAddonsToInstall,
].filter(Boolean);

if (hasInteractiveStories(rendererId)) {
addons.push('@storybook/addon-interactions');
Expand Down Expand Up @@ -265,12 +281,20 @@ export async function baseGenerator(
);
}

const extraPackagesToInstall =
typeof extraPackages === 'function'
? await extraPackages({
builder: builder || builderInclude,
framework: framework || frameworkInclude,
})
: extraPackages;

const allPackages = [
'storybook',
getExternalFramework(rendererId) ? undefined : `@storybook/${rendererId}`,
...frameworkPackages,
...addonPackages,
...extraPackages,
...extraPackagesToInstall,
].filter(Boolean);

const packages = [...new Set(allPackages)].filter(
Expand Down
7 changes: 5 additions & 2 deletions code/lib/cli/src/generators/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,17 @@ export type GeneratorOptions = {
builder: Builder;
linkable: boolean;
pnp: boolean;
projectType: ProjectType;
frameworkPreviewParts?: FrameworkPreviewParts;
// skip prompting the user
yes: boolean;
};

export interface FrameworkOptions {
extraPackages?: string[];
extraAddons?: string[];
extraPackages?:
| string[]
| ((details: { framework: string; builder: string }) => Promise<string[]>);
extraAddons?: string[] | ((details: { framework: string; builder: string }) => Promise<string[]>);
staticDir?: string;
addScripts?: boolean;
addMainFile?: boolean;
Expand Down
Loading

0 comments on commit 86e342c

Please sign in to comment.