简体   繁体   English

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

[英]How do you organize large JS/jQuery code bases across your entire website?

How do you organize large JS/jQuery codebases across your entire website? 你如何在整个网站上组织大型JS / jQuery代码库? 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. 关于如何组织代码片段有很多很好的资源,但没有真正关于如何将它们整合在一起并使每个部分适合到位:侧面广泛的代码组织,使用相同代码的多个页面,保持松散耦合的DRY,等等

Below is how I deal with it. 以下是我如何处理它。 I've never been comfortable 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. 将每个页面命名为一个全局对象是一个好主意吗?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. 每个页面都会收到主application.js文件。 Each additional page has it's own application.pagename.js file. 每个附加页面都有自己的application.pagename.js文件。 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. 我使用服务器端逻辑来包含文件(首先检查页面是否存在 - 某些页面不需要JS),然后按顺序初始化它们。

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/. 我的URL约定是/ page / subpage / id /。 I have about 10 pages and a whole slew of subpages, each subpage requiring their own logic. 我有大约10页和一大堆子页面,每个子页面都需要自己的逻辑。 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. 我的大部分代码已经模块化为jQuery UI小部件或jQuery插件,所以我要说这些文件中75%的代码都需要()来创建一个小部件并启动它。

I use requireJS to pull in widgets as necessary. 我根据需要使用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(){
        }
    }
};

To help me answer your specific questions, please allow me talk a little about JavaScriptMVC 's features: 为了帮助我回答您的具体问题,请允许我谈谈JavaScriptMVC的一些功能:

Controller will improve your jQuery widgets, taking care of setup / teardown, extensibility. Controller将改进你的jQuery小部件,负责设置/拆卸,可扩展性。

View adds client side templates that can be built into your app. View添加了可以内置到您的应用程序中的客户端模板。

Model abstracts the service / data layer minimizing and localizing JS changes if your server changes. 如果服务器发生更改, 模型会抽象化服务/数据层,从而最大限度地减少和更改JS更改。

Steal does dependency management, compression, and code cleaning. Steal执行依赖关系管理,压缩和代码清理。 It will even take all your scripts across all your pages, figure out shared dependencies, and combine scripts into an optimal payload. 它甚至可以覆盖所有页面中的所有脚本,找出共享依赖项,并将脚本组合到最佳有效负载中。

FuncUnit makes testing your apps as easy as possible. FuncUnit使您的应用程序测试尽可能简单。

DocumentJS ... well ... documents your code DocumentJS ......好......记录你的代码

.

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. 我使用StealJS的依赖管理系统将我需要的功能加载到我的页面中。 Dependency management is absolutely necessary on apps of a certain size. 对于特定大小的应用程序,依赖管理是绝对必要的。 RequireJS is a good choice if you are able to build it easily. 如果您能够轻松构建RequireJS,那么它是一个不错的选择。

How do you organize page specific code 你如何组织页面特定的代码

Page specific code should be as small as possible. 页面特定代码应尽可能小。 It typically involves loading dependencies and a "MainController". 它通常涉及加载依赖项和“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. StealJS可以帮助您获得非常佳的加载时间,但由于页面数量较多,您必须偏离JavaScriptMVC的标准文件夹组织。

RequireJS is more flexible, but you're going to have to load a lot of files. RequireJS更灵活,但您将不得不加载大量文件。 Not only will this be slow, this is going to start making you create lots of big JS files that aren't very organized. 这不仅会很慢,而且会开始让你创建大量不太有条理的大JS文件。

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. 但是要真正扩展开发,你真的需要一些东西,它允许你将你的应用分成几个小部分,轻松加载这些部分,并以某种方式使应用程序仍然在生产中快速运行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM