React Storybook SVG 无法在 'Document' 上执行 'createElement'
React Storybook SVG Failed to execute 'createElement' on 'Document'
我正在尝试将 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。
这是因为 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;
};
我得到它与
一起工作
...
module.exports = {
module: {
rules: [
{
test: /\.inline.svg$/,
loader: 'svg-react-loader'
}
]
}
}
在 Storybook 6 中,您必须像这样导入它:
import { ReactComponent as Border } from './images/border.inline.svg'
如果它也适用于您的版本,请尝试一下,因为这个问题是一年前的问题了。
Storybook V6 似乎更改了默认的 Webpack 配置。我发现上面的答案对我不起作用。
他们不再有 SVG 规则,因此对 SVG 的测试将出错或 return 返回未定义。
module.rules
上有一个 oneOf
规则,其中包含一个没有测试的加载程序作为最后一个规则:
{
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;
}
对我来说,这是因为我使用了错误的标签名称:
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;
我在 Content
标签内使用 TMDBLogo
标签时导入了 TMDBLogoImg
组件。
这是为我解决问题的另一种方法
import Border from './images/border.inline.svg'
然后在你的代码中
<img src={Border} alt="Border" className="w-25"/>
我正在尝试将 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。
这是因为 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;
};
我得到它与
一起工作...
module.exports = {
module: {
rules: [
{
test: /\.inline.svg$/,
loader: 'svg-react-loader'
}
]
}
}
在 Storybook 6 中,您必须像这样导入它:
import { ReactComponent as Border } from './images/border.inline.svg'
如果它也适用于您的版本,请尝试一下,因为这个问题是一年前的问题了。
Storybook V6 似乎更改了默认的 Webpack 配置。我发现上面的答案对我不起作用。
他们不再有 SVG 规则,因此对 SVG 的测试将出错或 return 返回未定义。
module.rules
上有一个 oneOf
规则,其中包含一个没有测试的加载程序作为最后一个规则:
{
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;
}
对我来说,这是因为我使用了错误的标签名称:
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;
我在 Content
标签内使用 TMDBLogo
标签时导入了 TMDBLogoImg
组件。
这是为我解决问题的另一种方法
import Border from './images/border.inline.svg'
然后在你的代码中
<img src={Border} alt="Border" className="w-25"/>