Why provide an ioc container for Vue3
Vue3 is fully capable of developing large-scale business systems due to its excellent responsive system and convenient functional features. However, we must not only be able to do it, but also do it better. The key to large-scale business systems is decoupling, thereby slowing down the growth of messy code. The ioc container is currently the best decoupling tool. Angular introduced the ioc container from the beginning, so it has always been in a leading position in business engineering, and has been waving to other front-end frameworks: "I'm waiting for you in front, and I hope to see you again in three years." So, I will try to take two steps forward, provide the ioc container in Vue3, and introduce other engineering capabilities based on it to get a new framework: Zova. Is it easy to use? I look forward to your trial and feedback
IOC Containers
There are two types of ioc containers in Zova:
-
global ioc container
(referred to as app container): During system initialization, a unique global bean container will be automatically created. Bean instances created in this container are all singleton mode -
component instance ioc container
(referred to as ctx container): When creating Vue component instances, the system will create a bean container for each of them. Bean instances created in this container can share data and logic within the scope of the component instance
Bean Class
Zova adopts a modular system, and Bean Classes are provided by different modules. When using the Bean Class inside the same module, you can directly locate it based on Class type
. When using cross-module, you can locate it based on Bean identifier
instead of Class type/file path
, which is conducive to achieving loose coupling between modules
Therefore, Zova provides two types of Bean Classes:
Anonymous bean
: The class decorated with@Local
is ananonymous bean
. This type of bean is only used within the module, there is no naming conflict, and it is easy to define and useNamed bean
: Except for@Local
, the classes decorated by the other decorator functions arenamed beans
. Zova provides a unified naming convention for such beans, which can avoid naming conflicts and facilitate cross-module usage
Injection mechanism
Zova provides the following injection mechanisms:
1. Bean Class
Use Bean Class
to lookup and inject bean instance in the ioc container, and automatically create one if not exist. This mechanism is generally used for same module injection
import { ModelTodo } from '../../bean/model.todo.js';
class ControllerTodo {
@Use()
$$modelTodo: ModelTodo;
}
2. Bean identifier
Use Bean identifier
to lookup and inject bean instance in the ioc container, and automatically create one if not exist. This mechanism is generally used for cross-module injection
and hierarchical injection
import type { ModelTabs } from 'zova-module-a-tabs';
class ControllerLayout {
@Use('a-tabs.model.tabs')
$$modelTabs: ModelTabs;
}
- Lookup and inject bean instance through
a-tabs.model.tabs
- Therefore, only the type of ModelTabs needs to be imported to maintain the loose coupling relationship between modules
3. Registration name
Lookup and inject bean instance in the ioc container through the registration name
, and return a null value if not exist. This mechanism is generally used for same module injection
and hierarchical injection
import type { ModelTodo } from '../../bean/model.todo.js';
class ControllerTodo {
@Use({ name: '$$modelTodo' })
$$modelTodo: ModelTodo;
}
- Lookup and inject the bean instance by the registration name
$$modelTodo
. Generally speaking, you should ensure that the bean instance has been injected in the ioc container in advance, otherwise a null value will be returned
4. Variable name
Lookup and inject the bean instance in the ioc container by the variable name
, and return a null value if not exist. This mechanism is generally used for same module injection
and hierarchical injection
import type { ModelTodo } from '../../bean/model.todo.js';
class ControllerTodo {
@Use()
$$modelTodo: ModelTodo;
}
- Lookup and inject the bean instance by the variable name
$$modelTodo
. Generally speaking, you should ensure that the Bean instance has been injected in the ioc container in advance, otherwise a null value will be returned
Injection scope
The default injection scope of anonymous bean
is ctx
, and the default injection scope of named bean
can be specified when defining it. Different scenes have different default injection scopes. In addition, when injecting, you can also override the default injection scope through the injectionScope
option in @Use
Zova provides the following injection scopes: app/ctx/new/host/skipSelf
1. app
If the injection scope is app
, then inject the bean instance in the global ioc container to achieve the singleton effect
// in module: test-module1
@Store()
class StoreCounter {}
// in module: test-module2
import type { StoreCounter } from 'zova-module-test-module1';
class Test {
@Use('test-module1.store.counter')
$$storeCounter: StoreCounter;
}
- The injection scope of
Store
isapp
by default, so the bean instance will be lookuped and injected in the global ioc container through the bean identifiertest-module1.store.counter
2. ctx
If the injection scope is ctx
, then inject the bean instance into the ioc container of the current component instance
// in module: a-tabs
@Model()
class ModelTabs {}
// in module: test-module2
import type { ModelTabs } from 'zova-module-a-tabs';
class ControllerLayout {
@Use('a-tabs.model.tabs')
$$modelTabs: ModelTabs;
}
- The injection scope of
Model
isctx
by default, so the bean instance will be lookuped and injected in the ioc container of the current component instance through the bean identifiera-tabs.model.tabs
3. new
If the injection scope is new
, then directly create a new bean instance
// in module: a-tabs
@Model()
class ModelTabs {}
// in module: test-module2
import type { ModelTabs } from 'zova-module-a-tabs';
class ControllerLayout {
@Use({ beanFullName: 'a-tabs.model.tabs', injectionScope: 'new' })
$$modelTabs: ModelTabs;
}
- Since the
injectionScope
option is specified asnew
, a new bean instance will be directly created through the bean identifiera-tabs.model.tabs
Hierarchical injection
Injection scope supports not only app/ctx/new
, but also host/skipSelf
which is called hierarchical injection
4. host
If the injection scope is host
, the bean instance will be lookuped in the ioc container of the current component instance and all parent containers in turn. If it does not exist, a null value is returned
// in parent component
import type { ModelTabs } from 'zova-module-a-tabs';
class Parent {
@Use('a-tabs.model.tabs')
$$modelTabs: ModelTabs;
}
// in child component
import type { ModelTabs } from 'zova-module-a-tabs';
class Child {
@Use({ injectionScope: 'host' })
$$modelTabs: ModelTabs;
}
- Since the parent component has already injected the
ModelTabs
bean instance, the child component can directly lookup and inject it -
Hierarchical injection
also supports all injection mechanisms:Bean Class/Bean identifier/Registration name/Variable name
5. skipSelf
If the injection scope is skipSelf
, then lookup the bean instance in all parent containers in turn. If it does not exist, a null value is returned
Github: https://github.com/cabloy/zova
Demo: https://zova.js.org/zova-demo/
Docs: https://zova.js.org/guide/essentials/ioc/introduction.html
Top comments (0)