简体   繁体   English

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

[英]How do I use Backbone.js with Require.js (r.js), but resulting in 2 files after I optimize it?

I have followed the basic tutorials (results in one file after you run r.js ) 我已经按照基本教程(运行r.js后得到一个文件)

The problem is, my main.js file at the end is 500KB. 问题是,我的main.js文件最后是500KB。 That's too big. 那太大了。 I want to split it into two files. 我想把它分成两个文件。

I want to optimize my main.js file into two files: 我想将main.js文件优化为两个文件:

  1. One that holds the front page and user profile pages, since they're most accessed 一个保存首页和用户个人资料页面的页面,因为它们访问最多
  2. One that holds all the other pages (ordering, account settings, profile settings, etc.) 一个包含所有其他页面(订购,帐户设置,配置文件设置等)

Most people will hit the front page and user profile pages, and I want those to load quickly first (while having the other pages load in the background in the 2nd main file) 大多数人会点击首页和用户个人资料页面,我希望首先快速加载(同时在第二个主文件中将其他页面加载到后台)

The problem is, I don't know how to do this. 问题是,我不知道该怎么做。 There are examples like this online , but these examples do not use Backbone. 有这样的例子在线 ,但这些例子不使用Backbone。 They don't cover how to deal with router and app.js 他们没有介绍如何处理路由器和app.js

I'm confused...because I only have one app.js , one router.js ...how can I split router.js into two files? 我很困惑...因为我只有一个app.js ,一个router.js ...我怎么能将router.js分成两个文件?

I don't know how to split my project up when dealing with Backbone. 在处理Backbone时,我不知道如何拆分我的项目。

Below is the code 下面是代码

HTML PAGE (the entry point for my Single Page Application) 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 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 App.js

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

});

Router.js 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
    }
});

As you can see , my entire app starts with main.js , goes to app.js , and finally goes to router.js . 如您所见,我的整个应用程序以main.js ,转到app.js ,最后转到router.js

How can I split this? 我怎么能分开这个?

I've created an example to show how it could be done. 我已经创建了一个示例来说明如何完成它。 It contains a skeleton of Backbone application. 它包含Backbone应用程序的框架。 The application there is split into: 那里的应用程序分为:

  • a main bundle which contains the core of the application and only renders a "main" view (called views/app here), 一个main包,它包含应用程序的核心,只呈现一个“主”视图(在这里称为views/app ),

  • and a secondary bundle which contains all other views. 以及包含所有其他视图的secondary包。

The secondary bundle is loaded only as needed. 仅在需要时加载secondary包。 In this application this means that it should be loaded only when the foo or bar views are used, and not before. 在这个应用程序中,这意味着它应该仅在使用foobar视图时加载,而不是之前加载。 (You can verify this by inspecting network operations in your browser.) (您可以通过检查浏览器中的网络操作来验证这一点。)

The key points are: 关键点是:

  1. The view in views/app is the "main" view of the application. views/app中的视图是应用程序的“主要”视图。 Loading it instantiates and renders the view right away. 加载它会立即实例化并呈现视图。

  2. The js/router module does not use the other views directly. js/router模块不直接使用其他视图。 It calls require to load the view first. 它调用require首先加载视图。 This makes the foo and bar function asynchronous. 这使得foobar函数异步。

  3. This is the part of the build.js file that divides the application into two bundles: 这是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. The optimized version needs an initial configuration like this: 优化版需要像这样的初始配置:

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

    This tells RequireJS that the modules views/foo and views/bar are loaded by loading secondary . 这告诉RequireJS通过加载secondary来加载模块views/fooviews/bar

Please read the README.md file for more details. 请阅读README.md文件以获取更多详细信息。

Based on the code you have shared, I've created a sample web-app and committed the code in git-hub . 根据您共享的代码,我创建了一个示例Web应用程序并将代码提交到git-hub

Application is divided into 2 modules: 申请分为2个模块:

  • main : contains modules/index/view and modules/profile/view maincontains modules/index/viewmodules/profile/view
  • other : contains 'modules/order/view and modules/search/view othercontains 'modules/order/viewmodules/search/view

When you request for modules/index/view or modules/profile/view , main.js is downloaded if not downloaded yet. 当您请求modules/index/viewmodules/profile/view ,如果尚未下载, main.js下载main.js Similarly when request is placed for modules/order/view or modules/search/view , other.js is downloaded if not downloaded yet. 类似地,当对modules/order/viewmodules/search/view发出请求时,如果尚未下载,则下载other.js Remember to use require.js v2.1.10 or greater, as it has bundle feature which is required for generating other.js . 请记住使用require.js v2.1.10或更高版本,因为它具有生成other.js所需的包功能。

You can further modularize it by defining order, search, profile as independent modules in build.js , so that they are downloaded only when needed. 您可以通过在build.js order, search, profile定义为独立模块来进一步模块化,以便仅在需要时下载它们。

Output of executing build command : 执行构建命令的输出:

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

The execution flow goes like this: index.html => media/js/main [it has index/view, profile/view, app.js and all the dependencies]. 执行流程如下: index.html => media/js/main [它有index/view, profile/view, app.js和所有依赖项]。 By default Index view is shown, as it is configured for home route. 默认情况下,显示索引视图,因为它是为主路由配置的。

When Profile links is clicked, no more files are downloaded, as main.js is already downloaded. 单击“配置文件”链接时,不再下载任何文件,因为已下载main.js When Search / Order links are clicked, other.js is downloaded. 单击“搜索/订购”链接时,将下载other.js

In your build profile you can specify how many modules do you want to create and which dependencies they have to include (see http://requirejs.org/docs/optimization.html#basics ). 在构建配置文件中,您可以指定要创建的模块数量以及它们必须包含的依赖项(请参阅http://requirejs.org/docs/optimization.html#basics )。

You can see the options here https://github.com/jrburke/r.js/blob/master/build/example.build.js , the part you're interested in starts on line 350. 你可以在https://github.com/jrburke/r.js/blob/master/build/example.build.js看到这些选项,你感兴趣的部分从第350行开始。

Also see How to use RequireJS build profile + r.js in a multi-page project for a deeper answer 另请参阅如何在多页项目中使用RequireJS构建配置文件+ r.js以获得更深入的答案

Splitting the code into two files is not the way to go. 将代码拆分为两个文件是不可取的。

Splitting the code into two files will only increase load times overall, as extra wrapper code would be needed. 将代码拆分为两个文件只会增加整体加载时间,因为需要额外的包装代码。 Also, splitting the code may unnecessarily increase the modularity of the code, causing design problems in future. 此外,拆分代码可能会不必要地增加代码的模块性,从而导致将来出现设计问题。

The way to go would to be to lazy-load the routed files (so you load your front page and user profile pages first), and then you can load the other files in the background after you've done loading the front page and user profile pages. 要做的就是延迟加载路由文件(这样你首先加载首页和用户配置文件页面),然后你可以在加载首页和用户后在后台加载其他文件个人资料页面

It is possible to split it - don't get me wrong - but doing so would just create unnecessary code, and really wouldn't help. 可以将它拆分 - 不要误解我的意思 - 但这样做会产生不必要的代码,实际上也无济于事。

Here a link that may help. 这里有一个可能有用的链接。

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

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