From 846114ba15690d6d522b13361f87c22147e1e4ac Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Wed, 14 Feb 2024 18:08:39 +0100 Subject: [PATCH 1/9] print a clear warning/instruction when users encounter https://github.com/storybookjs/storybook/issues/23972 --- .../core-common/src/utils/load-main-config.ts | 52 ++++++++++++++++++- code/lib/core-server/src/build-dev.ts | 2 +- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/code/lib/core-common/src/utils/load-main-config.ts b/code/lib/core-common/src/utils/load-main-config.ts index 492ede4f669..5d418e979b4 100644 --- a/code/lib/core-common/src/utils/load-main-config.ts +++ b/code/lib/core-common/src/utils/load-main-config.ts @@ -1,7 +1,9 @@ -import path from 'path'; +import path, { relative } from 'path'; import type { StorybookConfig } from '@storybook/types'; import { serverRequire, serverResolve } from './interpret-require'; import { validateConfigurationFiles } from './validate-configuration-files'; +import { readFile } from 'fs/promises'; +import chalk from 'chalk'; export async function loadMainConfig({ configDir = '.storybook', @@ -18,5 +20,51 @@ export async function loadMainConfig({ delete require.cache[mainJsPath]; } - return serverRequire(mainJsPath); + try { + const out = await serverRequire(mainJsPath); + return out; + } catch (e) { + if (!(e instanceof Error)) { + throw e; + } + if (e.message.match(/Cannot use import statement outside a module/)) { + const a = relative(process.cwd(), mainJsPath); + const line = e.stack?.match(new RegExp(`${a}:(\\d+):(\\d+)`))?.[1]; + const message = [ + `Storybook failed to load ${a}..`, + '', + `It looks like the file tried to load/import an ESM only module.`, + `Support for this is currently limited in ${a}.`, + `You can import ESM modules in your main file, but only as imperative imports.`, + '', + ]; + + if (line) { + const contents = await readFile(mainJsPath, 'utf-8'); + const lines = contents.split('\n'); + const num = parseInt(line, 10) - 1; + + message.push( + chalk.white( + `In your ${chalk.yellow(a)} file, this line threw an error: ${chalk.bold.cyan( + num + )}, which looks like this:` + ), + chalk.grey(lines[num]) + ); + } + message.push( + '', + `Convert the declarative import to an imperative import where they are used.` + ); + + const out = new Error(message.join('\n')); + + delete out.stack; + + throw out; + } + throw e; + // + } } diff --git a/code/lib/core-server/src/build-dev.ts b/code/lib/core-server/src/build-dev.ts index 67990ff2d43..4cb0de5efca 100644 --- a/code/lib/core-server/src/build-dev.ts +++ b/code/lib/core-server/src/build-dev.ts @@ -15,7 +15,7 @@ import { telemetry, oneWayHash } from '@storybook/telemetry'; import { join, relative, resolve } from 'path'; import { deprecate } from '@storybook/node-logger'; -import dedent from 'ts-dedent'; +import { dedent } from 'ts-dedent'; import { readFile } from 'fs-extra'; import { MissingBuilderError } from '@storybook/core-events/server-errors'; import { storybookDevServer } from './dev-server'; From b0955e630266160da5a86ee97d81b57fa231b7c6 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Thu, 15 Feb 2024 13:54:37 +0100 Subject: [PATCH 2/9] make message more useful --- .../lib/core-common/src/utils/load-main-config.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/code/lib/core-common/src/utils/load-main-config.ts b/code/lib/core-common/src/utils/load-main-config.ts index 5d418e979b4..85e3e9b0791 100644 --- a/code/lib/core-common/src/utils/load-main-config.ts +++ b/code/lib/core-common/src/utils/load-main-config.ts @@ -28,14 +28,14 @@ export async function loadMainConfig({ throw e; } if (e.message.match(/Cannot use import statement outside a module/)) { - const a = relative(process.cwd(), mainJsPath); - const line = e.stack?.match(new RegExp(`${a}:(\\d+):(\\d+)`))?.[1]; + const location = relative(process.cwd(), mainJsPath); + const line = e.stack?.match(new RegExp(`${location}:(\\d+):(\\d+)`))?.[1]; const message = [ - `Storybook failed to load ${a}..`, + `Storybook failed to load ${location}..`, '', `It looks like the file tried to load/import an ESM only module.`, - `Support for this is currently limited in ${a}.`, - `You can import ESM modules in your main file, but only as imperative imports.`, + `Support for this is currently limited in ${location}.`, + `You can import ESM modules in your main file, but only as dynamic import.`, '', ]; @@ -46,7 +46,7 @@ export async function loadMainConfig({ message.push( chalk.white( - `In your ${chalk.yellow(a)} file, this line threw an error: ${chalk.bold.cyan( + `In your ${chalk.yellow(location)} file, this line threw an error: ${chalk.bold.cyan( num )}, which looks like this:` ), @@ -55,7 +55,8 @@ export async function loadMainConfig({ } message.push( '', - `Convert the declarative import to an imperative import where they are used.` + chalk.white(`Convert the dynamic import to an dynamic import where they are used.`), + chalk.white(`Example:`) + ' ' + chalk.gray(`await import();`) ); const out = new Error(message.join('\n')); From f70ed9e6f9a2bab92e8ca76f05dc915f91a5c9c7 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Thu, 15 Feb 2024 14:18:27 +0100 Subject: [PATCH 3/9] use server error class --- .../core-common/src/utils/load-main-config.ts | 39 +++++----------- code/lib/core-events/package.json | 1 + .../core-events/src/errors/server-errors.ts | 44 +++++++++++++++++++ code/yarn.lock | 1 + 4 files changed, 58 insertions(+), 27 deletions(-) diff --git a/code/lib/core-common/src/utils/load-main-config.ts b/code/lib/core-common/src/utils/load-main-config.ts index 85e3e9b0791..b61c51dfa83 100644 --- a/code/lib/core-common/src/utils/load-main-config.ts +++ b/code/lib/core-common/src/utils/load-main-config.ts @@ -3,7 +3,7 @@ import type { StorybookConfig } from '@storybook/types'; import { serverRequire, serverResolve } from './interpret-require'; import { validateConfigurationFiles } from './validate-configuration-files'; import { readFile } from 'fs/promises'; -import chalk from 'chalk'; +import { MainFileESMOnlyImportError } from '@storybook/core-events/server-errors'; export async function loadMainConfig({ configDir = '.storybook', @@ -29,37 +29,22 @@ export async function loadMainConfig({ } if (e.message.match(/Cannot use import statement outside a module/)) { const location = relative(process.cwd(), mainJsPath); - const line = e.stack?.match(new RegExp(`${location}:(\\d+):(\\d+)`))?.[1]; - const message = [ - `Storybook failed to load ${location}..`, - '', - `It looks like the file tried to load/import an ESM only module.`, - `Support for this is currently limited in ${location}.`, - `You can import ESM modules in your main file, but only as dynamic import.`, - '', - ]; + const numFromStack = e.stack?.match(new RegExp(`${location}:(\\d+):(\\d+)`))?.[1]; + let num; + let line; - if (line) { + if (numFromStack) { const contents = await readFile(mainJsPath, 'utf-8'); const lines = contents.split('\n'); - const num = parseInt(line, 10) - 1; - - message.push( - chalk.white( - `In your ${chalk.yellow(location)} file, this line threw an error: ${chalk.bold.cyan( - num - )}, which looks like this:` - ), - chalk.grey(lines[num]) - ); + num = parseInt(numFromStack, 10) - 1; + line = lines[num]; } - message.push( - '', - chalk.white(`Convert the dynamic import to an dynamic import where they are used.`), - chalk.white(`Example:`) + ' ' + chalk.gray(`await import();`) - ); - const out = new Error(message.join('\n')); + const out = new MainFileESMOnlyImportError({ + line, + location, + num, + }); delete out.stack; diff --git a/code/lib/core-events/package.json b/code/lib/core-events/package.json index e582c124ddd..ce38d804143 100644 --- a/code/lib/core-events/package.json +++ b/code/lib/core-events/package.json @@ -81,6 +81,7 @@ "ts-dedent": "^2.0.0" }, "devDependencies": { + "chalk": "^4.1.0", "typescript": "^5.3.2" }, "publishConfig": { diff --git a/code/lib/core-events/src/errors/server-errors.ts b/code/lib/core-events/src/errors/server-errors.ts index 2b522ad291f..c4414189a96 100644 --- a/code/lib/core-events/src/errors/server-errors.ts +++ b/code/lib/core-events/src/errors/server-errors.ts @@ -1,3 +1,4 @@ +import chalk from 'chalk'; import dedent from 'ts-dedent'; import { StorybookError } from './storybook-error'; @@ -394,6 +395,49 @@ export class NoMatchingExportError extends StorybookError { } } +export class MainFileESMOnlyImportError extends StorybookError { + readonly category = Category.CORE_SERVER; + + readonly code = 5; + + constructor( + public data: { location: string; line: string | undefined; num: number | undefined } + ) { + super(); + } + + template() { + const message = [ + `Storybook failed to load ${location}..`, + '', + `It looks like the file tried to load/import an ESM only module.`, + `Support for this is currently limited in ${location}.`, + `You can import ESM modules in your main file, but only as dynamic import.`, + '', + ]; + if (this.data.line) { + message.push( + chalk.white( + `In your ${chalk.yellow( + this.data.location + )} file, this line threw an error: ${chalk.bold.cyan( + this.data.num + )}, which looks like this:` + ), + chalk.grey(this.data.line) + ); + } + + message.push( + '', + chalk.white(`Convert the dynamic import to an dynamic import where they are used.`), + chalk.white(`Example:`) + ' ' + chalk.gray(`await import();`) + ); + + return message.join('\n'); + } +} + export class GenerateNewProjectOnInitError extends StorybookError { readonly category = Category.CLI_INIT; diff --git a/code/yarn.lock b/code/yarn.lock index 755a51216c1..11a4a61e2df 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -5528,6 +5528,7 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/core-events@workspace:lib/core-events" dependencies: + chalk: "npm:^4.1.0" ts-dedent: "npm:^2.0.0" typescript: "npm:^5.3.2" languageName: unknown From a9f8b34469322cea9f9cc251e4fb3eab0978ecfd Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Thu, 15 Feb 2024 14:21:23 +0100 Subject: [PATCH 4/9] change to named exports --- code/lib/core-events/src/errors/server-errors.ts | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/code/lib/core-events/src/errors/server-errors.ts b/code/lib/core-events/src/errors/server-errors.ts index c4414189a96..30418e86e4c 100644 --- a/code/lib/core-events/src/errors/server-errors.ts +++ b/code/lib/core-events/src/errors/server-errors.ts @@ -1,4 +1,4 @@ -import chalk from 'chalk'; +import { bold, gray, grey, white, yellow } from 'chalk'; import dedent from 'ts-dedent'; import { StorybookError } from './storybook-error'; @@ -417,21 +417,19 @@ export class MainFileESMOnlyImportError extends StorybookError { ]; if (this.data.line) { message.push( - chalk.white( - `In your ${chalk.yellow( - this.data.location - )} file, this line threw an error: ${chalk.bold.cyan( + white( + `In your ${yellow(this.data.location)} file, this line threw an error: ${bold.cyan( this.data.num )}, which looks like this:` ), - chalk.grey(this.data.line) + grey(this.data.line) ); } message.push( '', - chalk.white(`Convert the dynamic import to an dynamic import where they are used.`), - chalk.white(`Example:`) + ' ' + chalk.gray(`await import();`) + white(`Convert the dynamic import to an dynamic import where they are used.`), + white(`Example:`) + ' ' + gray(`await import();`) ); return message.join('\n'); From c61535716f095e1b8b431c4501ed9a7abfad8bde Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Thu, 15 Feb 2024 14:30:30 +0100 Subject: [PATCH 5/9] fixes --- code/lib/core-events/src/errors/server-errors.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/lib/core-events/src/errors/server-errors.ts b/code/lib/core-events/src/errors/server-errors.ts index 30418e86e4c..884dd0c4dbf 100644 --- a/code/lib/core-events/src/errors/server-errors.ts +++ b/code/lib/core-events/src/errors/server-errors.ts @@ -408,10 +408,10 @@ export class MainFileESMOnlyImportError extends StorybookError { template() { const message = [ - `Storybook failed to load ${location}..`, + `Storybook failed to load ${this.data.location}..`, '', `It looks like the file tried to load/import an ESM only module.`, - `Support for this is currently limited in ${location}.`, + `Support for this is currently limited in ${this.data.location}.`, `You can import ESM modules in your main file, but only as dynamic import.`, '', ]; From 21945adfa403cfed1b73c1e4f50e6faf32cabe26 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Fri, 16 Feb 2024 16:03:13 +0100 Subject: [PATCH 6/9] throw when mainConfig is missing or unable to be evaluated, also throw when version is missing --- code/lib/cli/src/upgrade.ts | 46 +------------- .../core-common/src/utils/load-main-config.ts | 12 +++- .../src/utils/validate-configuration-files.ts | 6 +- .../core-events/src/errors/server-errors.ts | 61 ++++++++++++++++++- 4 files changed, 74 insertions(+), 51 deletions(-) diff --git a/code/lib/cli/src/upgrade.ts b/code/lib/cli/src/upgrade.ts index e9f4a8151b1..7f8485aae5d 100644 --- a/code/lib/cli/src/upgrade.ts +++ b/code/lib/cli/src/upgrade.ts @@ -6,6 +6,7 @@ import { withTelemetry } from '@storybook/core-server'; import { UpgradeStorybookToLowerVersionError, UpgradeStorybookToSameVersionError, + UpgradeStorybookUnknownCurrentVersionError, } from '@storybook/core-events/server-errors'; import chalk from 'chalk'; @@ -189,26 +190,11 @@ export const doUpgrade = async ({ ); const configDir = userSpecifiedConfigDir || inferredConfigDir || '.storybook'; - let mainConfigLoadingError = ''; - - const mainConfig = await loadMainConfig({ configDir }).catch((err) => { - mainConfigLoadingError = String(err); - return false; - }); + const mainConfig = await loadMainConfig({ configDir }); // GUARDS if (!storybookVersion) { - logger.info(missingStorybookVersionMessage()); - results = { preCheckFailure: PreCheckFailure.UNDETECTED_SB_VERSION }; - } else if ( - typeof mainConfigPath === 'undefined' || - mainConfigLoadingError.includes('No configuration files have been found') - ) { - logger.info(mainjsNotFoundMessage(configDir)); - results = { preCheckFailure: PreCheckFailure.MAINJS_NOT_FOUND }; - } else if (typeof mainConfig === 'boolean') { - logger.info(mainjsExecutionFailureMessage(mainConfigPath, mainConfigLoadingError)); - results = { preCheckFailure: PreCheckFailure.MAINJS_EVALUATION }; + throw new UpgradeStorybookUnknownCurrentVersionError(); } // BLOCKERS @@ -293,32 +279,6 @@ export const doUpgrade = async ({ } }; -function missingStorybookVersionMessage(): string { - return dedent` - [Storybook automigrate] ❌ Unable to determine Storybook version so that the automigrations will be skipped. - 🤔 Are you running automigrate from your project directory? Please specify your Storybook config directory with the --config-dir flag. - `; -} - -function mainjsExecutionFailureMessage( - mainConfigPath: string, - mainConfigLoadingError: string -): string { - return dedent` - [Storybook automigrate] ❌ Failed trying to evaluate ${chalk.blue( - mainConfigPath - )} with the following error: ${mainConfigLoadingError} - - Please fix the error and try again. - `; -} - -function mainjsNotFoundMessage(configDir: string): string { - return dedent`[Storybook automigrate] Could not find or evaluate your Storybook main.js config directory at ${chalk.blue( - configDir - )} so the automigrations will be skipped. You might be running this command in a monorepo or a non-standard project structure. If that is the case, please rerun this command by specifying the path to your Storybook config directory via the --config-dir option.`; -} - export async function upgrade(options: UpgradeOptions): Promise { await withTelemetry('upgrade', { cliOptions: options }, () => doUpgrade(options)); } diff --git a/code/lib/core-common/src/utils/load-main-config.ts b/code/lib/core-common/src/utils/load-main-config.ts index b61c51dfa83..cbd2785fa10 100644 --- a/code/lib/core-common/src/utils/load-main-config.ts +++ b/code/lib/core-common/src/utils/load-main-config.ts @@ -3,7 +3,10 @@ import type { StorybookConfig } from '@storybook/types'; import { serverRequire, serverResolve } from './interpret-require'; import { validateConfigurationFiles } from './validate-configuration-files'; import { readFile } from 'fs/promises'; -import { MainFileESMOnlyImportError } from '@storybook/core-events/server-errors'; +import { + MainFileESMOnlyImportError, + MainFileFailedEvaluationError, +} from '@storybook/core-events/server-errors'; export async function loadMainConfig({ configDir = '.storybook', @@ -50,7 +53,10 @@ export async function loadMainConfig({ throw out; } - throw e; - // + + throw new MainFileFailedEvaluationError({ + location: relative(process.cwd(), mainJsPath), + error: e, + }); } } diff --git a/code/lib/core-common/src/utils/validate-configuration-files.ts b/code/lib/core-common/src/utils/validate-configuration-files.ts index 57e1cffeab7..0f7c1ecaaeb 100644 --- a/code/lib/core-common/src/utils/validate-configuration-files.ts +++ b/code/lib/core-common/src/utils/validate-configuration-files.ts @@ -5,6 +5,7 @@ import slash from 'slash'; import { once } from '@storybook/node-logger'; import { boost } from './interpret-files'; +import { MainFileMissingError } from '@storybook/core-events/server-errors'; export async function validateConfigurationFiles(configDir: string) { const extensionsPattern = `{${Array.from(boost).join(',')}}`; @@ -20,9 +21,6 @@ export async function validateConfigurationFiles(configDir: string) { } if (!mainConfigPath) { - throw new Error(dedent` - No configuration files have been found in your configDir (${path.resolve(configDir)}). - Storybook needs "main.js" file, please add it (or pass a custom config dir flag to Storybook to tell where your main.js file is located at). - `); + throw new MainFileMissingError({ location: configDir }); } } diff --git a/code/lib/core-events/src/errors/server-errors.ts b/code/lib/core-events/src/errors/server-errors.ts index 884dd0c4dbf..d210f1c2302 100644 --- a/code/lib/core-events/src/errors/server-errors.ts +++ b/code/lib/core-events/src/errors/server-errors.ts @@ -400,6 +400,9 @@ export class MainFileESMOnlyImportError extends StorybookError { readonly code = 5; + public documentation = + 'https://github.com/storybookjs/storybook/issues/23972#issuecomment-1948534058'; + constructor( public data: { location: string; line: string | undefined; num: number | undefined } ) { @@ -428,7 +431,7 @@ export class MainFileESMOnlyImportError extends StorybookError { message.push( '', - white(`Convert the dynamic import to an dynamic import where they are used.`), + white(`Convert the static import to an dynamic import where they are used.`), white(`Example:`) + ' ' + gray(`await import();`) ); @@ -436,6 +439,47 @@ export class MainFileESMOnlyImportError extends StorybookError { } } +export class MainFileMissingError extends StorybookError { + readonly category = Category.CORE_SERVER; + + readonly code = 6; + + public readonly documentation = 'https://storybook.js.org/docs/configure'; + + constructor(public data: { location: string }) { + super(); + } + + template() { + return dedent` + No configuration files have been found in your configDir: ${yellow(this.data.location)}. + Storybook needs "main.js" file, please add it. + + You can pass a --config-dir flag to tell Storybook, where your main.js file is located at). + `; + } +} + +export class MainFileFailedEvaluationError extends StorybookError { + readonly category = Category.CORE_SERVER; + + readonly code = 7; + + public readonly documentation = 'https://storybook.js.org/docs/configure'; + + constructor(public data: { location: string; error: Error }) { + super(); + } + + template() { + return dedent` + Storybook couldn't evaluate your ${yellow(this.data.location)} file. + + ${this.data.error.message} + `; + } +} + export class GenerateNewProjectOnInitError extends StorybookError { readonly category = Category.CLI_INIT; @@ -510,3 +554,18 @@ export class UpgradeStorybookToSameVersionError extends StorybookError { `; } } + +export class UpgradeStorybookUnknownCurrentVersionError extends StorybookError { + readonly category = Category.CLI_UPGRADE; + + readonly code = 5; + + template() { + return dedent` + We couldn't determine the current version of Storybook in your project. + + Are you running the storybook CLI in a project without Storybook? + It might help if you specify your Storybook config directory with the --config-dir flag. + `; + } +} From a321a58d7280f9b4475a89d0f8b0b2f907c7d725 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Fri, 16 Feb 2024 16:58:33 +0100 Subject: [PATCH 7/9] improve --- code/lib/cli/src/upgrade.ts | 1 - .../core-common/src/utils/load-main-config.ts | 4 ++-- .../core-events/src/errors/server-errors.ts | 24 ++++++++++++------- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/code/lib/cli/src/upgrade.ts b/code/lib/cli/src/upgrade.ts index 7f8485aae5d..cb96bd79791 100644 --- a/code/lib/cli/src/upgrade.ts +++ b/code/lib/cli/src/upgrade.ts @@ -23,7 +23,6 @@ import { } from '@storybook/core-common'; import { automigrate } from './automigrate/index'; import { autoblock } from './autoblock/index'; -import { PreCheckFailure } from './automigrate/types'; type Package = { package: string; diff --git a/code/lib/core-common/src/utils/load-main-config.ts b/code/lib/core-common/src/utils/load-main-config.ts index cbd2785fa10..b5001418597 100644 --- a/code/lib/core-common/src/utils/load-main-config.ts +++ b/code/lib/core-common/src/utils/load-main-config.ts @@ -5,7 +5,7 @@ import { validateConfigurationFiles } from './validate-configuration-files'; import { readFile } from 'fs/promises'; import { MainFileESMOnlyImportError, - MainFileFailedEvaluationError, + MainFileEvaluationError, } from '@storybook/core-events/server-errors'; export async function loadMainConfig({ @@ -54,7 +54,7 @@ export async function loadMainConfig({ throw out; } - throw new MainFileFailedEvaluationError({ + throw new MainFileEvaluationError({ location: relative(process.cwd(), mainJsPath), error: e, }); diff --git a/code/lib/core-events/src/errors/server-errors.ts b/code/lib/core-events/src/errors/server-errors.ts index d210f1c2302..acdce05da1d 100644 --- a/code/lib/core-events/src/errors/server-errors.ts +++ b/code/lib/core-events/src/errors/server-errors.ts @@ -1,4 +1,4 @@ -import { bold, gray, grey, white, yellow } from 'chalk'; +import { bold, gray, grey, white, yellow, underline } from 'chalk'; import dedent from 'ts-dedent'; import { StorybookError } from './storybook-error'; @@ -421,9 +421,9 @@ export class MainFileESMOnlyImportError extends StorybookError { if (this.data.line) { message.push( white( - `In your ${yellow(this.data.location)} file, this line threw an error: ${bold.cyan( + `In your ${yellow(this.data.location)} file, line ${bold.cyan( this.data.num - )}, which looks like this:` + )} threw an error, which looks like this:` ), grey(this.data.line) ); @@ -431,8 +431,10 @@ export class MainFileESMOnlyImportError extends StorybookError { message.push( '', - white(`Convert the static import to an dynamic import where they are used.`), - white(`Example:`) + ' ' + gray(`await import();`) + white(`Convert the static import to an dynamic import ${underline('where they are used')}.`), + white(`Example:`) + ' ' + gray(`await import();`), + '', + 'For more information, please read the documentation link below.' ); return message.join('\n'); @@ -444,6 +446,8 @@ export class MainFileMissingError extends StorybookError { readonly code = 6; + readonly stack = ''; + public readonly documentation = 'https://storybook.js.org/docs/configure'; constructor(public data: { location: string }) { @@ -460,22 +464,26 @@ export class MainFileMissingError extends StorybookError { } } -export class MainFileFailedEvaluationError extends StorybookError { +export class MainFileEvaluationError extends StorybookError { readonly category = Category.CORE_SERVER; readonly code = 7; - public readonly documentation = 'https://storybook.js.org/docs/configure'; + readonly stack = ''; constructor(public data: { location: string; error: Error }) { super(); } template() { + const errorText = white( + (this.data.error.stack || this.data.error.message).replaceAll(process.cwd(), '') + ); + return dedent` Storybook couldn't evaluate your ${yellow(this.data.location)} file. - ${this.data.error.message} + ${errorText} `; } } From 6e4666a28fbb693bc89c8161219479b2bb4f79a0 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Tue, 20 Feb 2024 12:12:52 +0100 Subject: [PATCH 8/9] Apply suggestions from code review Co-authored-by: Yann Braga --- code/lib/core-events/src/errors/server-errors.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/code/lib/core-events/src/errors/server-errors.ts b/code/lib/core-events/src/errors/server-errors.ts index acdce05da1d..cf913ab0d22 100644 --- a/code/lib/core-events/src/errors/server-errors.ts +++ b/code/lib/core-events/src/errors/server-errors.ts @@ -411,10 +411,10 @@ export class MainFileESMOnlyImportError extends StorybookError { template() { const message = [ - `Storybook failed to load ${this.data.location}..`, + `Storybook failed to load ${this.data.location}`, '', `It looks like the file tried to load/import an ESM only module.`, - `Support for this is currently limited in ${this.data.location}.`, + `Support for this is currently limited in ${this.data.location}`, `You can import ESM modules in your main file, but only as dynamic import.`, '', ]; @@ -423,7 +423,7 @@ export class MainFileESMOnlyImportError extends StorybookError { white( `In your ${yellow(this.data.location)} file, line ${bold.cyan( this.data.num - )} threw an error, which looks like this:` + )} threw an error:` ), grey(this.data.line) ); @@ -431,10 +431,9 @@ export class MainFileESMOnlyImportError extends StorybookError { message.push( '', - white(`Convert the static import to an dynamic import ${underline('where they are used')}.`), + white(`Convert the static import to a dynamic import ${underline('where they are used')}.`), white(`Example:`) + ' ' + gray(`await import();`), '', - 'For more information, please read the documentation link below.' ); return message.join('\n'); @@ -457,7 +456,7 @@ export class MainFileMissingError extends StorybookError { template() { return dedent` No configuration files have been found in your configDir: ${yellow(this.data.location)}. - Storybook needs "main.js" file, please add it. + Storybook needs a "main.js" file, please add it. You can pass a --config-dir flag to tell Storybook, where your main.js file is located at). `; @@ -572,7 +571,7 @@ export class UpgradeStorybookUnknownCurrentVersionError extends StorybookError { return dedent` We couldn't determine the current version of Storybook in your project. - Are you running the storybook CLI in a project without Storybook? + Are you running the Storybook CLI in a project without Storybook? It might help if you specify your Storybook config directory with the --config-dir flag. `; } From 3a87bffc044404079e195208ed4155f4f615c648 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Tue, 20 Feb 2024 12:54:46 +0100 Subject: [PATCH 9/9] cleanup --- code/lib/core-events/src/errors/server-errors.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/lib/core-events/src/errors/server-errors.ts b/code/lib/core-events/src/errors/server-errors.ts index cf913ab0d22..a9a9e758d70 100644 --- a/code/lib/core-events/src/errors/server-errors.ts +++ b/code/lib/core-events/src/errors/server-errors.ts @@ -433,7 +433,7 @@ export class MainFileESMOnlyImportError extends StorybookError { '', white(`Convert the static import to a dynamic import ${underline('where they are used')}.`), white(`Example:`) + ' ' + gray(`await import();`), - '', + '' ); return message.join('\n');