Skip to content

Embed URL

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
What is your folder-structure preference for a large-scale Node.js project?

What is your folder-structure preference for a large-scale Node.js project?

0: Starting from Rails

This is the reference point. All the other options are based off this.

|-- app
|   |-- controllers
|   |   |-- admin
|   |   |   |-- postsController.js
|   |   |   `-- usersController.js
|   |   |-- postsController.js
|   |   |-- sessionsController.js
|   |   `-- usersController.js
|   |-- models
|   |   |-- post.js
|   |   `-- user.js
|   |-- views
|   |   |-- admin
|   |   |   `-- posts
|   |   |       |-- edit.jade
|   |   |       |-- index.jade
|   |   |       |-- new.jade
|   |   |-- layouts
|   |   |   `-- application.jade
|   |   `-- posts
|   |       |-- index.jade
|   |       `-- show.jade
|   `-- helpers
|       |-- admin
|       |   |-- postsHelper.js
|       |   `-- tagsHelper.js
|       `-- postsHelper.js
`-- config
|    |-- application.js
|    |-- locale
|        `-- en.js
|    |-- routes.js
`-- lib
`-- spec
|    |-- helper.js
|    |-- models
|    |   |-- postSpec.js
|    |   |-- userSpec.js
|    `-- acceptance
|        |-- loginSpec.js
|        |-- signupSpec.js
|        `-- postsSpec.js
`-- vendor
|    |-- javascripts
|    |   |-- jquery.js
|    |   |-- underscore.js
|    `-- stylesheets
|        `-- prettyPhoto.css

1: Rails-like, with nested /app folders for client, mobile, etc.

|-- app
|   |-- controllers
|   |-- models
|   |-- views
|   `-- browser
|       |-- controllers
|       |-- models
|       |-- views
|   `-- mobile
|       |-- controllers
|       |-- models
|       |-- views
`-- config
`-- lib
`-- spec
`-- vendor

Pros:

  • lends itself great to progressive enhancement so-to-speak. You start with just /app, and if your app starts growing, you add sub directories.
  • doesn't pollute the top-level directories, which have a pretty uniform convention across apps. However, people do add /themes to the top level, which is just about the same as adding /client to the top-level.

Cons:

  • Now you have /app/models and /app/browser, etc., which isn't a totally clear naming convention -- /app/models is for a subset of code for the server, while /app/browser is a totally different app. It's different than a namespace like /app/models/admin though, which makes sense.

My vote: no

2: A /app/client folder, similar to Rails' /app/assets

|-- app
|   |-- controllers
|   |-- models
|   |-- views
|   `-- client
|       `-- browser
|           |-- controllers
|           |-- models
|           |-- views
|       `-- mobile
|           |-- controllers
|           |-- models
|           |-- views
`-- config
`-- lib
`-- spec
`-- vendor

Pros:

  • The main reason you need these extra folders is for the different clients for the app. So putting them in /app/client conceptually makes a lot of sense. It's easy to reason about.
  • Similar to Rails, which has /app/assets/javascripts instead of /app/client. You don't want to start naming the folder /app/assets because, conceptually, everything is JavaScript, and calling one chunk of JavaScript "assets" and the rest "app" is conceptually jarring.

Cons:

  • You have deeply nested folders for core code, which can be annoying. /app/client/browser/controllers/postsController.js is 4 folders down. But with TextMate and CMD+T, it shouldn't be an issue.

You could also have this structure if you only had 1 client (or just a default client):

|-- app
|   |-- controllers
|   |-- models
|   |-- views
|   `-- client
|       |-- controllers
|       |-- models
|       `-- views

That's pretty clear, and it lends itself to agile development really well.

My vote: ✔

3: More top-level folders

|-- app
|   |-- controllers
|   |-- models
|   |-- views
|-- browser
|   |-- controllers
|   |-- models
|   |-- views
|-- mobile
|   |-- controllers
|   |-- models
|   |-- views
`-- config
`-- lib
`-- spec
`-- vendor

Pros:

  • Minimum folder nesting
  • model/view/controller folders are all at the same level

