@ teqfw / di

A algunos les encanta andar en bicicleta y a otros les encanta reinventarlas. Soy de los que reinventa las bicicletas para montarlas. Hace un par de años ya escribí en Habr sobre esta " bicicleta " mía: un contenedor DI para JavaScript. La discusión posterior de los principios de funcionamiento de los contenedores DI y su diferencia con el " Service Locator " me hizo avanzar bastante en la comprensión del trabajo de mi propia " bicicleta " y resultó no solo en una serie de artículos sobre Habré ( uno , dos , tres , cuatro ), sino también, en gran medida, la finalización de la propia " bicicleta ".





Debajo del corte: una descripción del trabajo del contenedor DI ( @ teqfw / di ) en el momento actual. Limitaciones: el contenedor está escrito en JavaScript puro (ES2015 +), funciona solo con código ES2015 +, decorado en módulos ES con la extensión *.mjs



. Ventajas: te permite cargar y usar los mismos módulos tanto en el navegador como en las aplicaciones de nodejs sin transpilación adicional.





Conceptos básicos sobre contenedores DI

Una llamada típica a un contenedor abstracto de objetos se ve así:





const obj = container.get(id);
      
      



La secuencia de acciones del contenedor:





  1. Determine por id qué tipo de objeto quiere obtener la persona que llama.





  2. Verifique el contenedor por la presencia del objeto solicitado, si el objeto está en el contenedor, devuélvalo





  3. Si es necesario crear el objeto, utilice la identificación para determinar dónde se encuentra el archivo con el código fuente del objeto y descargue las fuentes.





  4. ( ).





  5. .





  6. .





  7. ( ).





  8. .





— 5 , , .





ES-

, ES- — .., DI- ES-.





const obj = {name: 'Simple Object'};
class Clazz {
    constructor(spec) {
        this.name = 'instance from class constructor';
    }
}
function Factory(spec) {
    return {name: 'instance from factory'};
}
export {
    obj as ObjTmpl,
    Clazz as default,
    Factory,
}
      
      



, ES- (, ):





import Def from './es6.mjs';
import {Factory} from './es6.mjs';
import {ObjTmpl} from './es6.mjs';

const spec = {}; // empty specification
const instClass = new Def(spec);
const instFact = Factory(spec);
const instTmpl = Object.assign(ObjTmpl, {});
      
      



, DI-, ES-, :





  • ;





  • ;





— , , ( ) , DI- :





constructor(spec) {
    const dep = spec['depId'];
}
...
await container.get('dep1');
      
      



:





import Container from '@teqfw/di';

const container = new Container();
container.set('dep1', {name: 'first'});
container.set('dep2', {name: 'second'});

const obj = await container.get('dep1');
      
      



ES-, (, -).





@teqfw/di



:





  • : (connection



    , conf



    , i18n



    , …);





  • : (EsModuleId



    );





container.set(id, obj)



, ( ).





@teqfw/di



ES- , Module



(. “” “Javascript: ”).





, - . @teqfw/di



#



:





  • EsModuleId



    : ;





  • EsModuleId#ExportName



    : ExportName



    EsModuleId



    ;





  • EsModuleId#default



    EsModuleId#



    : default



    EsModuleId



    ;





@teqfw/di



:





class Clazz {
    constructor(spec) {}
}

function Factory(spec) {}
      
      



, (), — ( )? @teqfw/di



$



:





  • EsModuleId#ExportName



    : (, ) ExportName



    EsModuleId



    .





  • EsModuleId#ExportName$



    : , ( ), ExportName



    EsModuleId



    .





default



- ES- :





  • EsModuleId#default$







  • EsModuleId#$







  • EsModuleId$







Singleton

( ), . "" -$$



:





  • EsModuleId$



    EsModuleId#ExportName$



    : ( ) , .





  • EsModuleId$$



    EsModuleId#ExportName$$



    : .





, singleton’ — . DI- global-. - , , DI — .





@teqfw/di



:





let id1 = 'named'; // named singleton been added manually
let id2 = 'EsModId'; // ES module
let id3 = 'EsModId#'; // default export of ES module
let id4 = 'EsModId#name'; // named export of ES module
let id5 = 'EsModId$'; // singleton from default export
let id6 = 'EsModId$$'; // new instance from default export
let id7 = 'EsModId#name$'; // singleton from named export
let id8 = 'EsModId#name$$'; // new instance from named export
      
      



, , , ( ). @teqfw/di



:





constructor(spec) {
    const named = spec['namedSingleton'];
    const inst = spec['EsModId#name$$'];
    const single = spec['EsModId$'];
}
      
      



@teqfw/di



, , , , . , , .





ES-, . @teqfw/di



:





container.addSourceMapping('EsModId', './relative/path');
container.addSourceMapping('EsModId', '/absolute/path', true);
      
      



( ) , , — nodejs-. , .





, , , namespace’, _



:





EsModId_PathTo_Mod => /absolute/path/PathTo/Mod.mjs
      
      



El contenedor @ teqfw / di DI le permite usar tanto los módulos ES como dependencias, como también elementos individuales de la exportación de módulos ES, así como crear nuevas instancias de objetos o usar un solo objeto para toda la aplicación. Además, el mismo código se puede utilizar tanto en navegadores como en aplicaciones de nodejs.





Código típico para un módulo ES utilizado en @teqfw/di



:





export default class Mod {
    constructor(spec) {
        const Clazz = spec['Lib_Dep#'];
        const single = spec['Lib_Dep$'];
        const inst = spec['Lib_Dep$$'];
        // ...
    }
}
      
      



El habitual import



también se puede utilizar en el código, pero en este caso el código pierde la capacidad de ser utilizado simultáneamente en navegadores y en aplicaciones nodejs, ya que el formato de importación del navegador no es compatible con el formato nodejs.








All Articles