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

intentx-react-mvvm

v1.0.0

Published

Feature-driven MVVM runtime for React with reactive signals, ViewModels, optional dependency injection, plugins, and runtime lifecycle orchestration.

Downloads

2,568

Readme

⚛️ intentx-react-mvvm

NPM Version Downloads Bundle Size

LIVE EXAMPLE

🚀 A feature-based runtime engine for React applications with reactive signals, dependency injection, ViewModels, and plugin architecture.

Build scalable frontend systems using features, services, reactive signals, and lifecycle-aware business logic.


What is intentx-react-mvvm?

intentx-react-mvvm is a lightweight runtime layer for React applications inspired by backend frameworks like NestJS, Angular, and modular runtime systems.
Instead of putting all business logic inside components, the runtime introduces:

  • 🧩 Features
  • 💉 Optional Dependency Injection
  • 📡 Reactive Signals
  • 🧠 ViewModels
  • 🔌 Plugins
  • ⚛️ React Bindings

while still keeping React fully in control of rendering.

Built during random “I should probably sleep” sessions.


Why intentx-react-mvvm?

As React applications scale, architecture usually becomes difficult to maintain.

Common problems:

  • Business logic mixed with UI
  • Large component trees
  • Global state becoming difficult to organize
  • Tight coupling between services and components
  • Too many unnecessary re-renders
  • Hard-to-test business logic

intentx-react-mvvm solves this by introducing runtime-driven architecture with isolated features and reactive state.


Features

  • ⚡ Fine-grained reactive signals
  • 🧩 Feature-based architecture
  • 💉 Optional dependency injection
  • 🧠 ViewModel pattern
  • 📡 Computed signals
  • ⚛️ React hooks integration
  • 🔌 Plugin system
  • 🚦 Lazy feature loading
  • 📦 Runtime lifecycle
  • 🧱 Framework-agnostic core
  • ✅ Full TypeScript support

Mental Model

App
 ↓
Runtime
 ↓
Features
 ↓
ViewModels / Services
 ↓
Reactive Signals
 ↓
React Components

Installation

npm install intentx-react-mvvm

Quick Start

1. Create Feature

// features/user.feature.ts
import { defineFeature } from 'intentx-react-mvvm'

import { UserService } from './services/user.service'
import { UserVM } from './viewmodels/user.vm'

export default defineFeature({
  name: 'users',

  providers: [
    UserService,
    UserVM,
  ],

  onInit() {
    console.log('users feature mounted')
  },

  onDestroy() {
    console.log('users feature destroyed')
  },
})

2. Create Service

Services are plain TypeScript classes.

They can be used:

  • manually
  • with dependency injection
  • with runtime container
  • inside ViewModels
// services/user.service.ts
import { Injectable } from 'intentx-react-mvvm'

export interface User {
  id: number
  name: string
  email: string
}

@Injectable()
export class UserService {
  async findAll(): Promise<User[]> {
    await new Promise((r) => setTimeout(r, 500))

    return [
      {
        id: 1,
        name: 'John Doe',
        email: '[email protected]',
      },

      {
        id: 2,
        name: 'Jane Smith',
        email: '[email protected]',
      },

      {
        id: 3,
        name: 'Alice Brown',
        email: '[email protected]',
      },
    ]
  }
}

3. Create ViewModel

// viewmodels/user.vm.ts
import {
  computed,
  Injectable,
  ViewModel,
} from 'intentx-react-mvvm'

import {
  type User,
  UserService,
} from '../services/user.service'

@Injectable({
  deps: [UserService],
})
export class UserVM extends ViewModel {
  readonly users = this.signal<User[]>([])

  readonly keyword = this.signal('')

  readonly loading = this.signal(false)

  readonly filteredUsers = computed(() => {
    return this.users
      .get()
      .filter((x) =>
        x.name
          .toLowerCase()
          .includes(
            this.keyword
              .get()
              .toLowerCase(),
          ),
      )
  })

  constructor(
    private readonly userService: UserService,
  ) {
    super()
  }

  async onInit() {
    await this.load()
  }

  async load() {
    this.loading.set(true)

    try {
      const users =
        await this.userService.findAll()

      this.users.set(users)
    } finally {
      this.loading.set(false)
    }
  }

  setKeyword(keyword: string) {
    this.keyword.set(keyword)
  }
}

Manual Composition Mode

This mode skips the runtime dependency injection system entirely.

Useful for:

  • small apps
  • testing
  • custom factories
  • manual architecture control
import { defineFeature } from 'intentx-react-mvvm'

import { UserService } from './services/user.service'
import { UserVM } from './viewmodels/user.vm'

export default defineFeature({
  name: 'users',

  async onInit() {
    const userService =
      new UserService()

    const userVM =
      new UserVM(userService)

    await userVM.load()

    console.log('feature ready')
  },
})

4. Use ViewModel in React

import {
  useSignal,
  useViewModel,
} from 'intentx-react-mvvm/react'

import { UserVM } from '../viewmodels/user.vm'

