ChatGPT解决这个技术问题 Extra ChatGPT

How to concatenate and minify multiple CSS and JavaScript files with Grunt.js (0.3.x)

Note: This question is only relevant for Grunt 0.3.x and has been left for reference. For help with the latest Grunt 1.x release please see my comment below this question.

I'm currently trying to use Grunt.js to setup an automatic build process for first concatenating and then minifying CSS and JavaScript files.

I have been able to successfully concatenate and minify my JavaScript files, although each time I run grunt it seems to just append to the file instead of overwriting them.

As for the minifying or even concatenating CSS, I have been unable to do this as of yet!

In terms of grunt CSS modules I have tried using consolidate-css, grunt-css & cssmin but to no avail. Could not get my head around how to use them!

My directory structure is as follows (being a typical node.js application):

app.js

grunt.js

/public/index.html

/public/css/[various css files]

/public/js/[various javascript files]

Here is what my grunt.js file currently looks like in the root folder of my application:

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');

};

So just to summarise I need help with two questions:

How to concatenate and minify all my css files under the folder /public/css/ into one file, say main.min.css Why does grunt.js keep on appending to the concatenated and minified javascript files concat.js and concat.min.js under /public/js/ instead of overwriting them each time the command grunt is run?

Updated 5th of July 2016 - Upgrading from Grunt 0.3.x to Grunt 0.4.x or 1.x

Grunt.js has moved to a new structure in Grunt 0.4.x (the file is now called Gruntfile.js). Please see my open source project Grunt.js Skeleton for help with setting up a build process for Grunt 1.x.

Moving from Grunt 0.4.x to Grunt 1.x should not introduce many major changes.


j
jaime

concat.js is being included in the concat task's source files public/js/*.js. You could have a task that removes concat.js (if the file exists) before concatenating again, pass an array to explicitly define which files you want to concatenate and their order, or change the structure of your project.

If doing the latter, you could put all your sources under ./src and your built files under ./dest

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

Then set up your concat task

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

Your min task

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

The build-in min task uses UglifyJS, so you need a replacement. I found grunt-css to be pretty good. After installing it, load it into your grunt file

grunt.loadNpmTasks('grunt-css');

And then set it up

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

Notice that the usage is similar to the built-in min.

Change your default task to

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

Now, running grunt will produce the results you want.

dest
├── css
│   ├── concat.css
│   └── concat.min.css
└── js
    ├── concat.js
    └── concat.min.js

You are a genius! It never occurred to me that of course if I included concat in the same js folder that it would scoop it up and append it! I have started using cssmin and it works great! Thanks again.
Great, really great! But the files names are always concat.min.css and concat.min.js. If I modify something, rerun & deploy, people won't get the most recent version because the browser already cached it. There' some way to randomly name the file and link them according in the proper <link> and <script> tags?
@TárcioZemel You can include the package.json's version on the filename: concat.min-<%= pkg.version %>.js
You can use .dest like this cssmin: { css:{ src: '<%= concat.css.dest %>', dest: './css/all.min.css' } }` It's the result of the operation concat -> css
A
Augusto Altman Quaranta

I want to mention here a very, VERY, interesting technique that is being used in huge projects like jQuery and Modernizr for concatenate things.

Both of this projects are entirely developed with requirejs modules (you can see that in their github repos) and then they use the requirejs optimizer as a very smart concatenator. The interesting thing is that, as you can see, nor jQuery neither Modernizr needs on requirejs to work, and this happen because they erase the requirejs syntatic ritual in order to get rid of requirejs in their code. So they end up with a standalone library that was developed with requirejs modules! Thanks to this they are able to perform cutsom builds of their libraries, among other advantages.

For all those interested in concatenation with the requirejs optimizer, check out this post

Also there is a small tool that abstracts all the boilerplate of the process: AlbanilJS


This is very interesting but not relevant to the question since RequireJS is a module loader, it does not concatenate or minify AFAIK
Thanks! You are right, RequireJS is a module loader and it does not concatenate nor minify. But r.js (the RequireJS optimizer --> requirejs.org/docs/optimization.html) does it. More specifically, it concatenates your modules ordering them by dependencies. The guys from Modernizr and jQuery took advantage of the ordering algorithm of the tool and use it specifically as a smart concatenator. You can check their repos to see what they are doing.
Using grunt's concat or uglify, the resulted file is composed using the order from the specified source files configured. While RequireJS is based on dependency. Different approach yet can achieve the same result.
M
McGarnagle

I agree with above answer. But here is another way of CSS compression.

You can concat your CSS by using YUI compressor:

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;
    });
  });
}; 

In case if you are using 'grunt-css' you must needed Locale Npm module, so make sure when you are installing 'grunt-css' in must be in Locale Npm module.
Why would you want to do all this complexity and call a jvm in your build process? Just slows it all down for no reason.
I
Inc33

You don't need to add the concat package, you can do this via cssmin like this:

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']
        }
      }
    }

And for js, use uglify like this:

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

C
Community

I think may be more automatic, grunt task usemin take care to do all this jobs for you, only need some configuration:

https://stackoverflow.com/a/33481683/1897196