Uso de Requirejs para modularizar una App creada con Emberjs
0. Índice de contenidos.
- 1. Entorno
- 2. Introducción
- 3. ¿Qué vamos a utilizar?
- 4. Primer paso, Modularizar nuestra aplicación
- 5. Iniciar nuestra app
- 6. Cambiar de vista
- 7. Cambio de estado mediante controladores
- 8. Conclusiones
1. Entorno
Este tutorial está escrito usando el siguiente entorno:
- Hardware: Portátil Intel Core 2 CPU T7200 @ 2.00GHz x 2
- Sistema Operativo: Ubuntu 12.04 LTS x32
- Sublime text 2
2. Introducción
En este tutorial voy a enseñaros como utilizar Requirejs con una aplicación anteriormente creada con Emberjs,
voy a utilizar como ejemplo la aplicación que utilizó Daniel en el anterior tutorial.
3. ¿Qué vamos a utilizar?
Vamos a modularizar nuestra app con todas las ventajas que nos proporciona Requirejs.
Dado que en esta aplicación utilizamos Ember la convención de nombres será especial,
la iremos nombrando más adelante.
Para saber más de requirejs ver tutorial de require.
Os pongo un código de ejemplo en el que trabajé con Daniel: Enlace a github
4. Primer paso, Modularizar nuestra aplicación
Si le echásteis un ojo a la anterior aplicación, podréis ver que toda la app estaba en el mismo fichero, y era lo que conocemos como ‘espagueti’ o ‘chorizo’.
Y como es obvio no nos conviene tener un código de este tipo.
Lo que vamos a hacer es separar nuestra app en cuanto a vistas, modelos, controladores y templates en diferentes módulos.
Lo que haremos sera crear un fichero para cada cosa, y separarlo en carpetas, que tendremos que definir después en un fichero de configuración.
Como podéis ver tenemos nuestro fichero config al lado de nuestra app ‘main.js’ lo que tomaremos como directorio raiz.
Nota: Este no es el modelo de la App, sino el fichero principal desde el que crearemos la App.
Vamos a definir un módulo de configuracion para utilizarlo despues a la hora de crear nuestra app.
define({ app_name: "App", //nombre de la applicacion shim : { 'ember' : { deps: ['handlebars', 'jquery'], exports: 'Ember' } }, paths : { 'App': 'app/main', 'models': 'app/models', 'views': 'app/views', 'controllers': 'app/controllers', 'routes': 'app/routes', 'templates': 'app/templates', /*libs*/ 'jquery': 'libs/jquery/1.9.1/jquery', 'handlebars': 'libs/handlebars/1.0.rc.3/handlebars', 'ember': 'libs/ember/1.0.0-rc.2/ember', /*requirejs-plugins*/ 'text': 'libs/requirejs-plugins/text', 'hbs': 'libs/requirejs-plugins/hbs', 'domReady': 'libs/requirejs-plugins/domReady', 'store' : 'app/store' }, /*hbs plugin options*/ hbs: { disableI18n: true, templateExtension: "html" } });
Como podéis ver aquí definimos (en path) todas las rutas que vamos a utilizar más adelante, a la hora de definir las dependencias.
En este mismo codigo, línea 4, podemos ver como definimos una variable ember a la cual le asignamos unas dependencias. Deps.
5. Iniciar nuestra app
Una vez hecho esto, vamos a iniciar nuestra app.
Vamos a definir unas dependencias con require al fichero de configuración:
require(["config"], function(config){ requirejs.config(config); });
Dentro de esta función de callback, crearemos nuestra app.
Por lo que vamos a definir nuestras dependencias antes de hacerlo:
require(["App", "ember", "store"], function(App, Ember, store){ });
Como podéis ver , por parámetros vamos a recibir estas dependencias, por lo que podremos utilizar todos los atributos, funciones… de estas.
Vamos a crear ahora nuestra app:
root[app_name] = App = Ember.Application.create(App, {LOG_TRANSITIONS: true});
Ahora vamos a definir nuestra App.
Será un js que ejecutaremos al utilizar la dependencia del App, visto en el punto anterior.
Define([ //definimos las dependencias "app/router", "views/ApplicationView", "controllers/ApplicationController", "views/IndexView", "controllers/IndexController", "routes/IndexRoute", /*Aquí podemos incluir el resto de ruters, controladores, vistas... */ ], function(){ // Aquí inicializamos estas dependencias //Podríamos incluirlas como parámetros. /* Router */ var Router = require("app/router"); /* Global */ var ApplicationView = require("views/ApplicationView"); var ApplicationController = require("controllers/ApplicationController"); /* Controladores globales */ var UserController = require("controllers/UserController"); var ColorController = require("controllers/ColorController"); var ColorsController = require("controllers/ColorsController"); /* Index */ var IndexView = require("views/IndexView"); var IndexController = require("controllers/IndexController"); var IndexRoute = require("routes/IndexRoute"); /*Aquí podemos incluir el resto de ruters, controladores, vistas... */ /*Aplicamos el patron de módulos a nuestra app.*/ //Aquí le damos uso a esas dependencias var App = { Router: Router, ApplicationView: ApplicationView, ApplicationController: ApplicationController, UserController: UserController, ColorController: ColorController, ColorsController: ColorsController, IndexView : IndexView, IndexController : IndexController, IndexRoute : IndexRoute, /*Aquí podemos incluir el resto de ruters, controladores, vistas... */ }; return App; //Retornamos la App, ya que es un módulo para utilizarla fuera. });
Como veis definimos una serie de dependencias en el primer parámetro de define,
luego las inicializamos, aunque podriamos recibirlas por parámetro de la función de callback,
y saltarnos este paso.
Pero para tener ambos ejemplos y no tener demasiados parámetros… mejor mostraros la otra forma,
y ya sabeis lo dicho: si hay más de 3 parámetros en una función, divide y vencerás.
6. Cambiar de vista
Para poder navegar entre views, o vistas, lo que necesitamos es,
definir en un módulo router.js nuestras rutas.
Serán similares a las de la aplicación anterior, dado que para navegar entre templates es exactamente igual, pero esta vez definido como módulo.
define(["ember"], function(Ember){ var Router = Ember.Router.extend({}); Router.map(function(){ this.resource("menu",{path : "/menu" },function(){ this.route("selectColor"); this.route("watchColor"); }) }) return Router; });
Creamos un módulo para el controlador
define(["ember"], function(Ember){ var ApplicationController = Ember.Controller.extend(); return ApplicationController; });
Ahora vamos a crear un módulo para nuestro template:
//Comentado para que podais verlo. {{t main.application.title tagName="h1"}} {{outlet}} //
Finalmente crearemos un módulo para nuestra view:
define([ "ember", "text!templates/applicationTemplate.html" //definimos como dependencia los templates ], function(Ember, applicationTemplate) { var ApplicationView = Ember.View.extend({ //Aqui compilaremos con handlebars nuestro template defaultTemplate: Ember.Handlebars.compile(applicationTemplate) }); return ApplicationView; });
Nota: para poder enlazar bien nuestras rutas, controlar que habéis realizado estos pasos, incluso definir en vuestra app cada view, cada controlador, todo…
7. Cambio de estado mediante controladores
Para mantener un estado en nuestra aplicación, basta con tener un Store donde almacenamos nuestras variables, o acceder al controlador que mantiene estos estados.
Para acceder a los atributos, o funciones de un controlador desde otro basta con definir una dependencia como atributo llamado “needs:” ejemplo:
define(['ember'],function(Ember){ MenuSelectColorController = Ember.Controller.extend({ needs: ['Color', 'Colors'], init: function(){ this._super(); }, changeSelectedColor : function(newColor){ var colorController = this.get("controllers.Color"); colorController.changeSelectedColor(newColor.name); } }); return MenuSelectColorController; });
De esta manera conseguiremos acceder a las funciones y atributos de ColorController y ColorsController.
Como podéis ver la sintaxis de ember es similar, pero debemos definir las dependencias.
Una duda que me surgio es como enlazar un {{outlet}} a una vista determinada, y bastaba con tener bien enrutada nuestra app en el Router.
Si tenemos un {{outlet}} en menu, cargará a continuacion menu/index,
por lo tanto si queremos acceder a otras rutas desde nuestra app,
por ejemplo a menu/selectColor, lo tendremos que definir en nuestro router,
y después acceder a esta ruta mediante linkTo
{{#linkTo «menu.selectColor»}}
Otra manera es renderizar mediante el helper {{render}} de handlebars. Ej: {{render “user” this}}
Cargará el template: userTemplate
El segundo parámetro es el contexto a usar. This dentro de este bloque es user.
8. Conclusiones
De este modo tendremos nuestra app separada en distintos módulos,
por lo que tendremos todas las ventajas de este sistema, ya sea para reutilizar nuestro código,
para tener un código más limpio y ordenado, facilitar una futura refactorización y facilitar también la comprensión.
Más adelante haremos un tutorial de como internacionalizar una aplicación con Ember-i18n y separada en módulos con Requirejs y así profundizar un poco más.
Muy buen tuto, estuve buscando algo en español acerca de require, hay muy poco lamentablemente, me parece esencial para las aplicaciones que se hacen hoy en dia, tengo archivos js, de mas de 15000 lineas que son verdaderos monstruos, espero poco a poco ir modulando para que sea mucho mas facil editarlo, trabajar en svn, etc…