Storybook:无法使用@svgr/webpack 在 svg 文件上执行 'createElement'
Storybook: Failed to execute 'createElement' on svg files using @svgr/webpack
首先我的错误与描述的 . I'm using the @svgr/webpack 包将我的 .svg
文件导入为 React 组件的错误完全相同:
import Shop from './icons/shop.svg'
return <Shop />
它在我的应用程序上运行良好,但当我尝试在 Storybook 中执行相同操作时,出现此错误:
Failed to execute 'createElement' on 'Document': The tag name provided ('static/media/shop.61b51e05.svg') is not a valid name.
所以我将加载程序添加到我的 .storybook/main.js
文件中以扩展默认的 Storybook webpack 配置:
// ...
webpackFinal: async config => {
config.module.rules.push({
test: /\.svg$/,
enforce: 'pre',
loader: require.resolve('@svgr/webpack'),
});
错误仍然发生,所以我尝试按照 :
中的建议覆盖 .svg
文件的默认 Storybook 测试
const fileLoaderRule = config.module.rules.find(rule => { rule.test !== undefined ? rule.test.test('.svg') : '' });
fileLoaderRule.exclude = /\.svg$/;
但是我得到这个错误:
TypeError: Cannot set property 'exclude' of undefined
所以我决定对 rule.test
进行 console.log
并且奇怪的是,来自 Storybook 配置的唯一默认测试是这些:
{
test: /\.md$/,
...
}
{
test: /\.(js|mjs|jsx|ts|tsx)$/,
...
}
{
test: /\.js$/,
...
}
{
test: /\.(stories|story).mdx$/,
...
}
{
test: /\.mdx$/,
...
}
{
test: /\.(stories|story)\.[tj]sx?$/,
...
}
{
test: /\.(ts|tsx)$/,
...
}
如您所见,没有影响 .svg
文件的测试。那么有人知道为什么我的配置无法使用:
{
test: /\.svg$/,
enforce: 'pre',
loader: require.resolve('@svgr/webpack'),
}
我的故事书版本是 6.0.0-beta.3
。
您的 find
回调总是 return 秒 undefined
。将其更改为 return 正确的 bool:
const fileLoaderRule = config.module.rules.find(rule => rule.test && rule.test.test('.svg'));
无论如何,故事书的默认配置应该有一个图像规则:
/\.(svg|ico|jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/
。
所以你的代码(但有正确的查找回调)对我来说工作正常。
决赛 main.js
:
module.exports = {
stories: ['../src/**/*.stories.[tj]s'],
webpackFinal: config => {
// Default rule for images /\.(svg|ico|jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/
const fileLoaderRule = config.module.rules.find(rule => rule.test && rule.test.test('.svg'));
fileLoaderRule.exclude = /\.svg$/;
config.module.rules.push({
test: /\.svg$/,
enforce: 'pre',
loader: require.resolve('@svgr/webpack'),
});
return config;
}
};
像这样导入它:
import { ReactComponent as Shop } from './icons/shop.svg'
它正在将其转换为 React 组件,以便您可以将属性传递给它:
<Shop fill="tomato" {...args} />
由于我使用 webpack@4
,因此 @svgr/webpack@5
,我不得不使用 url-loader
。
module.exports = {
stories: ['../src/**/*.stories.@(ts|tsx|js|jsx)'],
webpackFinal: config => {
// remove svg from existing rule
const fileLoaderRule = config.module.rules.find(
(rule) => rule.test && rule.test.test('.svg')
)
fileLoaderRule.exclude = /\.svg$/
config.module.rules.push({
test: /\.svg$/,
use: ['@svgr/webpack', 'url-loader'],
})
return config
}
};
我尝试了这里写的所有方法,但总是报错:
TypeError: Cannot set property 'exclude' of undefined
最后,我安慰config.module.rules
,看到它的结构:需要的规则是config.module.rules[5].oneOf[2]
。所以我只是硬编码它:config.module.rules[5].oneOf[2] = ['@svgr/webpack']
.
我认为这是一个临时的肮脏解决方案,但它确实有效。希望有人指出如何使它更干净和防弹。
首先我的错误与描述的 .svg
文件导入为 React 组件的错误完全相同:
import Shop from './icons/shop.svg'
return <Shop />
它在我的应用程序上运行良好,但当我尝试在 Storybook 中执行相同操作时,出现此错误:
Failed to execute 'createElement' on 'Document': The tag name provided ('static/media/shop.61b51e05.svg') is not a valid name.
所以我将加载程序添加到我的 .storybook/main.js
文件中以扩展默认的 Storybook webpack 配置:
// ...
webpackFinal: async config => {
config.module.rules.push({
test: /\.svg$/,
enforce: 'pre',
loader: require.resolve('@svgr/webpack'),
});
错误仍然发生,所以我尝试按照
.svg
文件的默认 Storybook 测试
const fileLoaderRule = config.module.rules.find(rule => { rule.test !== undefined ? rule.test.test('.svg') : '' });
fileLoaderRule.exclude = /\.svg$/;
但是我得到这个错误:
TypeError: Cannot set property 'exclude' of undefined
所以我决定对 rule.test
进行 console.log
并且奇怪的是,来自 Storybook 配置的唯一默认测试是这些:
{
test: /\.md$/,
...
}
{
test: /\.(js|mjs|jsx|ts|tsx)$/,
...
}
{
test: /\.js$/,
...
}
{
test: /\.(stories|story).mdx$/,
...
}
{
test: /\.mdx$/,
...
}
{
test: /\.(stories|story)\.[tj]sx?$/,
...
}
{
test: /\.(ts|tsx)$/,
...
}
如您所见,没有影响 .svg
文件的测试。那么有人知道为什么我的配置无法使用:
{
test: /\.svg$/,
enforce: 'pre',
loader: require.resolve('@svgr/webpack'),
}
我的故事书版本是 6.0.0-beta.3
。
您的 find
回调总是 return 秒 undefined
。将其更改为 return 正确的 bool:
const fileLoaderRule = config.module.rules.find(rule => rule.test && rule.test.test('.svg'));
无论如何,故事书的默认配置应该有一个图像规则:
/\.(svg|ico|jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/
。
所以你的代码(但有正确的查找回调)对我来说工作正常。
决赛 main.js
:
module.exports = {
stories: ['../src/**/*.stories.[tj]s'],
webpackFinal: config => {
// Default rule for images /\.(svg|ico|jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/
const fileLoaderRule = config.module.rules.find(rule => rule.test && rule.test.test('.svg'));
fileLoaderRule.exclude = /\.svg$/;
config.module.rules.push({
test: /\.svg$/,
enforce: 'pre',
loader: require.resolve('@svgr/webpack'),
});
return config;
}
};
像这样导入它:
import { ReactComponent as Shop } from './icons/shop.svg'
它正在将其转换为 React 组件,以便您可以将属性传递给它:
<Shop fill="tomato" {...args} />
由于我使用 webpack@4
,因此 @svgr/webpack@5
,我不得不使用 url-loader
。
module.exports = {
stories: ['../src/**/*.stories.@(ts|tsx|js|jsx)'],
webpackFinal: config => {
// remove svg from existing rule
const fileLoaderRule = config.module.rules.find(
(rule) => rule.test && rule.test.test('.svg')
)
fileLoaderRule.exclude = /\.svg$/
config.module.rules.push({
test: /\.svg$/,
use: ['@svgr/webpack', 'url-loader'],
})
return config
}
};
我尝试了这里写的所有方法,但总是报错:
TypeError: Cannot set property 'exclude' of undefined
最后,我安慰config.module.rules
,看到它的结构:需要的规则是config.module.rules[5].oneOf[2]
。所以我只是硬编码它:config.module.rules[5].oneOf[2] = ['@svgr/webpack']
.
我认为这是一个临时的肮脏解决方案,但它确实有效。希望有人指出如何使它更干净和防弹。