50

I created a javascript application with all of the code in one file. The application has grown quite a bit and I think it's time to split it up into multiple files, but I'm having a hard time figuring out how to do this. I think the problem lies with how I have decided to build the app, which uses the following template:

var myApp = function(){

    //there are several global variables that all of the modules use;
    var global1, global2, module1, module2;

    global1 = {
        prop1:1
    };

    //There are also several functions that are shared between modules
    function globalFunction(){

    }

    var ModuleOne = function(){

        function doSomething(){
            //using the global function
            globalFunction();
        }

        return{
            doSomething:doSomething
        }
    };

    var ModuleTwo = function(){

        function doSomething(){
            //module 2 also needs the global function
            globalFunction();

            //Use the functionality in module 1
            //I can refactor this part to be loosely coupled/event driven
            module1.doSomething();
        }
    };

    module1 = new ModuleOne();
    module2 = new ModuleTwo();
};

Even if all of the modules were loosely coupled and event driven, I still don't know how I would go about splitting this into multiple files given each module's reliance on the shared functions/variables. Does anyone have suggestions?

4
  • Seriously though, tools like module8 solve your problem Commented Jan 6, 2012 at 2:25
  • 1
    Take a look at the design pattern in this article: adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth - you can split your module definition across multiple files in a way that lets common properties be shared but also lets you create variables or methods that are private just to a particular file. Commented Jan 6, 2012 at 2:30
  • @nnnnnn Thanks for that article. It's perfect. You should submit an answer with the link so I can accept it... Commented Jan 10, 2012 at 23:09
  • If the modules use shared functions/variables, then they aren't loosely coupled. Commented Jan 10, 2012 at 23:47

5 Answers 5

48

Take a look at the design pattern in this article: repost of Ben Cherry's "JavaScript Module Pattern: In-Depth" from 2010 - you can split your module definition across multiple files in a way that lets common properties be shared but also lets you create variables or methods that are private just to a particular file.

The basic idea is that the individual JS files add to the same module with code like this:

var MODULE = (function (my) {
     var privateToThisFile = "something";

    // add capabilities...

     my.publicProperty = "something";
    
    return my;
}(MODULE || {}));

Where in each JS file if MODULE is already defined (from another JS file) you add to it otherwise you create it. You can set it up so that it (mostly) doesn't matter what order the various files are included in.

The article details several variations, and of course you'll probably come up with your own tweaks...

Sign up to request clarification or add additional context in comments.

2 Comments

after an entire day breaking my head on how to proceed I'm glad I found this answer.
I believe this link is defunct.
4

not to add to the confusion, but coming from a C++ background, I've tried to construct something that resembles something like a c++ namespace in the manner described below. it works, but I'd like to know if this is an acceptable pattern for the OP ?

--------------------------------file main.js:----------------

var namespacename = function(){}

namespacename.mainvalue = 5;

namespacename.maintest = function() {
    var cm = new namespacename.game();
    cm.callme();
}

--------------------------------file game.js:----------------

namespacename.gamevalue = 15;

namespacename.game = function(){
    this.callme = function(){
        console.log( "callme" );
    }
}

namespacename.gametest = function() {
    console.log( "gametest:gamevalue:" + this.gamevalue );
    console.log( "gametest:mainvalue:" + this.mainvalue );
}

--------------------------------file index.html:--------------

<html>
    <head>
        <title>testbed</title>
    </head>

    <body onload="init();">
    </body>

    <script type="text/javascript" src="main.js"></script>
    <script type="text/javascript" src="game.js"></script>

    <script type="text/javascript">

        init = function() 
        {
            namespacename.maintest();
            namespacename.gametest();

            console.log( "html main:" + namespacename.mainvalue );
            console.log( "html game:" + namespacename.gamevalue );
        }

   </script>
</html>

2 Comments

Why declare namespacename as an empty function that is never called? You could declare it as an empty object with var namespacename = {} and the rest of your code wouldn't need to change.
If you come from C++, you must know that you will end with dozens and sometimes hundreds or thousands of files. You do not want to request that many js scripts from the server. Insteand it is better to pack all files in 1 script (using webpack for example)
3

Give require.js a shot. http://requirejs.org/

Example:

require(["dir/file"], function() {
    // Called when file.js loads
});

9 Comments

Yes, I looked into it, but I still don't know how I would solve the problem with the shared functions...
But how does that help split up what is currently a large file of interdependent code?
You make a file per class(Hence the OOP tag) and the script that runs simply pull those classes for use. If you show me the code I could help you distribute it across files.
@fabianhjr The code is structured exactly like the sample included in the question. How would you split up that sample? Thanks.
@fabianhjr There is no guessing required. The structure is in the question, as are the specific issues that I'm having with that structure. My question is asking for suggestions on how to fix those issues. If you don't have a suggestion other than calling it a "design issue" why bother responding?
|
2

You can put the shared functions and shared modules on the myApp object so they don't pollute the global namespace, but can be accessed anywhere without being inside the same closure.

myApp.moduleOne = function() {...}
myApp.moduleTwo = function() {...}
myApp.globalFunction = function() {...}

Then, you can define them in any file and use them in any file.

You could also just break the file up into multiple files, but require them to be included in a specific order that preserves your closure. If you're breaking up the files for practical editing reasons, but recombining and minimizing them for actual deployment, then this wouldn't cost you anything in terms of how you write code or how it's deployed, but would give you lots of smaller files for editing convenience.

2 Comments

myApp isn't the real name, I just used it for the example. Given your suggestion, I would need to change each call to globalFunction to myApp.globalFunction() correct?
@MarkBrown - correct. It's a little less desirable when writing code, but gives you more flexibility to segment your code into completely separate files that can be a lot more independent. I added another option to my answer too.
-2

My favorite solution to this is use server side scripting to include the other files inside my "main" file. For example, using Perl's Template Toolkit:

var myApp = function(){
    [% INCLUDE lib/module1.js %]
    [% INCLUDE lib/module2.js %]
    [% INCLUDE lib/module3.js %]
}

Or PHP:

var myApp = function(){
  <?php
    include 'lib/module1.js';
    include 'lib/module2.js';
  ?>
}

2 Comments

That's dynamically build javascript. This should be avoided in favour of static compilation rather then dynamic inclusion.
Both TT and PHP can be run from the console so you can easily write a build script if you want static compilation. Oh, plus TT can be configured to cache files so the compilation only needs to happen once.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.