1

I have a situation where I'm trying to consolidate several Javascript files into one, and conditionally apply them. I don't want to modify the actual files. Is there a way I can wrap these files and call them on demand?

The catch is, some of these files have function xyz() {} in them. So, wrapping them with if (false) { function xyz() {} } makes bad things happen.

For example, if this is my code...

if (includeFile) {
    /* The file */
    function foo() {}
    /* The file */
}

The problem becomes that Chrome will see foo() and place it in the global scope even if includeFile is false.

The easy solution would be to modify it to be var foo = function() {} but I can't modify these files.

I also have a general concern about running eval() on these functions since they are fairly huge. (Think jQuery wrapped in a function. If this isn't a problem then maybe eval is the answer?)

I was hoping I could nest functions and pass window in as the scope, but tried it on jsFiddle and it didn't seem to work.

(function() {
    function foo() {
        alert('it works');
    }
}).apply(window, []);

foo();

There are a few similar questions. But, none addressed the same situation that I have. Thanks.

Community
  • 1
  • 1
Dustin Graham
  • 2,054
  • 1
  • 20
  • 24
  • So the problem is there are name clashes between the multiple files - multiple function xyzs? Is modifying them really that bad - you're worried about introducing errors, or keeping compatible with upstream? Could you mechanically do the rename, e.g. sed or with a minifying tool somehow? – Rup Jan 10 '12 at 01:06
  • I'm thinking along the lines of a minifying tool or macro preprocessor also. How many `xyz`s do you have to deal with? And, is it really the best idea to put all this stuff in one file if only part of it is going to be executed on any given page? – Dagg Nabbit Jan 10 '12 at 01:28
  • Well, the idea is that depending on the page, and the context, we have too many files loading. Somewhere around 100 various resources (including css/images). So, in an attempt to cut down this number, we're trying to combine some files that get used often. In this case, some are libraries, and some are our in house code. Up until this point we had not worried about placing function xyz() {} in the global scope. With the new combined file, if (false) { function xyz() {} } ends up in the global scope, so we figured wrapping it in var foo = function() { function xyz() {} }; if (false) { foo(); } – Dustin Graham Jan 10 '12 at 15:30

1 Answers1

2

Have you considered using a library like require.js? There are several libraries out there that can do this for you in a more elegant fashion.

If you don't want a dependency-loading library, but you're using jQuery or some similar library, you can load scripts conditionally using an AJAX request (in jQuery, you'd use the script dataType). This is far better than a simple eval(), but less robust when you're trying to manage a series of dependencies.

Another option here, if you want to simply concatenate everything, is to wrap each file in an anonymous function and then assign the necessary elements to the window object, placing them in the global scope:

(function(window) {

    /* file 1 here */
    function xyz() {
        // etc ...
    }
    /* end file 1 */

    // now selectively choose what you want to be
    // in the global scope
    window.xyz = xyz;

}(window));

xyz();

This requires more work for you, however, to identify what you want to be available globally. Note that it's note necessary to pass window in as an argument to the anonymous function, but it's not a bad idea if you're going to be be referring to it multiple times (this speeds up references and allows for variable-name munging during code compression).

nrabinowitz
  • 55,314
  • 10
  • 149
  • 165
  • This is a good solution if we were writing all of the code from the beginning, but again the main focus of the question is that if it is possible to explicitly place a nested function in the global scope. – Dustin Graham Jan 10 '12 at 15:35
  • Ah, I see. Please see my edit - I think this addresses what you're going for. – nrabinowitz Jan 10 '12 at 20:58
  • Thanks. [That seems to work](http://jsfiddle.net/y9D7E/). From what I can tell, I think this is the best we're going to get. I can live with this, but I was really hoping for some sort of clever wrap. You can see how I'd like to be able to do something like (function() { function xyz() { } }).apply(window, []); as a sneaky solution. – Dustin Graham Jan 11 '12 at 06:35
  • Your `apply` trick only sets the value of `this` within the internal function - so you could do `(function() { this.xyz = function() { } }).apply(window, [])` instead of my version. But my version is probably more legible, and will compress better. – nrabinowitz Jan 11 '12 at 17:40
  • Actually, your version is also better with regards to my requirements where I don't want to edit the bulk of the file. In my situation, I'd prefer to add a few lines at the end instead of altering the combined code. Thanks. – Dustin Graham Jan 11 '12 at 18:41