你如何在整个网站上组织大型JS/jQuery代码库?

ehy*_*nds 42 javascript jquery

你如何在整个网站上组织大型JS/jQuery代码库?关于如何组织代码片段有很多很好的资源,但没有真正关于如何将它们整合在一起并使每个部分适合到位:侧面广泛的代码组织,使用相同代码的多个页面,保持松散耦合的DRY,等等

以下是我如何处理它.我从来都不习惯像这样组织我的代码,因为我认为它很草率并且可能导致可维护性/扩展问题,但我真的不知道更好.

我意识到我每个人都有他们自己的要求,而且没有交钥匙的解决方案,但我很想听到一些关于我做错了什么的意见,为什么我做错了,以及如何写更多的建议可维护的代码.

我认为我真正想要的是:

  1. 您如何处理需要在多个页面,多个页面上使用的逻辑?

  2. 你如何组织特定于页面的代码?将每个页面命名为一个全局对象是一个好主意吗?1.

  3. 您从一开始就做了什么,以确保随着您的应用变得越来越大,您不会不断重写您的组织模式?我可能在第四次迭代写这个东西.

每个页面都会收到主application.js文件.每个附加页面都有自己的application.pagename.js文件.我使用服务器端逻辑来包含文件(首先检查页面是否存在 - 某些页面不需要JS),然后按顺序初始化它们.

所以我的主页看起来像:

<script src="js/application.js"></script>
<script src="js/application.index.js"></script>
<script>
    MyApp.init();
    MyApp.index.init();
</script>
Run Code Online (Sandbox Code Playgroud)

我的URL约定是/ page/subpage/id /.我有大约10页和一大堆子页面,每个子页面都需要自己的逻辑.看这篇文章的最后一个例子.

我的大多数代码已经模块化为jQuery UI小部件或jQuery插件,所以我要说这些文件中75%的代码都需要()来创建一个小部件并启动它.

我根据需要使用requireJS来拉入小部件.

// 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(){
        }
    }
};
Run Code Online (Sandbox Code Playgroud)

Jus*_*yer 12

为了帮助我回答您的具体问题,请允许我谈谈JavaScriptMVC的一些功能:

Controller将改进你的jQuery小部件,负责设置/拆卸,可扩展性.

View添加了可以内置到您的应用程序中的客户端模板.

如果服务器发生更改,模型会抽象化服务/数据层,从而最大限度地减少和更改JS更改.

Steal执行依赖关系管理,压缩和代码清理.它甚至可以覆盖所有页面中的所有脚本,找出共享依赖项,并将脚本组合到最佳有效负载中.

FuncUnit使您的应用程序测试尽可能简单.

DocumentJS ......好......记录你的代码

.

现在就您的具体问题:

如何处理多个地方使用的逻辑?

我使用StealJS的依赖管理系统将我需要的功能加载到我的页面中.对于特定大小的应用程序,依赖管理是绝对必要的.如果您能够轻松构建RequireJS,那么它是一个不错的选择.

你如何组织页面特定的代码

页面特定代码应尽可能小.它通常涉及加载依赖项和"MainController".该主控制器将页面配置为遵守该页面的功能/业务要求.它通常被命名为:

App.Controllers.Main
Run Code Online (Sandbox Code Playgroud)

你怎么停止写相同的模式

好吧,我建议使用一个具有稳定模式进行开发的框架.此外,尽可能保持模块/插件/小部件的小(和可测试).这将使这些部件更改的可能性更小.

终于....

看来你最大的斗争紧张关系:

  • 共享功能
  • 多页
  • 及时加载时间

因此选择一个可靠的依赖管理工具是非常关键的.StealJS可以帮助您获得非常佳的加载时间,但由于页面数量较多,您必须偏离JavaScriptMVC的标准文件夹组织.

RequireJS更灵活,但您将不得不加载大量文件.这不仅会很慢,而且会开始让你创建大量不太有条理的大JS文件.

如果您对加载时间感到满意并且觉得它们不会导致您将代码压缩到不属于的文件中,那么您当前的解决方案似乎会起作用.

我认为可维护开发的秘诀在于您的系统/框架可以轻松地隔离问题.将应用程序分解为尽可能小的部分非常重要.另外,您应该测试这些部件.人们通过思考他们的页面功能来获得侧面跟踪.但是要真正扩展开发,你真的需要一些东西,它允许你将应用程序分解成很小的部分,轻松加载这些部分,并以某种方式使应用程序仍然在生产中快速运行.

  • 澄清一下:RequireJS可能在开发期间加载单个文件,但它有一个优化工具(http://requirejs.org/docs/optimization.html),允许您将模块优化/分组为一小组HTTP请求.优化工具也可以在开发中使用,它有一种方法可以只排除您可能想要自己调试的某些模块. (2认同)