如何解决 Storybook 中的别名?

Posted

技术标签:

【中文标题】如何解决 Storybook 中的别名?【英文标题】:How to resolve aliases in Storybook? 【发布时间】:2021-06-01 07:42:52 【问题描述】:

我有一个带有 Storybook 的 React/Typescript 项目。 Storybook 很好用,但是一旦我开始导入带别名的文件,它就会崩溃。

例子:

import Foo from "@components/foo" => crash
import Foo from "../../components/foo" => ok

该应用可以正常使用别名。该问题仅与 Storybook 有关。

这是我的故事书配置:

module.exports = 
  stories: ["../**/stories.tsx"],
  webpackFinal: (config) => 
    return 
      ...config,
      module: 
        ...config.module,
        rules: [
          
            test: /\.(ts|js)x?$/,
            exclude: /node_modules/,
            use:  loader: "babel-loader" ,
          ,
           test: /\.css$/, use: ["style-loader", "css-loader"] ,
           test: /\.(png|jpg|gif)$/, use: ["file-loader"] ,
          
            test: /\.svg$/,
            use: [
              
                loader: "babel-loader",
              ,
              
                loader: "react-svg-loader",
                options: 
                  jsx: true,
                ,
              ,
            ],
          ,
        ],
      ,
    ;
  ,
  typescript: 
    check: false,
    checkOptions: ,
    reactDocgen: "react-docgen-typescript",
    reactDocgenTypescriptOptions: 
      shouldExtractLiteralValuesFromEnum: true,
      propFilter: (prop) =>
        prop.parent ? !/node_modules/.test(prop.parent.fileName) : true,
    ,
  ,
;

我的 webpack 配置:

/* eslint-env node */
const path = require("path");
const TerserPlugin = require("terser-webpack-plugin");
const Dotenv = require("dotenv-webpack");
const htmlWebpackPlugin = require("html-webpack-plugin");

const isProductionMode = (mode) => mode === "production";

module.exports = () => 
  const env = require("dotenv").config( path: __dirname + "/.env" );
  const nodeEnv = env.parsed.NODE_ENV;
  return 
    mode: "development",
    entry: "./src/index.tsx",
    output: 
      path: path.join(__dirname, "./dist"),
      filename: "[name].[contenthash].bundle.js",
      publicPath: "/",
    ,
    resolve: 
      extensions: [".ts", ".tsx", ".js", "jsx", ".json"],
      alias: 
    "@api": path.resolve(__dirname, "src/api/"),
    "@assets": path.resolve(__dirname, "src/assets/"),
    "@components": path.resolve(__dirname, "src/components/"),
    "@containers": path.resolve(__dirname, "src/containers/"),
    "@data": path.resolve(__dirname, "src/data/"),
    "@i18n": path.resolve(__dirname, "src/i18n/"),
    "@models": path.resolve(__dirname, "src/models/"),
    "@pages": path.resolve(__dirname, "src/pages/"),
    "@src": path.resolve(__dirname, "src/"),
    "@stores": path.resolve(__dirname, "src/stores/"),
    "@utils": path.resolve(__dirname, "src/utils/"),
  ,
    ,
    module: 
      rules: [
        
          test: /\.(ts|js)x?$/,
          exclude: /node_modules/,
          use:  loader: "babel-loader" ,
        ,
         test: /\.css$/, use: ["style-loader", "css-loader"] ,
         test: /\.(png|jpg|jpeg|gif)$/, use: ["file-loader"] ,
        
          test: /\.svg$/,
          use: [
            
              loader: "babel-loader",
            ,
            
              loader: "react-svg-loader",
              options: 
                jsx: true,
              ,
            ,
          ],
        ,
      ],
    ,
    devServer: 
      historyApiFallback: true,
      port: 3000,
      inline: true,
      hot: true,
    ,
    plugins: [
      new HtmlWebpackPlugin(
        template: "./src/index.html",
      ),
      new Dotenv(),
    ],
    optimization: 
      minimize: isProductionMode(nodeEnv),
      minimizer: isProductionMode(nodeEnv) ? [new TerserPlugin()] : [],
      splitChunks:  chunks: "all" ,
    ,
  ;
;

如何解决这个问题?我使用的是 webpack 5.24.2 和 storybook 6.1.20,所以这些是最新版本。

