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:
- onPluginsLoad: Called when plugins are loaded (optional)
- beforeGenerate: Called before the generation process starts (optional)
- generate: The main generation function that creates output files (required)
- afterGenerate: Called after the generation process completes (optional)
- beforeWriteFiles: Called before files are written to disk (optional)
- 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
- Initialize: Plugin is loaded by the bundler during startup
- Load Config: Load Monicon configuration from
monicon.config.ts - Watch: Watch the config file for changes
- 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