如何将Backbone.js与Require.js(r.js)一起使用,但在优化后会产生2个文件?

时间:2014-04-02 20:40:24

标签: javascript html backbone.js requirejs r.js

我已经按照基本教程(运行r.js后的结果生成一个文件)

问题是,我最后的main.js文件是500KB。那太大了。我想把它分成两个文件。

我想将main.js文件优化为两个文件:

  1. 保存首页和用户个人资料页面的页面,因为他们访问次数最多
  2. 包含所有其他页面的内容(订购,帐户设置,配置文件设置等)
  3. 大多数人会点击首页和用户个人资料页面,我希望首先快速加载(同时在第二个主文件中将其他页面加载到后台)

    问题是,我不知道该怎么做。有examples like this online,但这些示例不使用Backbone。他们没有介绍如何处理路由器和app.js

    我很困惑...因为我只有一个app.js,一个router.js ...我怎么能将router.js分成两个文件?

    在处理Backbone时,我不知道如何拆分我的项目。

    以下是代码

    HTML PAGE(我的单页应用程序的入口点)

    <html>
    <head>
        <script type="text/javascript" data-main='/media/js/main' src='/media/js/lib/requirejs/require-jquery.js'></script>
    </head>
    <body>
        Hello
    </body>
    </html>
    

    Main.js

    require.config({
        paths:{
            jquery: 'lib/requirejs/require-jquery',
            jquery_ui:'lib/jquery-ui/jquery-ui-1.10.3.custom',
            underscore: 'lib/underscore/underscore-min',
            backbone:'lib/backbone/backbone-min',
            backbone_viewhelper:'lib/backbone/backbone.viewhelper',
            text: 'lib/requirejs/text',
            birthdaypicker: 'lib/birthdaypicker/bday-picker',
            //more paths
        },
        waitSeconds: 30,
        shim:{
            'underscore':{
                exports: '_'
            },
            'backbone':{
                deps:[ 'underscore', 'jquery'],
                exports: 'Backbone'
            },
            'backbone_viewhelper':{
                deps:['underscore','backbone']
            }
        }
    });
    
    
    require([
        'app',
        'json2',
        'jquery_ui',
        'backbone_viewhelper',
        'bootstrap_js',
        'bootstrap_select',
        'birthdaypicker',
        'accounting',
        'numbersonly',
        'main_alert',
        'string_tools',
        'plupload',
        //more things here
    ], function(App){
        App.initialize();
    });
    

    App.js

    define([
        'jquery',
        'underscore',
        'backbone',
        'router'
    ], function($, _, Backbone, Router){    
        var initialize = function(){
            Router.initialize();
        }
        return {
            initialize: initialize
        };
    
    });
    

    Router.js

    define([
        'jquery',
        'underscore',
        'backbone',
        'modules/index/view',
        'modules/home/view',
        'modules/listings_search/view',
        'modules/profile/view',
        //more modules
    ], function($, _, Backbone, indexView, homeView,searchView, profileView){
        var AppRouter = Backbone.Router.extend({
            initialize:function(){
                _.bindAll(this);
            },
            routes:{
                '':'index',
                'home': 'home',
                'register': 'register',
                'login': 'login',
                'listings(/start/:start)(/num/:num)': 'search',
                'listings/create': 'listingsCreate',
                'listings/:listing_id/edit': 'listingsEdit',
                'orders/listings/:listing_id/create': 'ordersCreate',
                'orders/buyer(/start/:start)(/num/:num)': 'ordersListBuyer',
                'orders/seller(/start/:start)(/num/:num)': 'ordersListSeller',
                'orders/:order_id': 'orders',
                'orders/:order_id/messages':'messages',
                '*actions': 'defaultAction'
                //more stuff
            },
            index:function(){
                app_router_view.show(indexView);
            },
            search:function(start, num){
                var options = {
                    filters:{
                        start: start,
                        num: num
                    }
                };
                app_router_view.show(searchView, options);
            },
            static:function(template){
                app_router_view.show(staticView, { static_view: { template: template }});
            },
            profile:function(){
                app_router_view.show(profileView);
            },
            passResetCode:function(code){
                app_router_view.show(passCodeView, {'code':code});
            },
            //more stuff
            home:function(){
                app_router_view.show(homeView);
            },
            defaultAction:function(actions){
                this.navigate('/', { trigger:true});
            }
        });
        var initialize = function(){
            var app_router = new AppRouter;
            Backbone.history.start({pushState:true, root: '/'});
            $(document).on('click', 'a:not([data-bypass])', function (evt) {
                var href = $(this).attr('href');
                if(href){
                    var protocol = this.protocol + '//';
                    if (href.slice(protocol.length) !== protocol && href != '#') {
                        evt.preventDefault();
                        app_router.navigate(href, { trigger: true});
                    }
                }else{
                }
            });
        };
        return {
            initialize:initialize
        }
    });
    

    正如您所看到的,我的整个应用都以main.js开头,转到app.js,最后转到router.js

    我怎么能分开这个?

