Late registering
&
Lazy loading

Gonzalo Ruiz de Villa Suárez
@gruizdevilla

Proyecto de ejemplo

Los fuentes los puedes encontrar en:

https://github.com/gonzaloruizdevilla/angularlazyload

Para arrancar el proyecto:

    $ npm install
    $ bower install
    $ npm start
    



De base,
AngularJS no permite
 el registro de artefactos
después de arrancar la aplicación.



Sin embargo,
se pueden acceder
a las piezas de registro
al arrancar la aplicación.



Al exponerlas, de forma artificial, podemos utilizarlas más adelante para registrar más artefactos.

Exponiendo métodos para registro posterior


module.config(
    function (
        $controllerProvider, 
        $compileProvider,
        $filterProvider, 
        $provide
    ) {
        module.lazy = {
            controller: $controllerProvider.register,
            directive: $compileProvider.directive,
            filter: $filterProvider.register,
            factory: $provide.factory,
            service: $provide.service
        };
   }
);

Para registrar un nuevo servicio una vez arrancada la aplicación:



module.lazy.factory('MySrv', function () {
    //factory body
});

Los tests unitarios se pueden complicar. Para evitarlo:



(module.lazy || module).factory('MySrv', function () {
    //factory body
});
    

Al probar unitariamente se registran antes de arrancar.

O mejor, si hacemos esto:

module.config(
    function (
        $controllerProvider,
        $compileProvider,
        $filterProvider,
        $provide
    ) {
        module.controller = $controllerProvider.register;
        module.directive = $compileProvider.directive;
        module.filter = $filterProvider.register;
        module.factory = $provide.factory;
        module.service = $provide.service;
    }
);
En la etapa de configuración, 
reemplazamos métodos inútiles por los que nos permiten registrar.

Limitaciones


  • No hay soporte oficial para estas técnicas.
  • La fase de configuración ya terminó, por lo tanto:
    • No se pueden configurar los nuevos recursos. Por lo tanto no tiene sentido registrar con provider, por ejemplo.
    • No se pueden decorar los nuevos recursos
    • No se pueden agregar nuevos módulos

En mi experiencia, estas limitaciones no son importantes para los recursos que tengo que cargar a posteriori.

Lazy load


Es importante encontrar la convención adecuada para tu proyecto: minimiza la configuración de lazy load.

La estrategia: apoyarse en las configuraciones de las rutas. Agrega en 'resolve' una función que devuelve una promesa que se resuelva al cargar las dependencias.

Script.js


Para el ejemplo, uso script.js, una superligera (1.5kb) librería de carga asíncrona de scripts:


bower install script.js --save


https://github.com/ded/script.js

Preparar la configuración de una ruta:




function resolveDependencies(config, dependencies) {
  config.resolve = {
    dependencies: function ($q, $rootScope) {
      var deferred = $q.defer();
      $script(dependencies, function () {
          $rootScope.$apply(function () {
              deferred.resolve();
          });
      });
      return deferred.promise;
    }
  };
}

Usando RequireJS


Los principios son los mismos,
pero ligeramente más complicado
por la idiosincrasia de AMD:

  • Pasa la referencia al módulo de AngularJS
    mediante los mecanismos de RequireJS
  • El arranque de la aplicación (bootstrap)
    de AngularJS se debe hacer de forma manual.

RequireJS o no RequireJS


  • RequireJS es mucho más potente,
    pero añade complejidad en:
    • Configuración: dependencias definidas dos veces
      en cada fichero, en 'define' y al registrar el recurso
      en AngularJS. Sin RequireJS, también hay
      esa duplicidad, pero se puede eliminar con
      convenciones en nomenclatura.
    • Testing más complicado con RequireJS.
      Con la primera técnica librería, el testing
      es el habitual de AngularJS.





¡Gracias!

Late registering and lazy load in AngularJS

By Gonzalo Ruiz de Villa

Late registering and lazy load in AngularJS

Late registering and lazy load in AngularJS

  • 4,038