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

runtime-registry

v1.0.0

Published

A runtime capability registry for micro-frontend architectures

Readme

RuntimeRegistry

一个轻量级、类型安全的运行时能力注册中心。提供命名空间隔离的能力注册和发现,并带有事件通知系统。

✨ 核心特性

  • 🎯 命名空间隔离:不同模块/插件/租户之间完全隔离,互不干扰
  • 🚀 高性能:基于原生 Map 的 O(1) 时间复杂度操作
  • 📦 类型安全:完整的 TypeScript 支持和泛型推导
  • 🔔 事件系统:外部 EventEmitter 集成,实时监听所有变更
  • 🪶 轻量级:最小依赖,简洁的 API 设计
  • 🔍 可观察性:内置调试和审查工具

🎯 适用场景

RuntimeRegistry 特别适合需要以下特性的场景:

核心优势

隔离性 - 不同模块/插件/租户需要完全隔离
可观察性 - 需要监听所有变更(审计、日志、调试)
动态性 - 运行时动态注册/注销能力
轻量级 - 不想引入重量级的 IoC 容器或状态管理库
类型安全 - TypeScript 项目需要完整的类型推导

典型应用

  • 🏗️ 微前端架构 - 不同应用间的能力共享和隔离
  • 🔌 插件系统 - 插件注册、发现和管理
  • 🎯 服务定位器 - 轻量级依赖注入和服务管理
  • 🏢 多租户系统 - 租户级别的配置和资源隔离
  • 🚦 功能开关 - 分环境、分用户组的特性管理
  • 📦 模块化配置 - 分模块的配置管理和热更新
  • 🎨 主题系统 - 多主题/皮肤的资源管理
  • 🧪 测试隔离 - 测试用例间的独立上下文
  • 💾 缓存管理 - 带命名空间和事件通知的内存缓存

Runtime 的含义

RuntimeRegistry 的 "Runtime" 强调在程序运行期间动态发现和管理能力。

  • ✅ 绑定可以是静态的(初始化时注册)
  • ✅ 也可以是动态的(运行时注册)
  • ✅ 发现总是运行时的(动态查找)

与 ESM/CommonJS 的关系

它是JS模块化开发在运行时的能力补充

| 特性 | ESM/CommonJS | RuntimeRegistry | |-----|--------------|-----------------| | 层次 | 模块系统层 | 应用层 | | 时机 | 加载时 | 运行时 | | 解决 | 代码组织 | 实例管理 | | 粒度 | 文件级 | 实例级 | | 绑定 | 静态路径 | 动态键值 |

典型组合使用:

// 用 ESM 组织代码
import { UserService } from './services/user';

// 用 RuntimeRegistry 管理实例
const services = registry.namespace('services');
services.set('userService', new UserService());

// 跨模块/跨应用访问(无需 import)
const userService = services.get('userService');

相比其他方案的优势

| 特性 | RuntimeRegistry | Redux | EventEmitter | 全局对象 | |-----|----------------|-------|--------------|---------| | 命名空间隔离 | ✅ | ❌ | ❌ | ❌ | | 类型安全 | ✅ | ✅ | ❌ | ❌ | | 事件通知 | ✅ | ✅ | ✅ | ❌ | | 性能 | ⚡ O(1) | 🐌 O(n) | ⚡ O(1) | ⚡ O(1) | | 包体积 | 🪶 极小 | 📦 较大 | 🪶 极小 | - | | 学习成本 | 📖 简单 | 📚 复杂 | 📖 简单 | 📖 简单 |

Installation

npm install runtime-registry eventemitter3

Quick Start

import EventEmitter from 'eventemitter3';
import { RuntimeRegistry, REGISTRY_EVENTS } from 'runtime-registry';

// Initialize with an EventEmitter
const emitter = new EventEmitter();
const registry = new RuntimeRegistry({ emitter });

// Listen to events
emitter.on(REGISTRY_EVENTS.REGISTER, (payload) => {
  console.log(`Registered: ${payload.namespace}/${payload.key}`);
});

// Create a namespace for your app
const app1 = registry.namespace('app1');

// Register capabilities
app1.set('userService', userService);
app1.set('authService', authService);

// Get capabilities
const service = app1.get('userService');

// Get all capabilities
const allServices = app1.get();
// { userService: {...}, authService: {...} }

📚 核心概念

命名空间隔离

RuntimeRegistry 使用命名空间提供完全的隔离机制。每个命名空间拥有独立的键值存储空间。

const mainApp = registry.namespace('main-app');
const pluginA = registry.namespace('plugin-a');
const pluginB = registry.namespace('plugin-b');

