3

I have an app in nodejs. In it, I define some global variables that are shared across multiple files. For example:

//common.js
async = requires("async");
isAuthenticated = function() {
  //...
  return false;
};

//run.js
require("common.js");
async.series([function () {
  isAuthenicated();
}], function () {
  console.log("done");
});

I want the async and isAuthenticated variables to be minified, but minified to the same thing in all files. It would look like the following:

//common.min.js
a = requires("async");
b = function() {
  //...
  return false;
};

//run.min.js
require("common.js");
a.series([function () {
  b();
}], function () {
  console.log("done");
});

How to do it in uglifyjs?

I'm currently looping through the files and using the command uglifyjs $file -m "sort,toplevel" -c > $file.min on each.

ATNASGDWNGTH
  • 876
  • 11
  • 26
  • 3
    Sharing the global scope between multiple files is an anti-pattern, not to mention you are talking about a savings of mere _bytes_. – Evan Davis Dec 24 '14 at 19:23
  • Why do you need this at all? – Vsevolod Goloviznin Dec 24 '14 at 21:23
  • uglify works best by compressing everything at once. you roll the dice when you try to get the same output from many runs or files. you can turn off var renaming and still crunch whitepsace and long-winded logic. – dandavis Dec 24 '14 at 22:17
  • Reducing the file size is not the main reason. I want the codes unreadable and to avoid from reverse engineering – ATNASGDWNGTH Dec 26 '14 at 02:37
  • 2
    Uglyfying will make reverse engineering (and debugging of course) only harder but not impossible. – try-catch-finally Dec 26 '14 at 10:36
  • I don't think unglyfying a server side code is a good thing to do. NodeJS is pretty anoying for debugging so don't make your life harder (and if you don't work alone you will make the life of your team harder) I don't see why you are protecting a server side code from reverse engineering. – thinklinux Dec 26 '14 at 10:43
  • 1
    My situation is delivering the codes and not providing a web service. Of course, I know there is no something which can completely prevent from reverse engineering in any languages. In JavaScript world, what I know the possible way to achieve it is uglifying the code. Otherwise how do you protect your code if you need to deliver the code. As for the testing, I will not do the debugging in the uglified code. In my build process, I will test the original code first before uglifying. – ATNASGDWNGTH Dec 26 '14 at 13:58
  • 1
    If you want to protect your code, write it in a compiled language and provide binaries. –  Dec 27 '14 at 07:42
  • There are really good solutions for debugging. you can use source maps (for both browserify & uglify) - which means you can actually see the folder structure of your original source. Usually you serve minified code in production to lower the "page speed" (which is network driven) (https://developers.google.com/speed/docs/insights/MinifyResources) – surui Jan 02 '15 at 15:34

4 Answers4

6
  • Don't use globals.
  • Use var async = reuqire('async') where needed.
  • Use module.exports in your specific modules you require.
  • Use something like browserify to generate a single js.
  • Uglify (or use a browserify transform named uglifyify)

For example, the simplest form (without using uglifyify)

$ browserify run.js | uglifyjs -c > run.min.js

Note that if you use your own code, like common.js, you should require it using a relative path, var common = require("./common").

I suggest you use the exports syntax:

// common.js code

exports.isAuthenticated = function() {
  //...
  return false;
};

And of course use it just as you would with async.js:

//run.js
var common = require("./common");
var async = require("async")
async.series([function () {
  common.isAuthenicated();
}], function () {
  console.log("done");
});

assuming both common.js & run.js reside in the same directory.

related question: How to get minified output with browserify?

A Side Note

The way you used async.series in your question has no real advantage. You could have just:

//run.js
var common = require("./common");

common.isAuthenicated();
console.log("done");

in Async series you usually call async functions:

async.series([
    function(callback){
        // do some stuff ...
        callback(null, 'one');
    },
    function(callback){
        // do some more stuff ...
        callback(null, 'two');
    }
],
// optional callback
function(err, results){
    // results is now equal to ['one', 'two']
}); 

so, I would expect to see something like:

// common.js code

exports.isAuthenticated = function(callback) {
  //...
  callback(null, false);
};

and then

//run.js
var common = require("./common");
var async = require("async")
async.series([common.isAuthenicated], function (err, results) {
  console.log("done with", results[0]);
});

I usually prefer a different "syntax"

// an example using an object instead of an array
async.series({
    one: function(callback){
        setTimeout(function(){
            callback(null, 1);
        }, 200);
    },
    two: function(callback){
        setTimeout(function(){
            callback(null, 2);
        }, 100);
    }
},
function(err, results) {
    // results is now equal to: {one: 1, two: 2}
});

But it's your call. The async examples were taken from https://github.com/caolan/async#seriestasks-callback

Community
  • 1
  • 1
surui
  • 1,522
  • 12
  • 17
1

You would want to concat the files before you go ahead and uglify them. Concatenation is the process of combining multiple files of code into one monolithic creature that knows everything about all parts of your code. This is often done in conjunction with uglyfying for several reasons, mainly for performance benefits (your app runs a lot faster if you only send 1 file to the client).

That being said, this is typically a practice that is done when your serving code to a client, not necessarily for back-end / server-side logic. Ideally no one but you or people with access to whatever service you're using to deploy said server code should see that side of your code. If your main concern is to prevent reverse-engineering, or make your code unreadable, I suggest obfuscating your code.

"This is omega site. Best encrypted level he has. Looks like obfuscated code to conceal its true purpose. Security through obscurity." - Q Skyfall 2012

0

If your globals are confined to common.js, you may try

uglifyjs --define-from-module common.js $file...

and remove require()s.

punund
  • 4,321
  • 3
  • 34
  • 45
0

In NodeJs there is the concept of defining global variables like posted in this thread:

global.myGlobalVar = "something visible to all modules";

I am too using uglify in my node apps, and it turned out that when using global.xyz, xyz does not get uglified.

disclaimer: I am totally aware that exposing global info is an anti pattern. But sometimes there is a good reason for it.

Hope that helps!

Community
  • 1
  • 1
akrsmv
  • 820
  • 9
  • 23