Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
318 views
in Technique[技术] by (71.8m points)

gruntjs - Why is it recommended to use concat then uglify when the latter can do both?

I keep seeing the recommendation for making JS files ready for production to be concat then uglify.

For example here, in on of Yeoman's grunt tasks.

By default the flow is: concat -> uglifyjs.

Considering UglifyJS can do both concatenation and minification, why would you ever need both at the same time?

Thanks.

question from:https://stackoverflow.com/questions/22544649/why-is-it-recommended-to-use-concat-then-uglify-when-the-latter-can-do-both

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Running a basic test to see if there is a performance difference between executing concat and then uglify vs. just uglify.

package.json

{
  "name": "grunt-concat-vs-uglify",
  "version": "0.0.1",
  "description": "A basic test to see if we can ditch concat and use only uglify for JS files.",
  "devDependencies": {
    "grunt": "^0.4.5",
    "grunt-contrib-concat": "^0.5.0",
    "grunt-contrib-uglify": "^0.6.0",
    "load-grunt-tasks": "^1.0.0",
    "time-grunt": "^1.0.0"
  }
}

Gruntfile.js

module.exports = function (grunt) {

    // Display the elapsed execution time of grunt tasks
    require('time-grunt')(grunt);
    // Load all grunt-* packages from package.json
    require('load-grunt-tasks')(grunt);

    grunt.initConfig({
        paths: {
            src: {
                js: 'src/**/*.js'
            },
            dest: {
                js: 'dist/main.js',
                jsMin: 'dist/main.min.js'
            }
        },
        concat: {
            js: {
                options: {
                    separator: ';'
                },
                src: '<%= paths.src.js %>',
                dest: '<%= paths.dest.js %>'
            }
        },
        uglify: {
            options: {
                compress: true,
                mangle: true,
                sourceMap: true
            },
            target: {
                src: '<%= paths.src.js %>',
                dest: '<%= paths.dest.jsMin %>'
            }
        }
    });

    grunt.registerTask('default', 'concat vs. uglify', function (concat) {
        // grunt default:true
        if (concat) {
            // Update the uglify dest to be the result of concat
            var dest = grunt.config('concat.js.dest');
            grunt.config('uglify.target.src', dest);

            grunt.task.run('concat');
        }

        // grunt default
        grunt.task.run('uglify');
    });
};

In src, I've put a bunch of JS files, including the uncompressed source of jQuery, copied several times, spread around into subfolders. Much more than what a normal site/app usually has.

Turns out the time it takes to concat and compress all of these files is essentially the same in both scenarios.
Except when using the sourceMap: true option on concat as well (see below).

On my computer:

grunt default      : 6.2s (just uglify)
grunt default:true : 6s   (concat and uglify)

It's worth noting that the resulting main.min.js is the same in both cases.
Also, uglify automatically takes care of using the proper separator when combining the files.

The only case where it does matter is when adding sourceMap: true to the concat options.
This creates a main.js.map file next to main.js, and results in:

grunt default      : 6.2s (just uglify)
grunt default:true : 13s  (concat and uglify)

But if the production site loads only the min version, this option is useless.

I did found a major disadvantage with using concat before uglify.
When an error occurs in one of the JS files, the sourcemap will link to the concatenated main.js file and not the original file. Whereas when uglify does the whole work, it will link to the original file.

Update:
We can add 2 more options to uglify that will link the uglify sourcemap to concat sourcemap, thus handling the "disadvantage" I mentioned above.

    uglify: {
        options: {
            compress: true,
            mangle: true,
            sourceMap: true,
            sourceMapIncludeSources: true,
            sourceMapIn: '<%= paths.dest.js %>.map',
        },
        target: {
            src: '<%= paths.src.js %>',
            dest: '<%= paths.dest.jsMin %>'
        }
    }

But it seems highly unnecessary.

Conclusion

I think it's safe to conclude that we can ditch concat for JS files if we're using uglify, and use it for other purposes, when needed.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...