Engineering

⌘K
  1. Home
  2. Docs
  3. Engineering
  4. React Progressive Web App...
  5. Storybook

Storybook

What is Storybook and Why do we Use It?

Storybook is UI to explore and design components in our project. Using it, developers can browse available components.

Frontend engineers can design components UI and behavior using Storybook, independently of the page or data source logic. This makes components easier to develop and test.

How to Use Storybook to Explore React Components

Lovia PWA project should have Storybook already set up. You can check this if the project has a .storybook/ folder. Launch Storybook by:

yarn storybook

Open http://localhost:6006/ . Now you can explore and play with components.

Adding/Editing Stories

Add or edit stories in src/stories/*.stories.tsx (in a project, these stories files can be anywhere)

Advanced: Setting Up Storybook

Storybook Tutorial videos

# Create an UmiJS project with antd
mkdir ant-storybook-v6
cd ant-storybook-v6
yarn create umi
# Choose app
# Choose antd + internationalization

# Add typescript, so storybook will detect it as TypeScript project instead of JavaScript project
yarn add --dev typescript

# Install storybook
npx sb init

# Start storybook
yarn storybook

Open http://localhost:6006/

Note: Storybook vs Bit.dev as component explorer? Bit seems to be more invasive, and opinionated while not entirely inline with what we want. Storybook is simpler to get started, can integrate with existing project, and has useful addons beyond just UI components.

Advanced: Storybook and Ant Design Pro

Due to how Ant Design Pro / UmiJS project is structured, the less-loader, and how Babel & webpack is configured, Storybook does not work out-of-the-box with Ant Design/Pro components.

TL;DR: Install package @storybook/preset-ant-design. Then modify .storybook/main.js like this:

const path = require('path');

module.exports = {
  stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
  addons: ['@storybook/addon-links', '@storybook/addon-essentials', '@storybook/preset-ant-design'],
  webpackFinal: async config => ({
    ...config,
    resolve: {
      ...config.resolve,
      alias: {
        ...config.resolve.alias,
        '@@': path.resolve(__dirname, '../src/.umi'),
      }
    }
  }),
};

References:

yarn add --dev @storybook/preset-ant-design

Then add the following to .storybook/main.js:

module.exports = {
  stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
  addons: ['@storybook/addon-links', '@storybook/addon-essentials', '@storybook/preset-ant-design'],
};

Problem:

When doing import { useIntl } from 'umi':


ERROR in ./node_modules/umi/dist/index.esm.js
Module not found: Error: Can't resolve '@@/core/umiExports' in '/home/ceefour/project/tmra/tmra-pwa/node_modules/umi/dist'
 @ ./node_modules/umi/dist/index.esm.js 2:0-35 2:0-35
 @ ./src/components/CampaignList/index.tsx
 @ ./src/stories/CampaignList.stories.tsx
 @ ./src sync ^\.(?:(?:^|\/|(?:(?:(?!(?:^|\/)\.).)*?)\/)(?!\.)(?=.)[^/]*?\.stories\.(js|jsx|ts|tsx))$
 @ ./.storybook/generated-stories-entry.js
 @ multi ./node_modules/@storybook/core-client/dist/esm/globals/polyfills.js ./node_modules/@storybook/core-client/dist/esm/globals/globals.js ./.storybook/storybook-init-framework-entry.js ./node_modules/@storybook/addon-docs/dist/esm/frameworks/common/config.js-generated-other-entry.js ./node_modules/@storybook/addon-docs/dist/esm/frameworks/react/config.js-generated-other-entry.js ./node_modules/@storybook/addon-links/dist/esm/preset/addDecorator.js-generated-other-entry.js ./node_modules/@storybook/addon-actions/dist/esm/preset/addDecorator.js-generated-other-entry.js ./node_modules/@storybook/addon-actions/dist/esm/preset/addArgs.js-generated-other-entry.js ./node_modules/@storybook/addon-backgrounds/dist/esm/preset/addDecorator.js-generated-other-entry.js ./node_modules/@storybook/addon-backgrounds/dist/esm/preset/addParameter.js-generated-other-entry.js ./node_modules/@storybook/addon-measure/dist/esm/preset/preview.js-generated-other-entry.js ./node_modules/storybook-addon-outline/dist/esm/preset/addDecorator.js-generated-other-entry.js ./.storybook/preview.js-generated-config-entry.js ./.storybook/generated-stories-entry.js (webpack)-hot-middleware/client.js?reload=true&quiet=false&noInfo=undefined

ERROR in chunk vendors~main [initial]
vendors~main.iframe.bundle.js
/home/ceefour/project/tmra/tmra-pwa/node_modules/umi/dist/index.esm.js
Cannot read property 'isProvided' of null
Child HtmlWebpackCompiler:
                          Asset      Size               Chunks  Chunk Names
    __child-HtmlWebpackPlugin_0  6.23 KiB  HtmlWebpackPlugin_0  HtmlWebpackPlugin_0
    Entrypoint HtmlWebpackPlugin_0 = __child-HtmlWebpackPlugin_0
    [./node_modules/html-webpack-plugin/lib/loader.js!./node_modules/@storybook/core-common/dist/cjs/templates/index.ejs] 1.98 KiB {HtmlWebpackPlugin_0} [built]
ModuleNotFoundError: Module not found: Error: Can't resolve '@@/core/umiExports' in '/home/ceefour/project/tmra/tmra-pwa/node_modules/umi/dist'
    at /home/ceefour/project/tmra/tmra-pwa/node_modules/webpack/lib/Compilation.js:925:10
    at /home/ceefour/project/tmra/tmra-pwa/node_modules/webpack/lib/NormalModuleFactory.js:401:22
    at /home/ceefour/project/tmra/tmra-pwa/node_modules/webpack/lib/NormalModuleFactory.js:130:21
    at /home/ceefour/project/tmra/tmra-pwa/node_modules/webpack/lib/NormalModuleFactory.js:224:22
    at /home/ceefour/project/tmra/tmra-pwa/node_modules/neo-async/async.js:2830:7
    at /home/ceefour/project/tmra/tmra-pwa/node_modules/neo-async/async.js:6877:13
    at /home/ceefour/project/tmra/tmra-pwa/node_modules/webpack/lib/NormalModuleFactory.js:214:25
    at /home/ceefour/project/tmra/tmra-pwa/node_modules/enhanced-resolve/lib/Resolver.js:213:14
    at /home/ceefour/project/tmra/tmra-pwa/node_modules/enhanced-resolve/lib/Resolver.js:285:5
    at eval (eval at create (/home/ceefour/project/tmra/tmra-pwa/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:15:1)
    at /home/ceefour/project/tmra/tmra-pwa/node_modules/enhanced-resolve/lib/UnsafeCachePlugin.js:44:7
    at /home/ceefour/project/tmra/tmra-pwa/node_modules/enhanced-resolve/lib/Resolver.js:285:5
    at eval (eval at create (/home/ceefour/project/tmra/tmra-pwa/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:15:1)
    at /home/ceefour/project/tmra/tmra-pwa/node_modules/enhanced-resolve/lib/Resolver.js:285:5
    at eval (eval at create (/home/ceefour/project/tmra/tmra-pwa/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:27:1)
    at /home/ceefour/project/tmra/tmra-pwa/node_modules/enhanced-resolve/lib/DescriptionFilePlugin.js:67:43
resolve '@@/core/umiExports' in '/home/ceefour/project/tmra/tmra-pwa/node_modules/umi/dist'
  Parsed request is a module
  using description file: /home/ceefour/project/tmra/tmra-pwa/node_modules/umi/package.json (relative path: ./dist)
    Field 'browser' doesn't contain a valid alias configuration
    resolve as module
      /home/ceefour/project/tmra/tmra-pwa/node_modules/umi/dist/node_modules doesn't exist or is not a directory
      /home/ceefour/project/tmra/tmra-pwa/node_modules/node_modules doesn't exist or is not a directory
      /home/ceefour/project/tmra/node_modules doesn't exist or is not a directory
      /home/ceefour/project/node_modules doesn't exist or is not a directory
      /home/ceefour/node_modules doesn't exist or is not a directory
      /home/node_modules doesn't exist or is not a directory
      /node_modules doesn't exist or is not a directory
      looking for modules in /home/ceefour/project/tmra/tmra-pwa/node_modules/umi/node_modules
        using description file: /home/ceefour/project/tmra/tmra-pwa/node_modules/umi/package.json (relative path: ./node_modules)
          Field 'browser' doesn't contain a valid alias configuration
      looking for modules in /home/ceefour/project/tmra/tmra-pwa/node_modules
        using description file: /home/ceefour/project/tmra/tmra-pwa/package.json (relative path: ./node_modules)
          Field 'browser' doesn't contain a valid alias configuration
          using description file: /home/ceefour/project/tmra/tmra-pwa/node_modules/umi/package.json (relative path: ./node_modules/@@/core/umiExports)
            no extension
              Field 'browser' doesn't contain a valid alias configuration
          using description file: /home/ceefour/project/tmra/tmra-pwa/package.json (relative path: ./node_modules/@@/core/umiExports)
            no extension
              Field 'browser' doesn't contain a valid alias configuration
              /home/ceefour/project/tmra/tmra-pwa/node_modules/umi/node_modules/@@/core/umiExports doesn't exist
            .mjs
              Field 'browser' doesn't contain a valid alias configuration
              /home/ceefour/project/tmra/tmra-pwa/node_modules/@@/core/umiExports doesn't exist

Clues:

Solution:

const path = require('path');

module.exports = {
  // ...
  webpackFinal: async config => ({
    ...config,
    resolve: {
      ...config.resolve,
      alias: {
        ...config.resolve.alias,
        '@@': path.resolve(__dirname, '../src/.umi'),
      }
    }
  }),
};

How can we help?

Leave a Reply

Your email address will not be published. Required fields are marked *