51

Hello I'm using uglifyJs to minify my javascript files, it's working well with one file at a time, what I'm loking for is to minify all the javascript files present in a folder called JS into a folder called JSM, to be clear I have 2 files inside my JS folder called test1.js and test2.js and I want to run uglify against that folder and generate test1.min.js and test2.min.js inside the JSM folder, so is there a way to do this? a command like :

uglifyjs -c -m JS/*.js JSM/*.min.js

Or any idea that can help me.

Thanks.

raina77ow
  • 103,633
  • 15
  • 192
  • 229
OussamaLord
  • 1,073
  • 5
  • 28
  • 39

10 Answers10

95

I know it might seem like a huge step but I would really recommend using grunt. It's really simple once you get the hang of it.

Here's a crash course:

  1. Install NodeJS
  2. Install Grunt CLI (just enter this in console/terminal):

    npm install -g grunt-cli
    
  3. Create a simple package.json file in the root of your project:

    {
      "name": "my-project-name",
      "version": "1.0.0",
      "devDependencies": {
        "grunt": "~0.4.2",
        "grunt-contrib-uglify": "~0.2.4",
        "grunt-contrib-watch" : "~0.5.3"
      }
    }
    
  4. Once you have that, just type: npm install to the console (in the root of your project). This will install the necessary grunt plugins/dependencies (from the package file above).

  5. Now create a simple gruntfile.js in the root of your project (it's a kind of config for your project):

    module.exports = function (grunt) {
        grunt.initConfig({
    
    
        // define source files and their destinations
        uglify: {
            files: { 
                src: 'js/*.js',  // source files mask
                dest: 'jsm/',    // destination folder
                expand: true,    // allow dynamic building
                flatten: true,   // remove all unnecessary nesting
                ext: '.min.js'   // replace .js to .min.js
            }
        },
        watch: {
            js:  { files: 'js/*.js', tasks: [ 'uglify' ] },
        }
    });
    
    // load plugins
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    
    // register at least this one task
    grunt.registerTask('default', [ 'uglify' ]);
    
    };
  6. Once that's done you just need to build it. Type in the console:

    grunt
    

    or - better - if you type execute the command below - grunt will monitor your source files for changes, and if you change any of them - it will build them automatically:

    grunt watch --force
    

You can then add more plugins, like: css minification, css preprocessors (less, sass, stylus), jshint, etc.

Dziad Borowy
  • 12,368
  • 4
  • 41
  • 53
  • 1
    Hi, thanks for you help but I do not see how this will work or solve my issue, I did all the steps and I get this :Running "watch" task waiting... ,I had to modify the code in "gruntfile.js" you have some errors in your code. I just want something to run at on time that can do what I want (as described above), thanks – OussamaLord Jun 09 '13 at 14:00
  • Hi. Sorry for errors (lots of copy&paste). If you can see the "Running watch task..." that's great! just save your js file and grunt should build that. Or just use `grunt` command to build files once. – Dziad Borowy Jun 09 '13 at 17:40
  • Hi, sorry this is the new message I get, nothing is created in my jsm folder: `C:\npm>grunt --force Running "uglify:file1" (uglify) task Warning: Uglification failed. Used --force, continuing. Warning: Cannot read property 'min' of undefined Used --force, continuing. Running "uglify:my_plugins" (uglify) task Warning: Uglification failed. Used --force, continuing. Warning: Cannot read property 'min' of undefined Used --force, continuing. Done, but with warnings` – OussamaLord Jun 09 '13 at 18:22
  • Hi. Just make sure that the file structure in gruntfile.js represents what you have, e.g. do you have file1.js in your js folder? As for my_plugins node - you can remove this. I only added this to show you what you could do... – Dziad Borowy Jun 09 '13 at 18:49
  • I updated the `gruntfile.js` in my response to reflect your file structure. – Dziad Borowy Jun 09 '13 at 18:50
  • Hi, sorry to boder you again but everything seems working I have `test1.js` in my `js` folder a `jsm` folder empty and the `gruntfile.js` with these changes : `.... uglify: {test1: { src: [ 'js/test1.js' ],dest: 'jsm/test1.min.js'}},watch: { js: { files: 'js/**/*.js', tasks: [ 'uglify' ] },} ...` Now I get : `Running "watch" task Waiting...` but nothing is created in jsm folder, what am I doing wrong? – OussamaLord Jun 09 '13 at 19:57
  • if you run `grunt watch` - that will watch for changes in files, and if you do not change anything - nothing will happen. If you want to uglify your files "now" - use just `grunt` (without watch) – Dziad Borowy Jun 09 '13 at 22:20
  • Hi, AWWWESOOME, thanks this is working , however this will not solve my issue, I see that I have to specify myself the files names in `gruntfile.js` `uglify: { test1: { src: [ 'js/test1.js' ], dest: 'jsm/test1.min.js' }.....` so what I wanted to do is uglifying all the content (files) inside `JS` folder without having to put the names of the files to uglify in the `gruntfile.js` file. Anyway thanks again. – OussamaLord Jun 09 '13 at 23:28
  • 7
    you can do better - with masks, you can uglify all files into one: `uglify: { tests: { src: [ 'js/*.js' ], dest: 'jsm/tests.min.js' } },` – Dziad Borowy Jun 10 '13 at 06:56
  • Hi, thanks a lot you are really awesome with `grunt`, we are close to end this topic, you were right it is uglifying all the files in `JS` folder into one file inside `JSM` folder, so what is the mask to uglify each file in `JS` folder in a separate file `*.min.js` inside JSM folder? and yes I know I asked you a lot of questions so Sorry this is the last one I will ask ;). – OussamaLord Jun 10 '13 at 09:07
  • Hi @OussamaLord, I updated my answer (and added comments) to do exactly what you want (I hope). I've also tested this and it now compiles each file separately. – Dziad Borowy Jun 10 '13 at 10:16
  • HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH, I don't know how to thank you, you are awesome, now it's doing exactly what I want, thank you so much, so this topic is closed now. Show me how can I leave feedback for you, you deserve it after all ;) – OussamaLord Jun 10 '13 at 10:28
  • 1
    You can mark my answer as "answer" (to close the topic) and click the up arrow next to it :-) And I'm happy to help! – Dziad Borowy Jun 10 '13 at 10:43
  • Don't we need a clean up first??? I think mine is going out of controller, and appending the script at the end of the min file... getting too large... – Val May 19 '14 at 15:55
