web-dev-qa-db-fra.com

comment réduire les fichiers js dans l'ordre via grunt-contrib-uglify?

J'ai un répertoire comme ci-dessous:

/dossier/b.js
/folder/jQuery.js
/folder/a.js
/folder/sub/c.js

Je veux minifier tous ces fichiers js dans un fichier js dans l'ordre :

jQuery.js -> a.js -> b.js -> c.js

Q:
1.Comment puis-je le faire via grunt-contrib-uglify? (En fait, il y a beaucoup de fichiers, il n'est pas pratique de spécifier tous les chemins de fichiers source individuellement)

2.btw, Comment puis-je obtenir des fichiers non minés lors du débogage et obtenir un fichier unique minifié lors de la publication et qu'il n'est pas nécessaire de changer la balise script en HTML (et comment écrire la balise script)?

36
talent

Bonnes questions!

1) Uglify réorganisera les fonctions dans le fichier de destination afin que les définitions de fonctions soient en haut et l’exécution de fonctions en bas, mais il semble qu'il préserve l’ordre des exécutions de fonctions. 

Cela signifie que la fonction jQuery exécutée pour définir ses fonctions globales sera placée en premier si vous vous assurez que jQuery est mentionné en premier dans la configuration de Uglify dans le fichier Grunt.

J'utilise cette config:

uglify: {
    options: {
        sourceMap: true
    },
    build: {
        files: {
            'public/all.min.js': ['public/js/vendor/jquery-1.10.2.min.js', 'public/js/*.js'],
        }
    }
}

2) Je ne pense pas qu'il existe un moyen précis d'y parvenir. Cela dépend de la structure Web, de la structure de modèles et du type d'exigences que vous avez. J'utilise express + jade et, dans ma mise en page principale, j'ai:

if process.env.NODE_ENV === 'production'
  script(src='/all.min.js')
else
  script(src='/js/vendor/jquery-1.10.2.min.js')
  script(src='/js/someScript.js')
  script(src='/js/otherScript.js')

Dans mon package.json j'ai:

"scripts": {
  "postinstall": "grunt"
},

Cela signifie que lorsque j'exécute npm install sur deploy (sur Heroku), grunt est exécuté pour minimiser/concaténer des fichiers et lorsque l'application est démarrée avec NODE_ENV=production, le javascript côté client minifié est utilisé. Je reçois localement les javascripts côté client d'origine pour faciliter le débogage. 

Les deux inconvénients sont:

  • Je dois synchroniser les deux listes de fichiers de script (dans le fichier Gruntfile et dans le fichier layout.js). Je résous ce problème en utilisant *.js dans le fichier Grunt, mais cela ne convient pas à tout le monde. Vous pouvez mettre la liste des javascripts dans le fichier Grunt et créer un modèle jade à partir de celui-ci, mais cela semble excessif pour la plupart des projets.
  • Si vous ne faites pas confiance à votre configuration Grunt, vous devez essentiellement tester l'exécution de l'application en utilisant NODE_ENV=production localement pour vérifier que la minification a fonctionné comme prévu.
25
gabrielf

Cela peut être fait en utilisant les tâches Grunt suivantes:

  1. https://github.com/gruntjs/grunt-contrib-concat concatenates files
  2. https://github.com/gruntjs/grunt-contrib-uglify minifies fichiers concaténés

MODIFIER

J'exécute généralement tous mes fichiers dans une tâche de concaténation Grunt à l'aide de grunt-contrib-concat . Ensuite, j'ai une autre tâche pour uglifier le fichier concaténé en utilisant grunt-contrib-uglify .

8
singh1469

Cela ne vous plaira probablement pas, mais le mieux est de définir vos fichiers source js en tant que modules AMD et d’utiliser Requirejs pour gérer l’ordre dans lequel ils se chargent. La tâche grunt-contrib-requirejs réclarera votre arbre de dépendance et concaténera les fichiers js dans l'ordre nécessaire dans un seul et même grand fichier js. Vous utiliserez ensuite uglify (en fait, r.js a uglify intégré) pour minifier le gros fichier.

https://github.com/danheberden/yeoman-generator-requirejs a un bon exemple de fichiers de gabarit et de modèle js sur lesquels travailler.

MODIFIER

J'ai récemment commencé à utiliser les modules CommonJS à la place d'AMD, qui est beaucoup plus proche des spécifications du module ES6. Vous pouvez obtenir les mêmes résultats (1 gros fichier Js conforme + concaténé) en exécutant les modules commonjs via Browserify . Il existe des plugins pour que grunt et gulp gèrent la tâche à votre place.

MODIFIER

Je voudrais ajouter que si votre site est écrit avec ES6, Rollup est le meilleur nouveau package de concaténation. En plus de regrouper vos fichiers, il procédera également à la création d'arborescence en supprimant des parties des bibliothèques que vous utilisez si elles sont incluses via une instruction import. Cela réduit votre base de code à ce dont vous avez besoin sans le fardeau de code que vous n'utiliserez jamais.

6
Patrick Gunderson

Je ne pense pas que vous puissiez faire cela avec la seule tâche de vexation, mais vous avez une multitude de choix qui pourraient conduire à votre résultat souhaité.

