diff --git a/code/builders/builder-webpack5/src/index.ts b/code/builders/builder-webpack5/src/index.ts index 0106cfea091d..45775dc7d04f 100644 --- a/code/builders/builder-webpack5/src/index.ts +++ b/code/builders/builder-webpack5/src/index.ts @@ -9,6 +9,7 @@ import { dirname, join, parse } from 'path'; import express from 'express'; import fs from 'fs-extra'; import { PREVIEW_BUILDER_PROGRESS } from '@storybook/core-events'; +import { WebpackCompilationError } from '@storybook/core-events/server-errors'; import prettyTime from 'pretty-hrtime'; @@ -195,8 +196,7 @@ const starter: StarterFunction = async function* starterGeneratorFn({ } if (stats.hasErrors()) { - // eslint-disable-next-line @typescript-eslint/no-throw-literal - throw stats; + throw new WebpackCompilationError({ error: stats }); } return { diff --git a/code/lib/core-events/src/errors/server-errors.test.ts b/code/lib/core-events/src/errors/server-errors.test.ts new file mode 100644 index 000000000000..9b0e08f01522 --- /dev/null +++ b/code/lib/core-events/src/errors/server-errors.test.ts @@ -0,0 +1,61 @@ +/* eslint-disable local-rules/no-uncategorized-errors */ +import { WebpackCompilationError } from './server-errors'; + +describe('WebpackCompilationError', () => { + it('should correctly handle error with error property', () => { + const error = new Error('Custom error message'); + const data = { + error, + }; + + const webpackError = new WebpackCompilationError(data); + + expect(webpackError.message).toBe(error.message); + }); + + it('should correctly handle error with error within error', () => { + const error = new Error('Custom error message'); + const data = { + error: new Error(), + }; + data.error = error; + + const webpackError = new WebpackCompilationError(data); + + expect(webpackError.message).toBe(error.message); + }); + + it('should correctly handle error with stats.compilation.errors', () => { + const compilationErrors = [new Error('Error 1 message'), new Error('Error 2 message')]; + const data = new Error() as Error & { + error: Error & { stats?: { compilation: { errors: Error[] } } }; + }; + data.error = new Error(); + data.error.stats = { + compilation: { + errors: compilationErrors, + }, + }; + + const webpackError = new WebpackCompilationError(data); + + expect(webpackError.message).toMatchInlineSnapshot(` + "Error: Error 1 message + + Error: Error 2 message" + `); + }); + + it('should correctly handle error without specific format', () => { + const errorMessage = 'Generic error message'; + const data = new Error() as Error & { + error: Error; + }; + + data.error = new Error(errorMessage); + + const webpackError = new WebpackCompilationError(data); + + expect(webpackError.message).toBe(errorMessage); + }); +}); diff --git a/code/lib/core-events/src/errors/server-errors.ts b/code/lib/core-events/src/errors/server-errors.ts index 93f7355a3024..5c1eb801ee57 100644 --- a/code/lib/core-events/src/errors/server-errors.ts +++ b/code/lib/core-events/src/errors/server-errors.ts @@ -137,3 +137,48 @@ export class InvalidStoriesEntryError extends StorybookError { `; } } + +export class WebpackCompilationError extends StorybookError { + readonly category = Category.BUILDER_WEBPACK5; + + readonly code = 1; + + private errorMessage = ''; + + constructor( + public data: { + error: + | (Error & { + error?: Error; + stats?: { compilation: { errors: Error[] } }; + compilation?: { errors: Error[] }; + }) + | { + compilation?: { errors: Error[] }; + }; + } + ) { + super(); + + if (data.error instanceof Error) { + if (data.error.error) { + this.errorMessage = data.error.error.message; + this.stack = data.error.error.stack; + } else if (data.error.stats && data.error.stats.compilation.errors) { + data.error.stats.compilation.errors.forEach((e: Error) => { + this.errorMessage += `${e.name}: ${e.message}\n\n`; + }); + } else { + this.errorMessage = data.error.message; + } + } else if (data.error.compilation?.errors) { + data.error.compilation.errors.forEach((e: Error) => { + this.errorMessage += `${e.name}: ${e.message}\n\n`; + }); + } + } + + template() { + return this.errorMessage.trim(); + } +} diff --git a/code/lib/core-server/src/withTelemetry.ts b/code/lib/core-server/src/withTelemetry.ts index e07387d1a918..086ee991e5ec 100644 --- a/code/lib/core-server/src/withTelemetry.ts +++ b/code/lib/core-server/src/withTelemetry.ts @@ -5,7 +5,7 @@ import { telemetry, getPrecedingUpgrade, oneWayHash } from '@storybook/telemetry import type { EventType } from '@storybook/telemetry'; import { logger } from '@storybook/node-logger'; -export type TelemetryOptions = { +type TelemetryOptions = { cliOptions: CLIOptions; presetOptions?: Parameters[0]; printError?: (err: any) => void;