Tower Application

The main application is defined in config/application.coffee and defaults to this:

class App extends Tower.Application
  @configure ->
    @use "favicon", Tower.publicPath + "/favicon.ico"
    @use "static", Tower.publicPath, maxAge: Tower.publicCacheDuration
    @use "profiler" if Tower.env != "production"
    @use "logger"
    @use "query"
    @use "cookieParser", Tower.cookieSecret
    @use "session", secret: Tower.sessionSecret, cookie: {domain: ".#{Tower.cookieDomain}"}
    @use "bodyParser"
    @use "csrf"
    @use "methodOverride", "_method"
    @use Tower.Middleware.Agent
    @use Tower.Middleware.Location
    @use Tower.Middleware.Router

module.exports = global.App = App

Structure of a Tower.js Project

.
|-- app
|   |-- client
|   |   |-- stylesheets
|   |-- controllers
|   |   |-- admin
|   |   |   |-- postsController.coffee
|   |   |   `-- usersController.coffee
|   |   |-- commentsController.coffee
|   |   |-- postsController.coffee
|   |   |-- sessionsController.coffee
|   |   `-- usersController.coffee
|   |-- models
|   |   |-- comment.coffee
|   |   |-- post.coffee
|   |   `-- user.coffee
|   |-- views
|   |   |-- admin
|   |   |   `-- posts
|   |   |       |-- _form.coffee
|   |   |       |-- edit.coffee
|   |   |       |-- index.coffee
|   |   |       |-- new.coffee
|   |   |       |-- show.coffee
|   |   |-- layouts
|   |   |   `-- application.coffee
|   |   |-- shared
|   |   `-- posts
|   |       |-- index.coffee
|   |       `-- show.coffee
|   `-- helpers
|       |-- admin
|       |   |-- postsHelper.coffee
|       |   `-- usersHelper.coffee
|       `-- postsHelper.coffee
`-- config
|    |-- application.coffee
|    |-- assets.coffee
|    |-- databases.coffee
|    |-- environments
|       |-- development
|       |-- production
|       `-- test
|    |-- locale
|       `-- en.coffee
|    |-- routes.coffee
`-- test
|    |-- helper.coffee
|    |-- models
|    |   |-- postTest.coffee
|    |   |-- userTest.coffee
|    `-- acceptance
|        |-- login.coffee
|        |-- signup.coffee
|        `-- posts.coffee

NPM and package.json

The package.json file is standard to all Node.js modules using NPM (which implements the CommonJS package format specification).

Without going into too much detail, here's what you need to know about each.

package.json

The package.json file is a JSON description of your project. This is the default package.json for a generated Tower.js app:

{
  "name":                 "my-app",
  "version":              "0.0.1",
  "description":          "Some one-liner description of your project.",
  "homepage":             "http://github.com/username/my-app",
  "main":                 "./server.js",
  "author":               "Your Name <your@email.com>",
  "keywords": [
    "node"
  ],
  "maintainers": [{
    "name":               "Your Name",
    "email":              "your@email.com"
  }],
  "contributors": [

  ],
  "licenses": [
    {
      "type":             "MIT",
      "url":              "http://mths.be/mit"
    }
  ],
  "bugs": {
    "url":                "http://github.com/username/my-app/issues"
  },
  "repository": {
    "type":               "git",
    "url":                "http://github.com/username/my-app.git"
  },
  "engines": {
    "node":               ">= 0.4.0"
  },
  "dependencies": {
    "tower":              ">= 0.3.0"
  },
  "devDependencies": {
    "coffee-script":      ">= 1.1.3",
    "stylus":             ">= 0.17.0",
    "uglify-js":          ">= 1.1.1",
    "design.io":          ">= 0.1.0"
  }
}

For all node modules that you'll need in both development and production environments, put them into dependencies. Anything that you just need for development (like uglify-js for javascript compression), put that into devDependencies.

To install just production dependencies, run this command from your project root:

npm install --production

You can also do this by setting NODE_ENV to production.

To install both dependencies and devDependencies, run this command:

npm install

Note: When you push your app to Heroku, it's compiled to a "slug". This makes it easy to clone and scale your app. The ideal is to minimize the size of that slug so it's faster to clone. The two biggest ways to do this are 1) minimize the number of images/pdfs/assets in your project (put them on S3 or something), and 2) minimize the number of modules you use in production. So if you only need gzipping to compile your assets for production, put that into your devDependencies.

NPM

Most of you are probably familiar with NPM, but here's just a quick list of helpful commands to streamline your development workflow.