// 相同的 key,不同的值 - 完全不冲突!
mainApp.set('userService', mainAppUserService);
pluginA.set('userService', pluginAUserService);
pluginB.set('userService', pluginBUserService);

事件系统

RuntimeRegistry 集成外部 EventEmitter 实例(来自 eventemitter3 或 Node.js events),实时通知所有变更。

事件类型:

  • registry:register - 注册新能力
  • registry:update - 更新已有能力
  • registry:unregister - 删除能力
  • registry:clear - 清空命名空间
import EventEmitter from 'eventemitter3';
import { RuntimeRegistry, REGISTRY_EVENTS } from 'runtime-registry';

const emitter = new EventEmitter();
const registry = new RuntimeRegistry({ emitter });

// Listen to all events
emitter.on(REGISTRY_EVENTS.REGISTER, (payload) => {
  console.log('Register:', payload);
  // { namespace, key, value, timestamp }
});

emitter.on(REGISTRY_EVENTS.UPDATE, (payload) => {
  console.log('Update:', payload);
  // { namespace, key, value, oldValue, timestamp }
});

emitter.on(REGISTRY_EVENTS.UNREGISTER, (payload) => {
  console.log('Unregister:', payload);
  // { namespace, key, oldValue, timestamp }
});

emitter.on(REGISTRY_EVENTS.CLEAR, (payload) => {
  console.log('Clear:', payload);
  // { namespace, count, timestamp }
});

📖 API Reference

RuntimeRegistry

constructor(options: RuntimeRegistryOptions)

创建新的 RuntimeRegistry 实例。

const registry = new RuntimeRegistry({ 
  emitter: new EventEmitter() 
});

namespace<T>(name: string): IScopedRegistry<T>

获取或创建命名空间的作用域注册表。重复调用返回相同实例。

const app1 = registry.namespace('app1');
const app1Again = registry.namespace('app1');
console.log(app1 === app1Again); // true

使用 TypeScript 泛型:

interface MyServices {
  userService: UserService;
  authService: AuthService;
}

const app = registry.namespace<MyServices>('app');
app.set('userService', userService); // 类型检查!
const user = app.get('userService'); // 类型:UserService | undefined

inspect(): Record<string, Record<string, any>>

获取所有命名空间及其内容,用于调试。

const result = registry.inspect();
// {
//   app1: { userService: {...}, authService: {...} },
//   app2: { userService: {...} }
// }

snapshot(): Map<string, Map<string, any>>

创建所有命名空间的快照。

const snapshot = registry.snapshot();
for (const [namespace, store] of snapshot) {
  console.log(`${namespace}:`, Array.from(store.entries()));
}

destroy(): void

销毁所有命名空间并清理,会为每个命名空间触发 clear 事件。

registry.destroy();

ScopedRegistry

set(key: string, value: any): void

注册或更新能力。首次注册触发 register 事件,更新时触发 update 事件。

app.set('userService', userService);      // 触发 'register'
app.set('userService', newUserService);   // 触发 'update'

get(key?: string): any

通过键获取能力,或省略键获取所有能力。

// 获取单个值
const service = app.get('userService');

// 获取所有值
const all = app.get();
// { userService: {...}, authService: {...} }

has(key: string): boolean

检查能力是否存在。

if (app.has('userService')) {
  // ...
}

delete(key: string): boolean

删除能力。如果删除成功返回 true,键不存在返回 false。删除时触发 unregister 事件。

const deleted = app.delete('userService');

clear(): void

清空此命名空间中的所有能力,触发 clear 事件并携带数量。

app.clear();

keys(): string[]

获取此命名空间中的所有键。

const keys = app.keys();
// ['userService', 'authService']

values(): any[]

获取此命名空间中的所有值。

const values = app.values();

entries(): Array<[string, any]>

获取所有条目的键值对数组。

const entries = app.entries();
// [['userService', {...}], ['authService', {...}]]

💡 使用示例

场景 1:插件系统

import EventEmitter from 'eventemitter3';
import { RuntimeRegistry, REGISTRY_EVENTS } from 'runtime-registry';

const emitter = new EventEmitter();
const pluginRegistry = new RuntimeRegistry({ emitter });

// 插件 A 注册
const markdownPlugin = pluginRegistry.namespace('plugin-markdown');
markdownPlugin.set('render', (text) => marked(text));
markdownPlugin.set('config', { supportGFM: true });

// 插件 B 注册
const highlightPlugin = pluginRegistry.namespace('plugin-highlight');
highlightPlugin.set('highlight', (code, lang) => hljs.highlight(code, { language: lang }));

// 主应用发现和使用插件
const markdown = pluginRegistry.namespace('plugin-markdown');
if (markdown.has('render')) {
  const renderer = markdown.get('render');
  const html = renderer('# Hello World');
}