Cons:

  • Having multiple top-level folders, all of which are mvc code, is not conceptually clear. They should be part of one directory (taking us back to #2). Having every folder at the top level be a completely conceptually distinct part of the app (database vs. app vs. config vs. tests) is a clarifying convention.

My vote: second choice, but no

4: Namespaces inside /app

|-- app
|   `-- client
|       |-- controllers
|       |-- models
|       |-- views
|   `-- mobile
|       |-- controllers
|       |-- models
|       |-- views
|   `-- server
|       |-- controllers
|       |-- models
|       |-- views
`-- config
`-- lib
`-- spec
`-- vendor

Pros:

  • Clear, normalized separation of concerns. Everything fits into the same folder structure, instead of having the "default" stuff in /app, and then also nesting components in there.

Cons:

  • For the simple case, you have to create a nested folder.
    • Counterargument: But, you're setup to easily add other clients for the app
  • By not having the default code go in the top level /app, it's not as clear that server code can be used on the client (e.g. using /app/server/models/user.js on the client. it makes sense if it's in /app/models/user.js however.).

My vote: no

5: Top-level /client and /server directories

This breaks convention, but it's an option. Rename /app to /server

|-- client
|   |-- controllers
|   |-- models
|   |-- views
|-- server
|   |-- controllers
|   |-- models
|   |-- views
`-- config
`-- lib
`-- spec
`-- vendor

Pros:

  • Clear: there is a client and server app.

Cons:

  • If you had multiple client apps (browser, mobile, ipad, etc.), you'd end up doing things like #2 or #3.

My vote: no

Which do you prefer?

I prefer folder structure #2.

@lancejpollard

Wrote these a while ago, still haven't landed on something I'm totally thrilled about.

@lancejpollard

Here is another idea:

|-- client
|   |-- config
|   |   |-- bootstrap.coffee
|   |   `-- routes.coffee
|   |-- controllers
|   |-- stylesheets
|   |-- templates
|   |-- tests
|   `-- views
|-- server
|   |-- config
|   |   |-- assets.coffee
|   |   |-- bootstrap.coffee
|   |   |-- credentials.coffee
|   |   |-- databases.coffee
|   |   |-- emails.coffee
|   |   |-- jobs.coffee
|   |   `-- routes.coffee
|   |-- templates
|   |   |-- layouts
|   |   `-- emails
|   `-- tests
|-- shared
|   |-- config
|   |   |-- application.coffee
|   |   `-- bootstrap.coffee
|   |-- models
|   `-- tests
`-- public
`-- client_modules
`-- node_modules
  • Starting to think about how to divide up the folders so you could break them into sub-projects, so one developer could work purely on the client, another on purely the server/api - where "shared" can be a refactored section so code becomes DRY
  • Tests go in each main section, so you can develop/run them totally separately.
    • "Shared" folder tests get executed in both client and server.
  • All top-level folders have 6 letters, so they align, :)
  • Instead of having the config/environments/test.coffee and related folders, just put it all in config/bootstrap.coffee with if statements.
  • You could even remove the config folders and put those files at the level above:
|-- client
|   |-- bootstrap.coffee
|   |-- routes.coffee
|   |-- controllers
|   |-- stylesheets
|   |-- templates
|   |-- tests
|   `-- views
|-- server
|   |-- assets.coffee
|   |-- bootstrap.coffee
|   |-- credentials.coffee
|   |-- databases.coffee
|   |-- emails.coffee
|   |-- jobs.coffee
|   |-- routes.coffee
|   |-- templates
|   |   |-- layouts
|   |   `-- emails
|   `-- tests
|-- shared
|   |-- application.coffee
|   |-- bootstrap.coffee
|   |-- models
|   `-- tests
`-- public
`-- client_modules
`-- node_modules

Questions:

  • Where should model mixins go? I don't like how "controller mixins" are called "helpers", and "model mixins" are called "concerns". But you don't want controllers/mixins and models/mixins because what if you have subclasses of a model, shouldn't it go into a sub folder? Or maybe you could have models/user.coffee and models/user/emailMixin.coffee and models/user/admin.coffee (or some more realistic subclass).
@lancejpollard

Probably a better way is this, because each chunk is kept conceptually in the same place. This is also similar to the way the new tower source codebase is organized:

|-- config
|   |-- client
|   |   |-- bootstrap.coffee
|   |   `-- routes.coffee
|   |-- server
|   |   |-- assets.coffee
|   |   |-- bootstrap.coffee
|   |   |-- credentials.coffee
|   |   |-- databases.coffee
|   |   |-- emails.coffee
|   |   |-- jobs.coffee
|   |   `-- routes.coffee
|   `-- shared
|-- controllers
|   |-- client
|   |-- server
|   `-- shared
|-- models
|   |-- client
|   |-- server
|   |   |-- user
|   |   |   `-- emailConcern.coffee
|   `-- shared
|   |   |-- post.coffee
|   |   `-- user.coffee
|-- stylesheets
|-- templates
|   |-- client
|   |-- server
|   |   |-- layouts
|   |   `-- emails
|   `-- shared
|   |   |-- posts
|   |   `-- users
`-- views
|   |-- client
|   |   |-- posts
|   |   `-- users
`-- public
`-- client_modules
`-- node_modules

Basically, there are these top-level folders:

|-- config
|-- controllers
|-- models
|-- stylesheets
|-- templates
|-- views
|-- public
|-- client_modules
`-- node_modules

And inside of each (other than public and *_modules) are:

|-- config
|-- client
|-- server
`-- shared

Maybe templates and views can become one and the same since "views" in this context would only really be on the client. And maybe stylesheets goes into client_modules. What are your thoughts?

@lancejpollard

can't edit comments...

I meant to say inside each folder are 3 folders, client, server, and shared (no config). Then inside each of those you would also have a tests folder to write tests specific to the environment.

@krainboltgreene

Alright, so I've got a structure that I think I can live with so far, and some details to back it up later:

.
├── apps
│   ├── browser
│   │   ├── abstractions
│   │   ├── controls
│   │   ├── database
│   │   ├── presenters
│   │   └── styles
│   ├── mobile
│   │   ├── abstractions
│   │   ├── controls
│   │   ├── database
│   │   ├── presenters
│   │   └── styles
│   └── server
│       ├── abstractions
│       ├── controls
│       ├── database
│       ├── lib
│       │   ├── environments
│       │   ├── helpers
│       │   ├── initializers
│       │   ├── settings
│       │   │   └── database.json
│       │   ├── routes.cofee
│       │   └── server.rb
│       ├── presenters
│       └── translations
├── bin
├── docs
├── logs
│   └── development.txt
├── public
│   └── assets
│       └── images
├── scripts
├── test
│   ├── browser
│   ├── mobile
│   └── server
│       ├── abstractions
│       ├── controls
│       └── presenters
├── tmp
├── vendor
│   ├── assets
│   │   ├── images
│   │   ├── scripts
│   │   └── styles
│   ├── libs
│   └── plugins
├── .gitignore
├── .npmignore
├── .slugignore
├── Cakefile
├── Procfile
├── README.mdown
├── Vendorfile
├── Watchfile
├── package.json
└── tower

46 directories, 14 files
@krainboltgreene

I've picked this structure because I'm pretty sure I'm done with the MVC style framework. I've been enthralled with PAC ever since I first read the whitepaper.

@lancejpollard

I don't want to switch to a non-mvc style because it is the most known and most documented, and easiest to understand, of the paradigms. I spent years going back and forth between all of these but in the end MVC, or at least the general structure that something like Rails provided, in the end has always been easy to follow.

I'm going to take a step back for a little and really think about all this stuff though, thanks.

@SkiftCreative

The first thing I thought when I saw these... was "why so many client/server/mobile" directories? THey all seem repetitive to me. From my perspective if you have an app you want to server to all of pc, mobile, tablet and so on, that is all done from views/css.

Also, sorry this came out to be longer than I intended.

Here is what I think could work. This is based on history of using cakephp, yii, and drupal. Remember, also thing about your urls being a REST interface. its the front end that needs to be abstracted from the back to split up developer, from themer.

|-- config
|   |-- assets.coffee
|   |-- bootstrap.coffee
|   |-- credentials.coffee
|   |-- databases.coffee
|   |-- emails.coffee
|   |-- jobs.coffee
|   |-- routes.coffee
|   |-- cron.coffee
|-- controllers
|   |-- components                      // components are things used across all controllers
|   |   |-- barComponent.coffee     
|   |-- fooController.coffee     
|-- models                              // since a model, is how you describe how something behaves in general...
|   |-- behaviors                       // a generic behavior, is something you can plug into any model. like drive for car, and motorcycle
|   |   |-- fooBehavior.coffee     
|   |-- datasources                     // a datasource defines other places a model can pull info from, OTHER than the db. say facebook, or twitter.
|   |   |-- email.coffee                // email is a DS because any model can send an email. saving to an email would effectively send it (or add them to cron jobs to be batched)
|   |-- emailConcern.coffee             // standard model
|   |-- user.coffee                     // standard model
|-- templates/views                     // this, is where to me you would start abstracting desktop vs mobile
|   |-- helpers                         // helpers are code snippets that are available in ALL html files (CODE not HTML)
|   |   |-- helper.coffee               // a helper script
|   |-- message                         // any error/growl message templates message
|   |-- foo                             // templates for the foo controller
|   |   |-- _form.coffee     
|   |   |-- index.coffee     
|   |-- layouts/themes                  // layouts, imho are where the difference is. These are essentially, themes
|   |   |-- email                       // email templates (could user html5/email boilerplate)
|   |   |   |-- config.coffee           // description of how this theme is loaded. assets.coffe only needs to load this, not all the files individually
|   |   |   |-- email.html     
|   |   |   |-- css                     // css styles cant normally be used for emails, but could there be a way to compile it to be inline?
|   |   |   |   |-- style.css      
|   |   |   |-- js                      // see css note
|   |   |   |   |-- script.coffee     
|   |   |   |-- img                     // see css note
|   |   |   |   |-- img.png     
|   |   |-- base/default
|   |   |   |-- config.coffee           // description of how this theme is loaded. assets.coffe only needs to load this, not all the files individually
|   |   |   |-- index.html     
|   |   |   |-- css                     // since these are fully qualified themes, they would keep the assets in there
|   |   |   |   |-- style.css     
|   |   |   |-- js     
|   |   |   |   |-- script.coffee     
|   |   |   |-- img     
|   |   |   |   |-- img.png     
|   |   |-- widget                      // maybe even have widget specific styles. more than one theme can probably be enabled
|   |   |   |-- config.coffee
|   |   |   |-- css
|   |   |   |   |-- style.css     
|   |   |   |-- js     
|   |   |   |   |-- script.coffee     
|   |   |   |-- img     
|   |   |   |   |-- img.png     
|   |   |-- mobile                      // themes can even inherit themes (though that would take work). 
|   |   |   |-- config.coffee     
|   |   |   |-- mobile.html     
|   |   |   |-- css                     // since these are fully qualified themes, they would keep the assets in there
|   |   |   |   |-- style.css     
|   |   |   |-- js     
|   |   |   |   |-- script.coffee     
|   |   |   |-- img     
|   |   |   |   |-- img.png     
|   |   |   |-- ipad                    // ipad subtheme? theoretically this can all be done with responsive css
|   |   |   |   |-- config.coffee       // themes will handle including subthemes, no need to make assets.coffee grab this.
|   |   |   |   |-- mobile.html     
|   |   |   |   |-- css                 // since these are fully qualified themes, they would keep the assets in there
|   |   |   |   |   |-- style.css
|   |   |   |   |-- js
|   |   |   |   |   |-- script.coffee
|   |   |   |   |-- img
|   |   |   |   |   |-- img.png
|-- data                                // this is new. this could be a place for uploads, or db dumps (migrations?)
|   |-- tmp
|   |-- db
|   |   |-- schema.coffee               // some frameworks will have a schema file to put all their model schemas in. could also be directory with file for each model.
|-- sites                               // explained below
|   |-- sites.coffee                    // sites config, explained below
|   |   default                         // webroot for default site
|   |   |-- config.coffee
|   |   |-- uploads
|   |   |-- public
|   |   |   |-- img
|   |   |   |-- css
|   |   |   |-- js
|   |   |   |-- index.js
|   |-- default                         // webroot for site1
|   |   |-- config.coffee
|   |   |-- uploads
|   |   |-- public
|   |   |   |-- img
|   |   |   |-- css
|   |   |   |-- js
|   |   |   |-- index.js
|-- plugins                             // these couple be plugins the user makes for their own system, that they may not want/need in npm
|   |--comments
|   |   |-- config.coffee
|   |   |-- script.coffee
|-- vendor                              // like plugins, scripts that are not npm modules, but are way to simple to be a plugin
|-- node_modules                        // npm modules, duh

descriptions:

Config:

assets: loads a themes config.coffee file (which should already load what it needs.) as well as anything else. using theme configs will make this file much simpler.

email: might be better as a models datasource, but i still need to soo how you are doing this.

cron: we could setup

Controllers

Controllers: as usual. these are controllers

Components: these are common code that all controllers need. this could be from basic validation to text formatting before sending to a model to be saved.

Models: all models can use a datasource. the db config is a given, but you should be able to say something like var schema = null if the model doesnt use a db.

bahaviours: a behavious is the same as a component but for a model. a model is a thing that does something. it knows how to do what it does. but sometimes we need to teach both cats, and dogs how to roll over. So we have a rollover behaviour. it adds a behaviour to any model that needs to use it. any common model code should belong in a behaviour.

datasource: by default, each model will use the configured db. in datasources if you have a datasource with the same name as the model, it will use it by default (model.coffee uses modelDS.coffee). And in that model datasource, you can tell it which db connection to use, and/or to use more than one datasource. say the userDS.coffee file tells the model to use both the user collection in the test db, as well as pull info from the other facebookDS.coffee. This way the user can pull data from both the db and facebook. models only need to use the twitterDS.coffee to pull users twitter data, for example. Also, these would only be what is in core. IMHO something like twitter/facebook datasources should belong in a plugin (described below);

template/views: this is where we split up from desktop to mobile clients. each subdirectory is a theme. and in the assets.coffee file, we list which themes would be 'enabled'. then the config.coffee in each theme will itself list all the needed assets for that theme that are needed to make it work. YOu can have a theme for anything. default/desktop, android/ios/mobile, tablet/ipad, touch, email, or any other group of 'templates' you want to add. each theme would be its own thing and it would know how to set itself up. You only ever have to include the config file

data: this is a new directory

uploads: this could be uploads from an end user. such as from an uploader or something else. This would typically not be from a development standpoint, from from a production use/end user standpoint. user uploads.

tmp: a temp dir for whatever is needed, like upload processing or caching.

db: some frameworks have users place their model schema into a schema dir/file rather than the model itself. it does separate things but also keeps all your db schema in one place. this could also go into the config/ or models/ dir. if in models dir you could have

    |-- user.coffee
    |-- user.schema (coffee)

that way they are still together, but factored out of for whatever reason you just need to get the scheme/layout of a model. if you keep it in the db directory, you could theoretically also put the db config file in here depending on how you want to do it.

plugins: plugins, are themselves, mini applications (even tower apps). each plugins could have its own mvc structure, or simply be a small collection of scripts. each plugin, like a them, has its own config file. the assets.coffee should only have to include this config file and it will be bootstrapped.

vendor: like plugins, but when you simply need to include a simple js file or library that does not need to be a plugin. you could for example put the jquery source in here, mootools, scriptalicious, YUI, or anything else. Another difference is that vendor scripts are delivered to the client, whereas plugins are mainly for application functionality and are server only.

node_modules: kinda obvious

sites: This allows us to run more than one site, for each backend. The examples above (default and site1) ONLY have differences of the public root. there is no other differences. I talk below about a way to separate this and what we can do with this. Basically, each site can map to a route, subdomain, path, or completely different domain.

NOTES. While this is a proposed layout, an individual developer may want it slightly tweaked. I vote to have an enironment variable of some sort for each directory which is an array of paths. for example, models could be:

var models = ["/models", "/plugins/*/models"]

Where the * matches any direct subdirectory of the plugins dir. This would also make it a lot easier for things like developing a CMS or if users need to abstract the viewt template to a shared place where designers only have access to the theme files. the path in the array could be on another part of the hard drive, or you could list a shared themes directory that is used between multiple tower apps

var themes = ["/themes/", "plugins/*/themes", "/srv/lib/tower/themes"]

This IMHO would be VERY powerful to have each directory customizable into wherever the user wants it to be. This also works for sites in the sites.coffee file (see below)

OK, now I know what you are thinking... "What about the browser/mobile/server apps that i needed?". well like I said, the main reason you need that stuff is because the mobile site will render differently than the desktop one. The core logic, is the same. it doesnt change how the app behaves. if you dont want functionality on the client, simply dont show that in the mobile theme. Also, if you do have functionality that may be slightly different on mobile, your controllers should render the theme based on the used client. just like .html and .json are different. if html, and client = mobile, dont send this object to the browser, just render differently. So basically, want to render different for mobile? make mobile use a different theme. Have functionality that will be different? make a separate site (see below)

"Well, i actually have 3 separate apps that do look differently, and does behave differently. but it talks to the same backend"

Ok, remember when I said that the focus of this is to abstract server rest api from client functionality? also remember my note above about configurable directories/sites. This is why.
with configurable directories you could have the backend ONLY have the backend, and no themes. just controllers/models/config. And make another site, customize the models dir to be the main app, and BAM it works. Well, thats one way. The other is when you have an app directory that is based on a core server, you can even do better.

Example, say your main site is structured like above. Now we want to make another app where the ONLY difference is the appearance. we could have an app dir as simple as this:

|-- config
|   |-- assets.coffee
|-- templates/views
|   |-- layouts/themes
|   |   |-- base/default
|   |   |   |-- config.coffee
|   |   |   |-- index.html
|   |   |   |-- css
|   |   |   |   |-- style.css
|   |   |   |-- js
|   |   |   |   |-- script.coffee
|   |   |   |-- img
|   |   |   |   |-- img.png

"wait how would this be possible? theres not even a public directory." well thinking of drupal in mind, in the servers config directory we could have a sites.coffee file. In that file we can define what domains, or paths would go to a different app.

    var sites = 
    { "default"     : "/srv/sites/domain1.com/app"
    , "domain2.com" : "/srv/sites/domain2.com/app"
    , "/app3      " : "/srv/sites/domain3.com/app"
    }

so the above site example would still use the same default public directory, but it would use a different theme. that would be the ONLY difference. I know there would be some things to work out to get this to work.

And basically, when you have one of these seperate app's, it changes only whats in the app file. doing this we could have one tower server powering many apps. Say in the other app, you use the same theme, but the difference is you talk to a different user document in mongo. so a different set of users.

|-- sites
|   |-- sites.coffee
|   |   default
|   |   |-- config.coffee
|   |   |-- models
|   |   |   |-- datasources
|   |   |   |   |-- userDS.coffee
|   |   |-- uploads

remember, only files added are changed. since user.coffee model uses the models/datasources/userDS.coffee by default if it is present, here in this datasource you simply only need to tell it to use a different database. now if you have a plugin describing a facebook datasource, in this userDS.coffee we would reference it as if it were a local datasource, just as we would normally. This example would also use the same default public root. if you wanted a different one, you would add another public root directory. This example, also uploads its files into its own uploads directory

ok, here is a really abstracted out example.

|-- config
|   |-- assets.coffee
|   |-- bootstrap.coffee
|   |-- credentials.coffee
|   |-- databases.coffee
|   |-- emails.coffee
|   |-- jobs.coffee
|   |-- routes.coffee
|   |-- cron.coffee
|-- controllers
|   |-- components
|   |   |-- barComponent.coffee
|   |-- fooController.coffee
|-- models
|   |-- behaviors
|   |   |-- fooBehavior.coffee
|   |-- datasources
|   |   |-- user.DB.coffee
|   |-- emailConcern.coffee
|   |-- user.coffee
|-- data
|   |-- tmp
|   |-- db
|   |   |-- schema.coffee
|-- sites
|   |-- sites.coffee
|-- plugins
|   |--comments
|   |   |-- config.coffee
|   |   |-- script.coffee
|-- vendor
|-- node_modules

pretty slim right? theres no views/templates dir. its in another folder. it also has no sites in it. theyre separated for designers below. default and site2

|-- default
|   |-- config.coffee
|   |-- uploads
|   |-- public
|   |   |-- img
|   |   |-- css
|   |   |-- js
|   |   |-- index.js
|   |-- plugins
|   |   |--comments
|   |   |   |-- config.coffee
|   |   |   |-- script.coffee
|   |-- vendor
|   |-- node_modules
|-- site2
|   |-- config.coffee
|   |-- uploads
|   |-- public
|   |   |-- img
|   |   |-- css
|   |   |-- js
|   |   |-- index.js
|   |-- plugins
|   |   |--comments
|   |   |   |-- config.coffee
|   |   |   |-- script.coffee
|   |-- vendor
|   |-- node_modules
|-- templates/views
|   |-- helpers
|   |   |-- helper.coffee
|   |-- message
|   |-- foo
|   |   |-- _form.coffee
|   |   |-- index.coffee
|   |-- layouts/themes
|   |   |-- email
|   |   |   |-- config.coffee
|   |   |   |-- email.html
|   |   |   |-- css
|   |   |   |   |-- style.css
|   |   |   |-- js
|   |   |   |   |-- script.coffee
|   |   |   |-- img
|   |   |   |   |-- img.png
|   |   |-- base/default
|   |   |   |-- config.coffee
|   |   |   |-- index.html
|   |   |   |-- css
|   |   |   |   |-- style.css
|   |   |   |-- js
|   |   |   |   |-- script.coffee
|   |   |   |-- img
|   |   |   |   |-- img.png
|   |   |-- widget
|   |   |   |-- config.coffee
|   |   |   |-- css
|   |   |   |   |-- style.css
|   |   |   |-- js
|   |   |   |   |-- script.coffee
|   |   |   |-- img
|   |   |   |   |-- img.png
|   |   |-- mobile
|   |   |   |-- config.coffee
|   |   |   |-- mobile.html
|   |   |   |-- css
|   |   |   |   |-- style.css
|   |   |   |-- js
|   |   |   |   |-- script.coffee
|   |   |   |-- img
|   |   |   |   |-- img.png
|   |   |   |-- ipad
|   |   |   |   |-- config.coffee
|   |   |   |   |-- mobile.html
|   |   |   |   |-- css
|   |   |   |   |   |-- style.css
|   |   |   |   |-- js
|   |   |   |   |   |-- script.coffee
|   |   |   |   |-- img
|   |   |   |   |   |-- img.png

"What happened here? The sites arent even in the sites directory." EXACTLY! This is what the /sites/sites.coffee file is for. You can have your core server in one place, and the site directory in another where only certain developers have access to it. Onle certain devs have access to this directory. Also note, the templates dir isnt in its own dir. in the site assets.coffee file we defined the templates array that the template directory is in the same directory as the main app folder, but now, only designers have access to this template dir. the theme, site data, and server are all able to be abstracted away from eachother. this way all the templates are separate from the code. designers have everything they need and can even style the helpers' output if need be.

also note something special. the sites, have their own plugins, vendor, node_modules dir. This idea is inspired byt drupal and its multisites. With this, you can have plugins/vendor/node_modules on the server, that will be available to ALL sites. and each site can have plugins/vendor/node_modules that are specific to that site.

remember, that ability is OPTIONAL. by default everything would be in the root folder as first described. and you would simply use it as that. Some of this * could * also be done via plugins or by using tower to build a cms.

I know this is a lot and advanced, and there is some magic... but that magic is only there to users who want to use it. if you dont want that magic then you dont have to use it. keep it how the default structure it. you dont have to separate the view or sites at all.

I hope this makes sense, if you have any question ill be happy to reply to them.

/rant
@maedi

Hey Luckysmack, I need to read this in more detail later but here are a few points:

I don't think Tower is for multiple 'sites' like Drupal is, you would create another codebase if you wanted to do this. By having multiple 'sites' you're dramatically increasing the complexity of the codebase.

You mentioned the concept of 'plugins'. In Drupal land this would be a 'module' and be half-way between a library and a node package. Do you think there is really a 3rd category here? Maybe plugins will become npm packages?

The uploads directory is a good idea, but I'm just wondering where this is all going now with the cloud. Do people use S3 by default now?

@maedi

Oh and I do really like the concept of behaviors, this is something I use currently in a Rails MVC. It doesn't have to be baked in by default but would be nice if it was... complex MVC apps can be messy without them.

Widgets are a great Rails concept too, just thinking it might be an 'add-on' and not in Tower core. I'm not a core Dev though so this is just thinking aloud.

@SkiftCreative

Yes regarding multisites, I agree it would be much more advanced. And I can easily see not wanting to include it because of that. In my last comment I was mainly discussing what others are doing and how the similar * could * be done in tower if it was decided to do so. Realistically, a multisite system would probably be more along the lines of something a cms or other system would do to build on top of this (this is also something I am trying to build myself. it is part of a requirement for an app I am building where multiple sites will share much of the same server side code and each site will have a different subset of functionality).

Plugins, yes these would ideally be npm modules that are made to be compatible with whatever system is built. Since the platform I am making will have a simple core and have its own plugins to enhance it, which will be either included with the core and enabled by a setting, or installable from npm. I think the key there is to keep the node/npm standards and make everything follow what people are familiar with.

uploads, database, etc could all be configured by a config/datasources/coffee file. In there you would define and source to save or pull data from. You can define that you shall either use uploads, json files, amazon s3, rackspace files (which on a rackspace server you can tie to a local directory i believe on a VPS), or whatever you want. those other options could each be an npm module defining how to connect and uses the api, and in the datasources.coffee file you would tell your app about that datasource module, and its credentials to pull/save data from/to it. Also this would obsolete the databases.coffee file since they would be defined as a data source, which is kinda what it is.

When you have a model, by default they use your default data source (usually mongo), but you could also have a datasources variable that would define what sources it uses. For example, User model could have something like

var datasources = ["mongodb", "facebook", "twitter"]

and a page model:

var datasources = ["mongodb", "s3"]

an file/upload model:

var datasources = ["uploads"]   // the datasource config would define where the uploads dir actually is.

I think behaviours/components would be great too. there tends to be code commonly shared between some models/controllers.

Yea I agree widgets could be optional too. But to me, a widget really would just be a special way to use a template. and anything beyond that would be up to the user to define, unless there is something that would be beneficial to have in core.

@SkiftCreative

Another option is similar to how django does it. it would still be mvc but the methodology on the stricture is a lot different. mostly related to the actual models, views, and controllers. So imagine the other directories here are the same. tmp, config, node_modules, plugins, vendor, etc. rather than:

|-- controllers
|   |-- fooController.coffee
|   |-- barController.coffee
|-- models
|   |-- foo.coffee
|   |-- bar.coffee
|-- views
|   |-- layout
|   |   |-- content.coffee
|   |   |-- header.coffee
|   |-- foo
|   |   |-- index.html
|   |   |-- _form.html
|   |-- bar
|   |   |-- index.html
|   |   |-- _form.html

we would have this

|-- apps
|   |-- foo
|   |   |-- fooController.coffee
|   |   |-- foo.coffee
|   |   |-- views
|   |   |   |-- index.html
|   |   |   |-- _form.html
|   |   |-- templates        // templates specific to the foo 'app'
|   |   |   |-- widget.coffee
|   |-- bar
|   |   |-- barController.coffee
|   |   |-- bar.coffee
|   |   |-- views
|   |   |   |-- index.html
|   |   |   |-- _form.html
|   |   |-- templates        // templates specific to the bar 'app'
|   |   |   |-- widget.coffee
|   |-- themes          // the normal app wide templates ( i still like the themes idea though)
|   |   |-- myTheme
|   |   |   |-- content.html

so rather than a folder for each of controllers, models, and views, we essentially have a mini 'app' for each part of functionality. so in the normal 'app/' dir, would be an independant app, or a few that maybe use/depend on each other. Doing this helps separate different parts of the app code from others. for example, I could create a 'comments' app that I can use for other apps. and it would be easier to just synlink that dir or copy code of one directory, than individual files. it forces you to make each app independent and testable on its own.

I really like this idea from a testing standpoint as well. it also makes the app easier to separate different jobs or tasks that it does. when you have something like a behaviour( for models), or components (for controllers) they can either be in their own app subdirectory, or in a special app/components, or app/behaviours directory.

@j
j commented

So, this may be a dumb question, but do you consider "client" code to be what the device sees? Aka, are the models something like Backbone models, and views Handlebars, etc? Or are those just ways to organize "multi-site" applications.

Lets say I have a website, mobile website, and a REST API. I want to share all the same domain models between all of these. Each one will have a different subset of "controllers|routes", "views" and more domain models, etc. Maybe even utility files / middlewares for each. So at first glance, the client namespace would be a decent place to organize multisite style applications.

Meaning... each "client" in "app" would literally be a separate instance of express() or restify() (on the API), and the root app.js or server.js would configure each accordingly.

OR, should I create separate repositories/projects for this, then create a main one too bootstrap them and bring them together.

i.e) I have a company with domain widgets.com which has an api, mobile version, and main site. I could have the following "repositories" / project names and be configured/packaged privately in NPM:

1) widgets-common:  this will be a library containing common models / utilities / middlewares / etc that all projects may share.
2) widgets-browser: typical "express" app
3) widgets-mobile:  typical "express" app
4) widgets-api:     typical "express" or "restify" app
5) widgets.com:     main repository which installs above dependencies and bootstraps them / starts servers / vhosts / etc, etc

Anyway, what do you think?

@mb-dev

I would recommend to watch this video:
http://confreaks.com/videos/759-rubymidwest2011-keynote-architecture-the-lost-years

I am considering grouping app by functionality:
so instead of the usual controllers/models/assets

There will be:

|-- app
|   |-- common
|   |   |-- common.coffee
|   |   |-- common.less
|   |-- users
|   |   |-- users.coffee
|   |   |-- users.less
|   |   |-- login.html
|   |   |-- logout.html
|   |   |-- register.html
|   |-- posts
|   |   |-- posts.coffee
|   |   |-- posts.less
|   |   |-- show.html
|   |   |-- form.html
|   |-- blog
|   |   |-- blog.coffee
|   |   |-- blog.less
|   |   |-- index.html

Pros: Like the video lists: your app functionality can now be learnt by looking at the top level structure. All files that activate a section on the site are right next to each other.

What are the cons?

Note: I included client side files only in the example, still trying to decide if I should tie in server side files too.

@vjpr

@mb-dev I am settling on a similar approach. Grouping by functionality is much easier to work with.

@flemay

@mb-dev and @vjpr: where do you put your server files in that structure?

@vanng822

don't have big project but here is the structure I use and works really well for me, more or less option 3
https://github.com/vanng822/appskeleton

@fidanov

I prefer something very similar to your first example (the rails inspired). Here is a tutorial about it and below is an example of an app applying it.

|--project
|  |--controllers/
|  |  |--comments.js
|  |  |--index.js
|  |  |--users.js
|  |  helpers/
|  |  |--dates.js
|  |--middlewares/
|  |  |--auth.js
|  |  |--users.js
|  |--models/
|  |  |--comment.js
|  |  |--user.js
|  |--public/
|  |  |--libs/
|  |  |--css/
|  |  |--img/
|  |--views/
|  |  |--comments/
|  |  |--|--comment.jade
|  |  |--users/
|  |  |--index.jade
|  |--tests/
|  |  |--controllers/
|  |  |--models/
|  |  |  |--comment.js
|  |  |--middlewares/
|  |  |--integration/
|  |  |--ui/
|  |--.gitignore
|  |--app.js
|  |--package.json

I've also prepared a small repository on GitHub, which uses the same structure, for any new projects. I will try keep its dependencies up to date.
https://github.com/terlici/base-express

@ssmereka

I prefer to group my files by feature, rather than function. So for example group all user related files (controllers, models, tests, and etc.) in a folder. Then that folder can be easily reused in other projects or when making changes it is easier to find the files affected. So for example:

I created a module to allow this type of file structure by dynamically requiring files.
https://github.com/ssmereka/crave

@dschinkel

Definitely everyone (even seasoned devs) should first watch Uncle Bob's vid as suggested by mb-dev. Talks about how your top level should not indicate what kind of app it is (Rails, CoffeeScript, etc.). The language shouldn't dominate your project structure at a top level. http://confreaks.tv/videos/rubymidwest2011-keynote-architecture-the-lost-years

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.