DEV Community

Tarun Mangukiya
Tarun Mangukiya

Posted on

Creating my first React Package - React-unicons

Hi guys,

Since long I wanted to work on and create package in React. I am mostly working in VueJS, thus this was a bit new experience for me.

Recently, we launched Unicons - an icon library containing 1000+ vector icons in unique line style as open source. And since then I wished to have package for React. Last Sunday, I was kinda free & thought to give it a try! And here I am writing this article.

How to

There were few ideas in my mind related to how I want to make it available. Some of them contains:

  1. Easy to use for everyone.
  2. Component based
  3. One should be able to load only icons that they need, keeping bundle size as low as possible.

I wrote a script that converts the SVGs to React components. I used folder based approach like lodash to keep the bundle size smaller. Every component gets compiled into different React component file and gets imported to common index.js for those who want to use all the icons.

Here is a sample component of comment icon:

import React from 'react';
import PropTypes from 'prop-types';

const UilComment = (props) => {
  const { color, size, ...otherProps } = props
  return React.createElement('svg', {
    xmlns: 'http://www.w3.org/2000/svg',
    width: size,
    height: size,
    viewBox: '0 0 24 24',
    fill: color,
    ...otherProps
  }, React.createElement('path', {
    d: 'M12,2A10,10,0,0,0,2,12a9.89,9.89,0,0,0,2.26,6.33l-2,2a1,1,0,0,0-.21,1.09A1,1,0,0,0,3,22h9A10,10,0,0,0,12,2Zm0,18H5.41l.93-.93a1,1,0,0,0,0-1.41A8,8,0,1,1,12,20Z'
  }));
};

UilComment.propTypes = {
  color: PropTypes.string,
  size: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
};

UilComment.defaultProps = {
  color: 'currentColor',
  size: '24',
};

export default UilComment;

The build script that I wrote looks something like this:

const path = require('path')
const fs = require('fs-plus')
const cheerio = require('cheerio')
const upperCamelCase = require('uppercamelcase')

const iconsComponentPath = path.join(process.cwd(), 'icons')
const iconsIndexPath = path.join(process.cwd(), 'index.js')
const uniconsConfig = require('@iconscout/unicons/icons.json')

// Clear Directories
fs.removeSync(iconsComponentPath)
fs.mkdirSync(iconsComponentPath)

const indexJs = []

uniconsConfig.forEach(icon => {
  const baseName = `uil-${icon.name}`
  const location = path.join(iconsComponentPath, `${baseName}.js`)
  const name = upperCamelCase(baseName)
  const svgFile = fs.readFileSync(path.resolve('node_modules/@iconscout/unicons', icon.svg), 'utf-8')

  let data = svgFile.replace(/<svg[^>]+>/gi, '').replace(/<\/svg>/gi, '')
  // Get Path Content from SVG
  const $ = cheerio.load(data, {
    xmlMode: true
  })
  const svgPath = $('path').attr('d')

  const template = `import React from 'react';
import PropTypes from 'prop-types';
const ${name} = (props) => {
  const { color, size, ...otherProps } = props
  return React.createElement('svg', {
    xmlns: 'http://www.w3.org/2000/svg',
    width: size,
    height: size,
    viewBox: '0 0 24 24',
    fill: color,
    ...otherProps
  }, React.createElement('path', {
    d: '${svgPath}'
  }));
};
${name}.propTypes = {
  color: PropTypes.string,
  size: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
};
${name}.defaultProps = {
  color: 'currentColor',
  size: '24',
};
export default ${name};`

  fs.writeFileSync(location, template, 'utf-8')

  // Add it to index.js
  indexJs.push(`export { default as ${name} } from './icons/${baseName}'`)
})

fs.writeFileSync(iconsIndexPath, indexJs.join('\n'), 'utf-8')

console.log(`Generated ${uniconsConfig.length} icon components.`)

Earlier I tried to use webpack and it didn't work out properly as it compiled them into single index.js file.

Publishing it as npm package

I learned how to publish it as a npm package so that everyone can use it via simple npm install. I've published it at https://www.npmjs.com/package/@iconscout/react-unicons

Use

You can use these icon by simple installing
npm i -s @iconscout/react-unicons

and then import individual icons in your component.

import React from 'react';
import UilReact from '@iconscout/react-unicons/icons/uil-react'

const App = () => {
  return <UilReact size="140" color="#61DAFB" />
};

export default App;

I have also added props to customise color and size.

I would love to have suggestions from DEV.to community on how I can improve it. :)

Top comments (1)

Collapse
 
nikrunic profile image
KRUNAL R PRAJAPATI

This is also beautiful website for free svg icon - custicon.com
24000+ free icons for use in web, iOS, Android, and desktop apps. Support for SVG. License: MIT, Free for commercial or personal use.
This provide svg icon and svg code and also provide the icon image and it should be free

Image description