最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How do you organize large JSjQuery code bases across your entire website? - Stack Overflow

programmeradmin6浏览0评论

How do you organize large JS/jQuery codebases across your entire website? There are plenty of good resources on how to organize pieces of your code, but nothing really about how to pull it all together and fit each piece into place: side wide code organization, multiple pages using the same code, staying DRY with loose coupling, etc.

Below is how I deal with it. I've never been fortable organizing my code like this, because I think it's sloppy and can lead to maintainability/scaling problems, but I don't really know any better.

I realize I everyone has their own set of requirements and there’s no turn-key solutions, but I’d love to hear some opinions about what I’m doing wrong, WHY I’m doing it wrong, and suggestions on how to write more maintainable code.

What I think I’m really trying to get at:

  1. How do you deal with logic that you need to use in multiple places, on multiple pages?

  2. How do you organize page-specific code? Is namespacing each page into a global object a good idea?1.

  3. What do you do from the start to ensure you’re not constantly re-writing your organization patterns as your app grows larger and larger? I’m probably on my 4th iteration writing this thing.2.

Each page receives the main application.js file. Each additional page has it's own application.pagename.js file. I use server side logic to include the files (first checking to see if one even exists for the page - some pages don't need JS), and then init them in order.

So my home page looks like:

<script src="js/application.js"></script>
<script src="js/application.index.js"></script>
<script>
    MyApp.init();
    MyApp.index.init();
</script>

my URL convention is /page/subpage/id/. I have about 10 pages and a whole slew of subpages, each subpage requiring their own logic. see the last example in this post.

Most of my code is already modularized into either jQuery UI widgets or jQuery plugins, so I'd say 75% of the code in these files is require()'ing a widget and initing it.

I use requireJS to pull in widgets as necessary.

// application.js
var MyApp = {
    init: function(){
        var self = this;

        // these widgets are available on every single page
        // notice the call to jquery.deparam.js - i'll use this later to init subpage logic.
        require(['js/widget1.js', 'js/widget2.js', 'js/widget3.js', 'js/jquery.deparam.js'], function(){

            // deparam the query string.  I'll use this later.
            self.querystring = $.deparam.querystring();

            // init widgets once the document is ready
            $(function(){
                $("#widget1").widget1();
                $("#widget2").widget2();

                // make these bindings available immediately as well.
                self.rebindable();
            });
        });
    },

    // I use jQuery UI Dialog extensively as a window manager, and each dialog is loaded
    // via an AJAX request.  I'll call this method after each AJAX request to
    // rebind some key widgets.
    rebindable: function(){
        $("#widget3").widget3();
    }
};

// application.index.js
// home page specific stuff.  this file is only included on the home page.
MyApp.index = {

    // my convention is that init is automatically called after the script
    // is included in a page, outside of a doc.ready statement.
    init: function(){
        var self = this;

        require(['js/widget4.js'], function(){
            $(function(){
                self.widget4( $("#foo") );
            });
        });
    },

    // passing elements to each method allows me to call this init code
    // outside of the index page.  I can require() this file, and only init
    // widget4, and even use a different element.
    widget4: function( element ){
        var config = {
            something: "custom to the home page"
        };

        element.widget4( config );
    }
};


// application.foo.js
// page "foo" stuff
MyApp.foo = {

    init: function(){
        var self = this;

        // this page happens to use the same widget3 and configuration present 
        // in MyApp.index.  this is where things can get sloppy and unmaintainable
        // really quickly.
        require(['js/application.index.js'], function(){
            $(function(){
                MyApp.index.widget3( $("#bar") );
            });
        });

        // page "foo" has three subpages (or actions) and require
        // their own logic.  url convention:  /foo/subpage1/
        // init whichever page we're on...
        switch( self.querystring.subpage ){
            case "subpage1":
                self.subpage1.init();
                break;
            case "subpage2":
                self.subpage2.init();
                break;
            case "subpage3":
                self.subpage3.init();
                break;
        }
    },

    subpage1: function(){
        init: function(){
            var self = this;

            // once the DOM is ready init dialog.
            $(function(){
                self.dialog( $("#openDialog") );
            });
        },

        dialog: function( element ){
            element.bind("click", function(){
                $('<div></div>').dialog({
                    open: function(){

                        // see what i'm doing here?
                        MyApp.rebindable();

                        // maybe more bindings specific to this
                        // dialog here
                    }
                });
            });
        }
    },

    subpage2: function(){
        init: function(){
        }
    },

    subpage3: function(){
        init: function(){
        }
    }
};