More on NPM here: http://npmjs.org/doc.

npm install

The first thing to do when you create a Tower project (or you git clone any node module from GitHub) is to cd into the project root and install the dependencies:

npm install

You can install a published npm module like this:

npm install coffee-script jade stylus

You can also install local modules:

npm install /Users/username/git/node/my-module

But when you're developing a module locally, it's a pain to constantly have to remove and reinstall it into the app that's using it. That's where npm link comes in.

npm link

The npm link command creates a symlink to a local node module that links it to the global npm module directory on your hard drive. First step is to link my-module to the global directory:

$ cd /Users/username/git/node/my-module
$ npm link
/usr/local/lib/node_modules/my-module -> /Users/username/git/node/my-module

Then in any local project that's using it, run:

$ npm link my-module
./node_modules/my-module -> /usr/local/lib/node_modules/my-module -> /Users/username/git/node/my-module

I love npm link, it makes development so much easier.

npm publish

To publish a module to the npm index, run:

npm publish

NPM Scripts

Sometimes you want to run some code before/after your module is installed. Do this by defining npm scripts in your package.json (http://npmjs.org/doc/scripts.html).

Here's a package.json that installs a RubyGem after the node module is installed:

{
  ...
  "scripts": {
    "install": "gem install nokogiri"
  }
}

Configuration

The Server

Auto-reloading Changed Files

Internally Tower.js knows when a file was changed. So when you refresh http://localhost:3000, it passes through the Tower.Middleware.Dependencies which re-requires any file that has changed. This makes development uber fast, and prevents you from having to restart the server whenever a file changes (i.e. nodemon). I mean, you can use nodemon if you want, it's a great project. But you don't need to.

The Client

The client application is defined exactly like the server application, they just tend to require different middleware and slightly different configuration.

Environments

Dotfiles

Dotfiles are for the most part just hidden files that different platforms use to store configuration data about your project.

In Tower.js, there's 3 by default:

.gitignore

This tells git the files and directories it should ignore.

.npmignore

This tells npm what to ignore when your module is published.

.slugignore

This tells Heroku what to ignore about your project.

Commands

tower new <name> [options]

tower server (todo)

Right now, node server works well and is pure node.

tower console (todo)

Use the Tower.js console to programmatically mess around with your application data.

tower console

tower generate <generator> [args] [options]

Helpers

Global Helpers

Tower.url
Tower.get
Tower.post
Tower.put
Tower.delete
Tower.destroy
Tower.action
Tower.constant

Underscore Helpers

_.stringify
_.camelize
_.parameterize
_.pluralize
_.singularize
_.humanize
_.titleize
_(2).days().fromNow().toDate()

Internationalization (I18n)

# config/locales/en.coffee
module.exports =
  hello: "world"
  forms:
    titles:
      signup: "Signup"
  pages:
    titles:
      home: "Welcome to %{site}"
  posts:
    comments:
      none: "No comments"
      one: "1 comment"
      other: "%{count} comments"
  messages:
    past:
      none: "You never had any messages"
      one: "You had 1 message"
      other: "You had %{count} messages"
    present:
      one: "You have 1 message"
    future:
      one: "You might have 1 message"

Watchfile

Tower uses Design.io's Watchfile to:

Default Watchfile

require('design.io').extension('watchfile')

require("design.io-stylesheets")
  compress: false
  ignore: /(public|node_modules)/
  paths:  File.directories("app/assets").concat File.directories("themes")
  write: (path, string) ->
    path = "public/stylesheets/#{path}".replace(/\.(css|styl|less)/, ".css")
    try
      File.write path, string, (error) ->
        console.log(error.stack) if error
    catch error
      console.log error.stack

require("design.io-javascripts")
  compress: false
  debug:    false
  ignore:   /(public|node_modules|server|spec.*[sS]pec)/
  #outputPath: (path) ->
  #  "spec/tmp/test.css"
  write: (path, string) ->
    path = "public/javascripts/#{path}".replace(/\.(js|coffee)/, ".js")
    #growl.notify("updated #{path}", { title: 'Stylesheets' })
    try
      File.write path, string, (error) ->
        console.log(error.stack) if error
    catch error
      console.log error.stack

# update .coffee file when .mustache file of same name changes      
watch /app\/views.*\.mustache/
  update: (path, callback) ->
    coffeePath = path.replace(".mustache", ".coffee")    
    LOG coffeePath
    if File.exists coffeePath
      File.touch coffeePath      
    callback()