NPM scripts como task runner

Los task runners son herramientas que nos ayudan a automatizar tareas repetitivas y de este modo optimizar nuestros recursos y tiempo. Los más conocidos son Grunt y Gulp, y aunque no está considerado un task runner, también podemos utilizar (mi querido) Webpack.

 

ppm scripts

 

En este post veremos como podemos reemplazar estas herramientas por simples comandos NPM para automatizar nuestras tareas. De este modo, además de tener mayor control sobre dichas tareas, nos ahorraremos bastante tiempo y esfuerzo ya que la curva de aprendizaje es casi nula.

 

Lo que hay que saber

Todos conocemos el famoso fichero package.json que utiliza NPM. En el encontramos información sobre el proyecto como name, version, dependencies, etc, además de un nodo llamado scripts donde básicamente escribiremos una lista clave/valor con los comandos que queremos que NPM ejecute.

{
  "name": "npm-scripts-demo",
  "version": "1.0.0",
  "scripts": {
    "npm-script-test": "node test.js"
  },
  "dependencies": {
    ...
  }
}

Para ejecutar nuestro script npm-script-test basta con ‘tirar’ en la terminal el siguiente comando:

npm run-script npm-script-test

Un punto interesante es que, en algunos casos, podemos necesitar ejecutar tareas previas o posteriores a nuestro comando, pues bien, podemos definirlas en el package.json manteniendo el mismo nombre del script principal y añadiendo el prefijo pre o post sin espacios:

{
  "scripts": {
    "presetup": "say starting setup...",
    "setup": "nam install",
    "possetup": "say setup complete!"
  }
}

Para ejecutarlos bastaría con ‘tirar’ el siguiente comando:

npm run setup

Básicamente así funcionan los scripts de NPM. Ningún misterio, verdad?

 

Automatizando tareas con scripts NPM

Ahora que  sabemos como funcionan y como podemos utilizar los scripts de NPM, es el momento de empezar a crear algunas tareas que sin duda querremos automatizar en nuestro proyecto.

Al lío! 

 

Convirtiendo SASS a CSS

Para esto lo primero será instalar node-sass:

npm install node-sass --save-dev

Ahora supongamos que tenemos un directorio scss/ que contien el archivo main.scss y que será el que queremos convertir y mover a una ubicación específica, en este caso a public/css/. Nuestro comando quedaría así:

"build-css": "node-sass scss/main.scss public/css/main.css"

Para configuraciones más avanzadas como añadir sourcemaps, controlar el indentado o el estilo del fichero generado, podéis echar un vistazo a la docu de node-sass.

 

Transpirando JavaScript

Lo primero en este caso es instalar Babel CLI:

npm install --save-dev babel-cli

Dependiendo de nuestras necesidades también tendremos que instalar algunos plugins de Babel. Por ejemplo, si trabajamos con ES6 deberemos instalar el plugin es2015:

npm install --save-dev babel-preset-es2015

Ahora ya podemos crear nuestro comando:

"build-js": "babel --presets es2015 js -d public/js"

Aclarar que la instrucción --presets indica a Babel que tiene que utilizar los presets que le siguen. En el caso de necesitar varios, se presentarían separados por comas.

La instrucción -d es la abreviatura de --out-dir y sirve para decir a Babel que ‘compile’ todo el directorio.

Si quisiésemos ‘compilar’ de archivo a archivo bastaría con el siguiente comando:

"build-js": "babel js/main.js -o public/js/main.js"

Para más info podéis visitar la docu de Babel.

 

Minificar JavaScript

Existen varias maneras de minificar nuestros ficheros JavaScript, pero ya que estamos utilizando Babel utilizaremos el preset babili.

npm install --save-dev babel-preset-babili

Y para utilizarlo tan solo hemos de incluir en el comando build-js el nuevo preset:

"build-js": "babel --presets=es2015,babili es6/main.js --out-file js/main.js"

Observando cambios en los archivos

Una de las tareas que más nos facilitan la vida a la hora de desarrollar aplicaciones web es que los archivos se ‘compilen’ automáticamente cada vez que salvamos algún cambio en nuestros ficheros JavaScript o CSS. A esta tarea se le suele denominar watching, y para ello tanto Babel como node-sass disponen de la instrucción --watch o -w.

Creemos un par de comandos para observar los cambios en nuestro JS y CSS:

"watch-css": "node-sass scss/main.scss public/css/main.css --watch",
"watch-js": "babel --presets babel-preset-es2015 js/main.js -o public/js/main.js --watch"

Sencillo, verdad?

Optimización

Hasta ahora hemos creado diferentes comandos para distintas tareas, pero podemos optimizar un poco nuestros scripts.

 

Variables

Pues si, podemos utilizar variables para optimizar nuestros scripts y ahorrarnos repetir código. Podemos almacenarlas en nuestro package.json en un nodo config:

{
  "name": "npm-scripts-demo",
  "version": "1.0.0",
  "config": {
    "js_input_path": "js",
    "js_output_path": "public/js",
    "css_input_path": "scss",
    "css_output_path": "public/css",
  }
}

Y utilizarlas:

"build-js": "babel $npm_package_config_js_input_path/main.js -o $npm_package_config_js_output_path/main.js"

Como veis la sintaxis se afea bastante al tener que añadir el prefijo $npm_package_config_ a cada variable por lo que personalmente no las utilizo.

 

Un script para dominar el mundo

Partiendo del concepto de que un script puede ejecutar a otro, podemos crear un comando que ejecute los scripts que queramos en cadena. Siguiendo con los ejemplos podemos crear uno que ‘compile’ nuestro código y otro que observe los cambios par refrescar el navegador:

"build": "npm run build-css | npm run build-js",
"watch": "npm run watch-css | npm run watch-js",

 

 

Conclusión

Aunque herramientas como Grunt y Gulp han sido y aún son de gran utilidad, el principal problema de dichas herramientas es que requieren de una curva de aprendizaje que en algunos casos puede ser bastante pronunciada. En mi caso he de reconocer que me ha costado bastante tiempo y dedicación dar con una configuración óptima para mis ficheros de configuración.

Por otro lado tenemos el añadido de los plugins, que, aunque existen un montón y cubren casi cualquier necesidad que nos pueda surgir, hay veces que el echo de buscar el que más se adapta a tus necesidades, aprender a configurarlo y ejecutarlo correctamente puede ser un dolor de cabeza.

Otro problema común suele ser la incompatibilidad entre diferentes versiones. Sobre todo cuando utilizamos muchos plugins, es posible que al actualizar nos encontremos con errores, lo cual también suele ser un buen dolor de cabeza.

Los scripts de NPM solucionan estos problemas y además, al menos bajo mi punto de vista, nos dan pleno control sobre nuestras tareas. Po otro lado, restamos dependencias a nuestros proyectos, lo cual también es un plus a tener en cuenta.

Esto es todo. Hasta la próxima!