mrichard / generator-marionette

Yeoman marionette generator a la AMD
329 stars 72 forks source link

Consider Brian Mann style AppModules and folder layout in the generator #37

Open thadk opened 10 years ago

thadk commented 10 years ago

On my last project I used this generator as a basis to parse out and follow Brian Mann's proposed Marionette app structure from his elegant-but-huge Rdio app (vid) (slides) that is now featured on Marionette's homepage. _Be prepared for the thought bomb._ Much is only covered in the audio.

The main difference from what we have here and over on this generator fork that adds modules is that his Marionette components are laid out and scoped by AppModules. As Brian Mann says, individual AppModules and isolated (Bower or otherwise) Components are the gateways to essentially all internal app interaction.

Here was my fairly successful folder structure:

app/
  scripts/
    apps/ - app modules container folder

      first-app-module/
        app-first-app-module.js - the AppModule definition and an initializer for the router, controllers, and a primary layout.
          => see fork elycruz/generator-marionette for this generated file. Name can begin with "app-"
        first-app-module-new.js - the first verb-oriented controller
        first-app-module-list.js - the second verb-oriented controller
        first-app-module.js - the single marionette router for this app module
        composite/ - Marionette CompositeViews for this AppModule
        collection/ - Marionette CollectionViews
        item/ - Marionette ItemViews
        layout/ - Marionette LayoutView including the default one
          first-app-module-layout.js  - default subregions for the AppModule
          another-controllers-layout.js

      second-app-module/
        app-second-app-module.js - the AppModule definition with an initializer for the router, controllers, and layout. Name begins with "app-"
          => see fork elycruz/generator-marionette. Name can begin with "app-"
        second-app-module-new.js - the first verb-oriented controller
        second-app-module.js - the single Marionette router for this app module
        composite/ - Marionette CompositeViews for this AppModule
        collection/ - Marionette CollectionViews
        item/ - Marionette ItemViews
        layout/ - Marionette LayoutView including the default one
          second-app-module-layout.js - default subregions for the AppModule
          another-controllers-layout.js

    entities/ - model and collection definitions
    application.js - primary app with highest level region creation and an initializer for 
    communicator.js - boilerplate messaging bus definition for requiring as needed.
    init.js - grunt generated bower_component includes and other custom theme_component requirejs definitions
    regionManager.js
    main.js - App.start()

  styles/ - SASS or LESS stylesheets
  templates/ -- hbs or jade templates 
  theme_components/ - manually managed components
  bower_components/ - automatic components

server/
  app.js -

test/
  SpecRunner.js - the test framework's own init.js
  spec/
    apps/
      first-app-module/ - AppModule structure is more explicitly separated in generated test folder
        controllers/
        routers/
        views/
          layout/
          item/
      second-app-module/
        controllers/
        routers/
        views/
    entities/

_Any comments? Is this a decent way to implement scoped AppModules productively that we could consider implementing in the mainline generator?_

I feel like Brian Mann's pattern reflects the best thinking from Ember.js and other parts of the javascript/rails ecosystem and it is nice to work with that within Marionette.

(We used this structure with a standard backbone backend PaaS API implemented with Kinvey rather than Rails as BM advocates.)

Brian Mann's outer structure: The big structure

Brian Mann's inner structure: The detail structure

thadk commented 10 years ago

I created an example gist of my module and I reworked it from the Readme.md, perhaps slightly more readable:

Directory structure

Golodhros commented 10 years ago

+1 to this!

j0hnsmith commented 10 years ago

+1

swilliamsui commented 10 years ago

+1

markbrouch commented 10 years ago

+1

ghost commented 10 years ago

+1

jcurtis commented 10 years ago

:pineapple:

sometxdude commented 10 years ago

+1

I've built a fairly big project with this generator, and one of the major pain points is the proliferation of files into a handful of folders. I was scrolling endlessly to find what I needed.

elycruz commented 10 years ago
About the folder structure of topic:

I'm currently building parts of an app using requirejs and backbone.marionette and the methodology that I've currently landed at is as follows:

In each modular app I reference modules in the other modular apps via alias paths (in require.paths config); e.g.:

// From within some other app other than above apps
require.config({
  paths: {
     // ...
    ma1: '../modular-app-1/src',
    ma1_tmpl: '../modular-app-1/templates',
    ma2: '../modular-app-2/src',
    ma2_tmpl: '../modular-app-2/templates'
    // ...
  }

Now included module calls look like ma1/modules/HelloWorldModule.

Here's an example of running all three apps from another app:

// If you've added initializers to your modules they will automatically initialize when 
you call their app starts.  There by allowing you to compose the apps as you 
please and still have them exist separately from each other (I can vouch for this, 
builds nicely, and allows you to really modularize your apps even have separate 
builds/distros of each (if necessary)!)

define([
    'ma1/application',
    'ma2/application',
    'ma3/application',
    'this-apps-path/application',
    'ma1/modules/SomeModule',
    'ma2/modules/AnotherModule',
    'ma3/modules/AnotherModule',
    'this-apps-path/modules/TestingModule'
],
    function (ma1_app, ma2_app, ma3_app, app) {
        $(function () {
            ma1_app.start();
            ma2_app.start();
            ma3_app.start();
            app.start();
        });
    });

The only thing to remember with this paradigm is that each modular app will have to use a path alias for itself (makes app's paths unique within modular-app-sphere): modular-app-1 is using ma1/..., modular-app-2 is using ma2/..., and the includer app is using it's own path (this-apps-path). Then all app'ed up composition apps have to do to use other apps is define their path aliases in their require paths config; e.g., (example above)

So I agree with @thadk having a feature like this in generator-marionette (or any framework generator-...) would greatly help development flow and also help dev's in wrangling their application architectures more easily. :+1:

elycruz commented 10 years ago

I'll will put this feature into the roadmap for my branch of generator-marionette.

rbouajram commented 10 years ago

+1

jeffreycahyono commented 10 years ago

+1

thadk commented 10 years ago

I have been lurking in Marionette 2.0's gitter chat room (https://gitter.im/marionettejs/backbone.marionette) and I noticed this new starter kit: https://github.com/thejameskyle/marionette-starter-kit

It isn't as automatable as this example and doesn't use real App modules, but in lieu of a full upgrade for generator-marionette, it could be a good starting point for new projects. The author is responsive.

One bonus is that it uses Browserify instead of requirejs, though it hasn't gone the whole way of using Gulp rather than Grunt.

ivadenis commented 9 years ago

For app modules I would also include templates, unit tests and css in there.