Importing SVGs - peter-mouland/react-lego-2017 GitHub Wiki

https://github.com/peter-mouland/react-lego/compare/svg

Being able to use SVG's inline within the HTML bring many advantages. Plus, allowing React to do this for me makes this even more desirable because we will be able to :

  • Style SVG's with CSS
  • Naturally use import statement to pull the SVG into components
  • Reduce HTTP calls (still important for a little while yet)

How is it done?

Using webpack-isomorphic-tools and svg-inline-loader allows NodeJS to 'understand' what to do when it sees the following code within your components :

import chevron from './chrevron.svg'
...
{chevron}

webpack-isomorphic-tools?

This package prevents files that NodeJS does not normally understand from crashing the app. This means that once setup we can require/import .svg files (or any image) within our javascript.

It does this by working with webpack to save references to the assets (into a webpack-assets.json file) and then use this file within its own server to intercept our own apps server calls. Clever stuff.

How did I do this?

Roughly, there are only 3 steps. This is the concept :

  1. isomorphic config We have to set which files to intercept and where to save the webpack-assets.json:
// isomorphic.config.js
export default {
  webpack_assets_file_path: path.join(__dirname, '..', '..', 'src', 'server', 'webpack-assets.json'),
  assets: {
    images: {
      extensions: [
        'jpeg', 'jpg', 'png', 'gif', 'svg'
      ]
    },
  }
};
  1. webpack config We must now tell webpack about the plugin
// webpack.config.js
const isomorphicConfig = require('./isomorphic.config.js');
const IsomorphicToolsPlugin = require('webpack-isomorphic-tools/plugin');
export default {
  ...
  plugins: [
    new IsomorphicToolsPlugin(isomorphicConfig)
  ]
  ...
}
  1. isomorphic server This server must start before our own express/koa server
// server.js
const IsomorphicTools = require('webpack-isomorphic-tools');
const server = express();
...
isomorphicTools.server('..').then(() => {
  server.listen(process.env.PORT, () => {
    console.log(`listening at http://localhost:${process.env.PORT}`); // eslint-disable-line
  });
})

Assuming the paths are correct, we should now almost have a server that doesn't die when an svg is imported.

Why use svg-inline-loader?

I was very keen to take advantage of being able to style my SVG to make one file to work on all devices. Basically, if we encoded it to base64 or used them as background-images, we would have to use multiple files where a single file would have done.

In my own SVG's i remove all generated id's and class names and replace them with my own. I also remove any inline styles to help ensure that we don't accidentally affect other inline-svgs that might be on the page. This can be done automatically using svgo-loader for example.

Go on then, How?

We only need to change the webpack config. Add the following to the module.loaders array:

{
  test: /\.svg$/,
  include: [/src/],
  loaders: ['svg-inline']
}

Bringing it all together

Now that we can import SVGs, we need a way of displaying them. I've opted for dangerously setting the inner html of a span to the contents of the SVG. I've done this as my SVG's are all internally controlled and i know they don't contain any malicious code. To make this simpler, I built a Svg component :

// Svg.js
import React, { PropTypes } from 'react';

export default class Svg extends React.Component {
  static propTypes = {
    markup: PropTypes.string.isRequired
  };

  render() {
    const { markup, className, ...props } = this.props;
    return <span dangerouslySetInnerHTML={{ __html: markup }} className={ className } {...props} />;
  }
}

I then re-use this Svg component each time I want to display an SVG on the page.

// my component.js
import chevron from './assets/chevron.svg';
import Svg from '../../components/Svg/Svg';

export default ({ ...props }) => (
  <div { ...props }>
    Look ma, an SVG!
    <Svg markup={chevron} className="my-first-svg" />
  </div>
);

To few all the changes I made, which include tests, styling and organising the following, take a look here: https://github.com/peter-mouland/react-lego/compare/svg

⚠️ **GitHub.com Fallback** ⚠️