AMD vs CJS
Uff, bueno, este tema da para debatir un largo rato, pero mi intento es mostrar mi investigación y una opción que adopté para mis proyectos hoy por hoy.
Se acuerdan cuando hablaba de organizar el código de JS, que ya no es scripting y creación de funciones colgadas por todos lados, que a medida que la web crece y hacemos aplicaciones, en vez de una paginita web con botones ya creamos aplicaciones web. Un inicio por el camino correcto al orden es desacoplar creando módulos y hablaba de como hacerlo en el post Patrones: Module y Namespace.
Bueno, avanzando sobre ese tema, existen definiciones y estandares para crear y utilizar módulos, de eso se trata este post. Vamos a ver de que se trata cada uno de estos enfoques para solucionar el problema.
AMD: Asynchronous Module Definition
La Definición Asíncrona de Módulos fue creada para definir módulos donde este mismo y sus dependencias puedan ser cargadas asincrónicamente. Un ejemplo de esto es el conocido RequireJS (en este post muestro una intro: RequireJS: Módulos y Dependencias).
Se puede decir que fue pensado especialmente para el Navegador donde es importante tener este tipo de asincronismo. También existen herramientas de optimización para el navegador donde es importante cargar lo necesario e indispensable mejorando la experiencia con nuestro sitio.
Demasiado texto, tiremos un poco de código para no dormirnos.
De esta manera puedo definir cada módulo de mi aplicación con sus dependencias a otros módulos y me aseguro que todo existe antes de utilizarlos.
CJS: Common JS
Ahora cambia un poco la idea, en CJS no tenemos “definición de módulos”, es decir, no escribimos un “define”, sino que se asume que sus dependencias ya están cargadas al momento de requerirlas.
Para este caso podemos decir que fue pensado para el Server (por ej. NodeJS), donde realizamos un require([módulo]) y lo tenemos, sin asincronismo:
Si bien, estamos de alguna manera definiendo sus dependencias con require(), la diferencia principal es que no lo hacemos antes de ejecutarse, es decir, podemos tener funciones y realizar esos require() desde cualquier parte del módulo, pero eso si, siempre se asume que ya está cargado.
AMD + CJS
Pero que pasa si intentamos utilizar el ejemplo anterior de CommonJS en el navegador?, definitivamente no va a funcionar.
Así como tampoco utilzar un define en NodeJS.
Entonces cual es mejor?, cuando?, donde?. Bueno, a mi parecer no hay uno mejor que el otro, ya explique para que fueron creados, ambos tienen sus pros y contras.
Mi problema, personal, es que me gusta AMD por su asincronismo, pero también me gusta CJS por el hecho de no definir dependencias y de poder utilizar mis módulos en NodeJS también (mientras no utilice DOM jeje), así que opté por utilizar ambos para el navegador.
Como?, bueno ahí esta lo divertido, simplemente envolviendo cada módulo CJS en uno de AMD, pero en tiempo de “compilación” (*) (sino sería medio extraño), es decir, usando GruntJS con la ayuda de WebMake.
(*) con “compilación” me refiero a la tarea en GruntJS, realmente no se esta “compilando” el javascript jaja.
En un futuro post voy a mostrar un poco mas de GruntJS, pero por el momento les dejo un proyecto base en Github sobre esto de AMD + CJS + GruntJS + WebMake (también tiene un poco de Backbone y Backbone Marionette )
https://github.com/pjnovas/base-client-project (les debo el Readme en Español)