场景 2:服务定位器 / 依赖注入

// 服务层
const services = registry.namespace('services');
services.set('logger', loggerService);
services.set('http', httpClient);
services.set('database', dbConnection);

// 仓储层
const repositories = registry.namespace('repositories');
repositories.set('userRepo', new UserRepository());
repositories.set('orderRepo', new OrderRepository());

// 在任何地方获取依赖
function createUserController() {
  const logger = services.get('logger');
  const userRepo = repositories.get('userRepo');
  return new UserController(logger, userRepo);
}

场景 3:多租户配置管理

// 租户 A
const tenantA = registry.namespace('tenant-company-a');
tenantA.set('theme', { primaryColor: '#ff0000' });
tenantA.set('features', ['chat', 'video', 'files']);
tenantA.set('quota', { storage: '100GB', users: 50 });

// 租户 B
const tenantB = registry.namespace('tenant-company-b');
tenantB.set('theme', { primaryColor: '#0000ff' });
tenantB.set('features', ['chat', 'files']); // 不包括 video
tenantB.set('quota', { storage: '500GB', users: 200 });

// 根据租户获取配置
function getTenantConfig(tenantId) {
  const tenant = registry.namespace(`tenant-${tenantId}`);
  return tenant.get();
}

场景 4:功能开关管理

// 开发环境
const devFlags = registry.namespace('flags-dev');
devFlags.set('newUI', true);
devFlags.set('experimentalAPI', true);
devFlags.set('debugMode', true);

// 生产环境
const prodFlags = registry.namespace('flags-prod');
prodFlags.set('newUI', false);
prodFlags.set('experimentalAPI', false);

// 监听功能开关变化
emitter.on(REGISTRY_EVENTS.UPDATE, (payload) => {
  if (payload.namespace.startsWith('flags-')) {
    console.log(`功能 ${payload.key} 从 ${payload.oldValue} 改为 ${payload.value}`);
    reloadFeature(payload.key);
  }
});

场景 5:微前端架构

import EventEmitter from 'eventemitter3';
import { RuntimeRegistry, REGISTRY_EVENTS } from 'runtime-registry';

// Create a global registry
const emitter = new EventEmitter();
const globalRegistry = new RuntimeRegistry({ emitter });

// Main application registers shared services
const mainApp = globalRegistry.namespace('main-app');
mainApp.set('router', router);
mainApp.set('store', store);
mainApp.set('eventBus', eventBus);

// Module A registers its services
const moduleA = globalRegistry.namespace('module-a');
moduleA.set('userService', {
  getUser: async (id) => { /* ... */ },
  updateUser: async (id, data) => { /* ... */ },
});

// Module B can have its own userService without conflicts
const moduleB = globalRegistry.namespace('module-b');
moduleB.set('userService', {
  getUserProfile: async (id) => { /* ... */ },
});

// Module C can discover and use services from other modules
const moduleC = globalRegistry.namespace('module-c');

// Get main app's router
const router = mainApp.get('router');

// Get Module A's user service
const userService = moduleA.get('userService');

场景 6:测试隔离

describe('User Tests', () => {
  let testContext;
  
  beforeEach(() => {
    const testId = `test-${Date.now()}`;
    testContext = registry.namespace(testId);
    
    // 为每个测试创建独立的 mock
    testContext.set('mockDB', createMockDB());
    testContext.set('mockAPI', createMockAPI());
    testContext.set('testData', generateTestData());
  });
  
  afterEach(() => {
    testContext.clear(); // 清理测试上下文
  });
  
  it('should create user', () => {
    const mockDB = testContext.get('mockDB');
    const testData = testContext.get('testData');
    // 测试逻辑...
  });
});

场景 7:事件监听和调试

// Log all registry changes in development
if (process.env.NODE_ENV === 'development') {
  emitter.on(REGISTRY_EVENTS.REGISTER, (payload) => {
    console.log(`[Registry] ✅ Registered: ${payload.namespace}/${payload.key}`);
  });

  emitter.on(REGISTRY_EVENTS.UPDATE, (payload) => {
    console.log(`[Registry] 🔄 Updated: ${payload.namespace}/${payload.key}`);
  });

  emitter.on(REGISTRY_EVENTS.UNREGISTER, (payload) => {
    console.log(`[Registry] ❌ Unregistered: ${payload.namespace}/${payload.key}`);
  });
}

场景 8:Module Federation 集成

// In your Module Federation setup
import { RuntimeRegistry } from 'runtime-registry';
import EventEmitter from 'eventemitter3';

// Create global registry
const emitter = new EventEmitter();
window.__RUNTIME_REGISTRY__ = new RuntimeRegistry({ emitter });

