React Storybook SVG无法在“文档”上执行“ createElement”

时间:2019-01-21 15:04:06

标签: reactjs webpack storybook

我正在尝试将Storybook添加到现有的React应用中,但是导入的svg文件出现错误。 svg的导入和使用方式如下:

import Border from './images/border.inline.svg'
...
<Border className="card__border" />

在运行和构建应用程序时,此方法有效,但在Storybook中出现错误。怎么会来?


Failed to execute 'createElement' on 'Document': The tag name provided ('static/media/border.inline.258eb86a.svg') is not a valid name.
Error: Failed to execute 'createElement' on 'Document': The tag name provided ('static/media/border.inline.258eb86a.svg') is not a valid name.

默认的webpack.config.js具有:

  ...
  {
    test: /\.inline.svg$/,
    loader: 'svg-react-loader'
  },
  ...

此外,现有代码使用的是webpack 3,而我使用的是Storybook V4。

5 个答案:

答案 0 :(得分:2)

之所以会这样,是因为Storybook的default webpack config有自己的svg配置:

{ 
  test: /\.(svg|ico|jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|cur|ani)(\?.*)?$/,
  loader: 'file-loader',
  query: { name: 'static/media/[name].[hash:8].[ext]' }
},

我很确定这是原因,因为您可以看到错误消息中概述的路径:query: { name: 'static/media/[name].[hash:8].[ext]' } -> static/media/border.inline.258eb86a.svg

解决方案可以是找到现有的加载程序并更改/或向其中添加排除规则。这是自定义.storybook/webpack.config.js的示例:

// storybook 4
module.exports = (_, _, config) => {
// storybook 5
module.exports = ({ config }) => {
  const rules = config.module.rules;

  // modify storybook's file-loader rule to avoid conflicts with your inline svg
  const fileLoaderRule = rules.find(rule => rule.test.test('.svg'));
  fileLoaderRule.exclude = /\.inline.svg$/;

  rules.push({
    test: /\.inline.svg$/,
    ...
    }],
  });

  return config;
};

答案 1 :(得分:2)

看起来 Storybook V6 他们已经更改了默认的 webpack 配置。我发现上述答案对我不起作用。

他们不再有 SVG 规则,因此对 SVG 的测试要么出错,要么返回 undefined。

oneOf 上有一个 module.rules 规则,它包含一个没有测试的加载器作为最后一条规则:

{
      loader: '/Users/alexwiley/Work/OneUp/resources/client/node_modules/react-scripts/node_modules/file-loader/dist/cjs.js',
      exclude: [Array],
      options: [Object]
}

这是罪魁祸首,您需要确保文件加载排除所有内联SVG文件,否则会出错。

将以下内容添加到您的 .storybook/main.js file

webpackFinal: async(config, { configType }) => {
config.module.rules.forEach((rule) => {
  if (rule.oneOf) {
    // Iterate over the oneOf array and look for the file loader
    rule.oneOf.forEach((oneOfRule) => {
      if (oneOfRule.loader && oneOfRule.loader.test('file-loader')) {
        // Exclude the inline SVGs from the file loader
        oneOfRule.exclude.push(/\.inline\.svg$/);
      }
    })
    // Push your SVG loader onto the end of the oneOf array
    rule.oneOf.push({
      test: /\.inline\.svg$/,
      exclude: /node_modules/,
      loader: 'svg-react-loader', // use whatever SVG loader you need
    })
  }
});
return config;

}

答案 2 :(得分:2)

对我来说这是因为我使用了错误的标签名称:

import React from 'react';
import RMDBLogo from '../../images/react-movie-logo.svg';
import TMDBLogo from '../../images/tmdb_logo.svg';


import { Wrapper, Content,LogoImg,TMDBLogoImg } from './Header.styles';

const Header = () => (
    <Wrapper>
        <Content>
            <LogoImg src={RMDBLogo} alt='RMDBLogo' />
            <TMDBLogo src={TMDBLogo} alt='TMDBLogo'/>
        </Content>
    </Wrapper>
);

export default Header;

我在 TMDBLogoImg 标签内使用 TMDBLogo 标签时导入了 Content 组件。

答案 3 :(得分:0)

我可以和它一起工作

...
module.exports = {
  module: {
    rules: [
      {
        test: /\.inline.svg$/,
        loader: 'svg-react-loader'
      }
    ]
  }
}

答案 4 :(得分:0)

在Storybook 6中,您必须像这样导入它:

import { ReactComponent as Border } from './images/border.inline.svg'

请尝试一下,如果该问题也适用于您的版本,因为该问题来自一年前。