How do you organize large JS/jQuery codebases across your entire website? There are plenty of good resources on how to organize pieces of your code, but nothing really about how to pull it all together and fit each piece into place: side wide code organization, multiple pages using the same code, staying DRY with loose coupling, etc.

Below is how I deal with it. I've never been fortable organizing my code like this, because I think it's sloppy and can lead to maintainability/scaling problems, but I don't really know any better.

I realize I everyone has their own set of requirements and there’s no turn-key solutions, but I’d love to hear some opinions about what I’m doing wrong, WHY I’m doing it wrong, and suggestions on how to write more maintainable code.

What I think I’m really trying to get at:

  1. How do you deal with logic that you need to use in multiple places, on multiple pages?

  2. How do you organize page-specific code? Is namespacing each page into a global object a good idea?1.

  3. What do you do from the start to ensure you’re not constantly re-writing your organization patterns as your app grows larger and larger? I’m probably on my 4th iteration writing this thing.2.

Each page receives the main application.js file. Each additional page has it's own application.pagename.js file. I use server side logic to include the files (first checking to see if one even exists for the page - some pages don't need JS), and then init them in order.

So my home page looks like:

<script src="js/application.js"></script>
<script src="js/application.index.js"></script>
<script>
    MyApp.init();
    MyApp.index.init();
</script>

my URL convention is /page/subpage/id/. I have about 10 pages and a whole slew of subpages, each subpage requiring their own logic. see the last example in this post.

Most of my code is already modularized into either jQuery UI widgets or jQuery plugins, so I'd say 75% of the code in these files is require()'ing a widget and initing it.

I use requireJS to pull in widgets as necessary.

// application.js
var MyApp = {
    init: function(){
        var self = this;

        // these widgets are available on every single page
        // notice the call to jquery.deparam.js - i'll use this later to init subpage logic.
        require(['js/widget1.js', 'js/widget2.js', 'js/widget3.js', 'js/jquery.deparam.js'], function(){

            // deparam the query string.  I'll use this later.
            self.querystring = $.deparam.querystring();

            // init widgets once the document is ready
            $(function(){
                $("#widget1").widget1();
                $("#widget2").widget2();

                // make these bindings available immediately as well.
                self.rebindable();
            });
        });
    },

    // I use jQuery UI Dialog extensively as a window manager, and each dialog is loaded
    // via an AJAX request.  I'll call this method after each AJAX request to
    // rebind some key widgets.
    rebindable: function(){
        $("#widget3").widget3();
    }
};

// application.index.js
// home page specific stuff.  this file is only included on the home page.
MyApp.index = {

    // my convention is that init is automatically called after the script
    // is included in a page, outside of a doc.ready statement.
    init: function(){
        var self = this;

        require(['js/widget4.js'], function(){
            $(function(){
                self.widget4( $("#foo") );
            });
        });
    },

    // passing elements to each method allows me to call this init code
    // outside of the index page.  I can require() this file, and only init
    // widget4, and even use a different element.
    widget4: function( element ){
        var config = {
            something: "custom to the home page"
        };

        element.widget4( config );
    }
};


