From 6a70e047d4215357ff43b89a7de2041f6f1a9d47 Mon Sep 17 00:00:00 2001 From: Jack Hsu Date: Tue, 2 Apr 2024 14:24:56 -0400 Subject: [PATCH] fix(webpack): bring back previous SVG and SVGR behavior for React projects --- .../src/react-webpack.test.ts | 64 +++++++++++++++++++ packages/react/.eslintrc.json | 1 + packages/react/package.json | 1 + .../lib/apply-react-config.ts | 26 ++++++++ 4 files changed, 92 insertions(+) create mode 100644 e2e/react-extensions/src/react-webpack.test.ts diff --git a/e2e/react-extensions/src/react-webpack.test.ts b/e2e/react-extensions/src/react-webpack.test.ts new file mode 100644 index 00000000000000..429590234dfd24 --- /dev/null +++ b/e2e/react-extensions/src/react-webpack.test.ts @@ -0,0 +1,64 @@ +import { + cleanupProject, + createFile, + listFiles, + newProject, + readFile, + runCLI, + runCLIAsync, + uniq, + updateFile, +} from '@nx/e2e/utils'; + +describe('Build React applications and libraries with Vite', () => { + beforeAll(() => { + newProject({ + packages: ['@nx/react'], + }); + }); + + afterAll(() => { + cleanupProject(); + }); + + // Regression test: https://github.com/nrwl/nx/issues/21773 + it('should support SVGR and SVG asset in the same project', async () => { + const appName = uniq('app'); + + runCLI( + `generate @nx/react:app ${appName} --bundler=webpack --compiler=babel --unitTestRunner=none --no-interactive` + ); + createFile( + `apps/${appName}/src/app/nx.svg`, + ` + + SVG for ${appName} + + ` + ); + updateFile( + `apps/${appName}/src/app/app.tsx`, + ` + import svgImg, { ReactComponent as Logo } from './nx.svg'; + export function App() { + return ( + <> + Alt for SVG img tag + + + ); + } + export default App; + ` + ); + + await runCLIAsync(`build ${appName}`); + + const outFiles = listFiles(`dist/apps/${appName}`); + const mainFile = outFiles.find((f) => f.startsWith('main.')); + const mainContent = readFile(`dist/apps/${appName}/${mainFile}`); + const svgFile = outFiles.find((f) => f.endsWith('.svg')); + expect(mainContent).toMatch(/Alt for SVG img tag/); + expect(svgFile).toBeTruthy(); + }, 300_000); +}); diff --git a/packages/react/.eslintrc.json b/packages/react/.eslintrc.json index 94e13c31110a1a..8c2a56fa639fa3 100644 --- a/packages/react/.eslintrc.json +++ b/packages/react/.eslintrc.json @@ -67,6 +67,7 @@ "babel-plugin-emotion", "babel-plugin-styled-components", "css-loader", + "file-loader", "less-loader", "react-refresh", "rollup", diff --git a/packages/react/package.json b/packages/react/package.json index 0c425c77365c50..3a03649a11a791 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -34,6 +34,7 @@ "@phenomnomnominal/tsquery": "~5.0.1", "@svgr/webpack": "^8.0.1", "chalk": "^4.1.0", + "file-loader": "^6.2.0", "minimatch": "9.0.3", "tslib": "^2.3.0", "@nx/devkit": "file:../devkit", diff --git a/packages/react/plugins/nx-react-webpack-plugin/lib/apply-react-config.ts b/packages/react/plugins/nx-react-webpack-plugin/lib/apply-react-config.ts index 7878d27ed758b2..fc3ad55fc81caf 100644 --- a/packages/react/plugins/nx-react-webpack-plugin/lib/apply-react-config.ts +++ b/packages/react/plugins/nx-react-webpack-plugin/lib/apply-react-config.ts @@ -11,6 +11,26 @@ export function applyReactConfig( if (options.svgr !== false) { removeSvgLoaderIfPresent(config); + // TODO(v20): Remove file-loader and use `?react` querystring to differentiate between asset and SVGR. + // It should be: + // use: [{ + // test: /\.svg$/i, + // type: 'asset', + // resourceQuery: /react/, // *.svg?react + // }, + // { + // test: /\.svg$/i, + // issuer: /\.[jt]sx?$/, + // resourceQuery: { not: [/react/] }, // exclude react component if *.svg?react + // use: ['@svgr/webpack'], + // }], + // See: + // - SVGR: https://react-svgr.com/docs/webpack/#use-svgr-and-asset-svg-in-the-same-project + // - Vite: https://www.npmjs.com/package/vite-plugin-svgr + // - Rsbuild: https://github.com/web-infra-dev/rsbuild/pull/1783 + // Note: We also need a migration for any projects that are using SVGR to convert + // `import { ReactComponent as X } from './x.svg` to + // `import X from './x.svg?react'; config.module.rules.push({ test: /\.svg$/, issuer: /\.(js|ts|md)x?$/, @@ -23,6 +43,12 @@ export function applyReactConfig( ref: true, }, }, + { + loader: require.resolve('file-loader'), + options: { + name: '[name].[hash].[ext]', + }, + }, ], }); }