3

With create-react-app and JavaScript/TypeScript, I understand I'm able to "import" an SVG as noted below. How may I do so with ReasonML?

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

function App() {
  return (
    <div>
      {/* Logo is an actual React component */}
      <Logo />
    </div>
  );
}
Raphael Rafatpanah
  • 19,082
  • 25
  • 92
  • 158
Ari
  • 4,121
  • 8
  • 40
  • 56

3 Answers3

4

Create React App uses webpack to transform SVG files into React components. If you’re using Reason with CRA, then all you need to do is provide a binding to the generated component. However, CRA will only transform the SVG into a component if the import statement is written exactly a certain way, which isn't how BuckleScript outputs import statements. (There's a GitHub issue about it here.) You have to import it with raw JavaScript and then bind to the imported value:

%bs.raw
{|import {ReactComponent as _Logo} from "./logo.svg"|};

module Logo = {
  [@react.component] [@bs.val] external make: unit => React.element = "_Logo";
};

/* And we can use it like a regular component: */
[@react.component]
let make = () =>
  <div>
    <Logo />
  </div>;

According to the CRA docs:

The imported SVG React Component accepts a title prop along with other props that a svg element accepts.

For any of the other props you want to use, you'll have to add them to your external binding.

If you're not using CRA, then you'll need to configure your bundler to do the same transformation. I'm not familiar with the internals of CRA, but this seems to be the relevant code from its webpack configuration.

2

We can use SVGR to handle the webpack loading and then import the module as we normally would.

const webpack = require('webpack');

module.exports = {
  entry: './src/index.js',
  module: {
    rules: [
      //...
      {
        test: /\.svg$/,
        use: ['@svgr/webpack'],
      },
    ],
  },
  //...
};
module Logo = {
  @bs.module(`../../../../src/img/logo.svg`) @react.component
  external make: {.} => React.element = "default"
}

... 

<Logo /> // works

source: https://blog.logrocket.com/how-to-use-svgs-in-react/

Raphael Rafatpanah
  • 19,082
  • 25
  • 92
  • 158
1

I am the author of another solution that doesn't involve webpack. It's a tool that can transform your svg files directly into .re files: https://github.com/MoOx/react-from-svg This can create files for react (dom) or react-native(-web) (=> files generated use react-native-svg). Feel free to try it :)

For example you can do (when the tool is installed from npm)

$ react-from-svg src/SVGs src/SVGs/components --with-native-for-reason --remove-fill

This will turns the files from svg/SVGs into React components into src/SVGs/components compatible for React Native with the Reason syntax. The last option remove all svg fill props so you can use them as icons.

Note that the generated components accept width, height & fill props so you can adjust them when used.

Last bonus: since webpack is not involved, you can use this transformation only when you update your SVGs files & use this code directly with a Node runtime (JSX from Reason gets removed when converted to JS so the code can be consumed directly via Node without any transformation - which can be handy for tiny static sites/pages).

MoOx
  • 8,423
  • 5
  • 40
  • 39