Gathering detailed insights and metrics for di-wise
Gathering detailed insights and metrics for di-wise
Gathering detailed insights and metrics for di-wise
Gathering detailed insights and metrics for di-wise
🧙♀️ Lightweight and flexible dependency injection library for JavaScript and TypeScript, w/wo ECMAScript decorators.
npm install di-wise
Typescript
Module System
Node Version
NPM Version
TypeScript (94.49%)
JavaScript (5.51%)
Total Downloads
1,477
Last Day
4
Last Week
17
Last Month
248
Last Year
1,477
85 Stars
182 Commits
2 Forks
1 Watching
1 Branches
1 Contributors
Latest Version
0.2.8
Package Id
di-wise@0.2.8
Unpacked Size
220.85 kB
Size
47.80 kB
File Count
39
NPM Version
10.9.0
Node Version
22.11.0
Publised On
07 Dec 2024
Cumulative downloads
Total Downloads
Last day
0%
4
Compared to previous day
Last week
-39.3%
17
Compared to previous week
Last month
-65.7%
248
Compared to previous month
Last year
0%
1,477
Compared to previous year
Lightweight and flexible dependency injection library for JavaScript and TypeScript, w/wo ECMAScript decorators.
1npm install di-wise 2 3pnpm add di-wise 4 5yarn add di-wise
Also available on JSR:
1deno add jsr:@exuanbo/di-wise
reflect-metadata
experimentalDecorators
requiredExample:
1import {createContainer, Inject, inject, Injectable, Scope, Scoped, Type} from "di-wise"; 2 3interface Spell { 4 cast(): void; 5} 6const Spell = Type<Spell>("Spell"); 7 8@Scoped(Scope.Container) 9@Injectable(Spell) 10class Fireball implements Spell { 11 cast() { 12 console.log("🔥"); 13 } 14} 15 16class Wizard { 17 @Inject(Wand) 18 wand!: Wand; 19 20 // Equivalent to 21 wand = inject(Wand); 22 23 constructor(spell = inject(Spell)) { 24 // inject() can be used anywhere during construction 25 this.wand.store(spell); 26 } 27} 28 29const container = createContainer(); 30container.register(Fireball); 31 32// Under the hood 33[Fireball, Spell].forEach((token) => { 34 container.register( 35 token, 36 {useClass: Fireball}, 37 {scope: Scope.Container}, 38 ); 39}); 40 41const wizard = container.resolve(Wizard); 42wizard.wand.activate(); // => 🔥
Build()
, Value()
Example:
1import {Build, createContainer, inject, Value} from "di-wise"; 2 3class Wizard { 4 equipment = inject( 5 Cloak, 6 // Provide a default value 7 Value({ 8 activate() { 9 console.log("👻"); 10 }, 11 }), 12 ); 13 14 wand: Wand; 15 16 constructor(wand: Wand) { 17 this.wand = wand; 18 } 19} 20 21const container = createContainer(); 22 23const wizard = container.resolve( 24 Build(() => { 25 // inject() can be used in factory functions 26 const wand = inject(Wand); 27 return new Wizard(wand); 28 }), 29); 30 31wizard.equipment.activate(); // => 👻
Example:
1import {createContainer, inject, Injectable, Type} from "di-wise"; 2 3const MagicSchool = Type<string>("MagicSchool"); 4const Spell = Type<{cast(): void}>("Spell"); 5 6// Parent container with shared config 7const hogwarts = createContainer(); 8hogwarts.register(MagicSchool, {useValue: "Hogwarts"}); 9 10@Injectable(Spell) 11class Fireball { 12 school = inject(MagicSchool); 13 cast() { 14 console.log(`🔥 from ${this.school}`); 15 } 16} 17 18// Child containers with isolated spells 19const gryffindor = hogwarts.createChild(); 20gryffindor.register(Fireball); 21 22const slytherin = hogwarts.createChild(); 23slytherin.register(Spell, { 24 useValue: {cast: () => console.log("🐍")}, 25}); 26 27gryffindor.resolve(Spell).cast(); // => 🔥 from Hogwarts 28slytherin.resolve(Spell).cast(); // => 🐍
Inherited
(default), Transient
, Resolution
, Container
Example for singleton pattern:
1import {createContainer, Scope} from "di-wise"; 2 3export const singletons = createContainer({ 4 defaultScope: Scope.Container, 5 autoRegister: true, 6}); 7 8// Always resolves to the same instance 9const wizard = singletons.resolve(Wizard);
Inherits the scope from its dependent. If there is no dependent (top-level resolution), behaves like Transient
.
1import {createContainer, Scope, Scoped} from "di-wise"; 2 3@Scoped(Scope.Container) 4class Wizard { 5 wand = inject(Wand); 6} 7 8const container = createContainer(); 9container.register( 10 Wand, 11 {useClass: Wand}, 12 {scope: Scope.Inherited}, 13); 14container.register(Wizard); 15 16// Dependency Wand will be resolved with "Container" scope 17const wizard = container.resolve(Wizard);
Creates a new instance every time the dependency is requested. No caching occurs.
Creates one instance per resolution graph. The same instance will be reused within a single dependency resolution, but new instances are created for separate resolutions.
1@Scoped(Scope.Resolution) 2class Wand {} 3 4class Inventory { 5 wand = inject(Wand); 6} 7 8class Wizard { 9 inventory = inject(Inventory); 10 wand = inject(Wand); 11} 12 13const container = createContainer(); 14const wizard = container.resolve(Wizard); 15 16expect(wizard.inventory.wand).toBe(wizard.wand);
Creates one instance per container (singleton pattern). The instance is cached and reused for all subsequent resolutions within the same container.
Type.Null
and Type.Undefined
Example:
1import {inject, Type} from "di-wise"; 2 3class Wizard { 4 wand = inject(Wand, Type.Null); 5 // ^? (property) Wizard.wand: Wand | null 6 7 spells = injectAll(Spell, Type.Null); 8 // ^? (property) Wizard.spells: Spell[] 9 // => [] 10}
@Inject()
or inject.by()
)Example:
1import {createContainer, Inject, inject} from "di-wise"; 2 3class Wand { 4 owner = inject(Wizard); 5} 6 7class Wizard { 8 @Inject(Wand) 9 wand!: Wand; 10 11 // Equivalent to 12 wand = inject.by(this, Wand); 13} 14 15const container = createContainer(); 16const wizard = container.resolve(Wizard); 17 18expect(wizard.wand.owner).toBe(wizard);
Injector
Example:
1import {createContainer, inject, Injector} from "di-wise"; 2 3class Wizard { 4 private injector = inject(Injector); 5 private wand?: Wand; 6 7 getWand() { 8 // Lazy load wand only when needed 9 return (this.wand ??= this.injector.inject(Wand)); 10 } 11 12 castAllSpells() { 13 // Get all registered spells 14 const spells = this.injector.injectAll(Spell); 15 spells.forEach((spell) => spell.cast()); 16 } 17} 18 19const container = createContainer(); 20const wizard = container.resolve(Wizard); 21 22wizard.getWand(); // => Wand
The injector maintains the same resolution context as its injection point, allowing proper handling of scopes and circular dependencies:
1import {createContainer, inject, Injector} from "di-wise"; 2 3class Wand { 4 owner = inject(Wizard); 5} 6 7class Wizard { 8 private injector = inject.by(this, Injector); 9 10 getWand() { 11 return this.injector.inject(Wand); 12 } 13} 14 15const container = createContainer(); 16const wizard = container.resolve(Wizard); 17 18const wand = wizard.getWand(); 19expect(wand.owner).toBe(wizard);
See discussion Does di-wise support constructor injection? #12
Example:
1import {applyMiddleware, createContainer, type Middleware} from "di-wise"; 2 3const logger: Middleware = (composer, _api) => { 4 composer 5 .use("resolve", (next) => (token) => { 6 console.log("Resolving:", token.name); 7 const result = next(token); 8 console.log("Resolved:", token.name); 9 return result; 10 }) 11 .use("resolveAll", (next) => (token) => { 12 console.log("Resolving all:", token.name); 13 const result = next(token); 14 console.log("Resolved all:", token.name); 15 return result; 16 }); 17}; 18 19const performanceTracker: Middleware = (composer, _api) => { 20 composer.use("resolve", (next) => (token) => { 21 const start = performance.now(); 22 const result = next(token); 23 const end = performance.now(); 24 console.log(`Resolution time for ${token.name}: ${end - start}ms`); 25 return result; 26 }); 27}; 28 29const container = applyMiddleware(createContainer(), [logger, performanceTracker]); 30 31// Use the container with applied middlewares 32const wizard = container.resolve(Wizard);
Middlewares are applied in array order but execute in reverse order, allowing outer middlewares to wrap and control the behavior of inner middlewares.
🏗️ WIP (PR welcome)
See API documentation.
Inspired by:
MIT License @ 2024-Present Xuanbo Cheng
No vulnerabilities found.
No security vulnerabilities found.