npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

plug-code

v2.4.0

Published

A reactive state management and UI framework for React

Readme

PlugC Framework ⚡

The missing piece for your React applications

A lightning-fast, modular state management and UI composition framework that just works.

npm version TypeScript

Quick StartFeaturesExamplesAPI Reference


🎯 Why PlugC?

Ever felt like existing state management is either too simple or too complex? PlugC bridges that gap.

// From this mess... 😰
const [users, setUsers] = useState([]);
const [filteredUsers, setFilteredUsers] = useState([]);
const [loading, setLoading] = useState(false);
const [searchQuery, setSearchQuery] = useState('');

useEffect(() => {
  const filtered = users.filter(u => 
    u.name.includes(searchQuery) || u.email.includes(searchQuery)
  );
  setFilteredUsers(filtered);
}, [users, searchQuery]);

// To this elegance ✨
api.filterStore('users', 'filteredUsers', searchQuery, 
  ['name', 'email'], 
  { debounce: 300, useWebWorker: 'auto' }
);

const users = useStore('filteredUsers');

✨ Features That Make You Smile

🚀 Blazing Fast

  • Web Workers for heavy operations
  • Built-in virtualization for 100k+ items
  • Smart caching and memoization
  • React 18 concurrent features

🧩 Truly Modular

  • Plugin architecture out of the box
  • Isolated feature modules
  • Dynamic loading support
  • Zero coupling between features

🎨 Flexible UI

  • Slot-based composition
  • Middleware for everything
  • Priority-based rendering
  • Component wrapping & injection

💪 Type-Safe

  • Full TypeScript inference
  • Auto-completion everywhere
  • Catch errors at compile time
  • No any types needed

🎬 Quick Start

Simple Mode - Perfect for Getting Started

import { createSimplePlugC } from 'plugc';

const { Provider, useStore, useAction } = createSimplePlugC({
  initialState: { count: 0 },
  actions: {
    increment(draft) { draft.count++ },
    decrement(draft) { draft.count-- }
  }
});

function Counter() {
  const count = useStore(s => s.count);
  const increment = useAction('increment');
  
  return <button onClick={increment}>{count}</button>;
}

function App() {
  return <Provider><Counter /></Provider>;
}

That's it! No boilerplate, no configuration files, no headaches.

Advanced Mode - For Serious Applications

import { createPlugC } from 'plugc';

type AppSchema = {
  stores: {
    todos: Todo[];
    user: User | null;
  };
  commands: {
    'todos:add': { payload: string; result: Todo };
  };
  slots: {
    'app.sidebar': { collapsed: boolean };
  };
};

const { api, SystemPlcRoot, useStore, useCommand } = createPlugC<AppSchema>();

// Type-safe, autocomplete-friendly, beautiful 🎨

🎪 Real-World Examples

E-Commerce Product Filtering

// Handle 50,000 products like a boss 💪
const ProductCatalog = () => {
  const [search, setSearch] = useState('');
  
  // Automatic web worker processing for large datasets
  api.filterStore(
    'allProducts',      // 50,000 items
    'searchResults',    // Filtered output
    search,
    ['name', 'description', 'sku'],
    { 
      debounce: 300,
      useWebWorker: 'auto',  // Magic! ✨
      onProgress: (done, total) => console.log(`${done}/${total}`)
    }
  );
  
  const results = useStore('searchResults');
  
  return <ProductGrid products={results} />;
};

Infinite Scroll with Virtualization

// Render 100,000 items smoothly 🚀
api.markVirtual('message-list', {
  itemHeight: 80,
  overscan: 10
});

api.register('message-list', 'message-item', ({ message }) => (
  <MessageCard {...message} />
));

function ChatWindow() {
  const messages = useStore('messages'); // 100k+ items
  const renderMessages = useSlot('message-list');
  
  return (
    <div data-virtual-scroll style={{ height: '100vh', overflow: 'auto' }}>
      {renderMessages({ items: messages })}
    </div>
  );
}

Plugin System (Like VSCode!)

// Install features like plugins
const DarkModePlugin = {
  name: 'dark-mode',
  state: { enabled: false },
  commands: {
    toggle: () => {
      api.setSubstore('dark-mode', 'enabled', (draft) => !draft);
    }
  },
  slots: {
    'app.settings': [{
      id: 'dark-mode-toggle',
      component: DarkModeToggle,
      priority: 100
    }]
  }
};

api.registerModule(DarkModePlugin);

// Later, load more features dynamically
await api.loadFeature(() => import('./plugins/analytics'));
await api.loadFeature(() => import('./plugins/notifications'));

Data Pipelines

// Transform data like a pro 🎯
api.makeTransform('user-data', 'validate', (data) => {
  if (!data.email) throw new Error('Email required');
  return data;
}, 0);

api.makeTransform('user-data', 'normalize', (data) => ({
  ...data,
  email: data.email.toLowerCase(),
  name: data.name.trim()
}), 10);

api.makeTransform('user-data', 'enrich', async (data) => {
  const avatar = await fetchAvatar(data.email);
  return { ...data, avatar };
}, 20);

// Process through the pipeline
const user = await api.getTransform('user-data', rawUserInput);

🎯 Choose Your Adventure

🚀 Performance Benchmarks

Rendering 10,000 items:
├─ PlugC (virtualized):     ~16ms  ✅
├─ Regular React:          ~450ms  ⚠️
└─ With useMemo:           ~180ms  📊

