Skip to content

Commit

Permalink
refactor code based on review comments
Browse files Browse the repository at this point in the history
  • Loading branch information
yannbf committed Aug 15, 2023
1 parent 8343357 commit 2df20ed
Show file tree
Hide file tree
Showing 18 changed files with 189 additions and 215 deletions.
48 changes: 29 additions & 19 deletions code/lib/core-events/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,31 +20,24 @@
},
"license": "MIT",
"sideEffects": false,
"typesVersions": {
"*": {
"*": [
"dist/index.d.ts"
],
"client-errors": [
"dist/errors/client-errors.d.ts"
],
"server-errors": [
"dist/errors/server-errors.d.ts"
]
}
},
"exports": {
".": {
"types": "./dist/index.d.ts",
"node": "./dist/index.js",
"require": "./dist/index.js",
"import": "./dist/index.mjs"
},
"./client-errors": {
"types": "./dist/errors/client-errors.d.ts",
"node": "./dist/errors/client-errors.js",
"require": "./dist/errors/client-errors.js",
"import": "./dist/errors/client-errors.mjs"
"./preview-errors": {
"types": "./dist/errors/preview-errors.d.ts",
"node": "./dist/errors/preview-errors.js",
"require": "./dist/errors/preview-errors.js",
"import": "./dist/errors/preview-errors.mjs"
},
"./manager-errors": {
"types": "./dist/errors/manager-errors.d.ts",
"node": "./dist/errors/manager-errors.js",
"require": "./dist/errors/manager-errors.js",
"import": "./dist/errors/manager-errors.mjs"
},
"./server-errors": {
"types": "./dist/errors/server-errors.d.ts",
Expand All @@ -57,6 +50,22 @@
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"typesVersions": {
"*": {
"*": [
"dist/index.d.ts"
],
"preview-errors": [
"dist/errors/preview-errors.d.ts"
],
"manager-errors": [
"dist/errors/manager-errors.d.ts"
],
"server-errors": [
"dist/errors/server-errors.d.ts"
]
}
},
"files": [
"dist/**/*",
"README.md",
Expand All @@ -79,7 +88,8 @@
"bundler": {
"entries": [
"./src/index.ts",
"./src/errors/client-errors.ts",
"./src/errors/preview-errors.ts",
"./src/errors/manager-errors.ts",
"./src/errors/server-errors.ts"
]
},
Expand Down
67 changes: 24 additions & 43 deletions code/lib/core-events/src/errors/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,43 +4,22 @@ Storybook provides a utility to manage errors thrown from it. Each error is cate

Storybook errors reside in this package and are categorized into:

1. **[Client errors](./client-errors.ts)**
- Errors which occur in the browser
- e.g. Rendering issues, addons, Storybook UI, etc.
- available in `@storybook/core-events/client-errors`
2. **[Server errors](./server-errors.ts)**
- Any Errors that happen in node
1. **[Preview errors](./preview-errors.ts)**
- Errors which occur in the preview part of Storybook
- e.g. Rendering issues, etc.
- available in `@storybook/core-events/preview-errors`
2. **[Manager errors](./manager-errors.ts)**
- Errors which occur
- e.g. Sidebar, addons, Storybook UI, Storybook router, etc.
- available in `@storybook/core-events/server-errors`
3. **[Server errors](./server-errors.ts)**
- Errorr which occur in node
- e.g. Storybook init command, dev command, builder errors (Webpack, Vite), etc.
- available in `@storybook/core-events/server-errors`

## When NOT to use categorized errors

If your code throws an error just so it gets handled elsewhere in the codebase, meaning it's not user facing, you may not need to use this framework. For instance:

```ts
const doAnAction = () => {
if(works) {
doSomething();
} else {
throw new Error('do the backup action instead!');
}
}

const doWork = () => {
try {
doAnAction();
} catch() {
// All good. The error is handled.
doABackupAction();
}
}
```

In this code, the error will never reach the user. You may either disable the eslint plugin rule for that line of code, or use a [HandledError implementation like done here](https://github.com/storybookjs/storybook/blob/next/code/lib/cli/src/HandledError.ts).

## How to create errors

First, find which file your error should be part of, based on the criteria above.
First, **find which file your error should be part of**, based on the criteria above.
Second use the `StorybookError` class to define custom errors with specific codes and categories for use within the Storybook codebase. Below is a detailed documentation for the error properties:

### Class Structure
Expand All @@ -60,13 +39,14 @@ export class YourCustomError extends StorybookError {

### Properties

| Name | Type | Description |
| ------------- | ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| category | `Category` | The category to which the error belongs. |
| code | `number` | The numeric code for the error. |
| template | `(...data: any[]) => string` | A properly written error message or a function that takes data arguments and returns an error, for dynamic messages. |
| documentation | `boolean` or `string` | Optional. Should be set to `true` **if the error is documented on the Storybook website**. If defined as string, it should be a custom documentation link. |
| telemetry | `boolean` | Optional. If set to `true`, telemetry will be used to send errors. **Only for client based errors**. |
| Name | Type | Description |
| ------------- | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| category | `Category` | The category to which the error belongs. |
| code | `number` | The numeric code for the error. |
| template | `() => string` | Function that returns a properly written error message. |
| data | `Object` | Optional. Data associated with the error. Used to provide additional information in the error message or to be passed to telemetry. |
| documentation | `boolean` or `string` | Optional. Should be set to `true` **if the error is documented on the Storybook website**. If defined as string, it should be a custom documentation link. |
| telemetry | `boolean` | Optional. If set to `true`, telemetry will be used to send errors. |

## Usage Example

Expand All @@ -89,13 +69,14 @@ export class InvalidFileExtensionError extends StorybookError {
telemetry = true;
documentation = 'https://some-custom-documentation.com/validation-errors';

// extra properties are defined in the constructor and available in any class method
constructor(extension: string) {
// extra properties are defined in the constructor via a data property, which is available in any class method
// always use this data Object notation!
constructor(public data: { extension: string }) {
super();
}

template(): string {
return `Invalid file extension found: ${extension}.`;
return `Invalid file extension found: ${this.data.extension}.`;
}
}

Expand All @@ -108,7 +89,7 @@ import {
throw StorybookIndexGenerationError();
// "SB_Generic_0001: Storybook failed when generating an index for your stories. Check the stories field in your main.js.

throw InvalidFileExtensionError('mtsx');
throw InvalidFileExtensionError({ extension: 'mtsx' });
// "SB_Validation_0002: Invalid file extension found: mtsx. More info: https://some-custom-documentation.com/validation-errors"
```

Expand Down
84 changes: 0 additions & 84 deletions code/lib/core-events/src/errors/client-errors.ts

This file was deleted.

32 changes: 32 additions & 0 deletions code/lib/core-events/src/errors/manager-errors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { StorybookError } from './storybook-error';

/**
* If you can't find a suitable category for your error, create one
* based on the package name/file path of which the error is thrown.
* For instance:
* If it's from @storybook/client-logger, then MANAGER_CLIENT-LOGGER
*
* Categories are prefixed by a logical grouping, e.g. MANAGER_
* to prevent manager and preview errors from having the same category and error code.
*/
export enum Category {
MANAGER_UI = 'MANAGER_UI',
MANAGER_API = 'MANAGER_API',
MANAGER_CLIENT_LOGGER = 'MANAGER_CLIENT-LOGGER',
MANAGER_CHANNELS = 'MANAGER_CHANNELS',
MANAGER_CORE_EVENTS = 'MANAGER_CORE-EVENTS',
MANAGER_ROUTER = 'MANAGER_ROUTER',
MANAGER_THEMING = 'MANAGER_THEMING',
}

export class ProviderDoesNotExtendBaseProviderError extends StorybookError {
readonly category = Category.MANAGER_UI;

readonly code = 1;

readonly telemetry = true;

template() {
return `The Provider passed into Storybook's UI is not extended from the base Provider. Please check your Provider implementation.`;
}
}
70 changes: 70 additions & 0 deletions code/lib/core-events/src/errors/preview-errors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import dedent from 'ts-dedent';
import { StorybookError } from './storybook-error';

/**
* If you can't find a suitable category for your error, create one
* based on the package name/file path of which the error is thrown.
* For instance:
* If it's from @storybook/client-logger, then CLIENT-LOGGER
*
* Categories are prefixed by a logical grouping, e.g. PREVIEW_ or FRAMEWORK_
* to prevent manager and preview errors from having the same category and error code.
*/
export enum Category {
PREVIEW_CLIENT_LOGGER = 'PREVIEW_CLIENT-LOGGER',
PREVIEW_CHANNELS = 'PREVIEW_CHANNELS',
PREVIEW_CORE_EVENTS = 'PREVIEW_CORE-EVENTS',
PREVIEW_INSTRUMENTER = 'PREVIEW_INSTRUMENTER',
PREVIEW_API = 'PREVIEW_API',
PREVIEW_REACT_DOM_SHIM = 'PREVIEW_REACT-DOM-SHIM',
PREVIEW_ROUTER = 'PREVIEW_ROUTER',
PREVIEW_THEMING = 'PREVIEW_THEMING',
FRAMEWORK_ANGULAR = 'FRAMEWORK_ANGULAR',
FRAMEWORK_EMBER = 'FRAMEWORK_EMBER',
FRAMEWORK_HTML_VITE = 'FRAMEWORK_HTML-VITE',
FRAMEWORK_HTML_WEBPACK5 = 'FRAMEWORK_HTML-WEBPACK5',
FRAMEWORK_NEXTJS = 'FRAMEWORK_NEXTJS',
FRAMEWORK_PREACT_VITE = 'FRAMEWORK_PREACT-VITE',
FRAMEWORK_PREACT_WEBPACK5 = 'FRAMEWORK_PREACT-WEBPACK5',
FRAMEWORK_REACT_VITE = 'FRAMEWORK_REACT-VITE',
FRAMEWORK_REACT_WEBPACK5 = 'FRAMEWORK_REACT-WEBPACK5',
FRAMEWORK_SERVER_WEBPACK5 = 'FRAMEWORK_SERVER-WEBPACK5',
FRAMEWORK_SVELTE_VITE = 'FRAMEWORK_SVELTE-VITE',
FRAMEWORK_SVELTE_WEBPACK5 = 'FRAMEWORK_SVELTE-WEBPACK5',
FRAMEWORK_SVELTEKIT = 'FRAMEWORK_SVELTEKIT',
FRAMEWORK_VUE_VITE = 'FRAMEWORK_VUE-VITE',
FRAMEWORK_VUE_WEBPACK5 = 'FRAMEWORK_VUE-WEBPACK5',
FRAMEWORK_VUE3_VITE = 'FRAMEWORK_VUE3-VITE',
FRAMEWORK_VUE3_WEBPACK5 = 'FRAMEWORK_VUE3-WEBPACK5',
FRAMEWORK_WEB_COMPONENTS_VITE = 'FRAMEWORK_WEB-COMPONENTS-VITE',
FRAMEWORK_WEB_COMPONENTS_WEBPACK5 = 'FRAMEWORK_WEB-COMPONENTS-WEBPACK5',
RENDERER_HTML = 'RENDERER_HTML',
RENDERER_PREACT = 'RENDERER_PREACT',
RENDERER_REACT = 'RENDERER_REACT',
RENDERER_SERVER = 'RENDERER_SERVER',
RENDERER_SVELTE = 'RENDERER_SVELTE',
RENDERER_VUE = 'RENDERER_VUE',
RENDERER_VUE3 = 'RENDERER_VUE3',
RENDERER_WEB_COMPONENTS = 'RENDERER_WEB-COMPONENTS',
}

export class MissingStoryAfterHmrError extends StorybookError {
readonly category = Category.PREVIEW_API;

readonly code = 1;

readonly telemetry = true;

constructor(public data: { storyId: string }) {
super();
}

template() {
return dedent`Couldn't find story matching id '${this.data.storyId}' after HMR.
- Did you just rename a story?
- Did you remove it from your CSF file?
- Are you sure a story with the id '${this.data.storyId}' exists?
- Please check the values in the stories field of your main.js config and see if they would match your CSF File.
- Also check the browser console and terminal for potential error messages.`;
}
}
1 change: 1 addition & 0 deletions code/lib/core-events/src/errors/server-errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export enum Category {
CORE_SERVER = 'CORE-SERVER',
CSF_PLUGIN = 'CSF-PLUGIN',
CSF_TOOLS = 'CSF-TOOLS',
CORE_COMMON = 'CORE-COMMON',
NODE_LOGGER = 'NODE-LOGGER',
TELEMETRY = 'TELEMETRY',
BUILDER_MANAGER = 'BUILDER-MANAGER',
Expand Down

0 comments on commit 2df20ed

Please sign in to comment.