Concatenar archivos resulta útil cuando, durante el desarrollo de nuestro proyecto, utilizamos varias hojas de estilo o archivos de JavaScript pero queremos utilizar únicamente una hoja de estilos y un archivo con el código de JavaScript cuando el proyecto este en producción.
Antes de empezar – si no lo hemos hecho – tenemos que instalar grunt y preparar el proyecto con los archivos package.json y Gruntfile.js
En esta ocasión voy a comenzar a trabajar en la carpeta demo-03 del demo de grunt anterior.
Más adelante incluyo la versión con las modificaciones que se realicen aquí.
Una vez que tenemos el proyecto preparado vamos a instalar el plugin grunt-contrib-concat en el proyecto.
$ npm install grunt-contrib-concat --save-dev
Después de instalar el plugin, el archivo package.json debe incluir grunt-contrib-concat como dependencia de desarrollo.
{
"name": "demo",
"version": "0.1.0",
"private": "true",
"description": "Crear un paquete json para utilizar grunt",
"main": "index.html",
"author": "eamexicano",
"license": "MIT",
"devDependencies": {
"grunt": "^0.4.5",
"grunt-contrib-concat": "^0.5.0"
}
}
Ahora vamos a trabajar en el archivo Gruntfile.js
Las tareas que vamos a hacer son:
- Configurar la tarea de concatenación. Definir los archivos a concatenar y cómo se van a configurar. Esto lo vamos a hacer dentro del bloque grunt.initConfig.
- Cargar el plugin – grunt.loadNpmTasks(‘grunt-contrib-concat’) – Este plugin contiene la tarea concat que vamos a utilizar.
- Registrar la tarea de concatenación como predeterminada para poderla utilizar al teclear grunt en la línea de comandos.
Así quedaría la estructura del archivo Gruntfile.js una vez realizadas las tareas dos y tres.
module.exports = function(grunt) {
/* Configuración de los plugins */
grunt.initConfig({
concat: {
/* Configuración para grunt-contrib-concat */
}
});
/* Cargar tarea(s) de los plugins instalados utilizando npm */
grunt.loadNpmTasks('grunt-contrib-concat');
/* Registrar un alias para las tareas o una función */
grunt.registerTask("default", ['concat']);
};
La configuración de la concatenación requiere un poco más de especificación y puede variar dependiendo del proyecto.
En este caso, como queremos concatenar los archivos – dentro de la misma carpeta en la que se encuentran – vamos a definir qué archivos vamos a concatenar – el origen – y qué archivo se va a generar con los archivos concatenados – el destino -.
Para esto creamos una propiedad – dentro del objeto concat – para cada tipo de archivo – css y js -.
Esta propiedad que a su vez es un objeto tiene dos propiedades src y dest.
En src utilizamos un arreglo que contiene el nombre de cada archivo a concatenar separado por comas.
El orden que tienen los archivos en el arreglo es el orden en el cuál se concatenan.
El archivo que se encuentra en dest es el archivo el cuál se va a generar con la tarea.
css: {
src: ["css/demo01.css", "css/demo02.css"],
dest: "css/demo.css"
},
js: {
src: ["js/demo01.js", "js/demo02.js"],
dest: "js/demo.js"
}
Así quedaría la primer versión de configuración de la tarea concat.
concat: {
css: {
src: ["css/demo01.css", "css/demo02.css"],
dest: "css/demo.css"
},
js: {
src: ["js/demo01.js", "js/demo02.js"],
dest: "js/demo.js"
}
}
Si ejecutamos la tarea en este momento obtenemos los siguientes archivos.
demo.css
html {
font-family: georgia, serif;
font-size: 24px;
background: #fff;
height: 100%;
position: relative;
}
body {
position: absolute;
top: 50%;
left: 50%;
height: 55px;
width: 320px;
margin: -55px 0 0 -160px;
}h1 {
text-align: center;
font-weight: normal;
cursor: pointer;
margin: 0;
}
p {
font-family: 'Times New Roman', Times, 'Georgia', serif;
text-align: center;
font-weight: 100;
cursor: pointer;
margin: 0;
}
demo.js
var titulo = document.getElementsByTagName('h1')[0];
function visualizar_contenido() {
var mensaje;
mensaje = titulo.textContent;
alert(mensaje);
}
titulo.addEventListener('click', visualizar_contenido);var parrafo = document.getElementsByTagName('p')[0];
function actualizar_contenido() {
parrafo.textContent = prompt("¿Nuevo contenido para el párrafo?");
}
parrafo.addEventListener('click', actualizar_contenido);
Si no tenemos un salto de línea al final del primer archivo – porque son dos los que se están concatenando – la primer línea del segundo archivo quedaría final de la primer línea del primer archivo. Para evitar que esto suceda podemos definir un separador dentro de las opciones de la tarea concatenar.
options: {
separator: "\n\n",
},
En este caso incluimos dos saltos de línea \n\n entre los archivos.
Configuración de la tarea concat actualizada.
Incluye saltos de línea entre los archivos que se van a concatenar.
concat: {
options: {
separator: "\n\n",
},
css: {
src: ["css/*.css", "!css/demo.css"],
dest: "css/demo.css"
},
js: {
src: ["js/*.js", "js/!demo.js"],
dest: "js/demo.js"
}
}
Nota:
Aunque es posible utilizar el comodín estrella – asterisco – para indicar que se quieren concatenar todos los archivos que se encuentran en un directorio, hay que tener cuidado cuando se utilice por dos razones.
- Si queremos asegurar que los archivos se concatenen en un orden determinado es mejor establecerlo explícitamente dentro del arreglo.
- Como los archivos generados se almacenan en la misma carpeta de los archivos de origen. Desde la segunda ocasión – ya que se encuentre el archivo destino lo va a tomar en cuenta para concatenarlo con el mismo. *
* Es posible utilizar el comodín sin que sucedan estos inconvenientes.
Para asegurar que los archivos se concatenen en el orden correcto habría que cambiarles el nombre – manera alfabética o secuencial – desde el sistema de archivos – 01-demo01.js, 02-demo02.js –
Para evitar que se utilice el archivo del destino como origen, después de que definamos que queremos incluir los archivos de determinado tipo, debemos utilizar el nombre del archivo destino de manera explícita pero tenemos que utilizar la negación – ! – antes de la ubicación del archivo.
css: {
src: ["css/*.css", "!css/demo.css"],
dest: "css/demo.css"
},
js: {
src: ["js/*.js", "!js/demo.js"],
dest: "js/demo.js"
}
La configuración del archivo Gruntfile.js quedaría de la siguiente manera:
module.exports = function(grunt) {
grunt.initConfig({
concat: {
options: {
separator: "\n\n",
},
css: {
src: ["css/demo01.css", "css/demo02.css"],
dest: "css/demo.css"
},
js: {
src: ["js/demo01.js", "js/demo02.js"],
dest: "js/demo.js"
}
}
});
/* Cargar tarea(s) de los plugins instalados utilizando npm */
grunt.loadNpmTasks('grunt-contrib-concat');
/* Registrar un alias para las tareas o una función */
grunt.registerTask("default", ['concat']);
};
Podemos ejecutar la tarea de concatenación como:
$ grunt concat
Como la definimos como tarea predterminada la podemos ejecutar únicamente con grunt.
$ grunt
También es posible concatenar únicamente las hojas de estilo o los archivos de JavaScript. Para hacer esto, después de especificar la tarea – concat – se utilizan dos puntos y utilizamos como parámetro el nombre de la propiedad que contiene los archivos a concatenar.
$ grunt concat:css
$ grunt concat:js
Una vez hecho esto no hay que olvidarse de actualizar los documentos html que utilicen las distintas hojas de estilo o códigos de JavaScript para que utilicen la versión concatenada en producción.
Si quieres revisar la configuración de concatenación puedes descargar el demo de grunt que incluye las dos versiones de configuración.
- demo-04 incluye la dependencia “grunt-contrib-concat” en el archivo package.json
- demo-05 incluye la configuración “explícita” – se define cada archivo a concatenar – en el archivo de Gruntfile.js
- demo-06 incluye la configuración “alterna” – se utiliza el comodín asterisco para seleccionar todos los archivos de un tipo y la negación para no seleccionar el archivo destino – en el archivo de Gruntfile.js
* Hay que recordar que, aunque están las dependencias en el archivo package.json, se tienen que instalar antes de utilizarse con npm.
$ npm install