6 minute read | a year ago
In this blog, I will be sharing some of the experiences I had while building React Native Icons. Here's a little background on why I created the site.
While I was doing a demo on React Native, I frequently needed icons. Each time, I had to search for icons online and convert them using the SVGR Playground. This process was tedious, involving copying or downloading the icon, uploading it to the site, and then converting it. To make this process easy for me, I thought, "Why not create a website featuring all my favorite icons?" This way, I could click on an icon, have it automatically converted to a React Native icon, and copied to my clipboard. All I would need to do is paste the icon into my project. This was the driving force behind the website.
Before creating the site, I had two questions in mind. The first one being, how to convert an SVG to a React Native SVG? The obvious answer was to use the SVGR Playground. Luckily, the project is open source, so I decided to fork it and modify the source code to fit my needs. The other question is how to get a list of all my icons? Again the obvious answer was to use the list of icons provided by React Icons
My goal was to create a tool to automate SVG to React Native SVG conversion—a script or a CLI tool would do. Upon checking SVGR's repo, I found they already had a CLI tool.
I created a sandbox to test the CLI, and everything worked perfectly. However, I needed to save some customized metadata in the generated files (in this case .mdx files).
SVGR allows for custom templates, but anything within those templates must be valid JavaScript syntax, thus creating a barrier for me. So, I cloned the repo and modified the source code to be able to add metadata to the generated files:
Basically, I manipulated the data right before it was written to the file, creating a customized SVG to MDX converter.
Next, I scaffolded a Next.js project and pasted the icons I had generated. I needed to transform these .mdx files into a format digestible by Next.js. Contentlayer was perfect for converting .mdx files to .json and exporting them. However, I realized my icons were React components (string format), which aren't displayable in the browser. I wanted to use tools like Babel's JSX transformer to convert the strings to valid JSX, but I realized that it's not an optimal way of doing things. Imagine looping over hundreds of icons, transforming every single one of them, before displaying them in the browser.
At this point, I decided to go with a different approach. Instead of converting the icons to components, why not just convert them directly to strings? This approach meant I had to drop SVGR's API at this stage. I did exactly that. I built a script to convert my SVG files to MDX files, allowing me to add custom metadata to the generated content.
The script worked fine, but now I had concerns with Contentlayer. Generating lists of icons from .mdx files with Contentlayer every time I started the server seemed inefficient, especially with a large number of icons. The project has thousands of icons; every time I start the server, Contentlayer will have to generate all of those icons, which was concerning. So, I decided to drop Contentlayer as well and write my own Contentlayer-like script to generate lists of icons only if necessary.
While writing the code and doing some testing, I found issues with data duplication and order in the generated files. I spent hours trying to figure out the issue. Eventually, I realized that the problem was a mix of asynchronous and synchronous functions during the file generation process. Switching to only asynchronous functions and awaiting all of them solved the problem.
Now that both my scripts are working fine, I need to find a way to clone the icons from their repositories based on the list of icons I got from React Icons. The goal was to loop over the list of icons and clone them based on their URL. The initial code I had looked like this:
This script worked fine locally. However, when I deployed the code to Vercel, I got the following error message:
With everything working, I fine-tuned the script to also generate index.d.ts files for TypeScript. The generated types look like this.
I imported the icons, looped over them, and rendered them on the webpage. I implemented a feature to convert icons to React Native Icons and copy them to the clipboard using SVGR's API if a user clicks on an icon.
This is how I built React Native icons.
Thanks for reading! I hope you learned something new.
Happy coding...