react-runtime-pipe
v1.0.0
Published
A backend-style runtime for React with middleware, DI, plugins, and structured action execution.
Downloads
1,486
Maintainers
Keywords
Readme
⚡ react-runtime-pipe
🚀 A backend-inspired execution runtime for React applications.
Build scalable frontend systems using middleware pipelines, typed actions, dependency injection, runtime context, plugins, orchestration, and event-driven execution.
Installation
npm install react-runtime-pipeWhat is react-runtime-pipe?
react-runtime-pipe is a lightweight runtime for executing backend-style logic in React applications.
It brings concepts like middleware, dependency injection, and orchestration into frontend code.
It provides:
- typed action execution
- middleware pipelines
- dependency injection
- runtime context
- plugins and event system
- retry and cancellation support
without enforcing any specific state management approach.
Why react-runtime-pipe?
Frontend apps often become hard to scale as logic spreads across components and async flows become inconsistent.
Common problems:
- business logic inside UI components
- duplicated async logic
- scattered dependencies
- tightly coupled side effects
- inconsistent orchestration
react-runtime-pipe solves this by introducing a structured execution layer:
- predictable execution flow
- composable middleware
- centralized orchestration
- backend-like architecture in frontend
- framework-agnostic design
Features
- ⚡ Runtime-first architecture
- 🧩 Middleware pipeline
- 🔌 Plugin system
- 🧠 Typed execution context
- 🛡 Action lifecycle hooks
- ♻️ Retry orchestration
- 📦 Dependency injection container
- 📡 Event bus system
- 📝 Full TypeScript inference
- 🚦 Abort/cancellation support
- 💾 Scoped execution cache
- ⚛️ React integration
- 🧱 Framework agnostic core
Mental Model
UI Event
↓
useAction()
↓
createExecutionContext()
↓
Plugins
↓
Middleware Pipeline
↓
Action Handler
↓
Service Layer
↓
Event Bus
↓
UI UpdateQuick Start
Create App
// app.ts
import { createApp } from 'react-runtime-pipe'
import { loggerPlugin } from 'react-runtime-pipe/plugin'
import { ApiService } from './services/api'
import { ApiServiceToken } from './tokens'
export const app = createApp({
services: [
{
token: ApiServiceToken,
useValue: new ApiService(),
},
],
})
app.plugin(loggerPlugin)
Define Action
import { defineAction } from 'react-runtime-pipe'
import { globalEvents } from 'react-runtime-pipe/react'
import { logger, retry } from 'react-runtime-pipe/middleware'
import { ApiServiceToken } from './tokens'
export const saveUserAction = defineAction({
name: 'save-user',
middleware: [logger, retry(3)],
async handler({ input, context }) {
context.logger.info('saving user', input)
const api = context.container.resolve(ApiServiceToken)
const user = await api.saveUser(input)
// context.events.$emit('user:saved', user)
globalEvents.$emit('user:saved', user)
return {
success: true,
user,
}
},
})Service Implementation
// api.ts
import { createRequestId } from 'react-runtime-pipe'
export class ApiService {
async saveUser(input: any) {
await new Promise((resolve) => {
setTimeout(resolve, 500)
})
return {
id: createRequestId(),
input,
}
}
}Tokens
// tokens.ts
import { createToken } from 'react-runtime-pipe'
import type { ApiService } from './services/api'
export const ApiServiceToken =
createToken<ApiService>('ApiService')React Usage
// Root.tsx
import React from 'react'
import {
useAction,
useEventBus,
globalEvents,
} from 'react-runtime-pipe/react'
import { saveUserAction } from './saveUser'
export function Root() {
const saveUser = useAction(saveUserAction)
useEventBus(
'user:saved',
() => {
alert('User saved successfully!')
},
globalEvents,
)
return (
<div>
<button
disabled={saveUser.loading}
onClick={() => {
saveUser.execute({
name: 'Tung',
})
}}
>
{saveUser.loading
? 'Saving...'
: 'Save User'}
</button>
{saveUser.error ? (
<pre>{String(saveUser.error)}</pre>
) : null}
</div>
)
}Bootstrap
// main.tsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import { RuntimeProvider } from 'react-runtime-pipe/react'
import { Root } from './Root'
import { app } from './app'
async function bootstrap() {
await app.run()
const rootElement =
document.getElementById('root')
if (!rootElement) {
throw new Error(
'Root element #root not found',
)
}
ReactDOM.createRoot(rootElement).render(
<React.StrictMode>
<RuntimeProvider app={app}>
<App />
</RuntimeProvider>
</React.StrictMode>,
)
}
bootstrap()Dependency Injection
import { createApp, createToken } from 'react-runtime-pipe'
class ApiService {
async saveUser() {}
}
const ApiServiceToken = createToken<ApiService>('ApiService')
const app = createApp({
services: [
{
token: ApiServiceToken,
useFactory: () =>
new ApiService(),
},
],
})Service Injection in Actions
import { defineAction } from 'react-runtime-pipe'
import { ApiServiceToken } from './tokens'
export const saveUserAction =
defineAction({
name: 'save-user',
async handler({
input,
context,
}) {
const api =
context.container.resolve(
ApiServiceToken,
)
return api.saveUser(input)
},
})useService hook
import { useService } from 'react-runtime-pipe/react'
import { ApiServiceToken } from './tokens'
export function UserPage() {
const api = useService(ApiServiceToken)
return null
}Runtime Context
| Property | Description | |---------------|--------------------------| | ctx.requestId | execution request id | | ctx.signal | abort signal | | ctx.logger | runtime logger | | ctx.container | dependency container | | ctx.events | execution event bus | | ctx.cache | scoped execution cache | | ctx.auth | authenticated user state |
Event Bus
Emit Event
globalEvents.$emit(
'user:saved',
user,
)Listen To Event
useEventBus(
'user:saved',
(payload) => {
console.log(payload)
},
globalEvents,
)Middleware
Middleware in react-runtime-pipe allows you to intercept and control the execution flow of an action.
Here is a simple example: Abort Middleware — used to stop execution if the request has been cancelled.
import type { Middleware } from 'react-runtime-pipe'
export const abortMiddleware: Middleware = async ({
context,
next,
}) => {
// check before executing the handler
context.throwIfAborted()
const result = await next()
// check after the handler finishes
context.throwIfAborted()
return result
}This middleware ensures that if the user triggers an abort (e.g. cancels a request or unmounts a component), the action is immediately stopped both before and after execution.
Plugins
import type { Plugin } from 'react-runtime-pipe'
const analyticsPlugin: Plugin = {
name: 'analytics',
setup({ app }) {
console.log('plugin setup')
},
}
app.plugin(analyticsPlugin)React Runtime Provider
import { RuntimeProvider } from 'react-runtime-pipe/react'
import { app } from './app'
export function Root() {
return (
<RuntimeProvider app={app}>
<App />
</RuntimeProvider>
)
}Action Lifecycle
useAction.execute()
↓
createExecutionContext()
↓
composeMiddleware()
↓
executeHandler()
↓
emitEvents()
↓
returnResult()Execution Cache
const cacheKey = 'user:1'
if (ctx.cache.has(cacheKey)) {
return ctx.cache.get(cacheKey)
}
const user = await api.getUser()
ctx.cache.set(cacheKey, user)
return userAbort Support
ctx.throwIfAborted()ctx.signal.addEventListener(
'abort',
() => {
console.log('cancelled')
},
)Full Example
import { defineAction } from 'react-runtime-pipe'
import {
logger,
retry,
auth,
} from 'react-runtime-pipe/middleware'
import { globalEvents } from 'react-runtime-pipe/react'
import { ApiServiceToken } from './tokens'
export const saveUserAction =
defineAction({
name: 'save-user',
middleware: [
auth,
logger,
retry(),
],
async handler({
input,
context,
}) {
const api =
context.container.resolve(
ApiServiceToken,
)
const user =
await api.saveUser(input)
globalEvents.$emit(
'user:saved',
user,
)
return {
success: true,
user,
}
},
})Comparison
| Criteria | react-runtime-pipe | Redux | React Query | |---------------------|--------------------|-------|-------------| | Middleware Pipeline | ✅ | ⚠️ | ❌ | | Dependency Injection| ✅ | ❌ | ❌ | | Runtime Context | ✅ | ❌ | ❌ | | Event Bus | ✅ | ❌ | ❌ | | Orchestration Layer | ✅ | ❌ | ⚠️ | | Async Data Handling | ⚠️ | ❌ | ✅ | | Plugin System | ✅ | ❌ | ❌ | | Action-based API | ✅ | ❌ | ❌ | | Execution Pipeline | ✅ | ❌ | ❌ |
Philosophy
You control:
- middleware
- plugins
- orchestration
- architecture
- services
react-runtime-pipe controls:
- execution
- lifecycle
- context
- typing
- pipelinesDesign
- Explicit execution
- Composition over inheritance
- Backend-inspired architecture
- Runtime-first design
- Framework-agnostic core
- Deterministic orchestration
When to Use
- Large React applications
- Complex async flows
- Plugin-based frontends
- Runtime orchestration systems
- Event-driven UI architecture
- Shared business execution layers
- Backend/frontend unified patterns
License
MIT
