如何使用 Next.js、Ant Design、Less 和 TypeScript 配置 Storybook.js Webpack

How can I configure Storybook.js Webpack with Next.js, Ant Design, Less, and TypeScript

我正在尝试配置 Storybook 以使用 Next.js、Ant Design、Less 和 TypeScript。我已经按照我可能找到的所有教程进行操作,但没有任何效果。我将 post 我的配置和下面的错误...

我的 .storybook/main.js 看起来像:

const path = require('path');

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

我的 .storybook/next-preset.js 看起来像:

const path = require('path');

module.exports = {
  webpackFinal: async (baseConfig, options) => {
    // Modify or replace config. Mutating the original reference object can cause unexpected bugs.
    const { module = {} } = baseConfig;

    const newConfig = {
      ...baseConfig,
      module: {
        ...module,
        rules: [...(module.rules || [])],
      },
    };

    // TypeScript with Next.js
    newConfig.module.rules.push({
      test: /\.(ts|tsx)$/,
      include: [
        path.resolve(__dirname, '../components'),
        path.resolve(__dirname, '../stories'),
      ],
      use: [
        {
          loader: 'babel-loader',
          options: {
            presets: ['next/babel'],
            plugins: ['react-docgen'],
          },
        },
      ],
    });
    newConfig.resolve.extensions.push('.ts', '.tsx');

    // // SCSS
    // newConfig.module.rules.push({
    //   test: /\.(s*)css$/,
    //   loaders: ['style-loader', 'css-loader', 'sass-loader'],
    //   include: path.resolve(__dirname, '../styles/global.scss'),
    // });

    // Less
    newConfig.module.rules.push({
      test: /\.less$/,
      use: [
        'style-loader',
        'css-loader',
        {
          loader: 'less-loader',
          options: {
            javascriptEnabled: true,
          },
        },
      ],
      include: path.resolve(__dirname, '../assets/styles'),
    });

    //
    // CSS Modules
    // Many thanks to https://github.com/storybookjs/storybook/issues/6055#issuecomment-521046352
    //

    // First we prevent webpack from using Storybook CSS rules to process CSS modules
    newConfig.module.rules.find(
      (rule) => rule.test.toString() === '/\.css$/'
    ).exclude = /\.module\.css$/;

    // Then we tell webpack what to do with CSS modules
    newConfig.module.rules.push({
      test: /\.module\.css$/,
      include: [
        path.resolve(__dirname, '../common/components'),
        path.resolve(__dirname, '../common/layout'),
      ],
      use: [
        'style-loader',
        {
          loader: 'css-loader',
          options: {
            importLoaders: 1,
            modules: true,
          },
        },
      ],
    });

    return newConfig;
  },
};

我的 .storybook/preview.js 看起来像:

require('../assets/styles/antd.less');

export const parameters = {
  actions: { argTypesRegex: '^on[A-Z].*' },
};

我的 antd.less 文件如下所示:

@import '~antd/dist/antd.less';

@primary-color: red;

最后,我的 next.config.js 看起来像:

const withLess = require('@zeit/next-less');
const withCSS = require('@zeit/next-css');

module.exports = withCSS({
  cssModules: true,
  cssLoaderOptions: {
    importLoaders: 1,
    localIdentName: '[local]___[hash:base64:5]',
  },
  ...withLess({
    lessLoaderOptions: {
      javascriptEnabled: true,
    },
  }),
});

我在尝试 运行 Storybook 时遇到的错误是:

ERROR in ./assets/styles/antd.less (./node_modules/css-loader/dist/cjs.js!./node_modules/less-loader/dist/cjs.js??ref--11-2!./node_modules/style-loader/dist/cjs.js!./node_modules/css-loader/dist/cjs.js!./node_modules/less-loader/dist/cjs.js??ref--16-2!./assets/styles/antd.less)
Module build failed (from ./node_modules/less-loader/dist/cjs.js):


import api from "!../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js";
              ^
Unrecognised input
      in /assets/styles/antd.less (line 1, column 16)
 @ ./assets/styles/antd.less 2:12-284 9:17-24 13:7-14 45:20-27 47:4-60:5 49:6-59:7 50:38-45 56:26-33 58:21-28 68:15-22
 @ ./.storybook/preview.js
 @ ./.storybook/preview.js-generated-config-entry.js
 @ multi ./node_modules/@storybook/core/dist/server/common/polyfills.js ./node_modules/@storybook/core/dist/server/preview/globals.js ./.storybook/storybook-init-framework-entry.js ./node_modules/@storybook/addon-docs/dist/frameworks/common/config.js-generated-other-entry.js ./node_modules/@storybook/addon-docs/dist/frameworks/react/config.js-generated-other-entry.js ./node_modules/@storybook/addon-links/dist/preset/addDecorator.js-generated-other-entry.js ./node_modules/@storybook/addon-actions/dist/preset/addDecorator.js-generated-other-entry.js ./node_modules/@storybook/addon-actions/dist/preset/addArgs.js-generated-other-entry.js ./node_modules/@storybook/addon-backgrounds/dist/preset/defaultParameters.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

如有任何帮助,我们将不胜感激。如果我只是从 Storybook 配置中省略所有 Less 配置,我可以让 Storybook 工作,但是 none 我对 Ant Design 的自定义会通过。

编辑 1: 我的相关依赖项是:

"css-loader": "^5.0.1",
"less-loader": "^5.0.0",
"style-loader": "^2.0.0",
"ts-loader": "^8.0.10",
"typescript": "^4.0.5",
"@storybook/addon-actions": "^6.0.28",
"@storybook/addon-essentials": "^6.0.28",
"@storybook/addon-links": "^6.0.28",
"@storybook/preset-ant-design": "0.0.1",
"@storybook/react": "^6.0.28",
"less": "^3.12.2",
"next": "^9.5.5",
"@zeit/next-css": "^1.0.1",
"@zeit/next-less": "^1.0.1",
""antd": "^4.8.0",

编辑 2: 这是 link 到 GitHub repo,您应该可以通过 运行ning npm installnpm run storybook.

重现问题

我发现问题出在使用原始 less webpack 加载器配置上。但是删除它并不是让它工作的唯一方法。

以下是您必须执行的几个步骤:

  • 在添加你的之前删除原来的 less loader:
baseConfig.module.rules = baseConfig.module.rules.filter(
  f => f.test.toString() !== '/\.less$/'
);
  • 通过包含它们也可以减少 antd 个文件:
{
  test: /\.less$/,
  include: [
    /[\/]node_modules[\/].*antd/,
    // ...
  ],
}
  • 简而言之,这是您的最终配置:
const path = require('path');

module.exports = {
  webpackFinal: async (baseConfig, options) => {
    const { module = {} } = baseConfig;
    
    // Remove original less loader
    baseConfig.module.rules = baseConfig.module.rules.filter(
      f => f.test.toString() !== '/\.less$/'
    );

    const newConfig = {
      ...baseConfig,
      module: {
        ...module,
        rules: [...(module.rules || [])],
      },
    };
    
    // ...

    // Less
    newConfig.module.rules.push({
      test: /\.less$/,
      include: [
        // Include antd to rebuild
        /[\/]node_modules[\/].*antd/,
        path.resolve(__dirname, '../assets/styles'),
      ],
      use: [
        'style-loader',
        'css-loader',
        {
          loader: 'less-loader',
          options: {
            javascriptEnabled: true,
          },
        },
      ],
    });

    //...

    return newConfig;
  },
};