Un flux de travail possible serait d'abord de concaténer (grunt-contrib-concat) les fichiers dans l'ordre en un seul fichier, puis de placer ce fichier concaténé dans uglify. Vous pouvez soit définir l'ordre de concat dans votre Gruntfile, ou vous utilisez l'un de ces plugins:

Le premier serait https://github.com/yeoman/grunt-usemin , où vous pouvez spécifier l'ordre dans votre fichier HTML, ajoutez des commentaires autour de votre bloc de script. Les gars de Google l'ont fait et c'est très agréable à utiliser.

La seconde serait https://github.com/trek/grunt-neuter , où vous pouvez définir certaines dépendances avec require, mais sans la majeure partie de require.js. Il nécessite des modifications dans votre code JS, de sorte qu'il risque de ne pas l'aimer. J'irais avec l'option un.

5
ddprrt

J'ai rencontré le même problème. Une solution rapide consiste simplement à changer les noms de fichiers - j'ai utilisé 1.jquery.min.js, 2.bootstrap.min.js, etc.

3
kocytean

Cela pourrait être uniquement lié à votre question mais je voulais quelque chose de similaire. Seule ma commande était importante de la manière suivante:

Je chargeais tous les fichiers de fournisseurs (angular, jquery et leurs plugins respectifs respectifs) avec un caractère générique (['vendor/**/*.js']). Mais certains plugins avaient des noms qui les faisaient charger avant angular et jquery. Une solution consiste à les charger manuellement en premier. 

['vendor/angular.js', 'vendor/jquery.js', 'vendor/**/*.js]

Heureusement, les poignées jQuery et angulaires sont chargées deux fois. Modifier: Bien que ce ne soit pas vraiment la meilleure pratique pour charger de telles bibliothèques de grande taille deux fois, causant un gonflement inutile de votre fichier minifié. (merci @Kano pour l'avoir signalé!)

Client-js était un autre problème; la commande était importante car elle nécessitait que le fichier d'application principal soit chargé en dernier, après le chargement de toutes ses dépendances. La solution à cela consistait à exclure puis à inclure:

['app/**/*.js', '!app/app.js', 'app/app.js']

Cela empêche le chargement de app.js avec tous les autres fichiers et ne l'inclut alors qu'à la fin.

2
laggingreflex

On dirait que la deuxième partie de votre question est toujours sans réponse. Mais laissez-moi essayer un par un.

Premièrement, vous pouvez joindre et modifier un grand nombre de fichiers js en un seul, comme expliqué précédemment par la réponse concat. Il devrait également être possible d'utiliser https://github.com/gruntjs/grunt-contrib-uglify car il semble y avoir des caractères génériques. Vous devrez peut-être expérimenter avec l'option 'expand = true' et les caractères génériques. Cela répond à votre première question. 

Pour la deuxième partie, disons que vous avez rejoint et aggravé big-mogly.js 

Maintenant, dans votre HTML, vous pouvez ajouter les directives suivantes: 

<!-- build:js:dist big-ugly.js -->
<script src="js1.js"></script>
<script src="js2.js"></script>
<!-- etc etc --> 
<script src="js100.js"></script>
<!-- /build -->

Ensuite, transmettez-le au préprocesseur Grunt HTML à l’adresse https://www.npmjs.com/package/grunt-processhtml dans le cadre de vos travaux Grunt.

Ce préprocesseur remplacera le bloc entier par 

<script src="big-ugly.js"></script>

Ce qui signifie que le fichier html doit être sémantiquement équivalent - avant et après les travaux de grunt; c'est-à-dire si la page fonctionne correctement sous sa forme native (pour le débogage) - la page transformée doit alors fonctionner correctement après le grunt - sans que vous deviez modifier manuellement les balises. 

2
vpathak

C'était la réponse de @ 1469 mais il n'a pas expliqué pourquoi cela fonctionnait. Utilisez concat pour mettre tous les fichiers js en un, ce module le fait dans l'ordre des noms de fichiers, donc je mets un préfixe aux noms de fichiers en fonction des commandes. Je crois qu'il a même d'autres options pour commander.

concat: {

        js: {
            options: {
                block: true,
                line: true,
                stripBanners: true
            },
            files: {
                'library/dist/js/scripts.js' : 'library/js/*.js',
            }
        }
    },

Ensuite, utilisez uglify pour créer la version laide minifiée:

uglify: {
      dist: {
        files: {
          'library/dist/js/scripts.min.js': [
            'library/js/scripts.js'
          ]

        },
        options: {

        }
      }
    },
1
Neo

Si votre problème était que vous aviez des fournisseurs qui devaient être chargés dans l’ordre (disons jquery avant tout plugin jquery). Je l'ai résolu en plaçant jquery dans son propre dossier appelé "! Jquery", en le plaçant effectivement au-dessus de la pile ..__ Ensuite, j'ai simplement utilisé concat comme d'habitude:

concat: {
  options: {
    separator: ';',
  },
  build: {
    files: [
      {
        src: ['js/vendor/**/*.js', 'js/main.min.js'],
        dest: 'js/global.min.js'
      }
    ]
  }
},
0
Maurice