rg88
rg88

Reputation: 20977

Convert a large javascript file into multiple files

My question: How would one best go about breaking a large, monolithic javascript object literal into multiple, discrete, files?

I have a single javascript file that consists of an object literal with many methods attached to it. It's getting quite long and I want to break it into smaller parts that can more easily be managed.

I've heard I can use AMD or CommonJS to organize things, I've heard I should use RequireJS, that I should use Webpack or Browserify, that I should use any number of other tools/techniques. After looking at these things I am confused as to what the best approach is.

How would you do it? How would you take a single object literal consisting of a few thousands lines of javascript (made up of functions like "search" and "login" and "user") and reorganize it into multiple files that are more easily dealt with by a group of developers? The single, giant file thing is just getting to unwieldy and the options seems to varied and unclear. This is a fairly simple app that uses vanilla JS, a little jQuery and sits on top of a Grails backend.

I think the question is pretty clear but if you really need code to look at here is an example of the sort of object literal I am talking about:

var myObj = {

    foo: "one",
    bar: "two",
    baz: false,
    deez: -1,

    login: function() {
        // lots and lots of code
    },

    user: function() {
        // lots and lots of code
    },

    beers: function() {
        // lots and lots of code
    },

    varieties: function() {
        // lots and lots of code
    }

    init: function() {
        myObj.login.init();
        myObj.user.init();
        // lots of jQuery document.ready stuff
    }
}

myObj.init();

Upvotes: 3

Views: 3103

Answers (3)

Greg Pettit
Greg Pettit

Reputation: 10830

Here's the pattern I use:

  • When possible, break concepts into their own sub-object
  • Regardless of sub-objects or not, declare any non-broken-up properties first, then add to it as needed
  • If the files are across multiple files and you do not wish to use sub-objects per-file, use a temporary object to hold additional properties, and then extend the original.

Sample:

var myObj = {
  foo: "one",
  bar: "two",
  baz: false,
  deez: -1
}

myObj.login = function() {
    // lots and lots of code
};

myObj.user = function() {
    // lots and lots of code
};

myObj.drinks = {
  beer: function() {},
  wine: function() {},
  sunnyDelight: {
    drinkIt: function() {},
    burp: function() {}
  }
};

myObj.init = function() {
  myObj.login.init();
  myObj.user.init();
  // lots of jQuery document.ready stuff
}

myObj.init();

Note that "drinks" is a concept unto itself, containing multiple properties and methods. Your concepts might be something like "ui", "utils", "data" or whatever the role of the contained properties happens to be.

For the extend point I made, there's not much code needed there either

// "utilities.js"
var myObj = {
  // a bunch of properties and/or methods
};

myObj.moreStuff = "more stuff!";

and then in another file you have two choices. Either add to the object without overwriting it (you will need the dot-notation to do this):

// "ui.js"
var myObj = myObj || {};

// adds the render object to the existing myObj
myObj.render = {
  header: function() {},
  dialogBox: function() {}
}

The above works particularly well if you sub-divide your concepts... because you can still have fairly monolithic objects that will not trample over the rest of myObj. But maybe you want to add directly to myObj without trampling and without subdividing concerns:

// "ui.js"
var myObj = myObj || {};

// ultimately, the CONTENTS of this object get merged into the existing myObj
var myObjSupplement = {
  header: function() {},
  dialogBox: function() {},
  heroBiscuit: "A yummy biscuit made from heroes!"
}

// using jQuery here, but it's not the only way to extend an object
$.extend(myObj, myObjSupplement)

I don't see TOO many opportunities to use the above, since myObjSupplement is now in the global namespace and defeats the purpose of limiting additions to the global namespace, but it's there if you need it.

[edited to add: ]

It might not go "without saying" as I thought-- but dividing into many different files probably works best if you have a build process in place that can concatenate them into one file suitable for minifying. You don't want to have 100 or even 6 separate files each requiring a synchronous HTTP call to fetch.

There are more modern and possibly 'better' approaches with technologies like AMD/RequireJS... but if the question is, "how do I divide up an object literal into several files", the above answer I've given is one I can stand behind.

Upvotes: 1

David Gomez
David Gomez

Reputation: 2772

You will a lot of suggestions and approaches to solve your problems, and I can't say any of them are wrong, they are just different.

My approach would be to use ES6 and its native module support.

To accomplish this I always use my own boilerplate named fabric which uses Webpack to compile the modules, Browsersync to help you on your development, Tape for unit testing, SASS for your CSS preprocessing, and Babel to compile a compatible ES5 bundle that you can easily use in your application.

Now, the way to use the ES6 modules is something like this with named exports:

//------ lib.js ------
export const sqrt = Math.sqrt;
export function square(x) {
    return x * x;
}
export function diag(x, y) {
    return sqrt(square(x) + square(y));
}

//------ main.js ------
import { square, diag } from 'lib';
console.log(square(11)); // 121
console.log(diag(4, 3)); // 5

Or using default exports:

//------ myFunc.js ------
export default function () { ... };

//------ main1.js ------
import myFunc from 'myFunc';
myFunc();

You can learn more about ES6 modules at 2ality

Upvotes: 2

Brandon Roberts
Brandon Roberts

Reputation: 74

While there are automated ways of doing this I'm sure, and I am also interested in seeing the answers this question gets, I would recommend simply going in and moving the method definitions into different files and calling the functions normally method(param); and linking the files to your html page.

This would serve multiple purposes, including the one you are looking to acheive of breaking your code down into more manageable modules. Among those purposes also include the fact that instead of having those definitions written to memory for every instance of the object, you would only define it once and make references to it whenever you need it.

Sorry I can't be of more help without actually seeing the JavaScript File.

You can reference this stack overflow example if you need more guidance in achieving this.

You don't have to have all of the methods defined in your objects or classes, it's better to modularize these methods into different files and use the <script src="path/to/your/script.js"> </script> tags to include them all with your html/php page

Upvotes: 0

Related Questions