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.
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 concat
options
.
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.
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.
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 Yeoman
s 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: ';',
}
}