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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@iocore/component

v1.0.12

Published

The Next-Generation Inversion of Control (IoC) Framework for Modern Applications.

Downloads

9

Readme

@iocore/component

npm version

IoCore 框架的核心组件和依赖注入系统。

提供了一个基于类的依赖注入容器和生命周期管理机制,使用装饰器来定义组件、它们的依赖关系以及初始化和终止逻辑。

安装

npm install @iocore/component reflect-metadata --save
# or
yarn add @iocore/component reflect-metadata

依赖

  • reflect-metadata: 用于支持装饰器元数据。

重要: 你需要在你的应用程序入口文件的顶部导入 reflect-metadata

import 'reflect-metadata';
// ... 你的其他代码

核心概念

Component

所有 IoCore 组件的基础类。任何希望被 IoCore 管理(注入、生命周期)的类都应该直接或间接地继承自 Component

Application

继承自 Component 的特殊抽象类,代表具有初始化 (initialize) 和终止 (terminate) 生命周期的组件,通常用于表示服务器、数据库连接池等需要启动和停止的服务。

Decorators (装饰器)

  • @Component.Injectable(callback?: IInjectableCallback): 类装饰器。
    • 必须 添加到所有希望被 IoCore 管理的 Component 类上。
    • 可选地接收一个 callback 函数 (ctx: Context<T>) => unknown | Promise<unknown>。这个回调函数会在组件实例创建 之后,但在注入到其他组件 之前 执行。ctx 参数包含:
      • ctx.value: 当前创建的组件实例。
      • ctx.wrap: 组件的包装器实例 (Wrap)。
      • ctx.callbacks: 一个数组,可以在这里 push 清理函数,这些函数会在组件销毁时执行。
  • @Component.Singleton: 类装饰器。
    • 标记一个组件为单例。IoCore 容器将只创建该类的一个实例,并在所有注入点共享它。
    • 默认情况下,组件是 非单例 的,每次注入都会创建一个新实例 (除非注入的是单例依赖)。
  • @Component.Inject(clazz: INewAble<T>): 属性装饰器。
    • 用于声明一个属性依赖。将指定的 clazz (必须是 @Component.Injectable 的类) 注入到该属性。
    • IoCore 会自动处理依赖的实例化和注入。
  • @Application.Server: 类装饰器 (快捷方式)。
    • 必须 添加到继承自 Application 的类上。
    • 它等同于 @Component.Singleton@Component.Injectable(ApplicationServer) 的组合,确保 Application 子类是单例,并自动处理 initializeterminate 方法的调用。

Meta

一个用于创建和管理装饰器元数据的工具类。它提供了 createClassDecorator, createPropertyDecorator, createMethodDecorator, createParameterDecorator 等静态方法,用于创建自定义装饰器并将元数据附加到类、属性、方法或参数上。

Wrap

内部类,用于包装每个注册的 Component 类。它负责管理组件的元数据、生命周期状态 (status)、依赖关系、上下文 (Context) 和实例化逻辑。

Context

每个组件实例(非单例)或单例组件的包装器 (Wrap) 都有一个关联的 Context。它存储了组件实例 (value) 和销毁时需要执行的回调 (callbacks)。

生命周期

  1. Preload (Component.preload(clazz)): 预加载组件类,返回 Wrap 实例。会递归预加载所有依赖。
  2. Start (wrap.start()): 启动组件 (及其依赖)。
    • 状态变为 INITING
    • 解析并预加载所有 @Inject 的依赖项。
    • 如果是单例,调用 create() 创建实例并缓存。
    • 执行 @Injectable 的回调函数。
    • (对于 Application 子类) 调用 initialize() 方法。
    • 状态变为 INTED (成功) 或 INTERR (失败)。
  3. Create (wrap.create()Component.create(clazz)): 创建组件实例。
    • 如果是单例且已创建,直接返回缓存的实例。
    • 创建新实例。
    • 递归创建并注入 非单例 依赖的新实例。
    • 注入 单例 依赖的共享实例。
    • 执行 @Injectable 的回调函数。
    • 返回实例或 Context
  4. Stop (wrap.stop()): 停止组件。
    • 状态变为 ENDING
    • 执行 Context.callbacks 中注册的清理函数 (按 LIFO 顺序)。
    • (对于 Application 子类) 调用 terminate() 方法。
    • 清空实例 (如果是单例)。
    • 状态变为 ENDED (成功) 或 ENDERR (失败)。
  5. Terminate (Application.terminate()): 停止所有已注册的 Application 组件。