// In each remote module
const registry = window.__RUNTIME_REGISTRY__;
const myModule = registry.namespace('my-module');

// Register module capabilities
myModule.set('init', () => {
  console.log('Module initialized');
});

myModule.set('routes', [
  { path: '/users', component: UsersPage },
  { path: '/profile', component: ProfilePage },
]);

// In host application
const myModule = registry.namespace('my-module');
if (myModule.has('init')) {
  myModule.get('init')();
}

const routes = myModule.get('routes');

场景 9:类型安全的服务注册表

// Define your service types
interface AppServices {
  userService: {
    getUser(id: string): Promise<User>;
    updateUser(id: string, data: Partial<User>): Promise<void>;
  };
  authService: {
    login(credentials: Credentials): Promise<Token>;
    logout(): void;
  };
  configService: {
    get(key: string): any;
    set(key: string, value: any): void;
  };
}

// Create typed registry
const app = registry.namespace<AppServices>('app');

// TypeScript will enforce types
app.set('userService', {
  getUser: async (id) => { /* ... */ },
  updateUser: async (id, data) => { /* ... */ },
});

// Type-safe retrieval
const userService = app.get('userService');
// Type: AppServices['userService'] | undefined

if (userService) {
  const user = await userService.getUser('123'); // Type-safe!
}

场景 10:动态模块加载

// Track loaded modules
const loadedModules = new Set<string>();

emitter.on(REGISTRY_EVENTS.REGISTER, (payload) => {
  if (payload.key === 'init') {
    loadedModules.add(payload.namespace);
    console.log(`Module ${payload.namespace} loaded`);
  }
});

// Load modules dynamically
async function loadModule(name: string, url: string) {
  const module = await import(url);
  const moduleRegistry = registry.namespace(name);
  
  // Module registers itself
  moduleRegistry.set('init', module.init);
  moduleRegistry.set('routes', module.routes);
  moduleRegistry.set('components', module.components);
  
  return moduleRegistry;
}

// Check if module is loaded
function isModuleLoaded(name: string): boolean {
  return loadedModules.has(name);
}

🎨 最佳实践

1. 命名空间命名规范

使用描述性的、层次化的命名:

// ✅ 推荐
registry.namespace('main-app');
registry.namespace('plugin-user-management');
registry.namespace('tenant-company-a');
registry.namespace('cache-users');

// ❌ 避免
registry.namespace('app1');
registry.namespace('m1');
registry.namespace('x');

2. 服务注册模式

在模块初始化时注册所有服务:

// module-init.ts
export function initModule(registry: RuntimeRegistry) {
  const moduleRegistry = registry.namespace('my-module');
  
  // 一次性注册所有服务
  moduleRegistry.set('userService', createUserService());
  moduleRegistry.set('authService', createAuthService());
  moduleRegistry.set('config', moduleConfig);
  
  return moduleRegistry;
}

3. 事件监听器清理

模块卸载时清理事件监听器:

const listeners: Array<() => void> = [];

// 添加监听器
const removeListener = emitter.on(REGISTRY_EVENTS.REGISTER, handler);
listeners.push(() => emitter.off(REGISTRY_EVENTS.REGISTER, handler));

// 卸载时清理
function cleanup() {
  listeners.forEach(remove => remove());
}

4. 错误处理

始终处理可能的 undefined 值:

const service = app.get('userService');
if (!service) {
  throw new Error('UserService not registered');
}

// 或使用可选链
const user = await app.get('userService')?.getUser('123');

5. 调试和审查

使用 inspect() 进行调试:

// 添加到浏览器控制台用于调试
if (typeof window !== 'undefined') {
  window.__DEBUG_REGISTRY__ = () => {
    console.table(registry.inspect());
  };
}

// 在控制台执行:__DEBUG_REGISTRY__()

⚡ 性能

  • Set 操作: O(1)
  • Get 操作: O(1)
  • Has 操作: O(1)
  • Delete 操作: O(1)
  • Clear 操作: O(n),其中 n 是命名空间中的键数量
  • Namespace 创建: O(1)

所有操作都使用原生 JavaScript Map,确保最优性能。

🔷 TypeScript 支持

RuntimeRegistry 使用 TypeScript 编写,提供完整的类型定义。使用泛型实现类型安全:

interface Services {
  api: ApiClient;
  auth: AuthService;
}

const app = registry.namespace<Services>('app');

// 类型检查生效!
app.set('api', apiClient);
app.set('auth', authService);

const api = app.get('api'); // 类型:ApiClient | undefined

🤝 贡献

欢迎贡献代码!请随时提交 Pull Request。

📄 许可证

MIT

💬 支持

如有问题或疑问,请在 GitHub 仓库中提交 issue。