Bundling custom icons for Iconify components

This article is a part of Iconify icon bundles code examples.

This example show how to create icon bundles for Iconify components from SVG files. It uses Iconify Tools to import SVG, clean them up, optimize and export to bundle.

Instructions

Installation:

npm install --save-dev @iconify/tools

Usage:

  • Change value of component to correct component. See below.
  • If you want script to output CommonJS code (that uses require()), set commonJS to true.
  • Change value of target to correct location of bundle.
  • Change value of source to correct location of SVG files.
  • Optionally change prefix to prefix you want to use for imported icons.
  • Run script.

Components

Values for variable component are package names for components:

Bundle script

example.ts
/**
* This is an advanced example for creating icon bundles for Iconify SVG Framework.
* It creates a bundle from all SVG files in a directory.
*
* This example uses Iconify Tools to import and clean up icons.
* For Iconify Tools documentation visit https://docs.iconify.design/tools/tools2/
*/

import { promises as fs } from 'fs';
import { dirname } from 'path';

// Installation: npm install --save-dev @iconify/tools
import {
   importDirectory,
   cleanupSVG,
   parseColors,
   isEmptyColor,
   runSVGO,
} from '@iconify/tools';

// Iconify component (this changes import statement in generated file)
// Available options: '@iconify/react' for React, '@iconify/vue' for Vue 3, '@iconify/vue2' for Vue 2, '@iconify/svelte' for Svelte
const component = '@iconify/react';

// Set to true to use require() instead of import
const commonJS = false;

// File to save bundle to
const target = 'lib/icons-bundle.js';

// SVG files location
const source = 'svg';

// Prefix to use for custom icons
const prefix = 'custom';

// Import icons
(async function () {
   // Import icons
   const iconSet = await importDirectory(source, {
       prefix,
   });

   // Validate, clean up, fix palette and optimise
   await iconSet.forEach(async (name, type) => {
       if (type !== 'icon') {
           return;
       }

       // Get SVG instance for parsing
       const svg = iconSet.toSVG(name);
       if (!svg) {
           // Invalid icon
           iconSet.remove(name);
           return;
       }

       // Clean up and optimise icons
       try {
           // Clean up icon code
           await cleanupSVG(svg);

           // Assume icon is monotone: replace color with currentColor, add if missing
           // If icon is not monotone, remove this code
           await parseColors(svg, {
               defaultColor: 'currentColor',
               callback: (attr, colorStr, color) => {
                   return !color || isEmptyColor(color) ? colorStr : 'currentColor';
               },
           });

           // Optimise
           await runSVGO(svg);
       } catch (err) {
           // Invalid icon
           console.error(`Error parsing ${name}:`, err);
           iconSet.remove(name);
           return;
       }

       // Update icon from SVG instance
       iconSet.fromSVG(name, svg);
   });
   console.log(`Imported ${iconSet.count()} icons`);

   // Export to JSON
   const json = iconSet.export();

   // Export to bundle
   let output = commonJS
       ? "const { addCollection } = require('" + component + "');\n\n"
       : "import { addCollection } from '" + component + "';\n\n";
   output += 'addCollection(' + JSON.stringify(json) + ');\n';

   // Create directory for output if missing
   const dir = dirname(target);
   try {
       await fs.mkdir(dir, {
           recursive: true,
       });
   } catch (err) {
       //
   }

   // Save to file
   await fs.writeFile(target, output, 'utf8');

   console.log(`Saved ${target} (${output.length} bytes)`);
})().catch((err) => {
   console.error(err);
});

Part of code is taken from Iconify Tools import examples.

Bundle generated by script above must be imported in your application:

import './icons-bundle.js';

If you are using require() and have set commonJS to true, use this code:

require('./icons-bundle.js');