Cómo concatenar y minimizar múltiples archivos CSS y JavaScript con Grunt.js (0.3.x)

99

Nota: Esta pregunta solo es relevante para Grunt 0.3.xy se ha dejado como referencia. Para obtener ayuda con la última versión de Grunt 1.x, consulte mi comentario debajo de esta pregunta.

Actualmente estoy tratando de usar Grunt.js para configurar un proceso de compilación automático para primero concatenar y luego minificar archivos CSS y JavaScript.

He podido concatenar y minificar con éxito mis archivos JavaScript, aunque cada vez que ejecuto gruñido parece que se anexa al archivo en lugar de sobrescribirlos.

En cuanto a la minificación o incluso la concatenación de CSS, ¡todavía no he podido hacer esto!

En términos de módulos CSS ronco He intentado usar consolidate-css, grunt-cssy cssminpero fue en vano. ¡No podía entender cómo usarlos!

Mi estructura de directorio es la siguiente (siendo una aplicación típica de node.js):

  • app.js
  • grunt.js
  • /public/index.html
  • / public / css / [varios archivos css]
  • / public / js / [varios archivos javascript]

Así es como se ve actualmente mi archivo grunt.js en la carpeta raíz de mi aplicación:

module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({
    pkg: '<json:package.json>',
    concat: {
      dist: {
        src: 'public/js/*.js',
        dest: 'public/js/concat.js'
      }
    },
    min: {
      dist: {
        src: 'public/js/concat.js',
        dest: 'public/js/concat.min.js'
      }
    },
    jshint: {
      options: {
        curly: true,
        eqeqeq: true,
        immed: true,
        latedef: true,
        newcap: true,
        noarg: true,
        sub: true,
        undef: true,
        boss: true,
        eqnull: true,
        node: true
      },
      globals: {
        exports: true,
        module: false
      }
    },
    uglify: {}
  });

  // Default task.
  grunt.registerTask('default', 'concat min');

};

Entonces, solo para resumir, necesito ayuda con dos preguntas:

  1. Cómo concatenar y minificar todos mis archivos CSS en la carpeta /public/css/en un solo archivo, digamosmain.min.css
  2. ¿Por qué grunt.js sigue agregando a los archivos javascript concatenados y minificados concat.jsy concat.min.jsdebajo en /public/js/lugar de sobrescribirlos cada vez que gruntse ejecuta el comando ?

Actualizado el 5 de julio de 2016 - Actualización de Grunt 0.3.xa Grunt 0.4.xo 1.x

Grunt.jsse ha movido a una nueva estructura en Grunt 0.4.x(el archivo ahora se llama Gruntfile.js). Consulte mi proyecto de código abierto Grunt.js Skeleton para obtener ayuda con la configuración de un proceso de compilación para Grunt 1.x.

Pasar de Grunt 0.4.xa Grunt 1.x no debería introducir muchos cambios importantes .

Jasdeep Khalsa
fuente

Respuestas:

107