【问题讨论】:

您是否尝试过在故事书配置中重复您的别名?不是 100% 肯定,但我认为传递给 webpackFinalconfig 是故事书的默认配置,并且对您的其他 webpack 配置一无所知。您可以尝试在 webpackFinal 中使用 console.logging config 进行确认。编辑进一步审查看起来你可以导入和合并你现有的 webpack 配置:storybook.js.org/docs/react/configure/… 如果我用“resolve”添加别名,它会显示“configuration.module 有一个未知属性 'resolve'”。如果我像在官方文档中那样导入 webpack,它会说“无法读取未定义的模块” 两件事,resolve 位于 webpack 配置的顶层,而不是在 config.module 之下。不是 100% 确定 webpack 导出/导入问题,但请注意您的 webpack 配置导出是一个函数,而不是普通对象,因此您需要调用它并将该调用的输出与故事书默认值合并导入工作。 【参考方案1】:

只需将其添加到您的.storybook/main.js

const path = require('path');

module.exports = 
  "stories": [
    "../components/**/*.stories.mdx",
    "../components/**/*.stories.@(js|jsx|ts|tsx)"
  ],
  "addons": [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    '@storybook/preset-scss',
  ],
  webpackFinal: async (config,  configType ) => 
    config.resolve.alias = 
      ...config.resolve.alias,
      '@/interfaces': path.resolve(__dirname, "../interfaces"),
    ;

    return config;
  

这里interface 是我项目根目录下的文件夹

对我有用

【讨论】:

【参考方案2】:

如果您使用的是 webpack 5,则需要指定应使用 webpack5,方法是在之前的答案之外还添加以下内容:

  core: 
    builder: "webpack5",
  ,

最终的 storybook/main.js 将类似于:

    // .storybook/main.js
const path = require('path');
const appWebpack = require(path.join(process.cwd(), 'webpack.config.js'));
module.exports = 
  stories: ['../src/**/*.stories.@(tsx|mdx)'],
  addons: [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    '@storybook/preset-scss'
  ],
  core: 
    builder: "webpack5",
  ,
  webpackFinal: async (config) => 
    config.resolve.modules = [
      ...(config.resolve.modules || []),
      ...[path.resolve(process.cwd(), "src")],
    ];
    config.resolve.alias = 
      ...(config.resolve.alias || ),
      ...appWebpack().resolve.alias,
    ;
    return config;
  ,
;

这将允许绝对路径和别名(当然,只要这些别名在您的主 webpack.config.js 和 jsconfig.json/tsconfig.json 中正确设置)

已编辑

特别是在别名方面遇到了麻烦,我又在 webpack 坎坷的道路上走了一趟。

我已经更新了上面 .storybook/main.js 的原始“final”,明确地合并了别名和模块节点。

编辑 2

请注意,eslint 会在你创建的全局装饰器中使用别名(并添加到 .storybook/preview.js)。你可以放心地忽略这一点——它们仍然有效。如果/当我也想出如何纠正这个问题时,我会回来添加第三次编辑。

【讨论】:

【参考方案3】:

当我遇到同样的问题时,这对我有用:

在开发部门yarn add -D tsconfig-paths-webpack-plugin 中安装一个包。 然后调整您的./storybook/main.js 配置:
... // other imports
const TsconfigPathsPlugin = require("tsconfig-paths-webpack-plugin");

...
webpackFinal: (config) => 
  config.resolve.plugins = config.resolve.plugins || [];
  config.resolve.plugins.push(
    new TsconfigPathsPlugin(
      configFile: path.resolve(__dirname, "../tsconfig.json"),
    )
  );

  return  ... 

...

【讨论】:

以上是关于如何解决 Storybook 中的别名?的主要内容,如果未能解决你的问题,请参考以下文章

我该如何解决这个关于 Storybook 和 Sass 的问题?

使用 Storybook/vue 时别名不起作用

如何解决ORACLE中表一得列名的别名为另一表中的某一字段的值?

sql 语句多层嵌套查询 使用别名 字段无效,如何解决(有图)

如何映射枚举以选择 Storybook 中的下拉列表?

如何根据另一个参数的值有条件地禁用 Storybook 中的控件?