// application.foo.js
// page "foo" stuff
MyApp.foo = {

    init: function(){
        var self = this;

        // this page happens to use the same widget3 and configuration present 
        // in MyApp.index.  this is where things can get sloppy and unmaintainable
        // really quickly.
        require(['js/application.index.js'], function(){
            $(function(){
                MyApp.index.widget3( $("#bar") );
            });
        });

        // page "foo" has three subpages (or actions) and require
        // their own logic.  url convention:  /foo/subpage1/
        // init whichever page we're on...
        switch( self.querystring.subpage ){
            case "subpage1":
                self.subpage1.init();
                break;
            case "subpage2":
                self.subpage2.init();
                break;
            case "subpage3":
                self.subpage3.init();
                break;
        }
    },

    subpage1: function(){
        init: function(){
            var self = this;

            // once the DOM is ready init dialog.
            $(function(){
                self.dialog( $("#openDialog") );
            });
        },

        dialog: function( element ){
            element.bind("click", function(){
                $('<div></div>').dialog({
                    open: function(){

                        // see what i'm doing here?
                        MyApp.rebindable();

                        // maybe more bindings specific to this
                        // dialog here
                    }
                });
            });
        }
    },

    subpage2: function(){
        init: function(){
        }
    },

    subpage3: function(){
        init: function(){
        }
    }
};
Share Improve this question edited Sep 8, 2010 at 14:38 ehynds asked Sep 8, 2010 at 14:05 ehyndsehynds 4,4633 gold badges26 silver badges23 bronze badges 4
  • 1 I was thinking about this myself this week. I recently joined a project team as the main javascript coder. The project has been going for over a year already so they have javascript all over the place. They have accumulated an extensive javascript library and made some effort to use namespaces, but a lot of pages have custom javascript that not only is written in pages and user controls but also some that is generated based on page or user control data. I have the daunting task of making sense of it all and trying to standardize as much as possible. – Silkster Commented Sep 8, 2010 at 14:41
  • (continued) Your method is a good start, but I can see where it can unmaintainable. Maybe you can devise a method for configuring pages and controls so that you don't have to use many switch statements. You might also check out Claypool (http://www.claypooljs.) to see if that might help. – Silkster Commented Sep 8, 2010 at 14:46
  • 1 @Silkster the link is broken: http//www.claypooljs. – Prisoner ZERO Commented May 19, 2011 at 11:38
  • Looks like it moved to the jQuery site: docs.jquery./Plugins/Claypool – Silkster Commented May 27, 2011 at 18:09
Add a ment  | 

1 Answer 1

Reset to default 13

To help me answer your specific questions, please allow me talk a little about JavaScriptMVC's features:

Controller will improve your jQuery widgets, taking care of setup / teardown, extensibility.

View adds client side templates that can be built into your app.

Model abstracts the service / data layer minimizing and localizing JS changes if your server changes.

Steal does dependency management, pression, and code cleaning. It will even take all your scripts across all your pages, figure out shared dependencies, and bine scripts into an optimal payload.

FuncUnit makes testing your apps as easy as possible.

DocumentJS ... well ... documents your code

.

Now on your specific questions:

How to deal with logic used in multiple places?

I use StealJS's dependency management system to load the functionality I need into my page. Dependency management is absolutely necessary on apps of a certain size. RequireJS is a good choice if you are able to build it easily.

How do you organize page specific code

Page specific code should be as small as possible. It typically involves loading dependencies and a "MainController". That main controller configures the page to obey the functional / business requirements of that page. It's typically namespaced as something like:

App.Controllers.Main

how do you stop writing the same patterns

Well, I suggest using a framework that has stable patterns for development. Also, keep your modules / plugins / widgets as small (and testable) as possible. This will make these parts much less likely to change.

Finally ....

It seems your biggest struggle tension between:

  • shared functionality
  • multiple pages
  • timely load times

So picking a solid dependency management tool is super critical. StealJS could help you get very optimal loading times, but you'd have to stray from JavaScriptMVC's standard folder organization due to your larger number of pages.

RequireJS is more flexible, but you're going to have to load a lot of files. Not only will this be slow, this is going to start making you create lots of big JS files that aren't very organized.

If you are happy with the loading times and feel like they won't cause you to squeeze code into files it doesn't belong, your current solution seems like it will work.

I think the secret to maintainable development is how easy your system/framework allows you to isolate concerns. It's important to break up your app into the smallest parts possible. Plus, you should be testing these parts. People get side-tracked by thinking about their pages functionality. But to really scale development you really need something that allows you to break up your app into little parts, load those parts easily, and somehow get the app to still run fast in production.

发布评论

评论列表(0)

  1. 暂无评论