4 个答案:

答案 0 :(得分:3)

我创建了an example来展示如何完成它。它包含Backbone应用程序的框架。那里的申请分为:

  • 一个main包,其中包含应用程序的核心 呈现“主”视图(此处称为views/app),

  • 以及包含所有其他观点的secondary捆绑包。

仅在需要时加载secondary包。在此应用程序中,这意味着只应在使用foobar视图时加载它,而不是之前加载。 (您可以通过检查浏览器中的网络操作来验证这一点。)

关键点是:

  1. views/app中的视图是该视图的“主要”视图 应用。加载它实例化并呈现正确的视图 程。

  2. js/router模块不直接使用其他视图。它 调用require首先加载视图。 这会使foo和。{ bar函数异步。

  3. 这是build.js文件的一部分 应用到两个包中:

    modules: [
        {
            name: "main"
        },
        {
            name: "secondary",
            // There no module named secondary in the source, so create it.
            create: true,
            // Make sure to include all the views other than the main one.
            include: [
                "views/foo",
                "views/bar"
            ],
            // Exclude everything we've included in `main`.
            exclude: ["main"]
        }
    ]
    
  4. 优化版需要像这样的初始配置:

      bundles: {
         "secondary": ["views/foo", "views/bar"]
      }
    

    这告诉RequireJS模块views/fooviews/bar 通过加载secondary加载。

  5. 请阅读README.md文件了解详情。

答案 1 :(得分:3)

根据您共享的代码,我创建了一个示例网络应用,并在git-hub中提交了代码。

申请分为两个模块:

  • maincontains modules/index/viewmodules/profile/view
  • othercontains 'modules/order/viewmodules/search/view

当您请求modules/index/viewmodules/profile/view时,如果尚未下载,则会下载main.js。同样,当modules/order/viewmodules/search/view发出请求时,如果尚未下载,则会下载other.js。请务必使用require.js v2.1.10或更高版本,因为它具有生成other.js所需的捆绑功能。

您可以通过在order, search, profile中将build.js定义为独立模块来进一步对其进行模块化,以便仅在需要时下载它们。

执行构建命令的输出:

media/js/main.js
----------------
media/js/lib/jquery/jquery-min.js
media/js/lib/underscore/underscore-min.js
media/js/lib/backbone/backbone-min.js
media/js/router.js
media/js/app.js
media/js/main.js
media/js/modules/index/model.js
media/js/modules/index/view.js
media/js/modules/profile/model.js
media/js/modules/profile/view.js

media/js/other.js
----------------
media/js/modules/order/model.js
media/js/modules/order/view.js
media/js/modules/search/model.js
media/js/modules/search/view.js

执行流程如下: index.html => media/js/main [它有index/view, profile/view, app.js和所有依赖项]。默认情况下,将显示“索引”视图,因为它是为主路由配置的。

单击“配置文件”链接时,不再下载任何文件,因为已下载main.js。 单击“搜索/订购”链接时,将下载other.js

答案 2 :(得分:0)

在您的构建配置文件中,您可以指定要创建的模块数量以及它们必须包含的依赖项(请参阅http://requirejs.org/docs/optimization.html#basics)。

您可以在此处看到https://github.com/jrburke/r.js/blob/master/build/example.build.js选项,您对第350行开始感兴趣的部分。

另请参阅How to use RequireJS build profile + r.js in a multi-page project以获得更深入的答案

答案 3 :(得分:0)

将代码分成两个文件是不可能的。

将代码拆分为两个文件只会增加整体加载时间,因为需要额外的包装代码。此外,拆分代码可能会不必要地增加代码的模块性,从而导致将来出现设计问题。

可行的方法是延迟加载路由文件(因此首先加载首页和用户个人资料页面),然后在完成加载后可以在后台加载其他文件首页和用户个人资料页面。

分割它是可能的 - 不要误解我的意思 - 但这样做只会产生不必要的代码,而且真的无济于事。

Here a link that may help.