Octubre de 2015
Volumen 30, número 10
Visual Studio - Bower: Herramientas modernas para desarrolladores web
De Adam Tuliper | Octubre de 2015
Durante mucho mucho tiempo, hemos vivido en un bonito jardín aislados del mundanal ruido. En este ecosistema protegido de desarrollo web, usábamos complejas tecnologías como, por ejemplo, ASP.NET y Visual Studio. El resto de herramientas se consideraban como soluciones inferiores. Formábamos parte de un imperio, por decirlo de algún modo, en el que estuvimos muy felices durante mucho tiempo.
No obstante, con el paso del tiempo, el desarrollo de culturas, herramientas, recursos, etc. se ha vuelto más fragmentado e incluso caótico. Aun así, durante este periodo han entrado en escena tecnologías bastante robustas, entre las que se incluyen Bootstrap, AngularJS, Git, jQuery, Grunt, Gulp o Bower, y los desarrolladores web acostumbrados al ecosistema de Microsoft han sacado partido a estas herramientas.
En esta primera parte de la serie de dos artículos, proporcionaré información general sobre Bower, un administrador de paquetes destinado, sobre todo, al desarrollo web front-end, aunque también puede usarse para otras tareas. En el segundo artículo, abordaré componentes como, por ejemplo, Grunt y Gulp, dos ejecutores de tareas basados en JavaScript que pueden usarse para realizar todo tipo de tareas como la copia de archivos, la minificación, la concatenación o incluso la compilación.
Grunt, Gulp y Bower son herramientas adicionales del arsenal de soluciones de desarrollo web. Visual Studio 2015 dispone del utillaje necesario para integrar estas herramientas, mientras que en Visual Studio 2012 y 2013 solo están disponible mediante complementos. En cualquier caso, es necesario instalar estas herramientas.
Posiblemente algunos se estarán preguntando si Microsoft no nos está obligando a aprender a usar más herramientas. ¿Acaso no funciona NuGet con los paquetes? ¿No es msbuild suficiente para las tareas de compilación? La respuesta a ambas preguntas es que sí; aunque no para todos los escenarios. Para los casos en los que las herramientas convencionales no son suficientes, Grunt, Gulp y Bower pueden ser muy útiles. En un proyecto web, es posible que queramos compilar Sass cada vez que se produzcan cambios en los archivos CSS. O bien, puede que necesitemos obtener las últimas versiones de Bootstrap o Angular sin esperar a que alguien en Microsoft cree un paquete NuGet. Estas tareas no se pueden realizar con NuGet o msbuild.
NuGet es una tecnología increíble compatible con Visual Studio, integrada en este producto y que continúa desarrollándose. Podemos seguir usándola para vuestros proyectos, sobre todo para binarios y proyectos que necesiten realizar cambios en las soluciones de Visual Studio. Cada vez que se publica una nueva versión de jQuery o Bootstrap, alguien debe crear y publicar un paquete NuGet para dicha versión. Sin embargo, gracias a que Bower puede usar el control de versiones semánticas, tan pronto como se publica una herramienta y se etiqueta en GitHub, Bower podrá usarla sin tener que esperar a que alguien cree un paquete de NuGet.
En el siguiente artículo, usaré el administrador de paquetes de nodos (npm) para la instalación de Bower y para varios elementos. Puesto que npm no se proporciona como descarga independiente, basta con instalar Node.js desde nodejs.org. Para más información sobre la instalación y el uso de npm, podemos visitar la página “Package Management and Workflow Automation” (Administración de paquetes y automatización de flujos de trabajo) de la Academia virtual de Microsoft en bit.ly/1EjRWMx.
Bower es un administrador de paquetes principales que suele usarse para el desarrollo web front-end y podríamos decir que es la única solución de administración de paquetes solo para front-end. La mayoría de paquetes usados en el desarrollo web front-end como, por ejemplo, Bootstrap, jQuery y AngularJS, pueden instalarse mediante npm o Bower, aunque en muchos casos la administración de dependencias resultará más sencilla con Bower (pese a que algunos no estén de acuerdo).
Los paquetes de Bower, a diferencia de los paquetes de NuGet, no están limitados a un único tipo de origen. Los paquetes de Bower pueden ser un extremo Git, una carpeta de un sistema de archivos, una dirección URL de archivos de contenido o comprimidos, y mucho más. Bower se integra con un registro de paquetes que muestra los paquetes publicados, aunque no es necesario que los paquetes estén incluidos en Bower para instalarlos.
Instalación y uso de Bower
Bower suele extraer el contenido de un repositorio Git, por lo que tendremos que instalar msysgit (msysgit.github.io) y seleccionar la opción para ejecutar desde el símbolo del sistema, tal como se muestra en la Ilustración 1.
Ilustración 1 Instalar msysgit con compatibilidad con el símbolo del sistema
Es posible usar npm para instalar Bower de manera global y usarlo desde cualquier punto del sistema. Solo es necesario instalar Bower una vez, no con cada proyecto.
npm install -g bower
Ya estamos todos preparados para usar Bower. Abriremos una línea de comandos a la raíz de la carpeta del proyecto y usaremos el formato siguiente para instalar un paquete en nuestro proyecto:
bower install <package name/url/zip/etc.> --save
Por ejemplo, para instalar jquery, basta con escribir:
bower install jquery --save
Probablemente las tres primeras palabras no necesiten mayor aclaración; sin embargo puede que sí sea necesario explicar el comando --save. Este parámetro hace que se escriba la entrada en el archivo bower.json para anotar que se ha instalado el paquete. (Bower no crea este archivo de forma predeterminada; es necesario indicarle que debe crearlo, tal como se explica a continuación.) De manera predeterminada, el comando de instalación de Bower crea la carpeta bower_components en la carpeta en la que se ejecuta el comando de instalación. El nombre de la carpeta bower_components puede personalizarse mediante un archivo de configuración de Bower .bowerrc.
En la Ilustración 2 veremos cómo la instalación del paquete jQuery genera muchos más archivos y carpetas de lo esperado. Lo único que queremos para el proyecto es el archivo jQuery.js, aunque en este caso obtendremos todo el árbol de código fuente de jQuery. Muchas instalaciones de paquetes proporcionan el árbol de código fuente al completo, lo que suele ser más de lo que en realidad buscamos. Esto lleva a los usuarios de Bower menos experimentados a preguntarse qué archivo deben usar.
Ilustración 2 Bower instala todo el árbol de código fuente de jQuery
Algunos proyectos publicarán una versión empaquetada de la aplicación sin incluir los archivos adicionales no deseados. Por ejemplo, el paquete de Bower de AngularJS es un repositorio de la raíz Angular en GitHub que se encuentra en github.com/angular/bower-angular. Al instalar este paquete (bower install angular --save), solo se obtendrán los archivos .js y .css a los que se necesita hacer referencia en las páginas HTML.
Para buscar paquetes, podemos ir a bower.io, usar Visual Studio IntelliSense (que se abordará más adelante) o buscar el repositorio de paquetes de Bower mediante la línea de comandos:
bower search jquery
También es posible instalar varios paquetes a la vez. Esto resulta especialmente útil cuando lo que queremos es crear un scripts de las instalaciones:
bower install jquery bootstrap-css angular
#or install a specific version of jquery ui
bower install jquery-ui#1.10.4
#install a github repository as a package
bower install https://github.com/SomeRepository/project.git
Bower crea una caché local de los paquetes instalados. En los sistemas Windows 8 y Windows 10 que uso, la carpeta de la caché predeterminada es C:\Usuarios\<MiNombre>\AppData\Local\bower\cache\packages (es posible anular esta ruta predeterminada en el archivo .bowerrc). Tal como se puede ver en la Ilustración 3, es posible administrar los paquetes almacenados en la caché mediante los comandos list y clean. Hay que tener en cuenta que Bower extrae la información de la caché local si es posible siempre que se ejecuta la instalación de Bower.
Ilustración 3 Uso de la caché local de Bower
#install jquery package for the first time
bower install jquery
#uninstall jquery package
bower uninstall jquery
#install from cache (ie works disconnected)
bower install jquery --offline
#show me the cache
bower cache list
#clean local cache
bower cache clean
#will fail, package no longer cached
bower install jquery --offline
Para paquetes que dependen de otros paquetes, Bower intenta instalar las dependencias necesarias en el sistema de archivos. Bower cuenta con un árbol de dependencias plano, lo que implica que las dependencias necesarias se instalan en /bower_components y no en el paquete que las necesita. Por ejemplo, el archivo bower.json para la interfaz de usuario de jQuery muestra una dependencia de “jquery”: “>=1.6,” lo que significa que si jQuery aún no está instalado, se instalará la versión más reciente del paquete jQuery en /bower_components, siempre que sea al menos de la versión 1.6.
La actualización o desinstalación de paquetes es un proceso bastante simple e incluye comprobaciones de versión y dependencias:
#will update based on version rules in bower.json, ex. "jquery": "~2.1.3"
#specifies any patch like 2.1.4 is acceptable to update, but 2.2.0 is not
bower update jquery
#will remove folder and reference in bower.json, but will prompt first
#if other packages have a dependency on jquery
bower uninstall jquery
Archivo bower.json
En este punto, si eliminara la carpeta /bower_components, no sabría qué paquetes se instalaron ni qué paquetes necesita mi aplicación. Si proporcionase el código fuente (sin paquetes) a otro desarrollador, o si lo usara en otro entorno como, por ejemplo, un servidor de compilación sin la carpeta bower_components, tanto el desarrollador como yo mismo tendríamos las manos atadas. En NuGet, esto equivale a perder el archivo packages.config. Lo ideal es que la aplicación disponga del archivo bower.json para que Bower pueda realizar un seguimiento de las versiones y dependencias del paquete, aunque esto es opcional.
Para crear el archivo bower.json, ejecutaremos el comando de inicio de Bower en la raíz del proyecto y seguiremos las instrucciones, tal como se muestra en la Ilustración 4.
Ilustración 4 Creación del archivo bower.json
C:\Users\Adam\Documents\WebApp> bower init
? name: MyWebApp
? version: 1.0.0
? description:
? main file:
? what types of modules does this package expose?
? keywords:
? authors: Adam Tuliper <adam.tuliper@gmail.com>
? license: MIT
? homepage:
? set currently installed components as dependencies? (Y/n) Y
? add commonly ignored files to ignore list? Yes
? would you like to mark this package as private which prevents it from being accidentally published to the registry? (y/N)
No hay que preocuparse si olvidamos crear el archivo bower.json e instalamos varios paquetes sin dicho archivo, o si olvidamos adjuntar los paquetes con la opción –save. Al ejecutar el comando de inicio de Bower, el sistema nos preguntará “set currently installed components as dependencies?” (¿Desea establecer como dependencias los componentes instalados actualmente?). Si respondemos que sí, Bower buscará los paquetes que se encuentren en /bower_components y agregará a la sección de dependencias lo que considere como paquetes raíz. Hay que tener en cuenta que si la interfaz de usuario de jQuery depende de jQuery, jQuery no se agregará como dependencia en el archivo con este método, ya que este componente se instala cuando se instala la interfaz de usuario de jQuery. Siempre es recomendable revisar la sección de dependencias generadas para asegurarnos de las dependencias que se muestran son las correctas.
Ahora podemos iniciar Bower para el proyecto en la línea de comandos en la carpeta raíz del proyecto web. A continuación, instalamos las dependencias. En la Ilustración 5 se ofrece un archivo bower.json de muestra.
Ilustración 5 Archivo bower.json de muestra
{
"name": "MyWebApp",
"version": "0.0.0",
"authors": [
"Adam Tuliper <adam.tuliper@anonymous>"
],
"license": "MIT",
"ignore": [
"node_modules",
"bower_components",
"test",
"tests"
],
"dependencies": {
"angular": "~1.4.3",
"bootstrap-css": "~3.3.4",
"jquery-ui": "~1.11.4"
},
"devDependencies": {
"angular-mocks": "~1.4.3"
}
}
}
La sección superior contiene información del paquete y del proyecto general. Otras secciones importantes son las secciones ignore, dependencies y devDependencies. La sección ignore excluye los archivos indicados si creamos un paquete de Bower desde esta aplicación. Esto no se aplica a este caso, ya que estoy trabajando con una aplicación web y no estoy creando mi propio paquete de Bower. Las secciones dependencies y devDependencies contienen todos los paquetes instalados que usará mi aplicación. En la sección siguiente se abordan con más detalle.
Administración de dependencias
Hemos visto que es posible especificar dos tipos distintos de dependencias en un archivo bower.json: dependencies y devDependencies. Los elementos de la sección dependencies se agregan al llamar, por ejemplo, el comando bower install jquery --save. Estos elementos son paquetes (como jQuery) que se ejecutarán en producción para la aplicación. Las entradas de devDependencies, por el contrario, son paquetes que no se usarán en la producción: marcos ficticios como, por ejemplo, los compiladores angular-mocks o less/sass. Estas entradas se agregan al usar, por ejemplo, la opción bower install angular-mocks --save-dev. Estos dos tipos de dependencias solo figuran en el archivo bower.json y no afectan al modo en que se usan estos archivos en el sistema de archivos de la aplicación. Si vamos a restaurar los paquetes en un entorno de control de calidad, por ejemplo, en teoría no será necesario instalar las dependencias devDependencies.
Para instalar todas las dependencias solo en la sección dependencies e ignorar todas las de la sección devDependencies, como para la creación de una compilación de producción, basta con usar la opción bower install –production.
Si queremos ver todas las dependencias que usa nuestra aplicación, podemos usar la opción bower list, que ofrece un resultado como el que se indica a continuación:
bower check-new Checking for new versions of the project dependencies..
MyWebApp#0.0.0 C:\Users\Adam\Documents\MyWebApp
├── angular#1.4.3 (1.4.4-build.4147+sha.bb281f8 available)
├─┬ angular-mocks#1.4.3 (1.4.4-build.4147+sha.bb281f8 available)
│ └── angular#1.4.3 (latest is 1.4.4-build.4147+sha.bb281f8)
├── bootstrap-css#3.3.4
├─┬ jquery-ui#1.11.4
│ └── jquery#2.1.4 (3.0.0-alpha1+compat available)
└── jquery1#2.1.4 (3.0.0-alpha1+compat available)
Demasiados archivos
Los usuarios con menos experiencia en Bower pronto se darán cuenta de que algunos paquetes contienen muchos archivos cuando, en realidad, solo necesitan un archivo. Algunos paquetes de Bower muestran uno o varios archivos en la sección de configuración principal necesarios para usar el paquete. Por ejemplo, jQuery incluye aproximadamente 90 archivos en el paquete cuando se instala. Sin embargo, para usar jQuery, solo necesitamos el archivo jQuery.js, por lo que la solución pasa por mirar en el elemento principal y comprobar que para jQuery solo hay un único archivo en la carpeta /dist:
{
"name": "jquery",
"version": "2.1.4",
"main": "dist/jquery.js",
...
}
Si miramos en la carpeta /dist para jQuery, también podremos encontrar el archivo jQuery.min.js y su archivo .map de depuración correspondiente. No obstante, no tendría sentido incluir estos archivos en el elemento principal, ya que nuestra intención es la de usar jQuery.js o jQuery.min.js en producción, no ambos archivos.
Si ejecutamos el comando bower list --paths, obtendremos todos los archivos principales de todos los paquetes instalados como, por ejemplo:
C:\Users\Adam\Documents\MyWeb> bower list --paths
angular: 'bower_components/angular/angular.js',
'bootstrap-css': [
'bower_components/bootstrap-css/css/bootstrap.min.css',
'bower_components/bootstrap-css/js/bootstrap.min.js'
],
jquery: 'bower_components/jquery/dist/jquery.js'
Los creadores de los paquetes son los responsables de comprobar que la sección principal muestra los archivos correctos.
Puesto que todos los archivos de los paquetes se encuentran de manera predeterminada, en la subcarpeta /bower_components, podríamos pensar que mis archivos HTML hacen referencia directamente a los archivos de esta carpeta de la manera siguiente:
<link rel="stylesheet" type="text/css"
href="/bower_components/bootstrap-css/css/bootstrap.min.css">
<script src="/bower_components/bootstrap-css/js/bootstrap.min.js" />
<script src="/bower_components/angular/angular.js" />
<script src="/bower_components/jquery/dist/jquery.js" />
En Internet podemos encontrar muchos ejemplos que hacen referencia a los archivos de la carpeta /bower_components. Esta no es una práctica recomendada. Es una práctica que no recomiendo. Particularmente, prefiero no implementar en producción esta carpeta junto con cientos o incluso miles de archivos potenciales cuando, en realidad, solo necesito un puñado de archivos que se minificarán y concatenarán en menos archivos. En el siguiente artículo sobre Grunt y Gulp abordaré esta técnicas. Por ahora, veremos una de las múltiples técnicas que permiten extraer los archivos principales mediante el módulo bower-installer.
El módulo bower-installer copiará todos los archivos principales en la estructura de carpetas especificada. En primer lugar, debemos instalar este módulo de forma global en la máquina mediante el comando npm install -g bower-installer.
A continuación, agregamos luna sección al archivo bower.json para especificar dónde deben copiarse estos archivos principales:
"install": {
"path": "lib"
},
Los archivos principales de cada paquete se ubicarán en una subcarpeta en el directorio \lib como, por ejemplo, lib\jquery\jQuery.js, lib\angular\angular.js.
Este proceso puede personalizarse. La documentación de dicho paquete se encuentra en bit.ly/1gwKBmZ.
Por último, ejecutamos bower-installer cada vez que queramos que los archivos se copien en las carpetas de destino. Nuevamente, existen varias maneras de realizar este proceso como, por ejemplo, usando Grunt o Gulp para copiar estos archivos con una tarea (es posible ver incluso los cambios de las carpetas); sin embargo, esta es una manera rápida de realizar este proceso con un mínimo de dependencias para empezar, ya que no requiere otros flujos de trabajo.
Servidores de compilación y control de código fuente
¿Qué ocurre cuando lo que queremos es instalar los paquetes necesarios en un servidor de compilación? Esto resulta útil en los escenarios en los que solo sabemos que el código se encuentra en el control de código fuente y todos los demás paquetes (Bower/NuGet, etc.) se instalan y/o compilan (Sass, Less, CoffeeScript y similares) en un servidor de compilación. Algunas tiendas controlarán el código fuente de todo, incluidas todas las dependencias de terceros y todos los binarios. Otras confiarán en el administrador de paquetes para que este restaure los paquetes en un entorno de prueba. Cuando proporciono un proyecto de Visual Studio, normalmente espero que los paquetes se restauren en las máquinas de los usuarios. La recomendación típica para Bower en términos de control de código fuente es la de controlar todo el código de terceros si es posible tener repositorios de gran tamaño o la de no controlar el código fuente de /bower_components si no queremos confiar en el administrador de paquetes.
Para instalar todas las dependencias y copiar los archivos principales solo con un archivo bower.json file, basta con ejecutar los comandos siguientes:
#Will read bower.json and install referenced packages and their dependencies
bower install
#Optional - copy each packages main{} files into your predefined path
bower-installer
¿Por qué no usar solo npm?
Algunos desarrolladores usan solo npm; mientras que otros optan por Bower y usan una mezcla. Existen muchos paquetes que se encuentran en los repositorios de Bower y npm, lo que facilita enormemente el flujo de trabajo. npm funciona muy bien no solo para aplicaciones Node.js, sino también para la administración de paquetes del lado cliente y del lado servidor. npm cuenta con un árbol de dependencias anidado, lo que implica que todas las dependencias se instalan en la subcarpeta node_components de cada paquete que se instala. Por ejemplo, si usamos tres paquetes y cada uno usa, a su vez, jQuery, todo el paquete jQuery se instalará tres veces. Las dependencias anidadas pueden crear una cadena de dependencias bastante larga. Debido a esto, los usuarios de Windows de npm casi seguro que se encontrarán en algún punto con el temido error de la longitud de la ruta. Por ejemplo: El nombre de directorio C:\Users\Adam\.......\node_modules\somePackageA \node_modules\somePackageB\node_modules\insight\node_modules\inquirer\node_modules\readline2\node_modules\strip-ansi\node_modules\ansi-rege ... es demasiado largo.
Esto se debe a la estructura de dependencias anidadas, aunque la versión beta de npm 3 incorpora una característica de nivelación. Mi objetivo no es convencer a nadie para que opte por una u otra opción, ya que se pueden usar ambas.
Bower, ASP.NET 5 y Visual Studio
Visual Studio 2015 ofrece compatibilidad con Bower y npm, incluida la instalación de paquetes e IntelliSense. Las versiones anteriores de Visual Studio pueden ofrecer esta misma funcionalidad, aunque es necesario descargar e instalar la extensión de paquetes de IntelliSense para Visual Studio. La Ilustración 6 muestra algunas de las opciones disponibles para administrar los paquetes en un archivo bower.json.
Ilustración 6 Opciones de paquetes de Visual Studio
Tal como se puede ver en la Ilustración 7, cuando se escribe un nombre de paquete, IntelliSense ofrece versiones y paquetes que coinciden con la cadena escrita, lo que permite ahorrar una búsqueda web o una línea de comandos. Tras realizar cambios en el archivo bower.json y guardarlo, el paquete se instalará de manera local sin que sea necesario usar la línea de comandos. Hasta aquí no hay nada que pueda considerarse específico de Visual Studio desde el punto de vista de los archivos. En otras palabras, es posible usar un archivo bower.json predeterminado de cualquier proyecto web.
Ilustración 7 Bower IntelliSense en Visual Studio
La Ilustración 8 muestra las dependencias de bower.json en el Explorador de soluciones, que indica cómo se integra Bower en los proyectos web y Visual Studio.
Ilustración 8 Dependencias de Bower en el Explorador de soluciones
Con ASP.NET 5, disponemos de una nueva estructura de proyecto en la que todos los archivos de la carpeta del proyecto se incluyen en el proyecto de forma predeterminada; sin embargo, solo los elementos de la carpeta /wwwroot del proyecto web se pueden abordar como contenido estático como, por ejemplo, los archivos HTML, CSS, de imágenes y JavaScript. Teniendo esto en cuenta, podemos establecer la configuración del archivo bower.json de manera que bower-installer copie las dependencias a esta carpeta (aunque la plantilla original de ASP.NET 5 usa Gulp para copiar los archivos preestablecidos en sus destinos correspondientes, tal como veremos en el artículo siguiente).
Los paquetes de NuGet siguen ofreciendo unos resultados increíbles, de ahí su amplia utilización y su compatibilidad con los proyectos de ASP.NET 5. Como nota adicional, la configuración de NuGet se incluyen en la sección dependencies del archivo project.json, pero se muestran en references en Visual Studio. Los paquetes originales de NuGet se usan como paquetes de lado del servidor para tareas como, por ejemplo, el registro y la compatibilidad MVC.
Resumen
Bower es una herramienta que puede integrarse fácilmente en el flujo de trabajo de front-end. Su API es fácil de usar y ofrece compatibilidad integrada con Visual Studio, por lo que se puede usar con npm y NuGet para administrar paquetes de front-end y back-end. Dedicar una o dos horas en aprender a usar Bower es un tiempo sin duda bien invertido.
Adam Tuliper es un evangelizador técnico sénior de Microsoft y vive en el soleado Sur de California. Adam destaca como desarrollador web, desarrollador de juegos, autor de Pluralsight y amante de todo tipo de tecnologías. Podemos encontrarlo en Twitter @AdamTuliper o en adamt@microsoft.com.
Gracias al siguiente experto técnico de Microsoft por revisar este artículo: Michael Palermo