nx
nx copied to clipboard
SVG default import behaviour changed for webpack
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";
I can confirm this after upgrading
export 'ReactComponent' (reexported as 'MyIcon') was not found in './icons/MyIcon.svg' (possible exports: default)
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.
I'm having the same issue after upgrading to 18.0.4
. Any updates on this?
Same issue for me after upgrading to 18.0.4
.
Bump, happens to me as well
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.
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;
});
I forgot to mention that I don't have control over webpack config as I'm only using Next.js.
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
},
},
]
});
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.
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"
}
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.
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.
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";
Is there an official solution to this or just the workarounds as described above? I'm still seeing this in 18.0.8.
Is there any solution within nx? I think this should be resolved immediately. project spec - nx version: 18.1.2, based library - react.
Facing the same issue, stopped working from v17.3.2
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
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.
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.