Monicon

Architecture

Understand Monicon's architecture, package structure, and how components work together

This guide explains Monicon's architecture, including package dependencies, the icon generation flow, and how different components work together.

Overview

Monicon is built as a monorepo with multiple packages that work together to provide a flexible, framework-agnostic icon management system. The architecture is designed to be modular, extensible, and easy to integrate with different build tools and frameworks.

Package Structure

Core Packages

@monicon/core (Core Engine)

The heart of Monicon, containing all the core functionality:

  • Bootstrap Function: Entry point for icon generation
  • Loaders: Fetch icons from different sources (remote, local, JSON)
  • Plugins: Transform icons into framework-specific components
  • Utilities: Config loading, file system operations, icon processing

@monicon/cli (Command Line Interface)

Command-line tool for generating icons outside of build processes. Uses @monicon/core to provide a CLI experience.

Bundler Integration Packages

All bundler packages depend on @monicon/core and provide seamless integration:

  • @monicon/vite - Vite plugin
  • @monicon/webpack - Webpack plugin
  • @monicon/rollup - Rollup plugin
  • @monicon/esbuild - esbuild plugin
  • @monicon/rspack - Rspack plugin
  • @monicon/metro - Metro bundler plugin (React Native)
  • @monicon/nuxt - Nuxt module

Core Architecture

The @monicon/core package is structured into four main components:

Components

Bootstrap

Entry point that orchestrates the entire icon generation process. It:

  • Loads configuration
  • Processes icons
  • Runs plugins
  • Writes output files

Loaders

Fetch icons from various sources:

  • Remote Collection: Fetch from Iconify CDN
  • Local Collection: Load from local file system
  • JSON Collection: Load from JSON files

Plugins

Transform raw SVG icons into framework-specific components:

  • Generic Plugin: Base plugin providing file generation capabilities (used internally by framework plugins)
  • React Plugin: Generate React/JSX components (built on Generic Plugin)
  • Vue Plugin: Generate Vue SFC components (built on Generic Plugin)
  • Svelte Plugin: Generate Svelte components (built on Generic Plugin)
  • Qwik Plugin: Generate Qwik components (built on Generic Plugin)
  • React Native Plugin: Generate React Native components with react-native-svg (built on Generic Plugin)
  • SVG Plugin: Generate plain SVG files (built on Generic Plugin)
  • Clean Plugin: Clean output directories
  • Debugger Plugin: Debug icon generation

Utils

Helper utilities for various operations:

  • Config Loader: Load and watch configuration files
  • File System: Handle file operations
  • Icon Processor: Process and transform icons
  • Plugin Loader: Load and execute plugins
  • SVG Utils: Parse and manipulate SVG content

Plugin System

Plugins are the core of Monicon's extensibility. Here's how the plugin system works:

Plugin Lifecycle

Each plugin can implement the following hooks:

  1. onPluginsLoad: Called when plugins are loaded (optional)
  2. beforeGenerate: Called before the generation process starts (optional)
  3. generate: The main generation function that creates output files (required)
  4. afterGenerate: Called after the generation process completes (optional)
  5. beforeWriteFiles: Called before files are written to disk (optional)
  6. afterWriteFiles: Called after files are written to disk (optional)

Creating Custom Plugins

Plugins are functions that return a configuration object:

import { ,  } from "@monicon/core/plugins";

export const : <void> = () => () => {
  return {
    : "monicon-txt-plugin",
    : () => {
      const : [] = [];

      for (const  of .) {
        .({
          : `output/${.}.txt`,
          : .,
        });
      }

      return ;
    },
  };
};

Generic Plugin Foundation

Most framework plugins (React, Vue, Svelte, Qwik, React Native, and SVG) are built on top of the Generic Plugin. The Generic Plugin provides a reusable foundation for file generation with flexible options:

  • outputPath: Function or string to determine where files are generated
  • fileName: Function or string to determine file names
  • extension: Function or string to determine file extensions
  • content: Function or string to generate file content

This architecture allows framework plugins to focus on their specific transformations (e.g., converting SVG to React JSX) while delegating file management to the generic plugin.

import {
  ,
  ,
  ,
} from "@monicon/core/plugins";

type  = <>;

type  = {
  ?: string;
};

export const : <> = () =>
  ({
    : "my-custom-plugin",
    : "custom",
    : () => `/* Custom content for ${.} */`,
    ...,
  });

Bundler Integration Flow

Bundler packages integrate Monicon into the build process:

How Bundler Plugins Work

  1. Initialize: Plugin is loaded by the bundler during startup
  2. Load Config: Load Monicon configuration from monicon.config.ts
  3. Watch: Watch the config file for changes
  4. Generate: When changes are detected, trigger icon generation via bootstrap()

Data Flow Example

Let's trace a complete example of generating a React icon component:

Key Design Principles

1. Framework Agnostic

The core is framework-agnostic. Framework-specific logic is isolated in plugins, making it easy to support new frameworks.

2. Build Tool Independent

Bundler integration packages are separate, allowing users to choose their preferred build tool or use the CLI.

3. Extensible

The plugin system allows users to create custom transformations and integrations.

4. Type Safe

Full TypeScript support with exported types for configuration and plugins.

Examples

Using Core Directly

import {  } from "@monicon/core";
import {  } from "@monicon/core/plugins";

await ({
  : ["mdi:home"],
  : [({ : "src/components/icons" })],
});

Using with Vite

import {  } from "vite";
import  from "@monicon/vite";
import {  } from "@monicon/core/plugins";

export default ({
  : [
    ({
      : ["mdi:home"],
      : [({ : "src/components/icons" })],
    }),
  ],
});

Using CLI

npx @monicon/cli generate --watch

On this page