在故事书 v6.4 中加载 css 模块 类 时出现问题

issue loading css module classes in storybook v6.4

我无法让故事书与我的 Gatsby 项目中的 css 模块配合使用。我能够呈现按钮组件,但它不会添加我的任何样式。在检查元素时,我只从以下代码中得到 undefined undefined

button.jsx

import React from "react"
import * as css from "./style.module.css"

const Button = ({ variant = "button", type, value = null }) => {
  const baseOfVariant = () => {
    if (variant === "input") {
      return (
        <input
          type={type}
          value={value}
          className={`${css.button} ${css.clear_button}`}
        />
      )
    }
    return (
      <button type={type} className={`${css.button} ${css.submit_button}`}>
        {value}
      </button>
    )
  }
  return baseOfVariant()
}

export default Button

button.stories.jsx

import React from "react"
import Button from "./button"

export default {
  title: "Button",
  component: Button,
}

export const Template = args => <Button {...args} />

export const ButtonRegular = Template.bind({})
ButtonRegular.args = {
  variant: "button",
  value: "Click Me",
  type: "submit",
}

main.js

module.exports = {
  stories: ["../src/**/*.stories.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
  addons: ["@storybook/addon-links", "@storybook/addon-essentials"],
  core: {
    builder: "webpack5",
  },
}

我的 devDeps 中的故事书内容

"devDependencies": {
    "@babel/core": "^7.14.6",
    "@babel/polyfill": "^7.12.1",
    "@storybook/addon-actions": "^6.4.0-alpha.2",
    "@storybook/addon-essentials": "^6.4.0-alpha.2",
    "@storybook/addon-links": "^6.4.0-alpha.2",
    "@storybook/addon-viewport": "^6.4.0-alpha.2",
    "@storybook/builder-webpack5": "^6.4.0-alpha.2",
    "@storybook/manager-webpack5": "^6.4.0-alpha.2",
    "@storybook/react": "^6.4.0-alpha.2",
    "babel-loader": "^8.2.2",
    "prettier": "2.2.1",
    "resize-observer-polyfill": "^1.5.1"
  }

Gatsby 需要使用以下语法导入 css 个模块:

import * as css from "./style.module.css"

其中 Storybook 仅识别此语法:

import css from "./style.module.css"

这是因为 Gatsby 和 Storybook 不使用相同的导入约定。幸运的是,您可以通过 .storybook/main.js 文件配置 Storybook css 模块导入机制。

const path = require("path")

module.exports = {
  // You will want to change this to wherever your Stories will live
  stories: ["../src/**/*.stories.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
  addons: ["@storybook/addon-links", "@storybook/addon-essentials"],
  core: {
    builder: "webpack5",
  },
  webpackFinal: async config => {
    // Prevent webpack from using Storybook CSS rules to process CSS modules
    config.module.rules.find(
      rule => rule.test.toString() === "/\.css$/"
    ).exclude = /\.module\.css$/

    // Tell webpack what to do with CSS modules
    config.module.rules.push({
      test: /\.module\.css$/,
      include: path.resolve(__dirname, "../src"),
      use: [
        {
          loader: "style-loader",
          options: {
            modules: {
              namedExport: true,
            },
          },
        },
        {
          loader: "css-loader",
          options: {
            importLoaders: 1,
            modules: {
              namedExport: true,
            },
          },
        },
      ],
    })
    // Transpile Gatsby module because Gatsby includes un-transpiled ES6 code.
    config.module.rules[0].exclude = [/node_modules\/(?!(gatsby)\/)/]
    // use babel-plugin-remove-graphql-queries to remove static queries from components when rendering in storybook
    config.module.rules[0].use[0].options.plugins.push(
      require.resolve("babel-plugin-remove-graphql-queries")
    )
    return config
  },
}

通过上述配置,Storybook 现在接受此导入语法并且 button.jsx 的样式正确。

import * as css from "./style.module.css"

如果有人正在寻找 sass/scss 相关修复程序

import * as style from "./style.module.scss"

其中 Storybook 仅识别此语法:

你的 .storybook/main.js 文件。

 const path = require("path");
    
    module.exports = {
        stories: ["../src/**/*.stories.{js,mdx}"],
        addons: [
            "@storybook/addon-docs",
            "@storybook/addon-actions",
            "@storybook/addon-controls",
            "@storybook/addon-a11y",
            "@storybook/addon-viewport",
        ],
        // https://gist.github.com/shilman/8856ea1786dcd247139b47b270912324
        core: {
            builder: "webpack5",
        },
        webpackFinal: async config => {
            // https://www.gatsbyjs.com/docs/how-to/testing/visual-testing-with-storybook/
            config.module.rules.push({
                test: /\.(js)$/,
                use: [
                    {
                        loader: require.resolve("babel-loader"),
                        options: {
                            presets: [
                                // use @babel/preset-react for JSX and env (instead of staged presets)
                                require.resolve("@babel/preset-react"),
                                require.resolve("@babel/preset-env"),
                            ],
                            plugins: [
                                // use @babel/plugin-proposal-class-properties for class arrow functions
                                require.resolve("@babel/plugin-proposal-class-properties"),
                                // use babel-plugin-remove-graphql-queries to remove static queries from components when rendering in storybook
                                require.resolve("babel-plugin-remove-graphql-queries"),
                                // use babel-plugin-react-docgen to ensure PropTables still appear
                                require.resolve("babel-plugin-react-docgen"),
                            ],
                        },
                    },
                ],
                exclude: [/node_modules\/(?!(gatsby)\/)/],
            });
    
            config.module.rules.push({
                test: /\.s[ac]ss$/i,
                oneOf: [
                    // module.scss files (e.g component styles.module.scss)
                    // https://webpack.js.org/loaders/style-loader/#modules
                    {
                        test: /\.module\.s?css$/,
                        use: [
                            // Add exports of a module as style to DOM
                            {
                                loader: "style-loader",
                                options: {
                                    esModule: true,
                                    modules: {
                                        namedExport: true,
                                    },
                                },
                            },
                            // Loads CSS file with resolved imports and returns CSS code
                            {
                                loader: "css-loader",
                                options: {
                                    esModule: true,
                                    modules: {
                                        namedExport: true,
                                    },
                                },
                            },
                            // Loads and compiles a SASS/SCSS file
                            {
                                loader: "sass-loader",
// only if you are using additional global variable
                                options: {
                                    additionalData: "@import 'src/styles/global.scss';",
                                    sassOptions: {
                                        includePaths: ["src/styles"],
                                    },
                                },
                            },
                        ],
                    },
                    // scss files that are not modules (e.g. custom.scss)
                    {
                        use: [
                            // Add exports of a module as style to DOM
                            "style-loader",
                            // Loads CSS file with resolved imports and returns CSS code
                            "css-loader",
                            // Loads and compiles a SASS/SCSS file
                            {
                                loader: "sass-loader",
// only if you are using additional global variable
                                options: {
                                    additionalData: "@import 'src/styles/global.scss';",
                                    sassOptions: {
                                        includePaths: ["src/styles"],
                                    },
                                },
                            },
                        ],
                    },
                ],
            });
    
            return config;
        },
    };

通过上述配置,Storybook 现在接受此导入语法并且 button.jsx 的样式正确。

import * as styles from "./style.module.scss"