React-redux-starter-kit: Webpack config use with React-Storybook?

Created on 10 Aug 2016  路  4Comments  路  Source: davezuko/react-redux-starter-kit

React-Storybook obviously doesn't work by default with the starter kit due to the webpack builds.

However, after setting up the webpack file inside my .storybook directory and making it es5-friendly:

.storybook/webpack.config.js:

require('babel-register')
module.exports = require('./webpack.config.babel.js')

.storybook/webpack.config.babel.js:

// contents of build/webpack.config.js

I get this error with the default Counter css module:
screen shot 2016-08-09 at 21 02 50

As well as this error:

ERROR in ./src/components/Counter/Counter.scss
Module parse failed: src/components/Counter/Counter.scss Unexpected token (1:0)
You may need an appropriate loader to handle this file type.

Apologies if this is actually more of a webpack problem than a starter kit problem, but I'm sure it'll help others if the use with storybook is clarified.

I can also imagine there are some base stylesheets as well which should go in a storybook config. I can find them eventually but it would be very nice if we could gather a storybook workflow here.

Most helpful comment

Building on Jeff's config above, I also had to add the ExtractTextPlugin to plugin, and config.rules to be able to import stylesheets.

[Updated 8-27-17] Also added devtool to get sourcemaps for debugging.

// .storybook/webpack.config.js
require('babel-register')

const config = require('../build/webpack.config.js')

module.exports = {
  plugins: config.plugins.filter(
    (plugin) => ['DefinePlugin', 'ProvidePlugin', 'ExtractTextPlugin'].includes(plugin.constructor.name)
  ),
  devtool: 'source-map',
  resolve: config.resolve,
  module: {
    loaders: config.module.loaders,
    rules: config.module.rules
  }
}

I also needed access to the Redux store in my stories. In most cases you won't need the store if you're writing stories for dumb components but I use redux-form which uses Redux for even the simplest form component.

I was also able to incorporate the redux store using this guide and the createStore method provided in store/createStore.js in place of configureStore that is referenced: https://medium.com/ingenious/storybook-meets-redux-6ab09a5be346

Finally, I was able to import the core stylesheet used in my app into each story with the following line

import 'styles/main.scss'

So a simple story for a LoginForm component which uses redux-form and thus redux, looks something like this:

// stories/LoginForm.js
import React from 'react'
import Provider from './Provider'
import { storiesOf } from '@storybook/react'
import { action } from '@storybook/addon-actions'
import LoginForm from 'components/LoginForm'
import 'styles/main.scss'

storiesOf('LoginForm', module)
  .addDecorator(story => <Provider story={story()} />)
  .add('basic', () => (
    <LoginForm
      onSubmit={action('submit')}
    />
  ))
  .add('locked', () => (
    <LoginForm locked />
  ))

Hope this helps

All 4 comments

After doing some searching, I found a fork of this starter kit that includes storybook. They selectively use only the loaders and sassResources in the default webpack config:

require('babel-register');
let mainWebpackConfig = require('../build/webpack.config.js').default;

module.exports = (storybookBaseConfig, configType) => {
  storybookBaseConfig.module.loaders = mainWebpackConfig.module.loaders;
  storybookBaseConfig.sassResources = mainWebpackConfig.sassResources;
  return storybookBaseConfig;
};

Seems to be working fine with this configuration.

Leaving this open in case there are any additional thoughts.

Would it be considered in-scope of this project to provide React Storybook by default? It's very useful, and I'm sure it'd reduce duplication of effort as we start new projects.

I wound up getting this to work via:

// .storybook/webpack.config.js
require('babel-register')

const config = require('../build/webpack.config.js').default

module.exports = {
  plugins: config.plugins.filter(
    (plugin) => ['DefinePlugin', 'ProvidePlugin'].includes(plugin.constructor.name)
  ),
  resolve: config.resolve,
  module: {
    loaders: config.module.loaders
  }
}
  • plugins: The DefinePlugin and ProvidePlugin inject globals which would otherwise not be found.
  • resolve: This tells webpack which paths to check when importing. This fixed issues where it couldn't find certain directories like static or lib.
  • module.loaders: This tells webpack how to handle loading certain file types.

Building on Jeff's config above, I also had to add the ExtractTextPlugin to plugin, and config.rules to be able to import stylesheets.

[Updated 8-27-17] Also added devtool to get sourcemaps for debugging.

// .storybook/webpack.config.js
require('babel-register')

const config = require('../build/webpack.config.js')

module.exports = {
  plugins: config.plugins.filter(
    (plugin) => ['DefinePlugin', 'ProvidePlugin', 'ExtractTextPlugin'].includes(plugin.constructor.name)
  ),
  devtool: 'source-map',
  resolve: config.resolve,
  module: {
    loaders: config.module.loaders,
    rules: config.module.rules
  }
}

I also needed access to the Redux store in my stories. In most cases you won't need the store if you're writing stories for dumb components but I use redux-form which uses Redux for even the simplest form component.

I was also able to incorporate the redux store using this guide and the createStore method provided in store/createStore.js in place of configureStore that is referenced: https://medium.com/ingenious/storybook-meets-redux-6ab09a5be346

Finally, I was able to import the core stylesheet used in my app into each story with the following line

import 'styles/main.scss'

So a simple story for a LoginForm component which uses redux-form and thus redux, looks something like this:

// stories/LoginForm.js
import React from 'react'
import Provider from './Provider'
import { storiesOf } from '@storybook/react'
import { action } from '@storybook/addon-actions'
import LoginForm from 'components/LoginForm'
import 'styles/main.scss'

storiesOf('LoginForm', module)
  .addDecorator(story => <Provider story={story()} />)
  .add('basic', () => (
    <LoginForm
      onSubmit={action('submit')}
    />
  ))
  .add('locked', () => (
    <LoginForm locked />
  ))

Hope this helps

Was this page helpful?
0 / 5 - 0 ratings

Related issues

renanvalentin picture renanvalentin  路  5Comments

ciokan picture ciokan  路  4Comments

liubko picture liubko  路  4Comments

marcelloromanelli picture marcelloromanelli  路  5Comments

nickgnd picture nickgnd  路  4Comments