24

If you're on Linux/Mac and have access to bash, you can use uglifyjs on multiple JS files like so:

rm *.min.js; for f in *.js; do short=${f%.js}; uglifyjs $f > $short.min.js; done
mmorrey
  • 103
  • 1
  • 5
Calpau
  • 921
  • 10
  • 21
  • 3
    How would you recursively go through a scripts folder? I have a javascripts folder, with directories inside of it like polyfills and libraries. Is there a way to run the for loop only recursively through the nested directories? – Costa Michailidis Mar 31 '17 at 21:08
  • My solution run over any path recursively and uses `terser` as a replacement to `uglifyjs` because it doesn't support ES6+ https://stackoverflow.com/a/65232798/2015609 – mbnoimi Dec 10 '20 at 10:33
16

npm-only way:

  1. run:

    npm install uglifyjs-folder --save-dev
    
  2. and afterwards add to your package.json something like:

    "uglifyjs": "uglifyjs-folder js -eo jsm"
    
  3. then run:

     npm run uglifyjs
    

Please note, if you'd need to generate to the same folder as the source files are (js), following should do the job:

  1. run:

    npm install del-cli uglifyjs-folder --save-dev
    
  2. and afterwards add to your package.json something like:

    "uglifyjs": "del js/*.min.js; uglifyjs-folder js -eo js"
    
  3. then run:

     npm run uglifyjs
    
Peter Butkovic
  • 11,143
  • 10
  • 57
  • 81
