gregberge / svgr

Transform SVGs into React components 🦁
https://react-svgr.com
MIT License
10.51k stars 417 forks source link

Nextjs Webpack SVG import loaded as Object instead of React Component #838

Closed bewards closed 1 year ago

bewards commented 1 year ago

🐛 Bug Report

When I use SVGR with webpack, I get Object instead of React Components.

To Reproduce, use this config:

/**
 * @type {import('next').NextConfig}
 */
const nextConfig = {
  // Set assetPrefix to our public URL
  assetPrefix: publicUrl,

  // Allow specifying a distinct distDir when concurrently running app in a container
  distDir: process.env.NEXTJS_DIST_DIR || '.next',

  // Make the same PUBLIC_URL available as an environment variable on the client bundle
  env: {
    PUBLIC_URL: publicUrl,
  },

  i18n: {
    // These are all the locales you want to support in your application.
    // These should generally match (or at least be a subset of) those in Sitecore.
    locales: ['en', 'es'],
    // This is the locale that will be used when visiting a non-locale
    // prefixed path e.g. `/styleguide`.
    defaultLocale: packageConfig.language,
  },
  reactStrictMode: true,
  productionBrowserSourceMaps: true,
  images: {
    dangerouslyAllowSVG: true,
  },
  compiler: {
    styledComponents: true,
  },
  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: /\.[jt]sx?$/,
        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;
  },
};

and import like this:

import App from './app.svg?react';

const Page = () => <App />;

export default Page;

Error Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.

Expected behavior I expect to get a React component.

package.json

{
    "name": "sc-test",
    "description": "Application utilizing Sitecore JavaScript Services and Next.js",
    "version": "21.0.5",
    "private": true,
    "engines": {
      "node": ">=12",
      "npm": ">=6"
    },
    "license": "Apache-2.0",
    "dependencies": {
      "@sitecore-jss/sitecore-jss-nextjs": "^21.0.5",
      "@svgr/webpack": "^6.5.1",
      "bootstrap": "^5.2.3",
      "classnames": "^2.3.2",
      "graphql": "~15.8.0",
      "graphql-tag": "^2.11.0",
      "next": "^12.3.4",
      "next-localization": "^0.12.0",
      "nprogress": "~0.2.0",
      "react": "^18.1.0",
      "react-dom": "^18.1.0",
      "react-router-dom": "^6.8.1",
      "sharp": "^0.31.3"
    },
    "devDependencies": {
      "@babel/core": "^7.20.12",
      "@graphql-codegen/cli": "^1.19.1",
      "@graphql-codegen/plugin-helpers": "^1.18.1",
      "@graphql-codegen/typed-document-node": "^1.18.4",
      "@graphql-codegen/typescript": "^1.21.1",
      "@graphql-codegen/typescript-operations": "^1.17.9",
      "@graphql-codegen/typescript-resolvers": "^1.17.10",
      "@graphql-typed-document-node/core": "^3.1.0",
      "@sitecore-jss/sitecore-jss-cli": "^21.0.5",
      "@sitecore-jss/sitecore-jss-dev-tools": "^21.0.5",
      "@storybook/addon-actions": "^6.5.15",
      "@storybook/addon-essentials": "^6.5.16",
      "@storybook/addon-interactions": "^6.5.16",
      "@storybook/addon-links": "^6.5.16",
      "@storybook/builder-webpack5": "^6.5.16",
      "@storybook/manager-webpack5": "^6.5.16",
      "@storybook/preset-scss": "^1.0.3",
      "@storybook/react": "^6.5.16",
      "@storybook/testing-library": "^0.0.13",
      "@svgr/webpack": "^6.5.1",
      "@types/fs-extra": "^11.0.1",
      "@types/node": "^14.6.4",
      "@types/nprogress": "^0.2.0",
      "@types/react": "^18.0.12",
      "@types/react-dom": "^18.0.5",
      "@typescript-eslint/eslint-plugin": "^4.29.1",
      "@typescript-eslint/parser": "^4.29.1",
      "axios": "^0.21.1",
      "babel-loader": "^8.3.0",
      "chalk": "~2.4.2",
      "chokidar": "~3.1.1",
      "constant-case": "^3.0.4",
      "cross-env": "~6.0.3",
      "css-loader": "^6.7.3",
      "dotenv": "^16.0.0",
      "eslint": "^7.32.0",
      "eslint-config-next": "^11.0.1",
      "eslint-config-prettier": "^6.15.0",
      "eslint-plugin-prettier": "^3.1.4",
      "eslint-plugin-yaml": "^0.2.0",
      "fs-extra": "^11.1.0",
      "graphql-let": "^0.16.2",
      "image-downloader": "^4.3.0",
      "npm-run-all": "~4.1.5",
      "prettier": "^2.1.2",
      "replace-in-file": "^6.3.5",
      "sass": "^1.57.1",
      "sass-alias": "^1.0.5",
      "sass-loader": "^13.2.0",
      "storybook-addon-breakpoints": "^1.0.0",
      "storybook-addon-next": "^1.7.1",
      "storybook-addon-next-router": "^4.0.2",
      "style-loader": "^3.3.1",
      "ts-node": "^9.0.0",
      "tsconfig-paths-webpack-plugin": "^4.0.0",
      "tsx": "^3.12.2",
      "typescript": "~4.3.5",
      "webpack-config-dump-plugin": "^3.0.1",
      "yaml-loader": "^0.6.0"
    },
    "scripts": {
      "bootstrap": "ts-node --project tsconfig.scripts.json scripts/bootstrap.ts && graphql-let",
      "lint": "eslint ./src/**/*.tsx ./src/**/*.ts ./scripts/**/*.ts",
      "next:dev": "cross-env NODE_OPTIONS='--inspect' APP_ENV=local next dev",
      "start:connected": "npm-run-all --serial bootstrap --parallel next:dev start:watch-components",
      "start:watch-components": "ts-node --project tsconfig.scripts.json scripts/generate-component-factory.ts --watch",
    },
    "browserslist": [
      "defaults and supports css-grid"
    ]
  }

End User Screenshot of Error svgr-error-end-user

Webpack dump webpack.config.dump.txt

bewards commented 1 year ago

Closing as I found the following configurations works for me after restarting the docker service where my application was running in:

/**
 * @param {import('next').NextConfig} nextConfig
 */
const svgrPlugin = (nextConfig = {}) => {
  return Object.assign({}, nextConfig, {
    webpack: (config, options) => {
      // Grab the existing rule that handles SVG imports
      const fileLoaderRule = config.module.rules.find((rule) => rule.test?.test?.('.svg'));

      config.module.rules.push(
        // Convert all other *.svg imports to React components
        {
          test: /\.svg$/,
          issuer: /\.[jt]sx?$/,
          resourceQuery: /react/,
          use: ['@svgr/webpack'],
        }
      );

      // Modify the file loader rule to ignore *.svg, since we have it handled now.
      fileLoaderRule.exclude = /\.svg$/i;
      fileLoaderRule.test = /\.(png|jpg|jpeg|gif|webp|avif|ico|bmp)$/i;

      console.log(config.module.rules);

      // Overload the Webpack config if it was already overloaded
      if (typeof nextConfig.webpack === 'function') {
        return nextConfig.webpack(config, options);
      }

      return config;
    },
  });
};

module.exports = svgrPlugin;
mrevanzak commented 9 months ago

i cant fix it :(