Search code examples
javascriptantbackbone.jssproutcore

Issue with concatenating a few javascript files


This is a complete noob question, but I gotta ask it anyway

I started playing with backbone.js a few days ago and I was really fascinated. As I got over the "ToDo", I started working on a project of my own. Coming from the world of Java, I prefer keeping everything in as many separate files as possible. Therefore, I split my models views, and routers into separate files, into separate folders.

The problem came when I tried to combine those fiels into one single applciation.js file. Again, coming from the Java world, I love when I can automate stuff, and even more, when I can use familiar tools like ant, to setup build processes for my javascript projects.

I got a sample ant build template which concatenates and minifies all the files in an arbitrary order. When it finished, I tried to run my JS app, and not surprisingly, it failed with a bunch of errors. Many of my models and views try to extend each other, others depende on them as components. If they are not defined in a proper order, the app just reaches a point where it is trying to execute extend of an undefined

I know from before that for JavaScript the order is very important, but somehow I was left with the impression that if all the scripts are in one single file, the JS parser will load all the stuff first and then will try to execute whatever is to be executed. Well, my assumption was wrong.

It is possible to list all the files in the specific order I want them, but do I really need to go for such a primitive step? Unfortunately after spending a few hours researching, I couldn't find anything better.

Is it really possible to concatenate JS files, which depend on each other, in an arbitrary order, without them clashing? I guess, the biggest problem is the fact that the extend function is actually being called, rather than each script simply defining and object literal

So, what's the solution?

UPDATE: I just saw that Sproutcore has its own builder. If SC is roughly similar to BB, in the way one creates and extends entities, how does the SC builder work without clashing?


Solution

  • There are many ways to do this, but here's my recipe. I prefix my development files with a number, starting from the one with no dependencies (base "classes", models that will be depended upon from other models, then views using these models, then routers calling those views, etc.).

    Then I use uglify-js (available as a node.js library, that you install using npm install uglify-js) to minify all my js in one file (don't know from your question if you use node.js server-side, though). Then I cat *.js | uglifyjs -o min/myfile.min.js. This will send the content of all my .js files (respecting the order of dependencies because of my prefix) to uglify, which will minify it and save it to a single file.

    Since I, too, like automation, I have this set up in a Makefile, though I guess it could be done using Ant (not too familiar with it). The relevant part of the Makefile look like this:

    TARGET_MIN_FILE = public/js/min/myfile.min.js
    JS = $(shell echo public/js/*.js)
    
    
    public/js/min/myfile.min.js: $(JS)
        cat $(JS) | uglifyjs -o $(TARGET_MIN_FILE)
    
    
    clean:
        rm -f $(TARGET_MIN_FILE)
    
    .PHONY: clean
    

    On the other hand, if you go for the asynchronous module definition (AMD) format, you can require() your modules and it will manage for you the dependency loading in the correct order (see Require.js for more info), as mentioned by TheShelfishMeme.