Seleccionar página

Hoy vamos a cambiar de aires dejando por un momento de lado Vue.js para montar el esqueleto de una aplicación con otro framework que ha gozado de una gran popularidad en los últimos años: angularjs. Y aprovechando el reciente lanzamiento de webpack 4, vamos a preparar un proyecto en el que utilizaremos este empaquetador para generar nuestro paquete final, y el servidor de desarrollo del mismo para ejecutar nuestra aplicación mientras trabajamos. Y todo ello partiendo de cero, ¡manos a la obra!

Instalando y configurando webpack 4

Puedes descargar el código completo de este ejemplo desde GitHub: oddbytes.net/blog

Empezamos por crear, en un directorio vacío, el fichero package.json con npm:

npm init -y

Vamos a modificar el paquete para hacerlo privado, no vaya a ser que lo publiquemos por error 😉 . Incluimos la linea

"private": true,
Y ya estamos listos para descargar las dependencias. Empezamos por las de webpack 4: el propio webpack y su interfaz de linea de comando, que nos servirá para ejecutarlo.Y como bonus adicional, el servidor de desarrollo de webpack que utilizaremos para servir en caliente nuestra aplicación:
npm i --save-dev webpack webpack-cli webpack-dev-server

Modificamos la sección scripts de package.json para incluir los comandos que utilizaremos durante el desarrollo para ejecutar la aplicación y posteriormente para crear el paquete distribuible:

"scripts": {
    "dev": "webpack-dev-server --open --hot --mode development",
    "build": "webpack --progress --hide-modules --mode production"
  },

El comando dev ejecuta webpack-dev-server indicándole que debe ejecutarse con actualizaciones en caliente y que nos debe abrir el navegador al arrancar. Además el pasamos el parametro --mode development para webpack, que se utiliza para usar la configuración predeterminada de desarrollo.

En el caso del script build, ejecutamos directamente webpack en modo producción para generar el paquete final con las opciones por defecto para esta configuración.

Y es que la última versión de webpack presume de ser “sin configuración”, es decir, de no necesitar de un fichero como las versiones anteriores para funcionar. Y esto es así pero solo para las configuraciones más básicas; como veremos mas adelante necesitaremos el fichero webpack.config.js para varias cosas, por lo que vamos a crearlo de entrada con un contenido muy básico, indicando el punto de entrada y el fichero empaquetado de salida y una pequeña configuración para el servidor de desarrollo:

const path = require('path');

module.exports = {
    entry: './src/app/app.module.js',
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist')
    },
    devServer: { 
        contentBase: path.join(__dirname, "src"), 
        compress: true, 
        port: 9000, 
        publicPath: "/dist/"
    }
}

Si no estás acostumbrado a los ficheros de configuracion de webpack, esto es lo que estamos haciendo:

  • entry: indicamos el punto de entrada que debe utilizar el empaquetador para recorrer nuestro proyecto y decidir qué es lo tiene que incluir en el paquete final. En nuestro caso sera el script ./src/app/app.module.js (más adelante veremos la estructura del proyecto)
  • output: salida del empaquetador: queremos obtener un paquete llamado bundle.js en la carpeta ./dist. Este fichero se generará cuando utilicemos webpack en modo production, ya que en modo development los paquetes de sirven desde memoria.
  • devServer: configuracion del servidor de desarrollo
    • port: no necesita explicación
    • compress: esta opción tampoco, ¿verdad?
    • contentBase: carpeta desde la que servir el contenido estático. En nuestro caso, y para esta demostracion, utiliaremos un fichero index.html en ./src
    • publicPath: ubicación desde la que servir los paquetes generados. Como en output hemos indicado la carpeta dist, aquí también 🙂
Con esto tenemos webpack listo para generar paquetes en los que se incluirá todo el javascript que utilicemos en nuestra aplicación. Pero vamos a ir un poco más allá y vamos a incluir también los ficheros css y html en el paquete final, de forma que el navegador se descargue todo lo necesario en una única petición. Esto nos permitirá tambien hacer que, ante cualquier cambio en un fichero .js, .html o .css durante el desarrollo nuestra aplicacion se recargue automáticamente en el navegador gracias a la recarga en caliente del servidor de desarrollo.
Para incluir estos ficheros necesitamos cargadores específicos de webpack. En el caso de los ficheros css, css-loader nos permitirá incluir las hojas de estilos en el paquete final como cadenas de texto, mientras que style-loader tomará las cadenas generados por el anterior y las pondrá dentro de tags <style> allá donde hagan falta. Los descargamos con npm:
npm i --save-dev css-loader style-loader

Hay que indicarle a webpack que utilice estos cargadores para los ficheros css. Esto se hace mediante la sección rules en la propiedad module del fichero webpack.config.js:

rules: [
{
    test: /\.css$/,
    use: ['style-loader', 'css-loader']
},

Esta configuración indica a webpack que para los ficheros .css debe usar en primer lugar el cargador css-loader y luego style-loader. Atención porque el orden en el que webpack utiliza los cargadores en los recursos correspondientes es el inverso al indicado en el array, del último al primero.

Vamos a añadir también un cargador para los fiheros html. raw-loader nos permite importar en el paquete final ficheros como cadenas:

npm i --save-dev raw-loader

Y añadimos la configuración a la seccion rules:

{
    test: /\.html$/,
    use: 'raw-loader'
}

Ya tenemos todos los elementos listos, vamos con la aplicación.

Creando la aplicación angular 1.6

Lo primero de todo, necesitamos instalar el paquete de angular. Además para el layout voy a utilizar  bootstrap , vpor lo que descargamos e instalamos ambos paquetes con npm:

npm i --save angular bootstrap-css-only

Vamos a generar un esqueleto muy simple de una aplicacion angular y para ello vamos a seguir el ejemplo de estructura  propuesto por angular-1.5-cli.

 Colocaremos nuestro código fuente en una carpeta src, con el archivo principal (index.html) en esta y los archivos de la aplicación dentro de una subcarpeta app.

Puesto que vamos a utilizar webpack para generar el paquete final, y este minifica el contenido de los ficheros javascript , es muy importante que tengamos en cuenta que angular 1.x utiliza inyección de dependencias. La  minificación cambiará el nombre de los parámetros de las funciones  por versiones mínimas de los mismos, y esto hará que nuestra aplicación no funcione correctamente. Para asegurarnos de que esto no ocurre, hay que indicar el parámetro ng-stricit-di en la definición de la aplicación en index.html:

<body ng-app="app" ng-strict-di ng-cloak>

Con este parámetro especificado, la aplicación no será capaz de invocar funciones que no usen anotación explicita de sus parámetros y por lo tanto no sean candidatas a ser minificadas. Puedes encontrar más información de este tema en la referencia de ngApp y en la  guia de inyeccion de dependencias de angularjs. En caso de tratar de utilizar una función que no este anotada en modo de inyección estricto nos encontraremos con un error como este en la consola:

Uncaught Error: [$injector:strictdi] function($window) is not using explicit annotation and cannot be invoked in strict mode

Nuestro fichero html queda así:

<body ng-app="app" ng-strict-di ng-cloak>

  <app>
    Cargando...
  </app>

  <script src="../dist/bundle.js"></script>
</body>

El único paquete que debemos cargar es el resultante del empaquetado, dist/bundle.js.

¿Recuerdas la configuracion de webpack que especificamos al principio? El fichero de entrada a nuestra aplicación va ser /src/app/app.module.js:

import 'bootstrap-css-only';
import angular from 'angular';
import appComponent from './app.component';
import ComponentsModule from './components/components';

angular.module('app', [
  ComponentsModule.name
]).component('app', appComponent);

En él importamos los componentes que necesitamos, tanto de código como de css o plantillas html (¿recuerdas css-loader y html-loader?)

import template from './app.component.html';
import './app.component.css';

const AppComponent = {
  template
};

export default AppComponent;
<div class="container-fluid">
  <div class="jumbotron">
    <h1> Oddbytes</h1>
    <h2>Cliente angular 1.6 con webpack 4</h2>
  </div>
</div>
  import angular from 'angular';
  const ComponentsModule = angular.module('app.components', [
]);
export default ComponentsModule;

El fichero app.component.css contendrá la hoja de estilo de nuestro primer componente, pero por el momento podemos dejarla vacía.

Ejecutando la aplicación

Ya tenemos todo lo necesario para desarrollar nuestra aplicación. Podemos poner en marcha el servidor de desarrollos utilizando el script que introdujimos al principio en package.json:

npm run dev

webpack recopilará y generara en memoria nuestro paquete, a la vez que el servidor de desarrollos arranca y nos sirve la aplicación en el puerto 9000. Cualquier cambio en los ficheros js, html o css provocará que se recompile de nuevo el paquete en caliente y se recargue automaticamente el navegador para mostrar los cambios.

Una vez que nuestra aplicación este lista para ser desplegada, tan solo tenemos que general el empaquetado en modo producción ejecutando

npm run build

Lo que nos generará el paquete bundle.js en la carpeta /dist.

Puedes descargar el código completo de este ejemplo desde GitHub: oddbytes.net/blog

 

 

 

Free WordPress Themes, Free Android Games