Filtering 50,000 items:
├─ PlugC (web workers):     ~45ms  ✅
├─ Array.filter (main):   ~320ms  ⚠️
└─ Lodash:                ~280ms  📊

State updates (1000 subscribers):
├─ PlugC:                   ~8ms  ✅
├─ Redux:                  ~35ms  📊
└─ Context API:           ~120ms  ⚠️

🧠 Core Concepts in 30 Seconds

// 1️⃣ STORES - Your state lives here
api.createStore('todos', []);
api.setStore('todos', (draft) => { draft.push(newTodo) });
const todos = useStore('todos');

// 2️⃣ COMMANDS - Your business logic
api.registerCommand('fetchUsers', async () => {
  const users = await fetch('/api/users').then(r => r.json());
  api.setStore('users', users);
});
await api.execute('fetchUsers');

// 3️⃣ SLOTS - Composable UI pieces
api.register('sidebar', 'user-menu', UserMenu, 100);
api.register('sidebar', 'notifications', Notifications, 90);
const renderSidebar = useSlot('sidebar');

// 4️⃣ WATCHERS - React to changes
api.watch('user', u => u?.id, (newId, oldId) => {
  console.log(`User changed: ${oldId} → ${newId}`);
});

// 5️⃣ DERIVES - Computed values
api.deriveStore('total', 'cart', ['cart', 'products'], 
  (cart, products) => calculateTotal(cart, products)
);

🎨 Beautiful Developer Experience

Auto-completion Everywhere

// TypeScript knows everything! 🧙‍♂️
const count = useStore('counter');        // ✓ number
const user = useStore('user');            // ✓ User | null
const invalid = useStore('notExist');     // ✗ Type error!

await api.execute('login', credentials);  // ✓ Returns User
await api.execute('login', 123);          // ✗ Type error!

Debug-Friendly

const { api } = createSimplePlugC({
  initialState: { /* ... */ },
  actions: { /* ... */ },
  options: { debug: true }  // 🐛 Detailed logging
});

📦 Installation

npm install plugc immer
yarn add plugc immer
pnpm add plugc immer

📋 Changelog

Latest Release v2.4

🎉 New Features

  • 🔗 Enhanced connect() API: Now supports custom selectors for fine-grained reactivity

    const UserDashboard = api.connect(
      ['user', 'todos:items'],
      (user, todos) => ({ userName: user?.name, count: todos.length }),
      ({ userName, count }) => <div>{userName} has {count} todos</div>
    );
  • connectSimple() Method: Lightweight connection without selectors for simple use cases

    const AutoSaver = api.connectSimple(
      ['todos:items'],
      () => {
        const todos = api.getSubstore('todos', 'items');
        useEffect(() => localStorage.setItem('todos', JSON.stringify(todos)), [todos]);
        return null;
      }
    );
  • 🎣 New React Hooks:

    • useConnect() - Hook version of connect() for inline usage
    • useConnectSimple() - Hook version of connectSimple()
    const { useConnect } = createPlugC<Schema>();
      
    const Dashboard = useConnect(
      ['user', 'settings'],
      (user, settings) => ({ name: user.name, theme: settings.theme }),
      ({ name, theme }) => <div className={theme}>Hello {name}</div>
    );
  • 🔍 Native Filtering System: Built-in filterStore() with web worker support

    • Automatic web worker delegation for large datasets
    • Configurable debouncing and matching strategies
    • LRU caching for improved performance
    • Progress callbacks for better UX
    api.filterStore('products', 'filtered', searchQuery, ['name', 'sku'], {
      debounce: 300,
      useWebWorker: 'auto',
      onProgress: (done, total) => setProgress(done / total)
    });

🐛 Bug Fixes

  • Fixed type inference issues in nested substores
  • Resolved memory leaks in watch/unwatch cycles
  • Corrected virtual scrolling position calculations
  • Fixed race conditions in async transform pipelines

🔧 Improvements

  • Stricter TypeScript definitions in both Simple and Advanced modes
  • Better type inference for command payloads and results
  • Enhanced autocomplete for slot names and props
  • Improved error messages with clearer debugging information
  • Optimized re-render performance for large dependency arrays

💥 Breaking Changes

None - this release is fully backward compatible!


🎯 Quick Comparisons

vs Redux

// Redux
const INCREMENT = 'INCREMENT';
const increment = () => ({ type: INCREMENT });
const reducer = (state = 0, action) => 
  action.type === INCREMENT ? state + 1 : state;
const store = createStore(reducer);
// + middleware setup, provider, selectors...

// PlugC
const { api } = createSimplePlugC({
  initialState: { count: 0 },
  actions: { increment: (draft) => { draft.count++ } }
});

vs Zustand

// Zustand
const useStore = create((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 }))
}));

// PlugC (Simple Mode)
const { useStore, useAction } = createSimplePlugC({
  initialState: { count: 0 },
  actions: { increment: (draft) => { draft.count++ } }
});

// BUT PlugC also gives you:
// ✅ Slots for UI composition
// ✅ Built-in virtualization
// ✅ Web workers for filtering
// ✅ Data pipelines
// ✅ Module system
// ✅ And more...

vs Jotai/Recoil

// Atoms everywhere
const countAtom = atom(0);
const doubleAtom = atom((get) => get(countAtom) * 2);
const usersAtom = atom([]);
// ...manage dozens of atoms

// PlugC - centralized, organized
const { api } = createPlugC({
  initialState: {
    count: 0,
    users: []
  }
});

api.deriveStore('double', 'computed', ['count'], 
  (count) => count * 2
);

Ready to plug in? ⚡

npm install plugc