Package Exports
- @teqfw/di
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@teqfw/di) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
@teqfw/di
Dependency Injection container based on ES6 modules (works for browsers & nodejs).
Proxy object for constructor specification is inspired by awilix.
Usage
Main object (./path/to/app/sources/App.mjs):
export default class Sample_App {
constructor({Sample_App_Config}) {
this.cfg = Sample_App_Config;
this.run = function () {}
}
}Dependency (./path/to/app/sources/App/Config.mjs):
export default class Sample_App_Config {
constructor() {}
}Load container, setup namespace mapping, get object:
import Container from "./path/to/Container.mjs";
const container = new Container();
// map sources relatively to this script
container.addSourceMapping("Sample", "./path/to/app/sources");
container.get("Sample_App").then(app => app.run());Modules
@teqfw/di works with ES6 modules that have export default defined.
export default class ClassName{}spec argument for constructor
Dependencies for functions and classes should be defined as properties of the spec object of the constructor:
export default function main_obj(spec) {
const dep1 = spec.dep1;
const dep2 = spec.dep2;
const dep3 = spec.dep3;
}spec object may be directly unfolded in constructor:
export default class MainObj {
constructor({dep1, dep2, dep3}) {}
}"Name to source" mapping
Each class or function should be placed in separate file ( ESM) and should be export default. ES modules can be grouped in folders inside one npm module:
- ./npm_module/
- ./src/
- ./App/
- ./Service/
- ./Download.mjs
- ./Upload.mjs
- ./Config.mjs
- ./Service/
- ./App.mjs
- ./App/
- ./src/
These names can be mapped to the structure above using Zend1 approach:
- App => ./npm_module/src/App.mjs
- App_Config => ./npm_module/src/App/Config.mjs
- App_Service_Download => ./npm_module/src/App/Service/Download.mjs
- App_Service_Upload => ./npm_module/src/App/Service/Upload.mjs
Namespaces roots
We can use namespaces to group all ESM objects (functions and classes) across npm modules:
- Vendor_Project_App => ./node_modules/@vendor/project/src/App.mjs
- Vendor_Service_Download => ./node_modules/@vendor/services/src/Download.mjs
Namespaces roots can be mapped to filesystem:
container.addSourceMapping("Vendor_Project", "./node_modules/@vendor/project/src");
container.addSourceMapping("Vendor_Service", "./node_modules/@vendor/services/src");Absolute and related mapping
const is_absolute = true;
container.addSourceMapping("Vendor_Project", "/pub/node_modules/@vendor/project/src", is_absolute);
container.addSourceMapping("Vendor_Service", "./node_modules/@vendor/services/src", !is_absolute);Dependency identifier
@teqfw/di container can handle 3 types of dependencies for ES-module Vendor_Project_Module_Object:
Vendor_Project_Module_Object(new instance): new object will be created for this type of dependency on every call;Vendor_Project_Module_Object$(default instance): one instance will be created on the first call, will be saved into the container and will be used on all subsequent calls later;Vendor_Project_Module_Object$name(named instance): one instance will be created on the first call, will be saved into the container withnameand will be used on all subsequent calls for thisnamelater;
export default class MainObj {
constructor(spec) {
const new_handler = spec.Vendor_Module_Handler_Update;
const default_cfg = spec.Vendor_Module_Config$;
const db_maria = spec.Vendor_Module_Connector$maria;
const db_postgres = spec.Vendor_Module_Connector$pg;
}
}nodejs start
import Container from "@teqfw/di";
const container = new Container();
container.addSourceMapping("Sample", "./path/to/src");
container.get("Sample_App").then(app => app.run());Browser start
Include main script as ES module to the page (see type="module"):
<!DOCTYPE html>
<html lang="en">
<head>
<script type="module" src="./main.mjs"></script>
</head>
</html>main.mjs:
import Container from "./path/to/Container.mjs";
const container = new Container();
container.addSourceMapping("Sample", "./path/to/src");
container.get("Sample_App").then(app => app.run());Example
Use as nodejs app:
$ node --experimental-modules ./example/s001/s001.mjs
// or
$ npm run-script exampleUse from browser
Place this module under web server then open page http://.../example/s001/s001.html
Expected output to console
'Sample_App_Config' instance is created.
'Sample_App_Service' instance is created.
'Sample_App_HandlerA' instance is created.
'Sample_App_Service' instance is created.
'Sample_App_HandlerB' instance is created.
Application 'Sample_App' is running (deps: [Sample_App_Config, Sample_App_HandlerA, Sample_App_HandlerB]).
Service running with 'Sample_App_HandlerA' param.
Service running with 'Sample_App_HandlerB' param.Installation
$ npm i @teqfw/di