8

Further to the above answer, I now have this set up in my .bashrc file:

alias minify='rm *.min.js; for f in *.js; do short=${f%.js}; uglifyjs $f > $short.min.js; done'
mmorrey
  • 103
  • 1
  • 5
4

uglify-js does not support ES6+ so I suggest to use terser (to install it run npm install terser -g) Below a shell script executing terser recursively for any path:

terser_path.sh

#!/bin/bash

####
# Tiny shell script for terser any JavaScript project
# usage:
# ./terser_path <path_to_your_project>
####

path="$1"

find $path -name '*.js' -type f | while read f
do
    folderpath=$(dirname "$f")
    filename=$(basename "$f") 
    extension="${filename##*.}"
    filename="${filename%.*}"
    nf=$folderpath/$filename.min.$extension

# ----- METHOD 1 : Replace the old file
#    terser "$f" --output "$f" --compress --mangle
# ----- METHOD 2 : Create .min.js file
    terser "$f" --output "$nf" --compress --mangle
     
done
mbnoimi
  • 490
  • 4
  • 21
  • This is great! I ran into an issue, however, where the function names are not being mangled. I tried adding --module to the the CLI command to tell it I'm using ES6 modules, which should also automatically enable --keep-fnames=false, but it still doesn't work for me. Adding `--keep-fnames=false` causes an error – I Stand With Israel Mar 02 '21 at 09:15
3

You can use this configuration in gruntfile.js:

uglify: {
        all: {
            files: [{
                expand: true,
                cwd: '<path to js folder>',
                src: ['**/*.js', '!*.min.js'],
                dest: '<path to js folder>',
                ext: '.js'
            }]
        }
    }
Kop4lyf
  • 4,520
  • 1
  • 25
  • 31
0

make a bat file with start at each row beginning

start uglifyjs app\main.js -mt sort -c -e -o app\main.ug.js
start uglifyjs app\lib.js -mt sort -c -e -r myfunctionname -o app\lib.ug.js
start uglifyjs app\controllers\bbbCtrl.js -mt sort -c  -o     app\controllers\bbbCtrl.ug.js
start uglifyjs app\controllers\aaaCtrl.js -mt sort -c -e -o app\controllers\aaaCtrl.ug.js
Fabio
  • 11
  • 3
0

you can use this npm module package

 npm i uglify-js-minify-css-allfiles
 npm i uglify-js clean-css
// making index.js file
const minifyAll = require('uglify-js-minify-css-allfiles');

// Folder Name (you will change all files in Folders)
minifyAll('../test/');

npm package site

0

using uglifyjs with PowerShell on windows.

use Powershell to iterate over all js files in a directory (including child folders if -recurse is supplied) and call uglifyjs command for each one.

Be aware that this code will overwrite the original files with the uglified version. If you don't needed this, change the parameters for the uglifyjs command.

    Get-ChildItem "some directory path" -Recurse -Filter *.js | 
Foreach-Object {
    echo $_.FullName
    uglifyjs $_.FullName -o $_.FullName
}
Anas Ghanem
  • 127
  • 7
0

Using bash script worked for me. You could use different commands or flags instead of uglifyjs "$file" -o "${file%.js}.min.js" -c -m.

To minify all .js files in your current directory as well as in all the sub-directories (NOTE: it has no depth limit so how much deeply nested sub-directories you have it would work on every .js file).

for file in $(find * -type f -iname "*.js"); do
uglifyjs "$file" -o "${file%.js}.min.js" -c -m 
done

Expected result : It will create minified .min.js files of every .js files inside your current directory as well as in all the sub-directories.

Warning : It will loop through all the directories and sub-directories. To limit sub-directory depth add -maxdepth <depth_limit_number>. for example first line could look like this, for file in $(find * -type f -iname "*.js" -maxdepth 3); do, to limit find for 3 sub-directories from your current directory. Use it on your own risk.

Doobied
  • 11
  • 3