使用示例

import 'reflect-metadata';
import Component, {
  Application,
  Context,
  IInjectableCallback,
} from '@iocore/component';

// --- 定义服务组件 ---

interface IDatabase {
  query(sql: string): Promise<string[]>;
}

// 模拟数据库连接 (Application)
@Application.Server // <=> @Component.Singleton + @Component.Injectable(ApplicationServer)
class DatabaseConnection extends Application implements IDatabase {
  private connectionId: string;

  async initialize(): Promise<void> {
    this.connectionId = `conn-${Math.random().toString(36).substring(2, 9)}`;
    console.log(`[DatabaseConnection] Initialized, ID: ${this.connectionId}`);
  }

  async terminate(): Promise<void> {
    console.log(`[DatabaseConnection] Terminated, ID: ${this.connectionId}`);
  }

  async query(sql: string): Promise<string[]> {
    console.log(`[DatabaseConnection ${this.connectionId}] Executing query: ${sql}`);
    await new Promise(res => setTimeout(res, 50)); // 模拟延迟
    return [`Result for: ${sql}`];
  }
}

// 服务注入回调示例
const userServiceCallback: IInjectableCallback<UserService> = (ctx) => {
  console.log(`[UserService Injectable Callback] UserService instance created. User count: ${ctx.value.getUserCount()}`);
  // 注册清理函数
  ctx.callbacks.push(() => {
    console.log(`[UserService Cleanup] Cleaning up UserService instance.`);
  });
};

// 用户服务 (普通 Component,非单例)
@Component.Injectable(userServiceCallback)
class UserService extends Component {
  // 注入单例的数据库连接
  @Component.Inject(DatabaseConnection)
  private db: IDatabase;

  private userCount = 0;

  constructor() {
    super();
    this.userCount = Math.floor(Math.random() * 100);
    console.log(`[UserService Constructor] Instance created.`);
  }

  async getUser(id: number): Promise<string> {
    const result = await this.db.query(`SELECT * FROM users WHERE id = ${id}`);
    return result[0] || 'User not found';
  }

  getUserCount(): number {
    return this.userCount;
  }
}

// --- 定义主应用程序 ---

@Application.Server
class MyApp extends Application {
  // 注入非单例的 UserService
  @Component.Inject(UserService)
  private userService1: UserService;

  // 再次注入,会得到一个新的 UserService 实例
  @Component.Inject(UserService)
  private userService2: UserService;

  // 注入单例的 DatabaseConnection
  @Component.Inject(DatabaseConnection)
  private db: IDatabase;

  async initialize(): Promise<void> {
    console.log('[MyApp] Initialized.');
  }

  async terminate(): Promise<void> {
    console.log('[MyApp] Terminated.');
  }

  async run() {
    console.log('\n--- Running MyApp ---');
    console.log('Checking db connection instance:', this.db === (this.userService1 as any).db ? 'Same instance' : 'Different instance'); // true
    console.log('Checking user service instances:', this.userService1 === this.userService2 ? 'Same instance' : 'Different instance'); // false

    const user1 = await this.userService1.getUser(1);
    console.log('User 1:', user1);
    console.log('User service 1 count:', this.userService1.getUserCount());

    const user2 = await this.userService2.getUser(2);
    console.log('User 2:', user2);
    console.log('User service 2 count:', this.userService2.getUserCount());

    console.log('--- Finished MyApp Run ---\n');
  }
}

// --- 启动和停止 --- (通常在入口文件)
async function bootstrap() {
  console.log('>>> Bootstrapping application...');
  // 预加载并启动 MyApp (会自动启动其依赖)
  // 方式一:通过 Component.create (适用于 Application)
  const myAppInstance = await Component.create(MyApp);
  await myAppInstance.run();

  // 方式二:通过 Application.start (更常用,内部调用 preload 和 create)
  // const myAppInstance = await Application.start(MyApp);
  // await myAppInstance.main(); // 假设 Application 有 main 方法

  console.log('\n>>> Tearing down application...');
  // 停止所有 Application 组件 (会按依赖反向顺序停止)
  await Application.terminate();
  console.log('>>> Application terminated.');
}

bootstrap();

贡献

欢迎提交 Pull Request。对于重大更改,请先开一个 Issue 来讨论您想要更改的内容。

许可证

MIT