{"id":26584169,"url":"https://github.com/webcomputing/inversify-components","last_synced_at":"2025-03-23T09:19:37.870Z","repository":{"id":25697607,"uuid":"78657349","full_name":"webcomputing/inversify-components","owner":"webcomputing","description":"Small framework on top of InversifyJS to enable component based dependency injection","archived":false,"fork":false,"pushed_at":"2025-01-21T14:21:46.000Z","size":459,"stargazers_count":29,"open_issues_count":10,"forks_count":7,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-02-21T15:51:52.093Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/webcomputing.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-01-11T16:28:01.000Z","updated_at":"2023-04-05T18:25:20.000Z","dependencies_parsed_at":"2023-01-14T03:10:25.414Z","dependency_job_id":null,"html_url":"https://github.com/webcomputing/inversify-components","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webcomputing%2Finversify-components","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webcomputing%2Finversify-components/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webcomputing%2Finversify-components/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webcomputing%2Finversify-components/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/webcomputing","download_url":"https://codeload.github.com/webcomputing/inversify-components/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245079063,"owners_count":20557406,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-03-23T09:19:37.142Z","updated_at":"2025-03-23T09:19:37.855Z","avatar_url":"https://github.com/webcomputing.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# inversify-components\nSmall framework on top of InversifyJS to enable component based dependency injection. \nEach component describes its interfaces and bindings with the help of descriptors, and never \naccesses the dependency injection container directly. This enables you to:\n- Develop loosely coupled and independent components, without exploiting your whole dependency injection container\n- Enable / disable / mock whole components in your application\n- Use scoped child containers, for example bind dependencies only to a http request\n- Implement the extension point pattern to \"plug-in\" extensions of components from other components\n\n## Installation\nInstall inversify-components and set it as an dependency in your local package.json:\n\n``npm i --save inversify-components``\n\n## Usage\n\n### Basic setup instructions\n\n1) Create the inversify-components container:\n```typescript\nimport { ContainerImpl } from \"inversify-components\";\nlet container = new ContainerImpl();\n// Also supports options:\n// let container = new ContainerImpl({ defaultScope: \"Singleton\" });\n```\n\n2) Create your main application, which acts as the [composition root][1]:\n```typescript\nimport { MainApplication } from \"inversify-components\";\n\nclass App implements MainApplication {\n  execute(container: Container) {\n    // Start your application using the container!\n  }\n}\n```\n\n3) Register all _components_ (see below) you would like to use:\n```typescript\nimport { descriptor } from \"my-component-descriptor\";\ncontainer.componentRegistry.addFromDescriptor(descriptor);\n```\n\n4) Register all bindings of all registered component descriptors\n```typescript\ncontainer.componentRegistry.autobind(container.inversifyInstance);\n```\n\n5) Optional: Configure some of your components:\n```typescript\ncontainer.componentRegistry.lookup(nameOfComponent).addConfiguration({\n  configurationKey: \"configurationValue\"\n});\n```\n\n6) Start your application\n```typescript\ncontainer.setMainApplication(new App());\ncontainer.runMain();\n```\n\n### Components and component descriptors\ninversify-components allows you to basically split your applications into independent components. To achieve this, each component exports\na `component descriptor`:\n```typescript\nimport { ComponentDescriptor } from \"inversify-components\";\n\nexport const descriptor: ComponentDescriptor = {\n  name: \"name-of-component\", // This must be unique for all registered components\n  bindings: {\n    root: (bindService, lookupService) =\u003e {\n      // Binding of services is very similar to inversifyJS:\n      bindService.bindGlobalService\u003cTypeOfService\u003e(\"service-name\").to(MyServiceClass);\n      \n      // MyServiceClass is now bound to \"name-of-component:service-name\" and available in all other components.\n    }\n  }\n};\n```\nNotice that each binding gets the unique component name as a prefix. This guarantees that there are not duplicate service bindings\nacross all registered components.\n\n#### Grab inversify container\nYou are also able to grab the inversify coontainer in a `ComponentDescriptor`:\n```typescript\nimport { ComponentDescriptor } from \"inversify-components\";\n\nexport const descriptor: ComponentDescriptor = {\n  name: \"name-of-component\", // This must be unique for all registered components\n  bindings: {\n    root: (bindService, lookupService, inversifyContainer) =\u003e {\n      // Unbind something..\n      inversifyContainer.unbind(\"service\");\n\n      bindService.bindGlobalService\u003cTypeOfService\u003e(\"service-name\").to(MyServiceClass);\n    }\n  }\n};\n```\nSo if needed, you are always in full control inside your dependency descriptors.\n\n#### Changing the scope of a binding\nThe above component descriptor executes bindings for the `root` scope. This is the default scope for inversify-components, which\nis executed automatically at `autobind`. But you could also register bindings for a specific scope, and execute this scope \nat application runtime to a specific point in time:\n```typescript\nimport { ComponentDescriptor } from \"inversify-components\";\n\nexport const descriptor: ComponentDescriptor = {\n  name: \"name-of-component\",\n  bindings: {\n    root: (bindService, lookupService) =\u003e {\n      bindService.bindGlobalService\u003cTypeOfService\u003e(\"service-name\").to(MyServiceClass);\n    }\n    request: (bindService, lookupService) =\u003e {\n      // Is not available at application start, but as soon as you open your \"request\" scope:\n      bindService.bindGlobalService\u003cTypeOfService\u003e(\"current-session\").toDynamicValue(....);\n    }\n  }\n};\n\n// In your MainApplication / App, as soon as you would like to open the above \"request\" scope:\n// 1) Create inversify child container\nlet scopedRequestContainer = container.inversifyInstance.createChild();\n\n// 2) Possibly bind some dependent values to this container, e. g. the current request headers and body:\nscopedRequestContainer.bind(\"request-body\").toConstantValue(currentRequestBody);\n\n// 3) Execute scoped \"request\" bindings in this container\ncontainer.componentRegistry.autobind(scopedRequestContainer, [], \"request\");\n\n// 4) Go on in your compoisiton root with child container\nscopedRequestContainer.get(...) // Maybe your request handler?\n```\n\n#### Using extension points\nTo enable plugging into your component, you can define _extension points_. This is done using symbols.\n\nComponent A: The component which owns the extension point and wants to load plugins:\n```typescript\nimport { ComponentDescriptor } from \"inversify-components\";\nimport { injectable, multiInject, optional } from \"inversify\";\n\nconst myExtensionPoints = {\n  \"firstExtensionPoint\": Symbol(\"first-extension-point\")\n}\n\nexport const descriptor: ComponentDescriptor = {\n  name: \"component-a\",\n  \n  // Register all available extension points\n  interfaces: myExtensionPoints\n};\n\n@injectable()\nclass ClassUsingPlugins {\n  // Now you can just inject all plugins registered at firstExtensionPoint and use them:\n  constructor(@optional() @multiInject(myExtensionPoints.firstExtensionPoint) plugins) {\n    this.plugins = plugins;\n  }\n}\n```\n\nComponent B: The component which adds a plugin to extension point firstExtensionPoint:\n```typescript\nexport const descriptor: ComponentDescriptor = {\n  name: \"component-b\",\n  bindings: {\n    root: (bindService, lookupService) =\u003e {\n      let extensionPoint = lookupService.lookup(\"component-a\").getInterface(\"firstExtensionPoint\");\n      bindService.bindExtension\u003cExtensionType\u003e(extensionPoint).to(MyPluginClass);\n    }\n  }\n};\n```\n\n### Configuration\nThe basic style of configuring components is described in [this gist][2]. This style enables you to define default and required configurations without hassle.\n\n#### Set default configuration\nYou can set a default configuration for your component by adding it to your descriptor:\n```typescript\nconst configuration: Configuration.Default = {\n  \"configurationKey\": \"configurationValue\";\n};\n\nexport const descriptor: ComponentDescriptor\u003cConfiguration.Default\u003e = {\n  name: \"my-component-name\",\n  defaultConfiguration: configuration\n}\n```\n\n#### Inject configuration values\nIn all of your classes, you can inject your component meta data, which includes the components configuration:\n```typescript\nimport { inject, injectable } from \"inversify\";\nimport { Component } from \"inversify-components\";\n\n@injectable()\nclass MyClass {\n  constrcutor(@inject(\"meta:component//my-component-name\") component: Component\u003cConfiguration.Runtime\u003e)\n    this.configuration = this.component.configuration;\n  }\n}\n```\n\n[1]: http://blog.ploeh.dk/2011/07/28/CompositionRoot/\n[2]: https://gist.github.com/antoniusostermann/a6cc1bb2056404682a827735b17df32a\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebcomputing%2Finversify-components","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwebcomputing%2Finversify-components","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebcomputing%2Finversify-components/lists"}