为什么建议使用concat然后uglify,后者可以同时使用uglify?

时间:2014-03-20 20:44:00

标签: gruntjs uglifyjs grunt-contrib-concat

我一直看到建议让JS文件准备好生产,然后uglify。

例如here,关于Yeoman的笨拙任务。

  

默认情况下,流程为:concat - > uglifyjs。

考虑到UglifyJS可以同时进行连接和缩小,为什么你需要同时进行这两种操作?

感谢。

2 个答案:

答案 0 :(得分:48)

运行基本测试,以查看执行concatuglifyuglify之间是否存在性能差异。

<强>的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');
    });
};

src中,我已经将一堆JS文件(包括未压缩的jQuery源)复制了几次,并传播到子文件夹中。远远超过普通网站/应用程序通常拥有的内容。

在两种情况下,连接和压缩所有这些文件所花费的时间基本相同 在<{1}}上使用sourceMap: true选项时外(见下文)。

在我的电脑上:

concat

值得注意的是,两种情况下得到的grunt default : 6.2s (just uglify) grunt default:true : 6s (concat and uglify) 都相同 此外,main.min.js在组合文件时会自动使用正确的分隔符。

唯一重要的是将uglify添加到sourceMap: true concat。 这会在options旁边创建一个main.js.map文件,结果为:

main.js

但是,如果生产站点仅加载grunt default : 6.2s (just uglify) grunt default:true : 13s (concat and uglify) 版本,则此选项无效。

我在min之前使用concat确实发现了一个主要的劣势
当其中一个JS文件发生错误时,uglify将链接到连接的sourcemap文件,而不是原始文件。当main.js执行整个工作时,链接到原始文件。

<强>更新
我们可以向uglify添加另外两个选项,将uglify源地图链接到uglify源地图,从而处理&#34;劣势&#34;我上面提到过。

concat

但这似乎非常不必要。

结论

我认为可以安全地得出结论,如果我们使用 uglify: { options: { compress: true, mangle: true, sourceMap: true, sourceMapIncludeSources: true, sourceMapIn: '<%= paths.dest.js %>.map', }, target: { src: '<%= paths.src.js %>', dest: '<%= paths.dest.jsMin %>' } } ,我们可以放弃concat获取JS文件,并在需要时将其用于其他目的。

答案 1 :(得分:27)

在您提及的示例中,我在下面引用的文件首先与concat连接,然后由uglify进行uglified / minified:

{
  concat: {
    '.tmp/concat/js/app.js': [
      'app/js/app.js',
      'app/js/controllers/thing-controller.js',
      'app/js/models/thing-model.js',
      'app/js/views/thing-view.js'
    ]
  },
  uglifyjs: {
    'dist/js/app.js': ['.tmp/concat/js/app.js']
  }
}

同样可以通过以下方式实现:

{
  uglifyjs: {
    'dist/js/app.js': [
      'app/js/app.js',
      'app/js/controllers/thing-controller.js',
      'app/js/models/thing-model.js',
      'app/js/views/thing-view.js'
    ]
  }
}

通常,任务clean将在写入临时文件夹(在此示例中为concat)的任务之后运行,并删除该文件夹中的任何内容。有些人还希望在clean之类的任务之前运行compass,以删除随机命名的图像精灵(每次运行任务时新生成的)。即使对于最偏执的人来说,这也会使轮子转动。

这完全取决于首选项和工作流程,以及何时运行jshint。有些人喜欢在编译之前运行它,有些人喜欢在编译文件上运行它。

包含大量JavaScript文件的复杂项目 - 或者拥有越来越多的同行&amp;贡献者可能会选择在uglify之外连接文件,以使事情更具可读性和可维护性。我认为这是Yeoman选择转换流程背后的原因。

根据项目的配置,

uglify可能是出了名的慢,因此首先将它与concat连接可能会有一些小的好处 - 但这必须得到确认。

concat还支持分隔符,uglifyREADME.md文件无关。

concat: {
  options: {
    separator: ';',
  }
}