Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/vue-ioc/vue-ioc
IoC and DI for Vue powered by InversifyJS and inspired by Angular Module syntactic sugar.
https://github.com/vue-ioc/vue-ioc
dependency-injection inversifyjs inversion-of-control ioc typescript vue
Last synced: about 2 months ago
JSON representation
IoC and DI for Vue powered by InversifyJS and inspired by Angular Module syntactic sugar.
- Host: GitHub
- URL: https://github.com/vue-ioc/vue-ioc
- Owner: vue-ioc
- Created: 2015-07-10T20:16:20.000Z (over 9 years ago)
- Default Branch: master
- Last Pushed: 2023-01-04T18:30:08.000Z (about 2 years ago)
- Last Synced: 2024-12-06T16:53:22.701Z (2 months ago)
- Topics: dependency-injection, inversifyjs, inversion-of-control, ioc, typescript, vue
- Language: TypeScript
- Homepage: https://codesandbox.io/s/k28n6rp36v
- Size: 2.93 MB
- Stars: 43
- Watchers: 3
- Forks: 2
- Open Issues: 44
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# vue-ioc
IoC and DI for [Vue](https://vuejs.org/) powered by [InversifyJS](http://inversify.io/)
and inspired by [Angular @Module](https://angular.io/guide/ngmodules) syntactic sugar.## Required Opinionated Stack
* [Vue](https://vuejs.org) 2.x
* [vue-class-component](https://github.com/vuejs/vue-class-component)
* [TypeScript](https://www.typescriptlang.org/) with config flags: `experimentalDecorators: true` and `emitDecoratorMetadata: true`## Features
1. **Hierarchical IoC Container** defined in `@Module` by `providers` (using [InversifyJS](http://inversify.io/) under the hood). The hierarchy is bound to Vue components tree.
2. **Autostart** - instantiating top level services when container has been started (for background tasks similar to `@Effects` from `ngrx`).
3. **@InjectReactive()** - makes injected dependency 'deeply reactive' in Vue template.
4. **Instance Handlers** - `@PostConstruct` and `@BeforeDestroy` - decorators for methods called when instance is created or destroyed by container.
5. **Custom Instance Handlers** ie. `@OnEvent('submitForm')`
6. **providedIn 'root' or 'self'** - select where will be bound @Injectable (friendly for tree shakeable singletons and lazy loaded @Modules)## Planned features (not ready yet)
7. **State Injectors** for [Vuex](https://vuex.vuejs.org/) and [MobX](https://mobx.js.org/).
8. **vue-cli** integration## Caveats / Limitations
* `@Module` can be bound only to Vue component.
* You can't use `@Inject()` for Vue component constructor arguments (because you can't define own constructor
using `vue-class-component`). Only Vue component class fields are supported.
## Installation`vue-ioc` uses following `peerDependencies`:
* `inversify`
* `reflect-metadata`
* `vue-class-component`
* `vue````bash
# NPM
npm install @vue-ioc/core inversify reflect-metadata vue-class-component vue --save# Yarn
yarn add @vue-ioc/core inversify reflect-metadata vue-class-component vue
```You must explicitly install `vue-ioc` via `Vue.use()` in your app main entrypoint:
```typescript
// main.ts
import Vue from 'vue'
import {VueIocPlugin} from '@vue-ioc/core'Vue.use(VueIocPlugin)
```## Quick Start
[![Edit vue-ioc basic example](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/k28n6rp36v?fontsize=14)
Create simple injectable service `HttpService`:
```typescript
// ./services/HttpService.ts
import {Injectable} from '@vue-ioc/core';@Injectable()
export class HttpService {
public get(url: string): Promise {
return fetch(url).then(rs => rs.json());
}
}
```Add root container using `@Module` decorator at your top level App component and setup providers:
```vue
// App.vue
import Vue from 'vue'
import Component from 'vue-class-component'
import {Module} from '@vue-ioc/core';
import {HttpService} from './services/HttpService';
import HelloWorld from './components/HelloWorld.vue';
@Module({
providers: [
HttpService
]
})
@Component({
components: { HelloWorld }
})
export default class App extends Vue {
}```
Inject `HttpService` to `` component:
```vue
// ./components/HelloWorld.vue
Hello {{user.firstName}} {{user.lastName}}!
import Vue from 'vue'
import Component from 'vue-class-component'
import {Inject} from '@vue-ioc/core';
import {HttpService} from '../services/HttpService';@Component()
export default class HelloWorld extends Vue {@Inject()
public httpService: HttpService;
public user = null;public async created() {
this.user = await this.httpService.get('./hello.json');
}
}```
## Providers
```typescript
@Module({
providers: [
// useClass
{ provide: HttpService, useClass: HttpService },
// useClass shortcut
HttpService,
// useValue
{ provide: HttpService, useValue: httpService },
// useFactory
{ provide: HttpService, useFactory: (injector) => /* ...injector.get(FooService)... */ }
]
})
```## providedIn
Default value: `'self'` Available values: `'root', 'self'`
`@Injectable( { providedIn: 'root' } )` will bind service in root (App) container always as singleton.
You may also override this setting at `@Module` providers level in both directions:
```typescript
@Module({
providers: [
{ provide: HttpService, useClass: HttpService, providedIn: 'root' }, // overrides @Injectable()
{ provide: OtherService, useClass: OtherService, providedIn: 'self' }, // overrides @Injectable( {providedIn: 'root'} )
]
})
```## Custom Instance Handlers
`@PostConstruct()` and `@BeforeDestroy()` are two built in instance listeners. You may create custom instance handlers
like `@OnEvent('submitForm')` by creating a decorator using `createInstanceHandlerDecorator`1. Prepare the most basic EventBus implementation:
```typescript
// bus/EventBus.ts
import Vue from 'vue';
import {Injectable} from '@vue-ioc/core';@Injectable()
export class EventBus {private bus: Vue = new Vue();
dispatch(name: string, data: any) {
this.bus.$emit(name, data);
}addListener(name: string, listener: (data: any) => void) {
this.bus.$on(name, listener)
}removeListener(name: string, listener: (data: any) => void) {
this.bus.$off(name, listener)
}
}```
2. Create `@OnEvent(name:string)` decorator
```typescript
// bus/OnEvent.ts
import {createInstanceHandlerDecorator} from '@vue-ioc/core';
import {EventBus} from './EventBus';export function OnEvent(name: string) {
return createInstanceHandlerDecorator(({injector, instance, method}) => {
// attach handler - a place where listeners should be attached
const bus: EventBus = injector.get(EventBus); // you have access to injector where all services can be retrieved
const boundMethod = instance[method].bind(instance); // bound method to `this` of instance
bus.addListener(name, boundMethod);
return () => {
// detach handler - a place where all listeners should be detached
bus.removeListener(name, boundMethod);
};
});
}
```3. Dispatch event from view:
```typescript
// view/Form.vue
Submit
import Vue from 'vue'
import Component from 'vue-class-component'
import {Inject} from '@vue-ioc/core';
import {EventBus} from '../bus/EventBus';@Component()
export default class SomeForm extends Vue {@Inject()
public bus!: EventBus;public submitForm() {
this.bus.dispatch('submitForm', { firstName: 'John', lastName: 'Doe'})
}
}```
4. Handle event in external action:```typescript
// actions/SubmitForm.ts
import {OnEvent} from '../bus/OnEvent'
import {Injectable} from '@vue-ioc/core';@Injectable()
export class SubmitForm {
@OnEvent('submitForm')
perform (data) {
// do something with data
}
}
```## Inversify Container Options
vue-ioc uses following default options for creating Inversify containers:
{
autoBindInjectable: false,
defaultScope: 'Singleton',
skipBaseClassChecks: true,
}
To override or add other options, please use `containerOptions` of plugin options:```typescript
Vue.use(VueIocPlugin, {
containerOptions: {
// options of Inversify container:
// https://github.com/inversify/InversifyJS/blob/master/wiki/container_api.md#container-options
}
})
```