export function UserPage() {
  const vm = useViewModel(UserVM)

  const keyword = useSignal(vm.keyword)

  const users = useSignal(vm.filteredUsers)

  const loading = useSignal(vm.loading)

  return (
    <div style={{ padding: 40 }}>
      <h1>Users</h1>

      <input
        value={keyword}
        onChange={(e) => {
          vm.setKeyword(
            e.currentTarget.value,
          )
        }}
      />

      {loading && <p>Loading...</p>}

      <ul>
        {users.map((user) => (
          <li key={user.id}>
            {user.name}
          </li>
        ))}
      </ul>
    </div>
  )
}

Signals

import {
  signal,
  computed,
  effect,
} from 'intentx-react-mvvm'

const count = signal(0)

const double = computed(() => {
  return count.get() * 2
})

effect(() => {
  console.log(count.get())
})

count.set(1)

Computed Signals

const firstName = signal('John')

const lastName = signal('Doe')

const fullName = computed(() => {
  return `${firstName.get()} ${lastName.get()}`
})

Effects

effect(() => {
  console.log(
    'count changed:',
    count.get(),
  )
})

Service Usage

Services are plain TypeScript classes.

You can use them in multiple ways depending on your architecture needs.


1. Manual Service Usage

export class UserService {
  async findAll() {
    return fetch('/api/users')
      .then((r) => r.json())
  }
}

const service = new UserService()

const users =
  await service.findAll()

Good for:

  • small apps
  • isolated modules
  • testing
  • simple business logic

2. ViewModel Injection (Recommended)

@Injectable({
  deps: [UserService],
})
export class UserVM extends ViewModel {
  constructor(
    private readonly userService: UserService,
  ) {
    super()
  }
}

Benefits:

  • centralized dependency management
  • easier testing/mocking
  • feature isolation
  • cleaner architecture

3. Runtime Container Access (Advanced)

const service =
  runtime.container.resolve(
    UserService,
  )

Useful for:

  • plugins
  • runtime extensions
  • infrastructure
  • dynamic systems

Avoid using this directly inside React components.


useSignal

const count = useSignal(vm.count)

useViewModel

const vm = useViewModel(UserVM)

Potential future factory mode:

const vm = useViewModel(() => {
  return new UserVM(
    new UserService(),
  )
})

ViewModel Lifecycle

export class UserVM extends ViewModel {
  async onInit() {
    console.log('mounted')
  }

  async onDestroy() {
    console.log('destroyed')
  }
}

Runtime Router

RuntimeRouter automatically collects routes from registered features.

import { BrowserRouter } from 'react-router-dom'

import {
  RuntimeProvider,
  RuntimeRouter,
} from 'intentx-react-mvvm/react'

export default function App() {
  return (
    <BrowserRouter>
      <RuntimeProvider runtime={runtime}>
        <RuntimeRouter runtime={runtime} />
      </RuntimeProvider>
    </BrowserRouter>
  )
}

Lazy Feature Loading

await runtime.loadFeature(() =>
  import('./features/admin.feature'),
)

Destroy Feature

await runtime.destroyFeature('users')

After destruction:

  • feature removed from runtime
  • providers disposed
  • lifecycle hooks executed
  • routes removed
  • subscriptions cleaned

Plugin Ideas

  • persistencePlugin
  • devtoolsPlugin
  • loggerPlugin
  • sentryPlugin
  • analyticsPlugin
  • i18nPlugin

Runtime API

| API | Purpose | | -------------------------- | ----------------------- | | use(plugin) | Install runtime plugin | | registerFeature(feature) | Register feature module | | loadFeature(loader) | Lazy load feature | | destroyFeature(name) | Dispose feature | | getFeatures() | Get registered features | | getRoutes() | Get runtime routes |


Comparison

| Feature | intentx-react-mvvm | Redux Toolkit | MobX | Zustand | | -------------------- | ------------------ | -------------- | ---- | -------- | | Reactive signals | ✅ | ❌ | ✅ | ⚠️ | | Dependency injection | ✅ | ❌ | ❌ | ❌ | | ViewModels | ✅ | ❌ | ⚠️ | ❌ | | Feature architecture | ✅ | ❌ | ❌ | ❌ | | Runtime lifecycle | ✅ | ❌ | ❌ | ❌ | | Plugin system | ✅ | ❌ | ❌ | ❌ | | Lazy feature loading | ✅ | ⚠️ | ❌ | ❌ | | Computed state | ✅ | ✅ | ✅ | ⚠️ | | React hooks | ✅ | ✅ | ✅ | ✅ | | Lightweight | ✅ | ⚠️ | ❌ | ✅ |


Philosophy

You control:
- Features
- Services
- ViewModels
- UI
- Plugins

intentx-react-mvvm controls:
- Runtime lifecycle
- Signals
- Feature orchestration
- React integration

Principles

  • Explicit over implicit
  • Feature-first architecture
  • Runtime-oriented execution
  • Composition over inheritance
  • Reactive state by default
  • Framework-agnostic core
  • Full TypeScript inference

When to Use

✅ Great Fit

  • Large React applications
  • Enterprise frontends
  • Plugin-based systems
  • Micro-frontends
  • Feature-driven architecture
  • Complex business logic

❌ Probably Overkill

  • Tiny apps
  • Static sites
  • Simple CRUD pages
  • Small prototypes

License

MIT