perfect-di
TypeScript icon, indicating that this package has built-in type declarations

1.0.2 • Public • Published

perfect-di

DI made simple.

Definitions

Service - a piece of code or data that is useful for the application that other services can use (depend on).
Provider - definition of a service dependencies and the exact way it should be created (provided).
Module - a group of interdependent services (providers).

Philosophy

This package was created with the following ideas and requirements in mind:

  • simple and transparent
    • module described in one place - ideally a single JSON
    • can be used without typescript - no decorators metadata tricks
    • no (web server) domain specific features
  • reusable modules that can be isolated and published on npm
    • no DI engine specific code in services
    • no binding to specific classes outside of the module - module doesn't import anything outside its directory
  • hierarchical modules
    • modules don't have to be complete - they can depend on services provided by the parent module
    • parent module can use services provided by child modules (submodules)
    • imports/exports between modules should be stated explicitly
  • desired features
    • lazy initialization of services
    • cyclic dependencies detection
    • one service with same dependencies used in multiple modules should be initialized once
    • (not implemented) module deinitialization

Usage

Example 1 - Four Services in One Module

All you need to get started is to define a Module object and call initModule on it.

import { initModule, Module } from 'perfect-di'
import { UserService } from './services/user.service'
import { MongodbService } from './services/mongodb.service'
import { ApiService } from './services/api.service'

const MainModule: Module = {
  providers: {
    'configSvc': { // data as a service
      init: () => {
        apiPort: 8080,
        dbUrl: 'mongodb://url',
      },
    },
    'apiSvc': {
      dependencies: ['configSvc', 'userSvc'],
      init: async (configSvc, userSvc) => {
        const api = new ApiService(userSvc)
        await api.lister(configSvc.apiPort)
        return api
      },
    },
    'userSvc': {
      dependencies: ['dbSvc'],
      init: (dbSvc) => new UserService(dbSvc)
    },
    'dbSvc': {
      dependencies: ['configSvc'],
      init: async (configSvc) => {
        const db = new MongodbService()
        await db.connect(configSvc.dbUrl)
        return db
      },
    },
  },
}

async main() {
  await initModule(MainModule)
}

main()

Example 2 - Submodules

There are multiple ways a provider can be defined in a module:

  • local provider - defined locally through the init function,
  • internal import - imported from submodule via importFrom: 'SubmoduleName',
  • external import - imported from parent module via importFrom: null.

In the last case parent module can rename external imports of its submodule through imports: { 'svcNameInSubmodule': 'svcNameInParent' } syntax.

# config.module.ts
const ConfigModule: Module = {
  providers: {
    'configSvc': {
      doExport: true, // make this provider usable by parent
      init: () => ConfigService,
    },
  },
}


# api.module.ts
const ApiModule: Module = {
  providers: {
    'configSvc': { importFrom: null }, // import this provider from parent
    'apiSvc': {
      doExport: true,
      dependencies: ['configSvc'],
      init: (configSvc) => new ApiService(configSvc),
    },
  },
}


# main.module.ts
const MainModule: Module = {
  providers: {
    'configSvc': { importFrom: 'Config' },
    'apiSvc': { importFrom: 'Api' },
  },
  submodules: {
    'Config': { module: ConfigModule },
    'Api': {
      module: ApiModule
      // imports: {
      //   'configSvc': 'configSvc',
      // },
    },
  }
}

Example 3 - Real Life Example

https://github.com/grabantot/data-net-backend/blob/master/src/modules/main.module.ts

Package Sidebar

Install

npm i perfect-di

Weekly Downloads

0

Version

1.0.2

License

ISC

Unpacked Size

38.9 kB

Total Files

26

Last publish

Collaborators

  • grabantot