diff --git a/bin/lib/utils.js b/bin/lib/utils.js index 6e9b73a0e..213fd890e 100644 --- a/bin/lib/utils.js +++ b/bin/lib/utils.js @@ -17,3 +17,16 @@ export const progress = (percentage, size = 20) => { }; export const baseStorybookUrl = url => url.replace(/\/iframe\.html$/, ''); + +export const rewriteErrorMessage = (err, message) => { + try { + // DOMException doesn't allow setting the message, so this might fail + // eslint-disable-next-line no-param-reassign + err.message = message; + return err; + } catch (ex) { + const error = new Error(message); + error.stack = err.stack; // try to preserve the original stack + return error; + } +}; diff --git a/bin/main.js b/bin/main.js index 89e941cab..d647608db 100755 --- a/bin/main.js +++ b/bin/main.js @@ -11,9 +11,11 @@ import getOptions from './lib/getOptions'; import { createLogger } from './lib/log'; import NonTTYRenderer from './lib/NonTTYRenderer'; import parseArgs from './lib/parseArgs'; +import { rewriteErrorMessage } from './lib/utils'; import getTasks from './tasks'; import fatalError from './ui/messages/errors/fatalError'; import fetchError from './ui/messages/errors/fetchError'; +import missingStories from './ui/messages/errors/missingStories'; import runtimeError from './ui/messages/errors/runtimeError'; import taskError from './ui/messages/errors/taskError'; import intro from './ui/messages/info/intro'; @@ -78,15 +80,10 @@ export async function runBuild(ctx) { ctx.log.error(fetchError(ctx, err)); return; } - try { - // DOMException doesn't allow setting the message, so this might fail - err.message = taskError(ctx, err); - } catch (ex) { - const error = new Error(taskError(ctx, err)); - error.stack = err.stack; // try to preserve the original stack - throw error; + if (err.message.startsWith('Cannot run a build with no stories')) { + throw rewriteErrorMessage(err, missingStories(ctx)); } - throw err; + throw rewriteErrorMessage(err, taskError(ctx, err)); } finally { // Handle potential runtime errors from JSDOM const { runtimeErrors, runtimeWarnings } = ctx; diff --git a/bin/ui/messages/errors/missingStories.js b/bin/ui/messages/errors/missingStories.js new file mode 100644 index 000000000..9210805b5 --- /dev/null +++ b/bin/ui/messages/errors/missingStories.js @@ -0,0 +1,20 @@ +import chalk from 'chalk'; +import dedent from 'ts-dedent'; + +import { error } from '../../components/icons'; +import link from '../../components/link'; + +export default ({ options, buildLogFile }) => { + const { buildScriptName } = options; + return dedent(chalk` + ${error} {bold Cannot run a build with no stories} + + Your statically built Storybook exposes no stories. This indicates a problem with your Storybook. Here's what to do: + + - Check the build log at {bold ${buildLogFile}} + - Run {bold npm run ${buildScriptName}} or {bold yarn ${buildScriptName}} yourself and make sure it outputs a valid Storybook by opening the generated {bold index.html} in your browser. + - Make sure you haven't accidently ignored all stories. See ${link( + 'https://www.chromatic.com/docs/ignoring-elements#ignore-stories' + )} for details. + `); +}; diff --git a/bin/ui/messages/errors/missingStories.stories.js b/bin/ui/messages/errors/missingStories.stories.js new file mode 100644 index 000000000..318da6492 --- /dev/null +++ b/bin/ui/messages/errors/missingStories.stories.js @@ -0,0 +1,11 @@ +import missingStories from './missingStories'; + +export default { + title: 'CLI/Messages/Errors', +}; + +export const MissingStories = () => + missingStories({ + options: { buildScriptName: 'build:storybook' }, + buildLogFile: '/path/to/project/build-storybook.log', + }); diff --git a/bin/ui/messages/errors/taskError.js b/bin/ui/messages/errors/taskError.js index 4f7d0769d..451fb3214 100644 --- a/bin/ui/messages/errors/taskError.js +++ b/bin/ui/messages/errors/taskError.js @@ -5,9 +5,9 @@ import { error } from '../../components/icons'; const lcfirst = str => `${str.charAt(0).toLowerCase()}${str.substr(1)}`; -export default function taskError({ title }, e) { +export default function taskError({ title }, err) { return dedent(chalk` ${error} {bold Failed to ${lcfirst(title)}} - ${e.message} + ${err.message} `); }