I'm building a component which loads SVG files. But when I use icon = import()
or icon = require()
, the value returned is a static-file-path instead of the content of the file.
this.prop.iconName = 'cart' (propType.oneOf)
const icon require(`../assets/svg/${iconName}.svg`)
console.log(icon)
Yields
static/media/cart.67bd7202.svg
The issue https://github.com/storybooks/storybook/issues/1776 is about a similar issue, except that I'm using the full control mode, and I did reset the server. I tried no custom loaders, svg-url-loader, url-loader and file-loader.
My current .storybook/webpack.config.js:
const path = require('path');
module.exports = (baseConfig, env, defaultConfig) => {
// Extend defaultConfig as you need.
// For example, add scss loader:
defaultConfig.module.rules.push({
test: /\.scss$/,
loaders: ['style-loader', 'css-loader', 'sass-loader'],
include: path.resolve(__dirname,'../')
});
defaultConfig.resolve.extensions.push('.scss');
// For example, add SVG loader:
defaultConfig.module.rules.push({
test: /\.svg$/,
loaders: ['svg-url-loader'],
include: path.resolve(__dirname,'../')
});
defaultConfig.resolve.extensions.push('.svg');
return defaultConfig;
};
Project webpack.config.js:
{
test: /\.svg$/,
use: [
{
loader: 'svg-url-loader',
options: {},
}
]
}
"webpack": "^4.27.1",
"webpack-cli": "^3.1.2",
"webpack-dev-server": "^3.1.14"
Command to run storybook locally: "start-storybook -p 9001 -s .storybook/static -c .storybook"
Can anyone help me in the right direction?
Okay, it took some time, but I was finally able to track down the problem.
I tried several loaders in a clean react app install without storybook, and found out that the loader I needed was "raw-loader" (I wanted the content of the file). The next problem was that I had already tried this loader in storybook and, like the others, it yielded the static file path instead of the content. I looked into various potential solutions, and at some point I stumbled on...:
require(`-!raw-loader!../assets/svg/${iconName}.svg`);
For anyone who doesn't know (I didn't), these are loader prefixes which allow you to override the order of the preloaders.
Problem is they're deprecated, but it did give a clear clue as to where to look next: storybook's default webpack config, which I'm extending using the "Full Control + default" mode. This config contains:
{
test: /\.(svg|ico|jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|cur|ani)(\?.*)?$/,
loader: '[long path]/file-loader/dist/cjs.js',
query: { name: 'static/media/[name].[hash:8].[ext]' }
}
I added a few lines to my .storybook/webpack.config.js
file, so it now looks like:
const path = require('path');
module.exports = (baseConfig, env, defaultConfig) => {
defaultConfig.module.rules.push({
test: /\.scss$/,
loaders: ['style-loader', 'css-loader', 'sass-loader'],
include: path.resolve(__dirname,'../')
});
defaultConfig.resolve.extensions.push('.scss');
defaultConfig.module.rules.push({
test: /\.svg$/,
loader: 'raw-loader',
include: path.resolve(__dirname,'../')
});
defaultConfig.resolve.extensions.push('.svg');
defaultConfig.module.rules.forEach(function(data, key) {
if (data.test.toString().indexOf('svg|') >= 0) {
defaultConfig.module.rules[key].test = /\.(ico|jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|cur|ani)(\?.*)?$/;
return false;
}
});
return defaultConfig;
};
Which technically resolves my problem. I like the fact that I can still use the default settings, but it's a pretty ugly hack. Not using the defaults feels even worse though... I have been unable to find clear instructions on how I'd build up all the necessary rules myself, and it feels like re-inventing the wheel.
Suggestions?
The same problem here with svg-inline-loader
. It worked well with v4.1.1. After v5.0.0 it returns a string (path to an svg file) instead of an svg tag.
{
test: /\.svg$/,
loader: 'svg-inline-loader',
},
What I found so far is that the loader is completely ignored by storybook in webpack extend mode.
Update: it is exactly what @VanDoornP says in a previous comment. Used the same hack for now.
The only thing that there is no 3rd argument in a module.exports function:
module.exports = (baseConfig, env, defaultConfig) => {...}
// should be
module.exports = ({ config }) => {
config.module.rules.push(...);
...
return config;
}
@shilman any eta on this thing? 馃槃
Played around with this today and came up with this partial workaround. Issue is still WIP: #5924
@shilman the weird thing is that this used to work with my webpack setup, (not full control) but it seems to just ignore my loaders now 馃槙seems like either something undocumented changed in the webpack api or something is broken..
pre-v5, this config worked for me without issue, post-v5 it doesn't do a thing, it just ignores it.
const path = require('path');
module.exports = {
module: {
rules: [
{
test: /\.scss$/,
loaders: ['style-loader', 'css-loader', 'sass-loader'],
include: path.resolve(__dirname, '../'),
},
{
test: /\.svg$/,
loader: 'svg-inline-loader',
},
{
test: /\.(ico|jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2)(\?.*)?$/,
loader: require.resolve('file-loader'),
query: {
name: 'static/media/[name].[hash:8].[ext]'
},
},
],
},
};
Looking at the docs, this should still be the correct way of using them but not a single rule seems to be used right now, it's not just the svg's that get frapped.
Boo-yah!! I just released https://github.com/storybooks/storybook/releases/tag/v5.1.0-alpha.7 containing PR #6104 that references this issue. Upgrade today to try it out!
Because it's a pre-release you can find it on the @next
NPM tag.
Closing this issue. Please re-open if you think there's still more to do.
@Pixelatex 5.1.0-alpha.7
should fix your problem since it restores 4.x "extend mode" webpack behavior. @VanDoornP has a slightly different problem since he's already using full-control mode. I'll patch it back into 5.0.x
once a few people have verified the fix. Please LMK!
Tested with svg-react-loader
and still get this error
Here is my webpack config
const path = require('path')
// Export a function. Accept the base config as the only param.
module.exports = async ({ config, mode }) => {
// `mode` has a value of 'DEVELOPMENT' or 'PRODUCTION'
// You can change the configuration based on that.
// 'PRODUCTION' is used when building the static version of storybook.
// Make whatever fine-grained changes you need
config.module.rules.push({
test: /\.scss$/,
loaders: [
'style-loader',
{
loader: 'css-loader',
options: { modules: true },
},
'sass-loader',
],
include: path.resolve(__dirname, '../'),
})
config.module.rules.push({
test: /\.svg$/,
include: path.resolve(__dirname, '../src/icons'),
exclude: /node_module/,
use: {
loader: 'svg-react-loader',
options: {
name: 'Icon'
}
}
})
// Return the altered config
return config
}
The component still render well when the development running with Gatsby, outside of Storybook.
@ng-hai You'll probably need to remove the existing svg loader and add yours in -- there's a conflict right now. You can look at the combined webpack config with the --debug-webpack
command-line option that was added in 5.0.2
It works @shilman, it works 馃槃
cc @elie222
I have the same error as @ng-hai , removing the existing SVG rules like @VanDoornP did solves that problem.
But now, another problem I have is that if I used babel with corejs 3 it will fail with missing polyfills. If I use corejs2 works just fine.
I think this should also be addressed because storybook does't specify the corejs version with babel and that also triggers an warning.
@radum Mind filing a separate issue about the corejs version?
@shilman Raised here #6294
I'm using @storybook/react 5.0.11 and found this config to work,
module.exports = async ({ config }) => {
config.resolve.extensions.push('.svg');
config.module.rules = config.module.rules.map( data => {
if (/svg\|/.test( String( data.test ) ))
data.test = /\.(ico|jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|cur|ani)(\?.*)?$/;
return data;
});
config.module.rules.push({
test: /\.svg$/,
use: [{ loader: require.resolve('babel-loader') },
{ loader: require.resolve('react-svg-loader') }]
});
return config;
};
FYI, just adding the following parts in .storybook/webpack.config.js
did the trick:
config.module.rules = config.module.rules.map( data => {
if (/svg\|/.test( String( data.test ) ))
data.test = /\.(ico|jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|cur|ani)(\?.*)?$/;
return data;
});
... and:
config.module.rules.push({
test: /\.svg$/,
use: [
{ loader: 'svg-inline-loader' }
]
});
=> I did not need to add .svg
in config.resolve.extensions
.
Thanks for your help!
Most helpful comment
FYI, just adding the following parts in
.storybook/webpack.config.js
did the trick:... and:
=> I did not need to add
.svg
inconfig.resolve.extensions
.Thanks for your help!