How to configure Webpack and Vite for Storybook
Storybook allows you to customize the webpack
configuration and your vite
configuration. For that, it offers two fields you can add in your .storybook/main.js|ts
file, called webpackFinal
and viteFinal
. These fields are functions that take the default configuration as an argument, and return the modified configuration. You can read more about them in the Storybook documentation for webpack
and the Storybook documentation for vite
.
You can use these fields in your Nx workspace Storybook configurations normally, following the Storybook docs. However, let's see how you can create a global configuration for every project in your workspace, and how you can override it for specific projects.
Global configuration
If you want to add a global configuration for Webpack or Vite in your workspace, you may create a .storybook/main.js
file at the root of your workspace. In that root .storybook/main.js|ts
file, you can add the webpackFinal
or viteFinal
field, and return the modified configuration. This will be applied to every project in your workspace.
webpack
and webpackFinal
The webpackFinal
field would look like this:
1webpackFinal: async (config, { configType }) => {
2 // Make whatever fine-grained changes you need that should apply to all storybook configs
3
4 // Return the altered config
5 return config;
6},
7
vite
and viteFinal
The viteFinal
field would look like this:
1async viteFinal(config, { configType }) {
2 if (configType === 'DEVELOPMENT') {
3 // Your development configuration goes here
4 }
5 if (configType === 'PRODUCTION') {
6 // Your production configuration goes here.
7 }
8 return mergeConfig(config, {
9 // Your environment configuration here
10 });
11 },
12
In the viteFinal
case, you would have to import the mergeConfig
function from vite
. So, on the top of your root .storybook/main.js|ts
file, you would have to add:
1import { mergeConfig } from 'vite';
2
Project-specific configuration
webpack
and webpackFinal
You can customize the webpack
configuration for a specific project by adding a webpackFinal
field in your project-specific .storybok/main.js|ts
file, like this:
1import type { StorybookConfig } from '@storybook/react-webpack5';
2
3const config: StorybookConfig = {
4 stories: ...,
5 addons: ...,
6 framework: {
7 name: '@storybook/react-webpack5',
8 options: {},
9 },
10 webpackFinal: async (config, { configType }) => {
11 // add your own webpack tweaks if needed
12 return config;
13 },
14};
15
16export default config;
17
If you are using a global, root-level, webpack
configuration in your project, you can customize or extend that for a specific project like this:
1import rootMain from '../../../.storybook/main';
2
3const config: StorybookConfig = {
4 ...rootMain,
5 stories: ...,
6 addons: ...,
7 framework: {
8 name: '@storybook/react-webpack5',
9 options: {},
10 },
11 webpackFinal: async (config, { configType }) => {
12 // apply any global webpack configs that might have been specified in .storybook/main.js
13 if (rootMain.webpackFinal) {
14 config = await rootMain.webpackFinal(config, { configType });
15 }
16 // add your own webpack tweaks if needed
17 return config;
18 },
19};
20
21export default config;
22
Take note how, in this case, we are first applying the global webpack
configuration, and then adding our own tweaks. If you don't want to apply any global configuration, you can just return your own configuration, and skip the rootMain.webpackFinal
check.
vite
and viteFinal
You can customize the vite
configuration for a specific project by adding a viteFinal
field in your project-specific .storybok/main.js|ts
file, like this:
1import type { StorybookConfig } from '@storybook/react-vite';
2import { mergeConfig } from 'vite';
3
4const config: StorybookConfig = {
5 stories: ...,
6 addons: ...,
7 framework: {
8 name: '@storybook/react-vite',
9 options: {
10 builder: {
11 viteConfigPath: 'apps/web/vite.config.ts',
12 },
13 },
14 },
15 async viteFinal(config, { configType }) {
16 return mergeConfig(config, {
17 ... <your config here>
18 });
19 },
20};
21
22export default config;
23
If you are using a global, root-level, vite
configuration in your workspace, you can customize or extend that for a specific project like this:
1import type { StorybookConfig } from '@storybook/react-vite';
2import { mergeConfig } from 'vite';
3import rootMain from '../../../.storybook/main';
4
5const config: StorybookConfig = {
6 ...rootMain,
7 stories: ...,
8 addons: ...,
9 framework: {
10 name: '@storybook/react-vite',
11 options: {
12 builder: {
13 viteConfigPath: 'apps/web/vite.config.ts',
14 },
15 },
16 },
17 async viteFinal(config, { configType }) {
18 return mergeConfig(config, {
19 ...((await rootMain.viteFinal(config, { configType })) ?? {})
20 });
21 },
22};
23
24export default config;
25