web-dev-qa-db-fra.com

Pourquoi est-il recommandé d'utiliser concat puis uglify alors que ce dernier peut faire les deux?

Je continue de voir la recommandation de préparer les fichiers JS pour la production à concat puis à uglify.

Par exemple ici , dans l'une des tâches de grognement de Yeoman.

Par défaut, le flux est: concat -> uglifyjs.

Étant donné qu'UglifyJS peut effectuer à la fois la concaténation et la minification, pourquoi auriez-vous besoin des deux en même temps?

Merci.

38
Francisc

Exécution d'un test de base pour voir s'il existe une différence de performances entre l'exécution de concat, puis de uglify par rapport à simplement 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');
    });
};

Dans src, j'ai mis un tas de fichiers JS, y compris la source non compressée de jQuery, copiée plusieurs fois, répartie dans des sous-dossiers. Beaucoup plus que ce qu'un site/application normal possède habituellement.

Il s'avère que le temps nécessaire pour concaténer et compresser tous ces fichiers est essentiellement le même dans les deux scénarios.
Sauf lorsque vous utilisez également l'option sourceMap: true Sur concat (voir ci-dessous).

Sur mon ordinateur:

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

Il est à noter que le main.min.js Résultant est le même dans les deux cas.
De plus, uglify se charge automatiquement d'utiliser le séparateur approprié lors de la combinaison des fichiers.

Le seul cas où cela importe est lors de l'ajout de sourceMap: true Au concatoptions.
Cela crée un fichier main.js.map À côté de main.js, Et se traduit par:

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

Mais si le site de production charge uniquement la version min, cette option est inutile.

J'ai trouvé un gros inconvénient en utilisant concat avant uglify.
Lorsqu'une erreur se produit dans l'un des fichiers JS, le sourcemap sera lié au fichier main.js Concaténé et non au fichier d'origine. Alors que lorsque uglify fait tout le travail, il sera un lien vers le fichier d'origine.

Mise à jour:
Nous pouvons ajouter 2 options supplémentaires à uglify qui lieront le uglify sourcemap à concat sourcemap, gérant ainsi le "désavantage" que j'ai mentionné ci-dessus.

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

Mais cela semble hautement inutile.

Conclusion

Je pense qu'il est prudent de conclure que nous pouvons abandonner concat pour les fichiers JS si nous utilisons uglify, et l'utiliser à d'autres fins, si nécessaire.

48
Alex Ilyaev

Dans l'exemple que vous mentionnez, que je cite ci-dessous, les fichiers sont d'abord concaténés avec concat puis uglifiés/minifiés par 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']
  }
}

La même chose pourrait être obtenue avec:

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

En règle générale, la tâche clean s'exécute ensuite après les tâches qui écrivent dans un dossier temporaire (dans cet exemple concat) et supprime le contenu de ce dossier. Certaines personnes aiment aussi exécuter clean avant des tâches comme compass, pour supprimer des choses comme des sprites d'image nommés de façon aléatoire (qui sont nouvellement générés à chaque exécution de la tâche). Cela permettrait aux roues de tourner même pour les plus paranoïaques.

Tout cela est une question de préférence et de workflow, comme c'est le cas avec quand exécuter jshint. Certaines personnes aiment l'exécuter avant la compilation, d'autres préfèrent l'exécuter sur des fichiers compilés.

Les projets complexes avec une quantité incroyable de fichiers JavaScript - ou avec un nombre de plus en plus important de pairs et de contributeurs, pourraient choisir de concaténer des fichiers en dehors de uglify juste pour que les choses soient plus lisibles et maintenables. Je pense que c'était le raisonnement derrière le choix de Yeomanflux de transformation.

uglify peut être notoirement lent en fonction de la configuration du projet, donc il peut y avoir un petit gain à le concaténer avec concat d'abord - mais cela devrait être confirmé.

concat prend également en charge les séparateurs, ce que uglify n'a pas pour autant que README.md les fichiers sont concernés.

concat: {
  options: {
    separator: ';',
  }
}
27
Wallace Sidhrée