How to synchronise/organise modules using requirej

2019-03-22 13:00发布

问题:

I organised the file structure of my web app, which is using RequireJs and Backbone.Marionette,in this way:

|- main.js
|- app.js
|- /subapp1
    |- subapp1.js
    |- subapp1.router.js
|- /subapp2
    |- subapp2.js
    |- subapp2.router.js
|- /colections
|- /views

To loads the modules I use requireJs.
Here's my code, for each module I put some questions.


// main.js
define([
    'app',
    'subapp1/subapp1.router',
    'subapp2/subapp2.router'
], function (app) {
    "use strict";
    app.start();
});

Questions:
1) Is right to load asynchronously the app and subapps even if subapps need app?
2) for the subApps is right to load the router which needs the app?


// app.js
/*global define*/
define([
    'backbone',
    'marionette',
    'models/user'
], function (Backbone, Marionette, UserModel) {
    "use strict";

    var App = new Marionette.Application();

    App.addRegions({
        header: '#header',
        sidebar: '#sidebar',
        mainColumn: '#main-column',
        rightColumn: '#right-column'
    });

    App.on("initialize:before", function () {
        this.userModel = new UserModel();
        this.userModel.fetch();
    });

    App.on("initialize:after", function () {
        Backbone.history.start();
    });

    return App;
});

Questions:
3) Since the subApps could need some models I decided to load it in app.js. Is it right this way?


// subapp1/subapp1.js
/*global define*/
define([
    'app',
    'subapp1/views/sidebarView',
    'subapp1/views/headerView'
], function (app, SidebarView, HeaderView) {
    "use strict";

    app.addInitializer(function(){
        app.header.show(new HeaderView({userModel: app.userModel}));
        app.sidebar.show(new SidebarView({userModel: app.userModel}));
    });

});

Questions:
4) about this module I am not sure about the app.addInitializer.
I am not sure for example if the app.userModel will be fetched when I perform app.header.show. Should it be ok?


// subapp1/subapp1.router.js
/*global define*/
define([
    'marionette',
    'tasks/app'
], function (Marionette, app) {
    "use strict";
    var Router = Marionette.AppRouter.extend({

        appRoutes: {
            'tasks': 'tasks',
            'tasks/:id': 'taskDetail',
            '*defaults': 'tasks'
        }

    });

    return new Router({
        controller: app
    });
});

Question:
5) is it ok to load from the main.js the subapp1/subapp1.router instead of subapp1/subapp1?

回答1:

1) Is right to load asynchronously the app and subapps even if subapps need app?

You should be able to asynchronously load your app and any of the sub-apps. If the sub-apps require the main app, they should list it as a dependency. RequireJS will resolve the dependencies for you.

Only thing you should watch out for are circular dependencies, but that shouldn't be anything you can't fix.

2) for the subApps is right to load the router which needs the app?

Listing the routers of your sub-apps in your main.js sounds right to me.

3) Since the subApps could need some models I decided to load it in app.js. Is it right this way?

A module should list any and all other modules it uses as its dependencies. Therefore, if app.js and subapp1/subapp1.js both require models/user.js, they should both list models/user.js as one of their dependencies.

This way, if you change any of the modules in such a way that it no longer requires models/user.js you can remove the dependency from that particular module without risk of missing dependencies in another module.

Besides being the savest way of managing your dependencies, it's also nice and clear for other developers or even yourself when looking at your code in the future.

4) about this module I am not sure about the app.addInitializer.

I am not sure for example if the app.userModel will be fetched when I perform app.header.show. Should it be ok?

Fetching data should be initiated manually. While showing a view in a Region does trigger the View to be rendered, it doesn't trigger the view's Model or Collection to fetch data.

What you can do, is to let your view listen to the events on your Model or Collection and re-render the view once the Model or Collection has successfully fetched new data. Marionette's CollectionView automatically binds some events to add, change and remove events of it's Collection in orde to automatically manage it's ItemViews if the Collection changes in any way.

5) is it ok to load from the main.js the subapp1/subapp1.router instead of subapp1/subapp1?

As I already stated in question 2, it's good to load your routers in main.js.

One reason to do this, is that you could decide not to load all your sub-apps up front, but instead only load them once they're actually needed. The moment such a sub-app's routes get triggered is as good a time as any to load that sub-app's core module and possibly some of it's dependencies, but that would of-course require the sub-app's Router to be activated before the sub-app is loaded.