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

[turbopack] SVG via svgr support #4832

Closed
pkolt opened this issue May 5, 2023 · 22 comments
Closed

[turbopack] SVG via svgr support #4832

pkolt opened this issue May 5, 2023 · 22 comments
Labels
kind: bug Something isn't working needs: triage New issues get this label. Remove it after triage

Comments

@pkolt
Copy link

pkolt commented May 5, 2023

What version of Turborepo are you using?

next@13.4.1

What package manager are you using / does the bug impact?

npm

What operating system are you using?

Mac

Describe the Bug

In Next.js, I use the SVG image include using the svgr webpack plugin.

// SiteLogo.svg
import LogoImage from 'public/images/logo.svg';

Next.js config:

// next.config.js
const nextConfig = {
  reactStrictMode: true,
  swcMinify: true,
  experimental: {
    appDir: true,
  },
  webpack(config) {
    // Support SVG (aviable )
    config.module.rules.push({
      test: /\.svg$/,
      use: ['@svgr/webpack'],
    });
    return config;
  },
  output: 'export',
};

module.exports = nextConfig;

Unfortunately when using next dev --turbo I get errors:

- error Error: Cannot find module 'public/images/logo.svg'

Expected Behavior

SVG pictures are loaded by picking up settings from next.config.js or by turbopack mechanisms.

To Reproduce

Open repository

npm ci
npx next dev --turbo

Reproduction Repo

https://github.com/pkolt/pkolt.ru

@pkolt pkolt added area: turborepo kind: bug Something isn't working needs: triage New issues get this label. Remove it after triage labels May 5, 2023
@sokra sokra changed the title SVG support SVG via svgr support May 8, 2023
@cpotey
Copy link

cpotey commented May 9, 2023

To chime in, I'm getting similar issues with SVGR after upgrading to 13.4.1 too

I'm importing SVGs in from a package/shared-ui/images dir, and am getting

You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
> <svg xmlns="http://www.w3.org/2000/svg" ...></svg>

Errors after importing/using in the Next 13.4 app router app (not in pages). Unsure whether this is a Next issue, or Turborepo one

@jridgewell jridgewell changed the title SVG via svgr support [turbopack] SVG via svgr support May 9, 2023
@jridgewell
Copy link
Contributor

jridgewell commented May 9, 2023

We don't currently support SVGR loader natively, though it could probably be enabled using experimental.turbo.loaders config option in your next.config.js:

module.exports = {
  experimental: {
    turbo: {
      loaders: {
        '.svg': ['@svgr/webpack'],
      },
    },
  },
};

Also @pkolt, the 'public/images/logo.svg' specifier in your import isn't support. To fix, you need to use '../public/images/logo.svg' (or whatever the appropriate number of ../s) to import from your public directly. Alternatively, you could use compilerOptions.paths in tsconfig.json to remap importing from public/* to your public directory:

{
  "compilerOptions": {
    "paths": {
      "public/*": ["./public/*"]
    }
  }
}

@pkolt
Copy link
Author

pkolt commented May 10, 2023

Hi @jridgewell !

I tried to do what you described, but unfortunately it did not help me. I get an error:

Снимок экрана 2023-05-10 в 19 24 09

There is a<svg> root element in my picture, you can see for yourself:

https://github.com/pkolt/pkolt.ru/blob/master/public/images/calendar.svg?short_path=e465239#L0-L1

Thanks!

@iipanda
Copy link

iipanda commented Jun 4, 2023

Hi @jridgewell !

I tried to do what you described, but unfortunately it did not help me. I get an error:
Снимок экрана 2023-05-10 в 19 24 09

There is a<svg> root element in my picture, you can see for yourself:

https://github.com/pkolt/pkolt.ru/blob/master/public/images/calendar.svg?short_path=e465239#L0-L1

Thanks!

I have the same issue, is there any fix available for this?

@tntchn
Copy link

tntchn commented Jun 8, 2023

Found a related issue here vercel/next.js#48140

It was caused by turbopack trying to get the dimension of svg but webpack already turn the import into a function

@stevenmunro
Copy link

Found a related issue here vercel/next.js#48140

It was caused by turbopack trying to get the dimension of svg but webpack already turn the import into a function

The whole world needs to know about this. I just fixed hours and hours of frustration by adopting this simple little change.

@osdiab
Copy link

osdiab commented Jun 26, 2023

Idk anything about how Turbopack nor Rust works but it seems

Hoping that SVG support becomes built in or more formally supported without hacks like the above!

@tntchn
Copy link

tntchn commented Oct 3, 2023

This issue seemed to be resolved in the latest with-turbopack-loaders example with rules option in next.config.js

https://github.com/vercel/next.js/blob/17ba84b7a7774ca09917ec3fbf44074d534b5c12/examples/with-turbopack-loaders/next.config.js#L1-L16

Works for me in my project, however with this config, the usage of <Image src={SvgFile} alt='' /> is not possible as turbopack takes svg files as js files

@karldivad
Copy link

karldivad commented Oct 6, 2023

Thanks @tntchn. It worked for me on both configs, just for changing a fill color 🥳
Node: v20.7.0
Next: 13.5.3

const nextConfig = {
  webpack(config) {
    config.module.rules.push({
      test: /\.svg$/i,
      use: ['@svgr/webpack'],
    })

    return config
  },
  experimental: {
    turbo: {
      rules: {
        '*.svg': {
          loaders: ['@svgr/webpack'],
          as: '*.js',
        },
      },
    },
  },
}

@Yongveloper
Copy link

감사해요@tntchn. 교체 색상을 변경하기 위해 두 가지 구성 모두에서 저에게 있었습니다. 🥳 개별: v20.7.0 다음: 13.5.3

const nextConfig = {
  webpack(config) {
    config.module.rules.push({
      test: /\.svg$/i,
      use: ['@svgr/webpack'],
    })

    return config
  },
  experimental: {
    turbo: {
      rules: {
        '*.svg': {
          loaders: ['@svgr/webpack'],
          as: '*.js',
        },
      },
    },
  },
}

This has completely resolved the issue, thank you!

@dmythro
Copy link

dmythro commented Jan 24, 2024

Thanks, it works with Next.js v14 as well. Wondering when it finally transitions from experimental to stable :)

@michaelhays
Copy link

This is working as expected with @svgr/webpack, should this issue be closed?

@dmythro
Copy link

dmythro commented Jan 30, 2024

Using it like that for the last few days, didn't see issues so far.

But it was not so easy to find, so I'd close it after documenting properly.

Wondering when can it go out of "experimental" though.

@bettiolo
Copy link

Worked for me too, can be closed.

@Anishali2
Copy link

Thanks @tntchn. It worked for me on both configs, just for changing a fill color 🥳 Node: v20.7.0 Next: 13.5.3

const nextConfig = {
  webpack(config) {
    config.module.rules.push({
      test: /\.svg$/i,
      use: ['@svgr/webpack'],
    })

    return config
  },
  experimental: {
    turbo: {
      rules: {
        '*.svg': {
          loaders: ['@svgr/webpack'],
          as: '*.js',
        },
      },
    },
  },
}

You saved my life thanks brother !

@Yihao-G
Copy link

Yihao-G commented May 14, 2024

How can I configure it if I want to keep the original .svg loader rule? Like the one documented on the SVGR website:

module.exports = {
  webpack(config) {
    // Grab the existing rule that handles SVG imports
    const fileLoaderRule = config.module.rules.find((rule) =>
      rule.test?.test?.('.svg'),
    )

    config.module.rules.push(
      // Reapply the existing rule, but only for svg imports ending in ?url
      {
        ...fileLoaderRule,
        test: /\.svg$/i,
        resourceQuery: /url/, // *.svg?url
      },
      // Convert all other *.svg imports to React components
      {
        test: /\.svg$/i,
        issuer: fileLoaderRule.issuer,
        resourceQuery: { not: [...fileLoaderRule.resourceQuery.not, /url/] }, // exclude if *.svg?url
        use: ['@svgr/webpack'],
      },
    )

    // Modify the file loader rule to ignore *.svg, since we have it handled now.
    fileLoaderRule.exclude = /\.svg$/i

    return config
  },

  // ...other config
}

@Anishali2
Copy link

Yihao

Which version of framework you are using ?

@Yihao-G
Copy link

Yihao-G commented May 14, 2024

Which version of framework you are using ?

I'm using Nextjs 14.2.3

@Anishali2
Copy link

I've configured this hope this helps you

If you are using turbo repo
file: /next.config.js

experimental: {
    turbo: {
      rules: {
        '*.svg': {
          loaders: ['@svgr/webpack'],
          as: '*.js'
        }
      }
    }
  },

and this is the svgr config
file: /next.config.js

  webpack(config) {
   const fileLoaderRule = config.module.rules.find((rule) =>
     rule.test?.test?.('.svg')
   )

   config.module.rules.push(
     {
       ...fileLoaderRule,
       type: 'javascript/auto',
       test: /\.svg$/i,
       resourceQuery: /url/ // *.svg?url
     },
     {
       test: /\.svg$/i,
       type: 'javascript/auto',
       issuer: fileLoaderRule.issuer,
       resourceQuery: { not: [...fileLoaderRule.resourceQuery.not, /url/] }, // exclude if *.svg?url
       use: ['@svgr/webpack']
     }
   )

   return config
 },

for typescript support use this
file root/svgr.d.ts

 import { FC, SVGProps } from 'react'
 const content: FC<SVGProps<SVGElement>>
 export default content
}

declare module '*.svg?url' {
 const content: any
 export default content
}

How I use those

file: root/src/assets/svg/index.ts
export { default as GlobeIcon } from './globe.svg'

file: root/src/assets/svg/globe.svg
note use the "currentColor" for color in svgr to modify the color according your style by just changing the text-color

<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 36 36"><path fill="currentColor" d="M29.52 22.52L18 10.6L6.48 22.52a1.7 1.7 0 0 0 2.45 2.36L18 15.49l9.08 9.39a1.7 1.7 0 0 0 2.45-2.36Z" class="clr-i-outline clr-i-outline-path-1"/><path fill="none" d="M0 0h36v36H0z"/></svg>

usage

import React from 'react'
import { GlobeIcon } from '@/src/assets/svg' // using  alias @ import

const IconUse = () => {
 return (
   <div>
     {/* im using tailwind css and this text color only works with currentColor value in fill */}
     <GlobeIcon className='text-red-500'/>
   </div>
 )
}

export default IconUse

:)

@daaain
Copy link

daaain commented Jun 3, 2024

If I understood right from the turbo docs page, the webpack() bit is pointless, it won't be used. Putting a console.log() in there I didn't get any output, so by all means seems to be true.

There's the with-turbopack-loaders example in the repo that covers this usecase and currently works with latest Next.js.

This all being said, I've wasted a few hours on this and just can't get it working with Next 14 and Typescript 5, always getting back {"src":"/_next/static/media/data-sources.b4ce7cbe.svg","width":24,"height":24,"blurDataURL":null,"blurWidth":0,"blurHeight":0} instead of a component, no matter what I try...

As a workaround, I'm just converting the SVGs to React components with https://react-svgr.com/playground/ now

@mirismaili
Copy link

mirismaili commented Jun 3, 2024

Like @Yihao-G I still have problem with loading .svgs using Turbopack. I want to configure the boundler to load .svgs in two ways according to my import method. If I just import it, it should be imported regularly (the default way in Next.js). And if I import it using ?react resource-query, it should be imported using SVGR.

And this is my webpack configuration:

webpack(config) {
  const defaultSvgLoader = config.module.rules.find((rule) => rule.test?.test?.('.svg'))
  config.module.rules.push(
    {
      ...defaultSvgLoader,
      test: /\.svg$/i,
      resourceQuery: {not: [...defaultSvgLoader.resourceQuery.not, /react/]}, // exclude if *.svg?react
    },
    {
      test: /\.svg$/i,
      issuer: defaultSvgLoader.issuer, // issuer: /\.[jt]sx?$/ doesn't work:
      // https://github.com/vercel/next.js/issues/48177#issuecomment-1506251112
      resourceQuery: /react/, // *.svg?react
      use: '@svgr/webpack',
    },
  )
  return config
}

As you can see, I can use ?react query to tell the boundler that I want a React component, and w/o it, it should be imported regularly (as StaticImageData).

How can I configure the similar behaviour for Turbopack?

@judewang
Copy link

judewang commented Jun 4, 2024

@mirismaili Turbopack doesn't support resourceQuery. We can import SVG as React component without passing "?react". If we want to use SVG image as src of an Image component, we don't have to statically import the SVG image, we can just pass the public path like /logo.svg as the src property. The downside is that we need to add width, height props, but it's ok for me as a workaround.

ndcunningham added a commit to nrwl/nx that referenced this issue Oct 31, 2024
<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->
Currently, if you are using Next.js 15 have SVGR enabled via `WithNx`
and are using turbopack. You could potentially have issues loading your
svg. This happens because of how webpack imports svg and not having an
additional configuration for turbopack (currently it is under the
experimental option).

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
Moving forward, we can call this out and deprecate the option to be
removed in Nx 21. As such should you need to use SVGs it is recommended
to do so manually. Something similar to [this
comment](vercel/turborepo#4832 (comment)).

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #
jaysoo pushed a commit to nrwl/nx that referenced this issue Oct 31, 2024
<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->
Currently, if you are using Next.js 15 have SVGR enabled via `WithNx`
and are using turbopack. You could potentially have issues loading your
svg. This happens because of how webpack imports svg and not having an
additional configuration for turbopack (currently it is under the
experimental option).

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
Moving forward, we can call this out and deprecate the option to be
removed in Nx 21. As such should you need to use SVGs it is recommended
to do so manually. Something similar to [this
comment](vercel/turborepo#4832 (comment)).

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind: bug Something isn't working needs: triage New issues get this label. Remove it after triage
Projects
None yet
Development

No branches or pull requests