Boilerplate para Angular 1.5 con webpack y ES6

Muchos nos emocionamos con la salida del primer realese de Angular2, pero tenemos que entender que Angular1.x no va a morir, y seguirán sacando versiones y solucionando problemas de versiones anteriores, en este caso vengo a hablarles de Angular 1.5

Angular 1.5

Components, components, components, components ahh y components.

En esta nueva versión nos trae algo genial y es el metodo .component() y toda la lógica orientada a componentes, no viene a sustituir del todo a las directivas, un componente es un componente, este extienden el html, tiene su controlador, sus bindings, en fin llegó para ser nuestro nuevo mejor amigo. Ya que en mi opinión las directivas están en agonía.

Para mayor aprendizaje decidí crear un boilerplate o plantilla para iniciar nuestros proyectos en Angular1.5 ya con una base lógica y no empezar con una “hoja en blanco”.

¿Que vamos a usar?

Para la lógica orientada a componentes y el buen código vamos a usar la guia de estilos de Todd Motto que aprovecho para recomendar su blog, es un crack.

Para la construcción del bundle usaremos Webpack que será explicado mas adelante con detalles en otro articulo.

Y obviamente programaremos con ES6 que con Webpack y unos de sus loaders usaremos Babel para la transpilación.

Para que nuestra plantilla tenga un buen aspecto usaremos Materialize, y aunque no se usará mucho, dejaré todo planteado para usar SASS como preprocesador.

Empezamos

Como dije anteriormente, vamos a usar la guía de estilos de Todd Motto, y esta nos indica que nuestro proyecto debe comenzar con un componente raíz.

Creare src/app/app.component.js

// /app/app.component.js
export const AppComponent = {
template: `
<nav-co></nav-co>
<div>
<div class="views" ui-view></div>
</div>
<footer-co></footer-co>
`
};

y crearemos nuestro punto de entrada /app/app.js que es el modulo que da para iniciar nuestro proyecto en angular.

// /app/app.js
import 'materialize-css/dist/css/materialize.min.css';
import '../style/app.scss';
import angular from 'angular'
import uiRouter from 'angular-ui-router'
import common from './common/common'
import components from './components/components'
import { AppComponent } from './app.component'
const root = angular  
.module('angularApp', [
uiRouter,
common,
components
])
.component('app', AppComponent)
.name;
export default root;

En este modulo importaremos angular y angular-ui-router, también los distintos módulos y el componente raíz.

Componente raíz que usaremos en nuestro index.html de la siguiente manera:

<body>
<app>
</app>
</body>

Según la guía de estilos de Todd, nos dice que debemos separar la estructura de nuestro proyecto en 2, app/common/ que tendrá todos nuestros componentes comunes, los que son reusables, en el caso del ejemplo, el footer y el navbar son los componentes comunes. Y app/components que es donde habitarán el resto de componentes de nuestra aplicación, recordemos que nuestro proyecto es totalmente orientado a componentes, y debemos hacernos la idea de que todo es un componente.

Hay varios tipos de componentes, pero mas adelante en otro articulo ampliaré mas sobre esto, o pueden ver la excelente explicación en la guía de estilos

Continuamos

Vamos a crear los componentes footer y el navbar que son los comunes

/app/common/nav/nav.component.js
export const NavComponent = {  
template: `<nav>
<div class="nav-wrapper">
<a href="#" class="brand-logo">My Angular WebPack</a>
<ul id="nav-mobile" class="right hide-on-med-and-down">
<li><a ui-sref="users" >Users</a></li>
<li><a ui-sref="about">About</a></li>
</ul>
</div>
</nav>`
};
/app/common/footer/footer.component.js
export const NavComponent = {  
template: ` <footer class="page-footer">
<div class="container">
<div class="row">
<div class="col l6 s12">
<h5 class="white-text">Welcome To Angular 1.5 Starter with Webpack & ES6</h5>
<p class="grey-text text-lighten-4">Boilerplate for Agular 1.5 using Webpack & ES6</p>
</div>
<div class="col l4 offset-l2 s12">
<ul>
<li><a class="grey-text text-lighten-3" ui-sref="home">Home</a></li>
<li><a class="grey-text text-lighten-3" ui-sref="about">About</a></li>
<li><a class="grey-text text-lighten-3" ui-sref="users" >Users</a></li>
</ul>
</div>
</div>
</div>
<div class="footer-copyright">
<div class="container">
<a class="grey-text text-lighten-4 right" href="#!">@HenryGBC</a>
</div>
</div>
</footer>`
};

Y creamos el modulo de estos componentes, para agregarlos

/app/common/common.js
import angular from 'angular'
import { NavComponent } from './nav/nav.component'
import { FooterComponent } from './footer/footer.component'
const common = angular
.module('app.common', [])
.component('navCo', NavComponent)
.component('footerCo', FooterComponent)
.name;
export default common;

La estructura de nuestros módulos quedarán de la siguiente manera (Ejemplo)

/home
home.html
home.scss
home.component.js
home.controller.js
home.service.js
home.spec.js
index.js

Se creó un modulo users, donde estará compuesto por los componentes /users-list y /user-detail

/app/components/user-list.component.js
import controller from './users-list.controller.js';
import template from './users-list.html';
export const UsersListComponent = {
bindings: {
usersList:'<'
},
controller,
template: `<div class="users">
<ul class="collection with-header">
<li class="collection-header"><h4>Users List</h4></li>
<li class="collection-item" ng-repeat="user in $ctrl.usersList">
<div>
<span ng-bind="user.name"></span>
<a ui-sref="user-detail({id: {{user.id}} })" class="secondary-content">
<i class="material-icons">send</i>
</a>
</div>
</li>
</ul>
</div>`
}
/app/components/user-list.controller.js

class UsersListController {
constructor(){}
$onInit(){
console.log(this.usersList);
}
}
export default UsersListController;

El component user-list donde se le pasara la lista de los usuarios y el controlador donde no se hará nada por los momentos, solo era la demostración de como se escribía un controlador.

Ahora el component user-detail, donde le pasaremos la data de cada usuario

import controller from './user-detail.controller.js';
import template from './user-detail.html';
export const UserDetailComponent = {
bindings: {
user:'<'
},
controller,
template: `<div class="user-detail">
<div class="col s12 m6">
<div class="card blue-grey darken-1">
<div class="card-content white-text">
<span class="card-title" ng-bind="$ctrl.user.name"></span>
<p>Username: <span ng-bind="$ctrl.user.username"></span></p>
<p>phone: <span ng-bind="$ctrl.user.phone"></span></p>
<p>Work: <span ng-bind="$ctrl.user.company.catchPhrase"></span></p>
</div>
<div class="card-action">
<a href="{{$ctrl.user.website}}">{{$ctrl.user.website}}</a>
</div>
</div>
</div>

<a ui-sref="users" class="waves-effect waves-light btn">Get Users</a>
</div>`
}

Ahora en el index.js es donde estará nuestro modulo de Users y la configuración del routing, olvidémonos ya de un archivo “routes.js” solo para las rutas.

//ap/users/index.js
import angular from 'angular';
import { UsersListComponent } from './users-list/users-list.component';
import { UserDetailComponent } from './user-detail/user-detail.component';
import UsersService from './users.service';
const users = angular
.module('users', [])
.component('usersList', UsersListComponent)
.component('userDetail', UserDetailComponent)
.service('UsersService', UsersService)
.config(($stateProvider, $urlRouterProvider) => {
$stateProvider
.state('users', {
url: '/users',
component: 'usersList',
resolve: {
usersList: (UsersService) => UsersService.getUsers()
}

})
.state('user-detail', {
url: '/users/:id',
component: 'userDetail',
resolve: {
user: (UsersService, $stateParams) => UsersService.getUser($stateParams.id)
}

})
$urlRouterProvider.otherwise('/');
})
.name;

export default users;

Utilizaremos el Servicio UsersService que mediante los resolve los llamaremos para que se cargue la data antes de cargar la pagina. Utilizamos una fake api que nos proporciona una lista de usuarios entre otras cosas https://jsonplaceholder.typicode.com/

/app/users/users.service.js
class UsersService{
constructor ($http){
this.$http = $http;
}
getUsers(){
return this.$http.get('https://jsonplaceholder.typicode.com/users').then(response => response.data);
}
getUser(id){
return this.$http.get(`https://jsonplaceholder.typicode.com/users/${id}`).then(response => response.data);
}
}
UsersService.$inject = ['$http'];
export default UsersService;

y finalmente en nuestro modulo components /app/components/components.js agregamos los módulos users, home y about, los dos últimos pueden verlos en el repositorio https://github.com/HenryGBC/my-angular-webpack

Puedo decir que me gustó mucho toda esta lógica orienta a componentes partiendo desde un componente raíz, y nos acerca cada vez mas a Angular2 que trabaja con componentes también.

Ya para probar y ejecutar el boilerplate vamos al repositorio https://github.com/HenryGBC/my-angular-webpack

//Instalar dependencias
npm install
//Correr servidor
npm start
//Construir el bundle
npm run build

Vemos una captura de pantalla del boilerplate

Y para finalizar agradecer y recomendar el blog de Todd Motto y su guía de estilos también el de Carlos Azaustre

Seguiré mejorando y escribiendo mas de lo que me apasiona..

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.