Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/andrewbastin/dioc

A 'too simple' and opinionated dependency injection library
https://github.com/andrewbastin/dioc

Last synced: about 1 month ago
JSON representation

A 'too simple' and opinionated dependency injection library

Awesome Lists containing this project

README

        

# dioc

A small and lightweight dependency injection / inversion of control system.

### About

`dioc` is a really simple **DI/IOC** system where you write services (which are singletons per container) that can depend on each other and emit events that can be listened upon.

### Demo

```ts
import { Service, Container } from "dioc"

// Here is a simple service, which you can define by extending the Service class
// and providing an ID static field (of type string)
export class PersistenceService extends Service {
// This should be unique for each container
public static ID = "PERSISTENCE_SERVICE"

public read(key: string): string | undefined {
// ...
}

public write(key: string, value: string) {
// ...
}
}

type TodoServiceEvent =
| { type: "TODO_CREATED"; index: number }
| { type: "TODO_DELETED"; index: number }

// Services have a built in event system
// Define the generic argument to say what are the possible emitted values
export class TodoService extends Service {
public static ID = "TODO_SERVICE"

// Inject persistence service into this service
private readonly persistence = this.bind(PersistenceService)

public todos = []

// Services cannot(*) have constructors, but init logic can be mentioned here
override onServiceInit() {
this.todos = JSON.parse(this.persistence.read("todos") ?? "[]")
}

public addTodo(text: string) {
// ...

// You can access services via the bound fields
this.persistence.write("todos", JSON.stringify(this.todos))

// This is how you emit an event
this.emit({
type: "TODO_CREATED",
index,
})
}

public removeTodo(index: number) {
// ...

this.emit({
type: "TODO_DELETED",
index,
})
}
}

// Services need a container to run in
const container = new Container()

// You can initialize and get services using Container#bind
// It will automatically initialize the service (and its dependencies)
const todoService = container.bind(TodoService) // Returns an instance of TodoService
```

### Demo (Unit Test)

`dioc/testing` contains `TestContainer` which lets you bind mocked services to the container.

```ts
import { TestContainer } from "dioc/testing"
import { TodoService, PersistenceService } from "./demo.ts" // The above demo code snippet
import { describe, it, expect, vi } from "vitest"

describe("TodoService", () => {
it("addTodo writes to persistence", () => {
const container = new TestContainer()

const writeFn = vi.fn()

// The first parameter is the service to mock and the second parameter
// is the mocked service fields and functions
container.bindMock(PersistenceService, {
read: () => undefined, // Not really important for this test
write: writeFn,
})

// the peristence service bind in TodoService will now use the
// above defined mocked implementation
const todoService = container.bind(TodoService)

todoService.addTodo("sup")

expect(writeFn).toHaveBeenCalledOnce()
expect(writeFn).toHaveBeenCalledWith("todos", JSON.stringify(["sup"]))
})
})
```

### Demo (Vue)

`dioc/vue` contains a Vue Plugin and a `useService` composable that allows Vue components to use the defined services.

In the app entry point:

```ts
import { createApp } from "vue"
import { diocPlugin } from "dioc/vue"

const app = createApp()

app.use(diocPlugin, {
container: new Container(), // You can pass in the container you want to provide to the components here
})
```

In your Vue components:

```vue

import { TodoService } from "./demo.ts" // The above demo
import { useService } from "dioc/vue"

const todoService = useService(TodoService) // Returns an instance of the TodoService class

```
# Developing
`dioc` repo uses [pnpm](https://pnpm.io/) for package management. Install it and run `pnpm install` to install dependencies.