Icons

Summary

TypeScript + tooling component library modified to parse source SVGs using svgr and expose them as React components.

In this level, we want to export our existing SVG icons as an icon library. We will be using bare-ts-tooling as a base layer, but can remove everything related to ESLint, as we are only going to deal with SVG source files.

There are different approaches to bundling icons as a library - for example, you can manually create a bundle directly from SVG files by writing a custom parser, or you could directly bundle the SVG files and embed them properly at runtime.

We want to expose clean ES Modules that are nicely tree-shakable, so we are going to convert the SVG icons to React components.

Converting SVG to TSX

As will all other libraries, we want to expose an ES Module with TypeScript declarations alongside it. If we would be creating a vanilla JS library, we could directly convert the SVGs into JS without any JS-TS transpiling.

We are going to use svgr to convert SVG to TSX:

  1. Install the SVGR cli: pnpm add -D @svgr/cli
  2. Place all your SVGs in one folder, e.g. src/icons.
  3. Create a script in your package.json that uses svgr to convert the icons to TSX:
    {
      "scripts": {
        "svgr": "svgr --icon 24 --typescript --out-dir tsx src/icons"
      }
    }
    (--icon is needed to that svgr keeps viewboxes - we're using icons with a base size of 24px here, so we're passing --icon 24 to avoid having svgr override all sizes with 1em)
  4. Adjust the tsup.config.ts to ingest the svgr output:
    import { defineConfig } from 'tsup'
     
    export default defineConfig({
      entry: ['tsx/index.ts'],
      target: 'esnext',
      format: 'esm',
      dts: true,
      sourcemap: true,
      minify: false
    })
  5. In tsconfig.json, change moduleResolution to node, as svgr doesn't use file extensions in the generated TSX.
  6. Add tsx (the svgr output directory) to your .gitignore.
  7. Add a clean script to your package.json:
    {
      "scripts": {
        "clean": "rm -rf tsx && rm -rf dist"
      }
    }
  8. Cable all scripts together into a build script:
    {
      "scripts": {
        "build": "pnpm clean && pnpm svgr && tsup"
      }
    }

Running pnpm build should now

  • remove old build files,
  • generate TSX based on the SVG files in src/icons, and
  • convert the generated TSX into a nice bundle.

That's it!