Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using svgr with webpack 5 #551

Closed
vyachsed opened this issue Apr 14, 2021 · 26 comments
Closed

Using svgr with webpack 5 #551

vyachsed opened this issue Apr 14, 2021 · 26 comments

Comments

@vyachsed
Copy link

vyachsed commented Apr 14, 2021

Hi! I am using two kinds of imports in my application, like: import starUrl from './star.svg' and import { ReactComponent as Star } from './star.svg'
This works well if using file-loader. But in webpack 5 the file-loader, raw-loader, raw-loader is deprecated. Now we need to use asset-modules (https://webpack.js.org/guides/asset-modules/). I tried to use all kinds, but nothing worked for me.

@open-collective-bot
Copy link

Hey @vyachsed 👋,
Thank you for opening an issue. We'll get back to you as soon as we can.
Please, consider supporting us on Open Collective. We give a special attention to issues opened by backers.
If you use SVGR at work, you can also ask your company to sponsor us ❤️.

@vyachsed vyachsed reopened this Apr 15, 2021
@feRpicoral
Copy link

feRpicoral commented Apr 15, 2021

UPDATE: My problem is actually webpack config related, not SVGR's nor NextJS'.

I'm also having problems with SVGR and Webpack5. I'm using NextJS and when enabling Webpack5, I get the following error:

ValidationError: Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
 - configuration[0].module.rules[3].issuer has an unknown property 'test'. These properties are valid:
   object { and?, not?, or? }
 - configuration[1].module.rules[3].issuer has an unknown property 'test'. These properties are valid:
   object { and?, not?, or? }

configuration[0].modules.rules[3] is the following:

{
  test: /\.svg$/,
  issuer: { test: /\.(js|ts|jsx|tsx)x?$/ },
  use: [ '@svgr/webpack' ]
}

When removing the issuer it does work.

I tried changin

 issuer: { 
    test: '/\\.(js|ts|jsx|tsx)x?$/'
 }

to

issuer: {
    and: [ '/\\.(js|ts|jsx|tsx)x?$/' ]
 }

which resulted in no compile errors but SVGR wasn't working.

@ssbb
Copy link

ssbb commented Apr 17, 2021

@feRpicoral I believe you can use just issuer: /\.(js|ts)x?$/

@jahirfiquitiva
Copy link

I got it working but it's showing this:

<w> [webpack.cache.PackFileCacheStrategy/webpack.FileSystemInfo] Resolving '@babel/core/lib/config/validation/option-assertions' in /Users/jahir/dev/jahir/synaptiko/fe/node_modules/@babel/plugin-proposal-object-rest-spread/node_modules/@babel/core/lib/config/validation for build dependencies doesn't lead to expected result '/Users/jahir/dev/jahir/synaptiko/fe/node_modules/@babel/plugin-proposal-object-rest-spread/node_modules/@babel/core/lib/config/validation/option-assertions.js', but to '/Users/jahir/dev/jahir/synaptiko/fe/node_modules/@babel/plugin-proposal-object-rest-spread/node_modules/@babel/core/node_modules/@babel/core/lib/config/validation/option-assertions.js' instead. Resolving dependencies are ignored for this path.
<w>  at unknown 4 @babel/core/lib/config/validation/option-assertions
<w>  at file dependencies /Users/jahir/dev/jahir/synaptiko/fe/node_modules/@babel/plugin-proposal-object-rest-spread/node_modules/@babel/core/lib/config/validation/options.js
<w>  at file /Users/jahir/dev/jahir/synaptiko/fe/node_modules/@babel/plugin-proposal-object-rest-spread/node_modules/@babel/core/lib/config/validation/options.js
<w>  at file dependencies /Users/jahir/dev/jahir/synaptiko/fe/node_modules/@babel/plugin-proposal-object-rest-spread/node_modules/@babel/core/lib/config/partial.js
<w>  at file /Users/jahir/dev/jahir/synaptiko/fe/node_modules/@babel/plugin-proposal-object-rest-spread/node_modules/@babel/core/lib/config/partial.js
<w>  at file dependencies /Users/jahir/dev/jahir/synaptiko/fe/node_modules/@babel/plugin-proposal-object-rest-spread/node_modules/@babel/core/lib/config/index.js
<w>  at file /Users/jahir/dev/jahir/synaptiko/fe/node_modules/@babel/plugin-proposal-object-rest-spread/node_modules/@babel/core/lib/config/index.js
<w>  at file dependencies /Users/jahir/dev/jahir/synaptiko/fe/node_modules/@babel/plugin-proposal-object-rest-spread/node_modules/@babel/core/lib/transform-file.js
<w>  at file /Users/jahir/dev/jahir/synaptiko/fe/node_modules/@babel/plugin-proposal-object-rest-spread/node_modules/@babel/core/lib/transform-file.js
<w>  at file dependencies /Users/jahir/dev/jahir/synaptiko/fe/node_modules/@babel/plugin-proposal-object-rest-spread/node_modules/@babel/core/lib/index.js
<w>  at file /Users/jahir/dev/jahir/synaptiko/fe/node_modules/@babel/plugin-proposal-object-rest-spread/node_modules/@babel/core/lib/index.js
<w>  at file dependencies /Users/jahir/dev/jahir/synaptiko/fe/node_modules/@babel/plugin-proposal-object-rest-spread/lib/index.js
<w>  at file /Users/jahir/dev/jahir/synaptiko/fe/node_modules/@babel/plugin-proposal-object-rest-spread/lib/index.js
<w>  at file dependencies /Users/jahir/dev/jahir/synaptiko/fe/node_modules/workbox-build/node_modules/@babel/preset-env/lib/available-plugins.js
<w>  at file /Users/jahir/dev/jahir/synaptiko/fe/node_modules/workbox-build/node_modules/@babel/preset-env/lib/available-plugins.js
<w>  at file dependencies /Users/jahir/dev/jahir/synaptiko/fe/node_modules/workbox-build/node_modules/@babel/preset-env/lib/index.js
<w>  at file /Users/jahir/dev/jahir/synaptiko/fe/node_modules/workbox-build/node_modules/@babel/preset-env/lib/index.js
<w>  at file dependencies /Users/jahir/dev/jahir/synaptiko/fe/node_modules/workbox-build/build/lib/bundle.js
<w>  at file /Users/jahir/dev/jahir/synaptiko/fe/node_modules/workbox-build/build/lib/bundle.js
<w>  at file dependencies /Users/jahir/dev/jahir/synaptiko/fe/node_modules/workbox-webpack-plugin/build/generate-sw.js
<w>  at file /Users/jahir/dev/jahir/synaptiko/fe/node_modules/workbox-webpack-plugin/build/generate-sw.js
<w>  at file dependencies /Users/jahir/dev/jahir/synaptiko/fe/node_modules/workbox-webpack-plugin/build/index.js
<w>  at file /Users/jahir/dev/jahir/synaptiko/fe/node_modules/workbox-webpack-plugin/build/index.js
<w>  at file dependencies /Users/jahir/dev/jahir/synaptiko/fe/node_modules/next-pwa/index.js
<w>  at file /Users/jahir/dev/jahir/synaptiko/fe/node_modules/next-pwa/index.js
<w>  at file dependencies /Users/jahir/dev/jahir/synaptiko/fe/next.config.js
<w>  at file /Users/jahir/dev/jahir/synaptiko/fe/next.config.js
<w>  at resolve commonjs /Users/jahir/dev/jahir/synaptiko/fe/next.config.js

@gauravkrp
Copy link

gauravkrp commented May 10, 2021

I'm also facing this issue
image

@JonasBa
Copy link

JonasBa commented May 12, 2021

I took a peek at how docusaurus does this in their config and I made it compile w/o errors using the following config:

const config = {
  future: {
    webpack5: true,
  },
  webpack(config, options) {
    config.module.rules.push({
      test: /\.svg?$/,
      oneOf: [
        {
          use: [
            {
              loader: '@svgr/webpack',
              options: {
                prettier: false,
                svgo: true,
                svgoConfig: {
                  plugins: [{removeViewBox: false}],
                },
                titleProp: true,
              },
            },
          ],
          issuer: {
            and: [/\.(ts|tsx|js|jsx|md|mdx)$/],
          },
        },
      ],
    })

    return config
  },
}

Hope it helps 🙏🏼

@Perni1984
Copy link

Perni1984 commented May 18, 2021

@JonasBa for me the viewbox attribute is still stripped from my svgs despite removeViewBox: false - can you confirm the options passed to svgo works in your case?

Edit: The option works, it was my fault as I didn't have proper camelCase naming for the viewBox attribute as mentioned in svg/svgo#505 (comment)

@meetajhu
Copy link

meetajhu commented May 27, 2021

If you are trying to handle both css/scss also need svgr component, import using file-loader(Webpack 4) aka AssetModule(assets/resource in Weback5) try something like this

{
          test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,          
          oneOf: [
            {
              type: "asset/resource",
              generator: { //remove this if not required
                filename: "static/media/images/[name][ext]",
              },
              issuer: {//Only use file-loader aka assets/resource for svg's referenced in css/scss
                and: [/\.(sa|sc|c)ss$/],
              },
            },
          ],
        },
        {//use SVGR for imports in js/jsx files
          test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
          oneOf: [
            {
              use: [
                'babel-loader',
                {
                  loader: '@svgr/webpack',
                  options: {
                    babel: false,
                    icon: true,
                  },
                }
              ],
              issuer: {
                and: [/\.(js|jsx)$/],
              },
            },
          ],
        },

Then you import like this js/jsx

import starUrl from './star.svg'

@gupta-ji6
Copy link

@JonasBa you're a life savior, thank you for sharing this 🙏🏻🙏🏻🙏🏻

@marella
Copy link

marella commented Jun 17, 2021

I made a small loader new-url-loader that provides the functionality of both url-loader and file-loader using asset modules. For example, you can replace url-loader using:

{
  test: /\.svg$/,
- use: ['@svgr/webpack', 'url-loader'],
+ oneOf: [
+   {
+     dependency: { not: ['url'] },
+     use: ['@svgr/webpack', 'new-url-loader'],
+   },
+   {
+     type: 'asset', // Use 'asset/resource' for file-loader
+   },
+ ],
}

Now you can continue to use both the URL and React component:

import starUrl, { ReactComponent as Star } from './star.svg';

See README for more info. I also created a minimal example.

@njerschow
Copy link

I tried the solution mentioned by @JonasBa but I'm still getting

TypeError: unsupported file type: undefined (file: undefined) about my SVG images, is anyone else getting this as well or is this an svgr related problem?

@getahead-dev
Copy link

@njerschow fixed with this vercel/next.js#26130 (comment)

@privateOmega
Copy link

privateOmega commented Jun 20, 2021

Anyone still looking for a fix, its not that file-loader still can't be used along with webpack5, it just needs some additional modification. Try the following out. type: "javascript/auto" part specifies not to use the asset resources step and allows us to use file-loader, url-loader or any of the other loaders to attain the same.

{
                test: /\.svg$/,
                use: [
                    {
                        loader: "@svgr/webpack"
                    },
                    {
                        loader: "file-loader"
                    }
                ],
                type: "javascript/auto",
                issuer: {
                    and: [/\.(ts|tsx|js|jsx|md|mdx)$/]
                }
            },

@mapreal19
Copy link

@privateOmega thank you, this is what worked for me.

@allpwrfulroot
Copy link

This posted solution worked for me, sharing here to maybe save someone some time: https://stackoverflow.com/questions/61498644/storybook-failed-to-execute-createelement-on-svg-files-using-svgr-webpack

@levymetal
Copy link

Note that issuer is not respected when importing via require.context. See: webpack/webpack#9309. To get around this, you can leverage oneOf in your webpack config and define the rules for asset modules before @svgr/webpack. oneOf uses the first set of rules that match, which allows you to omit issuer on the last set.

I'm unclear whether type: 'javascript/auto' is necessary here as the assets matched by the final rule shouldn't be getting processed by asset modules. I get the exact same behaviour with & without it, YMMV.

{
  test: /\.svg$/,
  oneOf: [
    {
      issuer: /\.s?css$/,
      type: 'asset/resource',
    },
    {
      use: [
        {
          loader: '@svgr/webpack',
          options: {
            svgoConfig: {
              plugins: [{removeViewBox: false}],
            },
          },
        },
        {
          loader: 'file-loader',
        },
      ],
      type: 'javascript/auto',
    },
  ],
},

@renyuns
Copy link

renyuns commented Jul 30, 2021

I made a small loader new-url-loader that provides the functionality of both url-loader and file-loader using asset modules. For example, you can replace url-loader using:

{
  test: /\.svg$/,
- use: ['@svgr/webpack', 'url-loader'],
+ oneOf: [
+   {
+     dependency: { not: ['url'] },
+     use: ['@svgr/webpack', 'new-url-loader'],
+   },
+   {
+     type: 'asset', // Use 'asset/resource' for file-loader
+   },
+ ],
}

Now you can continue to use both the URL and React component:

import starUrl, { ReactComponent as Star } from './star.svg';

See README for more info. I also created a minimal example.

tks 👍👍👍

@zhimng
Copy link

zhimng commented Aug 16, 2021

I took a peek at how docusaurus does this in their config and I made it compile w/o errors using the following config:

const config = {
  future: {
    webpack5: true,
  },
  webpack(config, options) {
    config.module.rules.push({
      test: /\.svg?$/,
      oneOf: [
        {
          use: [
            {
              loader: '@svgr/webpack',
              options: {
                prettier: false,
                svgo: true,
                svgoConfig: {
                  plugins: [{removeViewBox: false}],
                },
                titleProp: true,
              },
            },
          ],
          issuer: {
            and: [/\.(ts|tsx|js|jsx|md|mdx)$/],
          },
        },
      ],
    })

    return config
  },
}

Hope it helps 🙏🏼

This works, and I think the documentation on issuer should be updated, otherwise it's really confusing.

@todorpr
Copy link

todorpr commented Sep 2, 2021

I was struggling to load a sprite SVG using this syntax:

import { ReactComponent as Sprite } from './sprite.svg'

function App() {
  return (
    <>
      <Sprite
        style={{
          position: 'absolute',
          width: 0,
          height: 0,
          overflow: 'hidden'
        }}
      />
      <div className="App">
      ...

Nothing from this thread worked. What did the trick was this config:

    {
        test: /\.svg$/,
        use: [
          {
            loader: '@svgr/webpack',
            options: {
              prettier: false,
              svgo: false,
              svgoConfig: {
                plugins: [{ removeViewBox: false }]
              },
              titleProp: true,
              ref: true
            }
          },
          {
            loader: 'file-loader',
            options: {
              name: 'static/media/[name].[hash].[ext]'
            }
          }
        ],
        issuer: {
          and: [/\.(ts|tsx|js|jsx|md|mdx)$/]
        }
      }

Got this config from React script's webpack config

@gregberge
Copy link
Owner

OK guys, I think we have a webpack bug here. Isn't it? Anything SVGR can do as a workaround?

@nikhilnayyar2
Copy link

nikhilnayyar2 commented Sep 14, 2021

@levymetal thanks. I have modified your answer.

Lets say we have a react.svg file of size more than 200KB.

Webpack config:

            {
                test: /\.svg$/,
                oneOf: [
                    {
                        issuer: /\.[jt]sx?$/,
                        resourceQuery: /react/, // *.svg?react
                        use: ['@svgr/webpack']
                    },
                    {
                        type: 'asset',
                        parser: {
                            dataUrlCondition: {
                                maxSize: 200
                            }
                        }
                    },
                ],
            },

In your react component:

import "@styles/index.css";

import React, { useState } from 'react';
import ReactDOM from 'react-dom';
import svg from '@assets/react.svg';
import Svg from '@assets/react.svg?react';

function App() {
    return (
        <div>
            <img src={svg} width="200" height="200" />
            <div id="css-svg-sample"></div>
            <Svg  width="200" height="200" viewBox="0 0 3500 3500"/>
        </div>
    )
}

ReactDOM.render(
    <React.StrictMode>
        <App />
    </React.StrictMode>,
    document.getElementById('root')
);

css file:

#css-svg-sample {
  background-image: url(@assets/react.svg);
  background-size: contain;
  width: 200px;
  height: 200px;
}

Since our react.svg file > 200KB, webpack output 1 file only. That single file is referenced by webpack in css background-image property and img src attribute.

Here is the demo: https://github.com/nikhilnayyar002/react-min

References:
https://webpack.js.org/configuration/module/#ruleoneof
https://react-svgr.com/docs/webpack/#handle-svg-in-css-sass-or-less

No need to add file-loader & url-loader!

@birdofpreyru
Copy link

If you use babel-loader you can use my babel-preset-svgr to let Babel handle it.

@ywroh
Copy link

ywroh commented Nov 19, 2021

@privateOmega fixed with this gregberge/svgr/issues/551 (comment)

oh thank @privateOmega so much I struggled all day yesterday, but I solved it with the code you gave me. thank you!.

@gregberge
Copy link
Owner

Part of new documentation.

@SuperOleg39
Copy link

Somebody knows workaround for typescript?

import Svg from '@assets/react.svg?react'; - looks like it is impossible to create declaration file for this pattern

@SuperOleg39
Copy link

Sorry, it was code editor typings resolution problems.
Simple pattern like *.svg?svgr works:

declare module '*.svg?svgr' {
  import type { ComponentType, SVGProps } from 'react';

  type SvgComponent = ComponentType<SVGProps>;

  const Svg: SvgComponent;

  export = Svg;
}

JoeDravarol added a commit to JoeDravarol/dine-restaurant that referenced this issue Feb 14, 2023
Fixing Typescript "Cannot find module" for svg assets:
[svgr d.ts](gregberge/svgr#551 (comment))
JoeDravarol added a commit to JoeDravarol/dine-restaurant that referenced this issue Feb 14, 2023
* fix: remove lineHeight whitespace

* feat: mobile about

* feat: tablet about

Fixing Typescript "Cannot find module" for svg assets:
[svgr d.ts](gregberge/svgr#551 (comment))

* feat: desktop about
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests