nx icon indicating copy to clipboard operation
nx copied to clipboard

SVG default import behaviour changed for webpack

Open jamieathans opened this issue 1 year ago • 3 comments

Current Behavior

As described here - https://nx.dev/recipes/react/adding-assets-react#adding-images-fonts-and-files, the default import for image assets (including svg) should be able to be used as the src for an image tag.

This appears to have changed for svg as now the default import seems to be the ReactComponent as described here - https://nx.dev/recipes/react/adding-assets-react#adding-svgs and in fact the syntax described:

import { ReactComponent as Logo } from './logo.svg';

actually causes an error.

Expected Behavior

Functionality as described here - https://nx.dev/recipes/react/adding-assets-react#adding-svgs which was working using NX 17.3.2

GitHub Repo

No response

Steps to Reproduce

Nx Report

Node   : 20.11.0
   OS     : darwin-arm64
   npm    : 10.2.4

   nx                 : 18.0.4
   @nx/js             : 18.0.4
   @nx/jest           : 18.0.4
   @nx/linter         : 18.0.4
   @nx/eslint         : 18.0.4
   @nx/workspace      : 18.0.4
   @nx/cypress        : 18.0.4
   @nx/devkit         : 18.0.4
   @nx/eslint-plugin  : 18.0.4
   @nx/react          : 18.0.4
   @nx/storybook      : 18.0.4
   @nrwl/tao          : 18.0.4
   @nx/web            : 18.0.4
   @nx/webpack        : 18.0.4
   typescript         : 5.3.3

Failure Logs

No response

Package Manager Version

No response

Operating System

  • [X] macOS
  • [ ] Linux
  • [ ] Windows
  • [ ] Other (Please specify)

Additional Information

Image assets are exported from a shared NX library:

Example index.ts

export {default as logo, ReactComponent as LogoSvg} from "./lib/images/logo.svg";

jamieathans avatar Feb 11 '24 01:02 jamieathans

I can confirm this after upgrading export 'ReactComponent' (reexported as 'MyIcon') was not found in './icons/MyIcon.svg' (possible exports: default)

smasala avatar Feb 11 '24 21:02 smasala

I'm experiencing this bug too. To reproduce the issue: create a new integrated workspace with a react app, choosing webpack as bundler. Then trying to import an SVG as described in the docs throws the export 'ReactComponent' was not found error. However the default export actually returns the ReactComponent but it cannot be used properly becase TypeScript types are not expecting a React component as a default export. So a possible workaround is using the default export with @ts-ignore directive where the component is used, but it is not a clean way at all. Possible solutions are: update types and add a migrations to reflect this new behavior (if desired), or restore the previous behavior.

mbellagamba avatar Feb 13 '24 09:02 mbellagamba

I'm having the same issue after upgrading to 18.0.4. Any updates on this?

tonvanalebeek avatar Feb 16 '24 11:02 tonvanalebeek

Same issue for me after upgrading to 18.0.4.

balfons avatar Feb 20 '24 12:02 balfons

Bump, happens to me as well

davidearci avatar Feb 20 '24 17:02 davidearci

In my case, the solution to load SVGs was to install file-loader manually. Previously, this package was included in one of NX packages as a dependency, which was not the case in NX v18.

bojanbass avatar Feb 20 '24 21:02 bojanbass

This is failing for me as well, and seems to be some unexpected interaction with svgr babel plugin at:

https://github.com/gregberge/svgr/blob/0ae0413eaef2442af129bfc88847867d0ab8afa5/packages/babel-plugin-transform-svg-component/src/variables.ts#L259

Value of previousExport was the webpack file asset export (I assume result of file-loader), and is now not set.

webpack.config.js workaround like @bojanbass suggested

// Nx plugins for webpack.
module.exports = composePlugins(withNx(), withReact(), (config, { options, context }) => {
  // Update the webpack config as needed here.
  // e.g. config.plugins.push(new MyPlugin())
  // For more information on webpack config and Nx see:
  // https://nx.dev/packages/webpack/documents/webpack-config-setup
  const svgRule = config.module.rules.find((rule) => typeof rule === 'object' && rule.test.toString().includes('svg'));
  if (svgRule) {
    svgRule.use = [
      {
        loader: require.resolve('@svgr/webpack'),
        options: {
            svgo: false,
            titleProp: true,
            ref: true,
        },
      },
      {
        loader: require.resolve('file-loader'),
        options: {
            name: '[name].[hash].[ext]',
        },
      },
    ]
  }

  return config;
});

tzuge avatar Feb 21 '24 03:02 tzuge

I forgot to mention that I don't have control over webpack config as I'm only using Next.js.

bojanbass avatar Feb 21 '24 07:02 bojanbass

Given file-loader is deprecated for webpack 5, and if you only ever consume the react component, you can also provide the option exportType: 'named' to the svgr loader.

This is the webpack config I'm using now, although I'd prefer it if the nx typings could easily be overridden to support using the default export to obtain the react component instead.

  config.module.rules.filter(rule => rule.test?.toString().includes('svg')).forEach(rule => {
    rule.use = [
      {
        loader: require.resolve('@svgr/webpack'),
        options: {
          svgo: false,
          titleProp: true,
          ref: true,
          exportType: 'named' // typings provided by nx require named exports
        },
      },
    ]
  });

mpetito avatar Feb 21 '24 13:02 mpetito

It is worth mentioning the SVGR docs with updated asset modules usage:

{
  test: /\.svg$/i,
  type: 'asset',
  resourceQuery: /url/, // *.svg?url
},
{
  test: /\.svg$/i,
  issuer: /\.[jt]sx?$/,
  resourceQuery: { not: [/url/] }, // exclude react component if *.svg?url
  use: ['@svgr/webpack'],
},

this approach does not require the file-loader dependency and automatically inlines small SVGs while being explicit in the asset import syntax.

victorlacorte avatar Feb 22 '24 13:02 victorlacorte

We ran into the same issue while upgrading to 18.0.4. A quick hotfix, that makes is work again is setting up a .svgrrc config file at the workspace root with following content:

{
  "exportType": "named"
}

belaczek avatar Feb 23 '24 12:02 belaczek

We ran into the same issue while upgrading to 18.0.4. A quick hotfix, that makes is work again is setting up a .svgrrc config file at the workspace root with following content:

{
  "exportType": "named"
}

I haven't tried this myself yet - but would make sense accordig to the svgr webpack documention

Please note that by default, @svgr/webpack will try to export the React Component via default export if there is no other loader handling svg files with default export. When there is already any other loader using default export for svg files, @svgr/webpack will always export the React component via named export.

If you prefer named export in any case, you may set the exportType option to named.

jamieathans avatar Feb 24 '24 01:02 jamieathans

We ran into the same issue while upgrading to 18.0.4. A quick hotfix, that makes is work again is setting up a .svgrrc config file at the workspace root with following content:

{
  "exportType": "named"
}

For us placing it in the workspace root works in the dev server ("nx serve", using Webpack), but not with production builds ("nx build"). Then the file placed at the workspace root seems to be ignored.

It does work if the .svgrrc is placed in all of the individual app directories.

remcogerlich avatar Mar 07 '24 08:03 remcogerlich

As a follow up - since my project uses both SVGs as assets and React Components, the solution that worked for me was as described by @tzuge - https://github.com/nrwl/nx/issues/21773#issuecomment-1955792729.

This allowed for the following code to continue to work.

export {default as logo, ReactComponent as LogoSvg} from "./lib/images/logo.svg";

jamieathans avatar Mar 08 '24 00:03 jamieathans

Is there an official solution to this or just the workarounds as described above? I'm still seeing this in 18.0.8.

airowe avatar Mar 12 '24 13:03 airowe

Is there any solution within nx? I think this should be resolved immediately. project spec - nx version: 18.1.2, based library - react.

ThejanNim avatar Mar 19 '24 08:03 ThejanNim

Facing the same issue, stopped working from v17.3.2

BogdanMihalca avatar Mar 27 '24 18:03 BogdanMihalca

I ran into this, and it appears I can workaround it by taking the old SVGR/file loader configuration/massaging and do the same thing on the Webpack config returned from NX.

Took this old code and basically brought it into my webpack config to happen on the final config returned from NX's plugins: https://github.com/nrwl/nx/commit/395eb70336cb1346548705d7c41d896b4a6c6cbb#diff-8002181282b96d97d2967089ded642ca10c05ceee5313e5a0fafed3fa278e5e3L71

bigcakes avatar Mar 29 '24 20:03 bigcakes

We'll bring back the deprecated file-loader and add some tests around it. Eventually we'll need to remove file-loader since it is deprecated and not updated for 3 years, but we can do that in Nx 20.

If anyone is using SVGR, we'll add ?react querystring to differentiate between SVGR components and regular assets.

jaysoo avatar Apr 02 '24 17:04 jaysoo

This issue has been closed for more than 30 days. If this issue is still occuring, please open a new issue with more recent context.

github-actions[bot] avatar May 04 '24 00:05 github-actions[bot]