concat.js se incluye en los concatarchivos fuente de la tarea public/js/*.js. Podría tener una tarea que elimine concat.js(si el archivo existe) antes de volver a concatenar, pasar una matriz para definir explícitamente qué archivos desea concatenar y su orden, o cambiar la estructura de su proyecto.

Si hace lo último, puede poner todas sus fuentes debajo ./srcy sus archivos construidos debajo./dest

src
├── css
   ├── 1.css
   ├── 2.css
   └── 3.css
└── js
    ├── 1.js
    ├── 2.js
    └── 3.js

Luego configura tu tarea concat

concat: {
  js: {
    src: 'src/js/*.js',
    dest: 'dest/js/concat.js'
  },
  css: {
    src: 'src/css/*.css',
    dest: 'dest/css/concat.css'
  }
},

Tu tarea mínima

min: {
  js: {
    src: 'dest/js/concat.js',
    dest: 'dest/js/concat.min.js'
  }
},

La tarea mínima incorporada usa UglifyJS, por lo que necesita un reemplazo. Encontré que grunt-css es bastante bueno. Después de instalarlo, cárguelo en su archivo gruñido

grunt.loadNpmTasks('grunt-css');

Y luego configúralo

cssmin: {
  css:{
    src: 'dest/css/concat.css',
    dest: 'dest/css/concat.min.css'
  }
}

Tenga en cuenta que el uso es similar al min incorporado.

Cambia tu defaulttarea a

grunt.registerTask('default', 'concat min cssmin');

Ahora, correr gruntproducirá los resultados que desea.

dest
├── css
   ├── concat.css
   └── concat.min.css
└── js
    ├── concat.js
    └── concat.min.js
jaime
fuente
1
¡Eres un genio! ¡Nunca se me ocurrió que, por supuesto, si lo incluía concaten la misma jscarpeta, lo recogería y lo agregaría! ¡Empecé a usar cssmin y funciona muy bien! Gracias de nuevo.
Jasdeep Khalsa
1
¡Genial, realmente genial! Pero los nombres de los archivos son siempre concat.min.cssy concat.min.js. Si modifico algo, lo vuelvo a ejecutar y lo implemento, la gente no obtendrá la versión más reciente porque el navegador ya la almacenó en caché. ¿Hay alguna forma de nombrar aleatoriamente el archivo y vincularlos de acuerdo con las etiquetas <link>y adecuadas <script>?
Tárcio Zemel
3
@ TárcioZemel Puede incluir la versión package.json en el nombre del archivo:concat.min-<%= pkg.version %>.js
Rui Nunes
1
Puede usar .destasí cssmin: { css:{ src: '<%= concat.css.dest %>', dest: './css/all.min.css'}} `Es el resultado de la operaciónconcat -> css
Ivan Black
12

Quiero mencionar aquí una técnica muy, MUY interesante que se está utilizando en grandes proyectos como jQuery y Modernizr para concatenar cosas.

Ambos proyectos están completamente desarrollados con módulos requirejs (puedes ver eso en sus repositorios de github) y luego usan el optimizador requirejs como un concatenador muy inteligente. Lo interesante es que, como puede ver, ni jQuery ni Modernizr necesitan en requirejs para funcionar, y esto sucede porque borran el ritual sintético de requirejs para poder deshacerse de requirejs en su código. ¡Así que terminan con una biblioteca independiente que se desarrolló con módulos requirejs! Gracias a esto, pueden realizar compilaciones de sus bibliotecas, entre otras ventajas.

Para todos aquellos interesados ​​en la concatenación con el optimizador requirejs, consulte esta publicación

También hay una pequeña herramienta que abstrae todo el texto estándar del proceso: AlbanilJS

Augusto Altman Quaranta
fuente
Esto es muy interesante pero no relevante para la pregunta ya que RequireJS es un cargador de módulos, no concatena ni minimiza AFAIK
Jasdeep Khalsa
¡Gracias! Tienes razón, RequireJS es un cargador de módulos y no concatena ni minimiza. Pero r.js (el optimizador RequireJS -> requirejs.org/docs/optimization.html ) lo hace. Más específicamente, concatena sus módulos ordenándolos por dependencias. Los chicos de Modernizr y jQuery aprovecharon el algoritmo de ordenación de la herramienta y lo usaron específicamente como un concatenador inteligente. Puede consultar sus repositorios para ver qué están haciendo.
Augusto Altman Quaranta
Usando grunt's concat o uglify, el archivo resultante se compone usando el orden de los archivos fuente especificados configurados. Mientras RequireJS se basa en la dependencia. Un enfoque diferente pero puede lograr el mismo resultado.
priyabagus
10

Estoy de acuerdo con la respuesta anterior. Pero aquí hay otra forma de compresión CSS.

Puede configurar su CSS usando el compresor YUI :

module.exports = function(grunt) {
  var exec = require('child_process').exec;
   grunt.registerTask('cssmin', function() {
    var cmd = 'java -jar -Xss2048k '
      + __dirname + '/../yuicompressor-2.4.7.jar --type css '
      + grunt.template.process('/css/style.css') + ' -o '
      + grunt.template.process('/css/style.min.css')
    exec(cmd, function(err, stdout, stderr) {
      if(err) throw err;
    });
  });
}; 
Anshul
fuente
En caso de que esté utilizando 'grunt-css', debe necesitar el módulo Locale Npm, así que asegúrese de que cuando instale 'grunt-css' debe estar en el módulo Locale Npm.
Anshul
7
¿Por qué querría hacer toda esta complejidad y llamar a un jvm en su proceso de compilación? Simplemente ralentiza todo sin ningún motivo.
Michael salmon
3

No necesita agregar el paquete concat, puede hacerlo a través de cssmin de esta manera:

cssmin : {
      options: {
            keepSpecialComments: 0
      },
      minify : {
            expand : true,
            cwd : '/library/css',
            src : ['*.css', '!*.min.css'],
            dest : '/library/css',
            ext : '.min.css'
      },
      combine : {
        files: {
            '/library/css/app.combined.min.css': ['/library/css/main.min.css', '/library/css/font-awesome.min.css']
        }
      }
    }

Y para js, use uglify así:

uglify: {
      my_target: {
        files: {
            '/library/js/app.combined.min.js' : ['/app.js', '/controllers/*.js']
        }
      }
    }
Inc33
fuente