How to use @svgr/webpack with Shakapacker 7 and rails 6

88 views Asked by At

Recently, I have decided to move from Webpacker to Shakapacker. I am using Shakapacker v7. I am trying to use @svgr/webpack for loading svg images as React Component.

My package.json file looks like

{
  "babel": {
    "presets": [
      "./node_modules/shakapacker/package/babel/preset.js",
      "@babel/preset-react"
    ],
    "plugins": [
      "@babel/plugin-proposal-class-properties",
      "@babel/syntax-dynamic-import",
      "@babel/plugin-proposal-object-rest-spread",
      "@babel/plugin-transform-runtime"
    ]
  },
  "dependencies": {
    "@babel/core": "7",
    "@babel/plugin-syntax-dynamic-import": "^7.8.3",
    "@babel/plugin-transform-runtime": "7",
    "@babel/preset-env": "7",
    "@babel/preset-react": "^7.14.5",
    "@babel/runtime": "7",
    "@reduxjs/toolkit": "^1.8.4",
    "@svgr/webpack": "^8.1.0",
    "@tinymce/tinymce-react": "^3.10.1",
    "@types/babel__core": "7",
    "@types/webpack": "5",
    "axios": "^0.21.1",
    "babel-loader": "8",
    "babel-plugin-transform-class-properties": "^6.24.1",
    "bootstrap": "^3.3.7",
    "coffeescript": "1.12.7",
    "compression-webpack-plugin": "9",
    "core-js": "^3.8.3",
    "dompurify": "^2.2.6",
    "eslint": "^8.34.0",
    "improved-yarn-audit": "^3.0.0",
    "jest-svg-transformer": "^1.0.0",
    "jquery": "^3.5.1",
    "jquery-ujs": "^1.2.2",
    "lodash": "^4.17.21",
    "moment": "^2.29.4",
    "postcss-cssnext": "^3.1.1",
    "postcss-smart-import": "^0.7.6",
    "prop-types": "^15.6.0",
    "rc-pagination": "^3.1.17",
    "react": "^17.0.2",
    "react-big-calendar": "^1.8.2",
    "react-bootstrap": "0.33.1",
    "react-burger-menu": "^3.0.6",
    "react-calendar": "^4.6.0",
    "react-datepicker": "^4.6.0",
    "react-dom": "^17.0.2",
    "react-dropzone": "^14.2.2",
    "react-easy-sort": "^1.5.1",
    "react-icons": "^4.3.1",
    "react-jwt": "^1.1.2",
    "react-moment": "^1.1.3",
    "react-on-rails": "^10.1.0",
    "react-redux": "^8.0.2",
    "react-router-dom": "^6.2.2",
    "react-scripts": "^5.0.0",
    "react-select": "^5.2.2",
    "react-switch": "^6.0.0",
    "react-tooltip": "^4.2.13",
    "shakapacker": "7.2.2",
    "slugify": "^1.6.5",
    "terser-webpack-plugin": "5",
    "webpack": "5",
    "webpack-assets-manifest": "5",
    "webpack-cli": "4",
    "webpack-merge": "5",
    "yarn-audit-fix": "^10.0.1"
  }
}

my webpack.config.js file looks like

const { merge, generateWebpackConfig } = require('shakapacker')
const path = require('path')

const options = {
  resolve: {
    extensions: [
      '.jsx',
      '.mjs',
      '.js',
      '.ts',
      '.tsx',
      '.sass',
      '.scss',
      '.css',
      '.module.sass',
      '.module.scss',
      '.module.css',
      '.png',
      '.svg',
      '.gif',
      '.jpeg',
      '.jpg',
      '.erb',
      '.coffee',
      '.vue'
    ],
    modules: [
      path.join(__dirname, '../../node_modules'),
      path.join(__dirname, '../../app/client/bundles')
    ],
  },
  module: {
    rules: [
      {
        test: /\.svg$/,
        loader: '@svgr/webpack',
        options: {
          jsx: true
        }
      }
    ]
  }
}

const webpackConfig = generateWebpackConfig()

module.exports = merge({}, webpackConfig, options)

My React Component looks like

import React from 'react';
import MySvg from './my-svg.svg';

const MyComponent = () => {
  return (
    <div>
      <MySvg />
    </div>
  );
};

export default MyComponent;

I always gets an error while running above component as Failed to execute 'createElement' on 'Document': The tag name provided ('/packs/static/images/my-svg-bba2a3d91ed89ztfvbad83.svg') is not a valid name.

Can someone help me figure out what am I doing wrong here? Thanks

1

There are 1 answers

0
Praful Patel On

After encountering challenges for nearly 2 days, I managed to resolve the issue by implementing the following solution.

Overriding Shakapacker File Rules:

const { generateWebpackConfig } = require('shakapacker')

const webpackConfig = generateWebpackConfig()

const svgRule = webpackConfig.module.rules.find(rule => rule.test.test('.svg'));
svgRule.test = /\.(bmp|gif|jpe?g|png|tiff|ico|avif|webp|eot|otf|ttf|woff|woff2)$/

Adding Custom Configuration for @svgr/webpack:

module.exports = {
  module: {
    rules: [
      {
        test: /\.svg$/i,
        issuer: /\.[jt]sx?$/,
        use: [{ loader: '@svgr/webpack', options: { icon: true } }],
      }
    ],
  },
}

Integration in webpack.config.js:

Ensure to load your custom configuration in the webpack.config.js file:

const { merge } = require('shakapacker')
const customConfig = require('path-to-custom-config')
module.exports = merge(webpackConfig, customConfig)

By applying these changes, you'll effectively override the file rules in Shakapacker and configure Webpack to load SVG files as React components using @svgr/webpack. This setup should address the issues you've encountered. If you have further questions or need additional clarification, feel free to ask!