|
| 1 | ++++ |
| 2 | +title = "Aurelia 2 + Storybook + Vite" |
| 3 | +authors = ["Dwayne Charrington"] |
| 4 | +description = "We're excited to announce early support for Storybook in Aurelia 2. Learn how Storybook simplifies your development workflow." |
| 5 | +date = 2025-02-06T05:46:52+10:00 |
| 6 | +lastmod = 2025-02-06T05:46:52+10:00 |
| 7 | +tags = ["aurelia2", "vite", "storybook"] |
| 8 | ++++ |
| 9 | + |
| 10 | +Many of you in the Aurelia community have been asking for Storybook support in Aurelia 2 and while official integration with the Storybook team is still in the works, we've got you covered with a plugin that allows you to use Storybook with Aurelia 2 now. |
| 11 | + |
| 12 | +This early release version is a work in progress and we're looking for feedback from the community, but only currently supports the Vite bundler (Webpack support is coming soon). |
| 13 | + |
| 14 | +## What is Storybook? |
| 15 | + |
| 16 | +Storybook is a tool for building UI components and pages in isolation. It's a popular tool for building UI components and pages in isolation. |
| 17 | + |
| 18 | +## How to use Storybook with Aurelia 2 |
| 19 | + |
| 20 | +To use Storybook with Aurelia 2, you need to install the following packages: |
| 21 | + |
| 22 | +```bash |
| 23 | +npm install --save-dev @aurelia/storybook |
| 24 | +``` |
| 25 | + |
| 26 | + |
| 27 | +You'll also need to ensure you have the necessary Storybook dependencies. These might already be present in your Aurelia 2 project, but if not, install them: |
| 28 | + |
| 29 | +```bash |
| 30 | +npm install --save-dev @storybook/addons @storybook/core-events @storybook/builder-vite @storybook/core-common @storybook/preview-api @storybook/types |
| 31 | +``` |
| 32 | + |
| 33 | +### Configuration |
| 34 | + |
| 35 | +Next, we'll configure Storybook to work seamlessly with Aurelia 2 by creating a directory called `.storybook` in the root of your project and adding the following files: |
| 36 | + |
| 37 | +1. **`.storybook/main.ts`** |
| 38 | + |
| 39 | + Create or update your `.storybook/main.ts` file. This file tells Storybook how to build your stories and which addons to use. |
| 40 | + |
| 41 | + ```typescript |
| 42 | + import type { StorybookConfig } from '@storybook/core-common'; |
| 43 | + import { mergeConfig } from 'vite'; |
| 44 | + |
| 45 | + const config: StorybookConfig & { viteFinal?: (config: any, options: any) => any } = { |
| 46 | + stories: ['../src/stories/**/*.stories.@(ts|tsx|js|jsx|mdx)'], |
| 47 | + addons: [ |
| 48 | + // Optional but recommended addons: |
| 49 | + // '@storybook/addon-links', |
| 50 | + // '@storybook/addon-essentials', |
| 51 | + // '@storybook/addon-interactions' |
| 52 | + ], |
| 53 | + framework: { |
| 54 | + name: '@aurelia/storybook', |
| 55 | + options: {}, |
| 56 | + }, |
| 57 | + core: { |
| 58 | + builder: '@storybook/builder-vite', |
| 59 | + }, |
| 60 | + viteFinal: async (viteConfig) => { |
| 61 | + viteConfig.optimizeDeps = viteConfig.optimizeDeps || {}; |
| 62 | + viteConfig.optimizeDeps.exclude = viteConfig.optimizeDeps.exclude || []; |
| 63 | + if (!viteConfig.optimizeDeps.exclude.includes('@aurelia/runtime-html')) { |
| 64 | + viteConfig.optimizeDeps.exclude.push('@aurelia/runtime-html'); |
| 65 | + } |
| 66 | + return mergeConfig(viteConfig, { |
| 67 | + // ...any additional Vite configuration you might need |
| 68 | + }); |
| 69 | + }, |
| 70 | + }; |
| 71 | + |
| 72 | + export default config as any; |
| 73 | + ``` |
| 74 | + |
| 75 | +2. **`.storybook/preview.ts`** |
| 76 | + |
| 77 | + This file lets you customize the rendering environment for your stories. Create or update `.storybook/preview.ts` with the following: |
| 78 | + |
| 79 | + ```typescript |
| 80 | + // .storybook/preview.ts |
| 81 | + export { render, renderToCanvas } from '@aurelia/storybook'; |
| 82 | + ``` |
| 83 | + |
| 84 | + This imports the necessary rendering functions from the `@aurelia/storybook` plugin. |
| 85 | + |
| 86 | +3. **Add scripts to your package.json** |
| 87 | + |
| 88 | + Add the following scripts to your `package.json` file: |
| 89 | + |
| 90 | + ```json |
| 91 | + "storybook": "storybook dev -p 6006", |
| 92 | + "build-storybook": "storybook build" |
| 93 | + ``` |
| 94 | + |
| 95 | +### Writing Your First Story |
| 96 | + |
| 97 | +Now comes the fun part, writing stories for your Aurelia 2 components! Let's use a simple `HelloWorld` component as an example: |
| 98 | + |
| 99 | +```typescript |
| 100 | +// src/components/hello-world.ts |
| 101 | +import { customElement, bindable } from 'aurelia'; |
| 102 | +
|
| 103 | +@customElement({ |
| 104 | + name: 'hello-world', |
| 105 | + template: '<button click.trigger="increment()">${message} - Count: ${count}</button>', |
| 106 | +}) |
| 107 | +export class HelloWorld { |
| 108 | + @bindable message = 'Hello World'; |
| 109 | + |
| 110 | + count = 0; |
| 111 | + |
| 112 | + increment() { |
| 113 | + this.count++; |
| 114 | + } |
| 115 | +} |
| 116 | +``` |
| 117 | + |
| 118 | + |
| 119 | +Here's how you would create a story for this component: |
| 120 | + |
| 121 | +```typescript |
| 122 | +// src/stories/hello-world.stories.ts |
| 123 | +import { HelloWorld } from '../components/hello-world'; |
| 124 | +import { action } from '@storybook/addon-actions'; |
| 125 | +import { userEvent, within } from '@storybook/testing-library'; |
| 126 | +
|
| 127 | +const meta = { |
| 128 | + title: 'Components/HelloWorld', |
| 129 | + component: HelloWorld, |
| 130 | + render: (args) => ({ |
| 131 | + template: `<hello-world message.bind="message" on-increment.bind="onIncrement"></hello-world>`, |
| 132 | + }), |
| 133 | + argTypes: { |
| 134 | + message: { control: 'text' }, |
| 135 | + onIncrement: { action: 'increment' } |
| 136 | + } |
| 137 | +}; |
| 138 | +
|
| 139 | +export default meta; |
| 140 | +
|
| 141 | +export const Default = { |
| 142 | + args: { |
| 143 | + message: "Hello from Storybook!", |
| 144 | + }, |
| 145 | +}; |
| 146 | +
|
| 147 | +export const Interactive = { |
| 148 | + args: { |
| 149 | + message: "Click the button!", |
| 150 | + }, |
| 151 | + play: async ({ canvasElement }) => { |
| 152 | + const canvas = within(canvasElement); |
| 153 | + const button = canvas.getByRole('button'); |
| 154 | + await userEvent.click(button); |
| 155 | + await userEvent.click(button); |
| 156 | + await userEvent.click(button); |
| 157 | + } |
| 158 | +}; |
| 159 | +``` |
| 160 | + |
| 161 | +In this story: |
| 162 | + |
| 163 | +- We define the component we're showcasing (`HelloWorld`). |
| 164 | +- We use `argTypes` to enable controls for the `message` prop in the Storybook UI. |
| 165 | +- We create a `Default` story with a basic message. |
| 166 | +- We create an `Interactive` story that uses the `play` function to simulate user interactions (clicking the button). |
| 167 | + |
| 168 | +### Running Storybook |
| 169 | + |
| 170 | +With your stories in place, start Storybook with: |
| 171 | + |
| 172 | +```bash |
| 173 | +npm run storybook |
| 174 | +``` |
| 175 | + |
| 176 | +This will launch Storybook in your browser, where you can interact with your `HelloWorld` component and see it in action! |
| 177 | + |
| 178 | +## Examples |
| 179 | + |
| 180 | +You can find examples of Storybook stories for Aurelia 2 components in the [Aurelia Storybook repository](https://github.com/aurelia/storybook) in the `apps` directory which showcases how to use the new plugin. |
| 181 | +## Contributing and Feedback |
| 182 | + |
| 183 | +This is an early release, and we're eager to hear your feedback! Please report any issues or suggestions on the project's GitHub repository. We're also open to contributions, so feel free to submit pull requests. The repository is available at [https://github.com/aurelia/storybook](https://github.com/aurelia/storybook). |
| 184 | + |
| 185 | +## Acknowledgements |
| 186 | + |
| 187 | +A special thanks to Dmitry (@ekzobrain on GitHub) for his pioneering work on Storybook support for earlier versions of Storybook, which laid some of the groundwork for this implementation. |
| 188 | + |
| 189 | +## Conclusion |
| 190 | + |
| 191 | +We're incredibly excited about this integration and believe it will significantly enhance your Aurelia 2 development workflow. Give it a try, experiment with your components, and let us know what you think! We're committed to making this integration even better as Aurelia 2 matures. |
| 192 | + |
| 193 | + |
0 commit comments