Dependencies
On this page
In this section, we will explain how dependency management is handled by the framework. This is a very important feature, especially in case of big projects in which you will have to split your source code in several files.
ES6 modules
Dana uses the Javascript ES6 modules notation
to load classes and configuration files for the application.
A class is declared in a module as follows:
import $Class from "@Class";
export default $Class.declare("MyClass", { /* class def */ });
Did you know?
- A module should contain only one class (don’t write a module with multiple classes inside it)
- The
_MyClass
variable is an alias (i.e. the tooling is creating the variable with the full path of the class) - Class names are unique (two classes can not have the same name)
@Class
refers to the class namedClass
(i.e. you don’t need to know the full path of a class to load it)
Aliases
The framework provides class names and class constructors aliases for all framework classes. This mechanism allows to move classes to different packages without any impact on the application side.
There are two different kinds of aliases:
_Class
which is referencing the fully qualified name of a Class.$Class
as a reference to the Class constructor from which you can create instance.
Caution
This implies that all class names are unique.
Injection
The framework comes with a dependency injection (DI) mechanism where the implementation of components used in the application, are resolved by the configuration. A Component declares an abstract class or an abstract model that must be implemented. For a component, there may be multiple implementations. You never need to import a specific implementation (otherwise, you need to import the component by its name and the tooling will inject the right implementation depending on your configuration).
First, you need to declare your component like this:
import $Abstract from "@Abstract";
/**
* @component
*/
export default $Abstract.declare("AbstractSearch", {
search: function() {
return this._search();
},
/**
* @abstract
*/
_search: function() {
return this._notImplementedPromise("_search");
}
);
Caution
- You MUST annotate the class with the
@component
in the JSDoc of the class header. - The class name of a Component must begin with Abstract as prefix.
Then, here is a typical implementation of the component:
import $AbstractSearch from "@AbstractSearch";
/**
* @implementation
*/
export default $AbstractSearch.declare("DefaultSearch", {
/**
* @override
*/
_search: function() {
// do your implementation !
}
);
Caution
- You must annotate the class with the
@implementation
in the JSDoc of the class header. - Most of the time the implementations are offered by the
vendors
. - The core may sometimes offer default implementation (in such case, they are called
Core<ComponentName>
).
And finally, you can use the “Search” component in your application:
import $Search from "@Search";
// $Search will be resolved to right implementation
// In this example, $Search === $DefaultSearch
);