Подтвердить что ты не робот

Почему рекомендуется использовать concat, а затем ouglify, когда последний может сделать то и другое?

Я продолжаю видеть рекомендацию для того, чтобы файлы JS, готовые к выпуску, были concat, а затем uglify.

Например здесь, в разделе задач Йомана.

По умолчанию поток: concat → uglifyjs.

Учитывая, что UglifyJS может выполнять как конкатенацию, так и минимизацию, зачем вам когда-нибудь понадобиться оба одновременно?

Спасибо.

4b9b3361

Ответ 1

Запуск базового теста, чтобы увидеть, есть ли разница в производительности между выполнением concat, а затем uglify и только 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');
    });
};

В src я поставил кучу JS файлов, включая несжатый источник jQuery, скопированный несколько раз, и распространяется в подпапки. Гораздо больше, чем обычно имеет обычный сайт/приложение.

Выключает время, необходимое для concat и сжатия всех этих файлов, по сути, одинаково в обоих сценариях.
За исключением при использовании опции 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 до uglify.
При возникновении ошибки в одном из JS файлов, sourcemap будет ссылаться на конкатенированный файл main.js, а не на исходный файл. Если uglify выполняет всю работу, ссылка будет на исходный файл.

Update:
Мы можем добавить еще 2 опции к uglify, которые свяжут исходную карту uglify с concat sourcemap, тем самым обработав "недостаток", упомянутый выше.

    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 файлов, если мы используем uglify и использовать его для других целей, когда это необходимо.

Ответ 2

В приведенном ниже примере, который я цитирую ниже, файлы сначала конкатенируются с concat, а затем uglified/minimified на uglify:

{
  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 - или со все большим числом равноправных пользователей и участников могут выбрать объединение файлов вне uglify только для удобства чтения и обслуживания. Я думаю, что это было причиной выбора Yeoman выбора потока преобразования.

uglify может быть заведомо медленным в зависимости от конфигурации проекта, поэтому может быть некоторое небольшое усиление в конкатенации с помощью concat сперва, но это должно быть подтверждено.

concat также поддерживает разделители, которые uglify не относятся к файлам README.md.

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