webentwicklung-frage-antwort-db.com.de

Warum ist es empfehlenswert, concat und uglify zu verwenden, wenn letzteres beides kann?

Ich sehe immer wieder die Empfehlung, JS-Dateien für die Produktion vorzubereiten, um sie zu komprimieren und zu hässlich zu machen.

Zum Beispiel hier , in einer von Yeomans Grunzaufgaben.

Standardmäßig lautet der Flow: concat -> uglifyjs.

In Anbetracht dessen, dass UglifyJS sowohl Verkettung als auch Minimierung ausführen kann, warum würden Sie jemals beide gleichzeitig benötigen?

Vielen Dank.

38
Francisc

Ausführen eines Basistests, um festzustellen, ob es einen Leistungsunterschied zwischen der Ausführung von concat und dann uglify im Vergleich zu nur uglify gibt.

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 habe ich eine Reihe von JS-Dateien abgelegt, einschließlich der unkomprimierten Quelle von jQuery, die mehrmals kopiert und in Unterordnern verteilt wurden. Viel mehr als das, was eine normale Site/App normalerweise hat.

Es hat sich herausgestellt, dass die Zeit, die zum Zusammenfassen und Komprimieren all dieser Dateien benötigt wird, in beiden Szenarien im Wesentlichen gleich ist.
außer bei Verwendung des sourceMap: true Option auch für concat (siehe unten).

Auf meinem Computer:

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

Es ist erwähnenswert, dass das resultierende main.min.js ist in beiden Fällen gleich.
Außerdem sorgt uglify beim Kombinieren der Dateien automatisch für die Verwendung des richtigen Trennzeichens.

Der einzige Fall, in dem es wichtig ist, ist das Hinzufügen von sourceMap: true zum concatoptions.
Dadurch wird ein main.js.map Datei neben main.js und führt zu:

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

Wenn die Produktionsstätte jedoch nur die Version min lädt, ist diese Option unbrauchbar.

Ich habe einen großen Nachteil mit concat vor uglify gefunden.
Wenn in einer der JS-Dateien ein Fehler auftritt, wird die Verknüpfung von sourcemap mit der verketteten main.js Datei und nicht die Originaldatei. Wenn uglify die gesamte Arbeit erledigt, wird wird auf die Originaldatei verlinkt.

pdate:
Wir können 2 weitere Optionen zu uglify hinzufügen, die die uglify-Quellkarte mit der concat-Quellkarte verknüpfen und so den oben erwähnten "Nachteil" beseitigen.

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

Aber es scheint höchst unnötig.

Fazit

Ich denke, es ist sicher zu schließen, dass wir concat für JS-Dateien wegwerfen können, wenn wir uglify verwenden, und es bei Bedarf für andere Zwecke verwenden können.

48
Alex Ilyaev

In dem Beispiel, das Sie erwähnen, werden die Dateien zuerst mit concat verkettet und dann mit uglify verkleinert:

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

Das gleiche könnte erreicht werden mit:

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

Normalerweise wird die Task clean nach Tasks ausgeführt, die in einen temporären Ordner schreiben (in diesem Beispiel concat) und den Inhalt in diesem Ordner löschen. Einige Leute führen auch gerne clean vor Aufgaben wie compass aus, um Dinge wie zufällig benannte Image-Sprites zu löschen (die jedes Mal neu generiert werden, wenn die Aufgabe ausgeführt wird). Dies würde die Räder auch für die paranoidesten drehen lassen.

Dies ist alles eine Frage der Präferenz und des Workflows, genau wie der Zeitpunkt, zu dem jshint ausgeführt werden soll. Einige Leute möchten es vor der Kompilierung ausführen, andere ziehen es vor, es auf kompilierten Dateien auszuführen.

Komplexe Projekte mit einer unglaublichen Menge an JavaScript Dateien - oder mit einer immer größeren Anzahl von Kollegen und Mitwirkenden - können sich dafür entscheiden, Dateien außerhalb von uglify zu verketten, um die Lesbarkeit und Wartbarkeit zu verbessern. Ich denke, das war die Begründung für Yeomans Wahl von Transformationsfluss.

uglify kann in Abhängigkeit von der Projektkonfiguration notorisch langsam sein, daher kann es etwas vorteilhafter sein, es zuerst mit concat zu verknüpfen - dies muss jedoch bestätigt werden.

concat unterstützt auch Trennzeichen, die uglify nicht so weit wie README.md Dateien sind betroffen.

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