drumkit

Plugin Driven, Full Stack Web Framework for Node.js

npm install drumkit
1 downloads in the last month

DrumKit

WARNING! This framework is currently in very early development, it may be broken or may break at any time.

DrumKit is a plugin-powered, full-stack Web development framework for Node.js.

Installation

DrumKit is dependent on Node.js and NPM. If you have both, you can install DrumKit globally:

npm install -g drumkit

It is important to install this globally so that you have access to the drumkit command across your system. All DrumKit modules on the other hand will be installed locally in each of your DrumKit projects.

Getting Started

DrumKit will bootstrap a project directory for you with the create command:

cd ~/myapps
drumkit create new-app

This will generate a DrumKit application in ~/myapps/new-app and will use npm to install your dependencies. Once your app is installed, you can start the server:

cd new-app
drumkit start

By default, your app will be running at http://localhost:8765.

Running the Console

You also can interact with your code in a REPL by firing up the console:

cd path/to/your/app
drumkit console

Now Build Your App!

  1. Build models with dk-model (see also dk-model-couchdb and dk-couchdb).

  2. Build view templates and helpers with dk-template.

  3. Build routes with dk-routes.

  4. Check out these other DrumKit plugins:

  5. Build your own plugins with drumkit plugin [pluginName]

dk-core

WARNING! This framework is currently in very early development, it may be broken or may break at any time.

The dk-core plugin provides core functionality for the DrumKit.js framework. Currently it has no configuration options.

Installation

Install the package with npm:

npm install dk-core

Available Commands

drumkit start [env]

cd into a project directory and run drumkit start to start up your DrumKit.js application. The env defaults to development.

drumkit console [env]

cd into a project directory and run drumkit console to start up your application in a coffeescript REPL console. The env defaults to development.

drumkit consolejs [env]

Works the same as drumkit console except it uses straight JavaScript rather than CoffeeScript.

drumkit plugin pluginName

Bootstraps a new Drumkit plugin at ./plugins/pluginName.

dk-assets

An Asset Manager Plugin for DrumKit.js

WARNING! This framework is currently in very early development, it may be broken or may break at any time.

Installation

You can install dk-assets using npm:

npm install dk-assets

Getting Started

Out of the box, dk-assets assumes that you have a public folder with js and css subdirectories:

- public
  - css
  - js

Any files inside the public dir are automatically served, so public/images/logo.png will be available at http://localhost:8080/images/logo.png. You can change the location or name of your public directory by specifying it with dk.assets.config.

All JS and CSS files can be automatically packaged (concatenated) into single files for faster loading. You can turn packaging on by running dk.assets.config with the package option set to true.

Plugin Developers Guide

If you have JS and/or CSS assets that you want included in the asset packages, use the package method. It takes a the URL that you want to serve the asset at, followed by either the path to your static asset file or a function that returns JS/CSS. If you package a coffeescript or stylus file, they will be automatically compiled to JS and CSS on the fly:

# Package a coffeescript file, serve at /js/my-file.js
dk.assets.package "/js/my-file.js", "#{__dirname}/some-dir/my-file.coffee"

# Package a stylus file, serve at /css/my-file.css
dk.assets.package "/css/my-file.css", "#{__dirname}/some-dir/my-file.stylus"

# Package the result of a function as a file
dk.assets.package "/js/dynamic.js", ->
  "console.log('This could be something dynamically generated.');"

For assets in your plugin that you want to serve but not package (ie images), you can use the serve method, which behaves similarly to package:

# Serve a coffeescript file at /js/my-file.js
dk.assets.package "/js/my-file.js", "#{__dirname}/some-dir/my-file.coffee"

# Serve a stylus file at /css/my-file.css
dk.assets.package "/css/my-file.css", "#{__dirname}/some-dir/my-file.stylus"

# Serve the result of a function at /js/dynamic.js
dk.assets.package "/js/dynamic.js", ->
  "console.log('This could be something dynamically generated.');"

Full API

dk.assets.config(options)

Available options:

  • dir: (String) Sets the path to your public directory. All files in this directory will be automatically served. Defaults to "public"
  • package: (Boolean) Sets whether dk-assets should package all JS and CSS files into a single JS and CSS file (ie /js/all.js and /css/all.css). This is preferable a production environment. Defaults to false
# Use a nonstandard public directory, package CSS and JS files
dk.assets.config dir: "nonstandard/public-dir", package: true

dk.assets.package(url, fileOrFunction, serve=true)

Use the package method in order to make a JS or CSS file available at a given URL, and add it to the package. Any coffeescript or stylus file will automatically be compiled on the fly.

# Package a coffeescript file, serve at /js/my-file.js
dk.assets.package "/js/my-file.js", "#{__dirname}/some-dir/my-file.coffee"

# Package a stylus file, serve at /css/my-file.css
dk.assets.package "/css/my-file.css", "#{__dirname}/some-dir/my-file.stylus"

# Package the result of a function as a file
dk.assets.package "/js/dynamic.js", ->
  "console.log('This could be something dynamically generated.');"

dk.assets.serve(url, fileOrFunction)

Serves the given file (or string generated by the passed function) at the URL. This file is not added to the JS or CSS packages, and will not be automatically loaded on the page. Coffeescript and stylus code will be compiled on the fly.

# Serve a coffeescript file at /js/my-file.js
dk.assets.package "/js/my-file.js", "#{__dirname}/some-dir/my-file.coffee"

# Serve a stylus file at /css/my-file.css
dk.assets.package "/css/my-file.css", "#{__dirname}/some-dir/my-file.stylus"

# Serve the result of a function at /js/dynamic.js
dk.assets.package "/js/dynamic.js", ->
  "console.log('This could be something dynamically generated.');"

dk.assets.jsFiles()

Returns an array of relative URLs for all packaged JS files. If the package option is true, it will return ["/js/all.js"].

# Get all the packaged JS URLs
dk.assets.jsFiles() # returns ["/js/thisFile.js", "/js/thatFile.js", etc...]

dk.assets.cssFiles()

Returns an array of relative URLs for all packaged CSS files. If the package option is true, it will return ["/css/all.css"].

# Get all the packaged CSS URLs
dk.assets.cssFiles() # returns ["/css/thisFile.css", "/css/thatFile.css", etc...]

dk-couchdb

WARNING! This framework is currently in very early development, it may be broken or may break at any time.

The dk-couchdb plugin gives you access to CouchDB databases in a DrumKit.js app.

Installation

Install the package locally with npm:

npm install dk-couchdb

On the Server

new dk.couchdb()

Create a database connection to a CouchDB instance running at http://localhost:5984 by instantiating a dk.couchdb object with your database name:

db = new dk.couchdb "my-database-name"

If your CouchDB is running on another host or port, you can pass these in as options:

db = new dk.couchdb "my-database-name", host: "myhost.com", port: 1234

db.get(id, function(err, data){})

Single documents can be fetched by id using the get instance method. This is an asynchronous operation, so the second argument is a required callback.

db.get "some-id", (err, doc) ->
  if err
    console.log "Error: #{err}"
  else
    console.log "Got doc", doc

db.view(viewName, function(err, docs){})

Multiple documents can be fetched using a CouchDB view with the view instance method. This is an asynchronous operation, so the second argument is a required callback.

db.view "my-design-doc/all", (err, docs) ->
  if err
    console.log "Error: #{err}"
  else
    console.log "Got docs", docs

db.save(data, function(err, doc){})

You can create or update a document using the save instance method. This is an asynchronous operation, so the second argument is a required callback. If the data has an id key, it will be an update, otherwise save will create a new document.

data = {firstName: "Chris", lastName: "Powers"}
db.save data, (err, doc) ->
  if err
    console.log "Error: #{err}"
  else
    console.log "Saved doc", doc

db.destroy(id, function(err){})

You can remove a document from the database using the destroy instance method with the document id. This is an asynchronous operation, so the second argument is a required callback.

db.destroy "some-id", (err) ->
  if err
    console.log "Error: #{err}"
  else
    console.log "Removed the document"

In the Browser

Currently dk-couchdb is not available directly in the browser, use dk-model instead.

dk-model-couchdb

A CouchDB Model adapter for DrumKit.

WARNING! This framework is currently in very early development, it may be broken or may break at any time.

Installation

Install this plugin with npm:

npm install dk-model-couchdb

Getting Started

All you need to do is include this plugin in your package.json file and you should be good to go. dk-model-couchdb will automatically hook into dk-model and dk-couchdb for you, so no configuration should be necessary on your end.

dk-model

WARNING! This framework is currently in very early development, it may be broken or may break at any time.

The dk-model plugin provides a database-agnositic persistence layer API to DrumKit.js that can be used both on the server and the browser.

Installation

Install dk-model using npm:

npm install dk-model

Getting Started

By default, dk-model expects your project to have a models directory that will automatically load your model files from there. If you want to use a different directory, you can configure the dir option:

dk.model.config dir: "#{__dirname}/nonstandardModelDir"

Model classes are created using the dk.model method, which takes the model name and a callback as parameters. The callback function will be called with your new model class as the an argument. Inside the callback function is where you should add instance methods, class methods and properties to your class. For example:

dk.model "User", (User) ->
  # These are the attributes that will be persisted
  User.property "firstName", String
  User.property "lastName", String

  # Class methods, this will print:
  #   Property: firstName, Type: String
  #   Property: lastName, Type: String
  User.printProperties = ->
    for name, type of this.properties
      console.log "Property: #{name}, Type: #{type}"

  # Instance methods (ie methods on prototype object)
  User::fullName = ->
    "#{@firstName} #{@lastName}"

Model classes are generated by the CoffeeScript class construct, so you are able to use prototypal inheritance.

To access your new model class in other files you can use the dk.model method without the callback:

User = dk.model "User"
john = new User firstName: "John", lastName: "Smith"
john.fullName() # returns "John Smith"

CRUD Operations

The goal of dk-model is to provide the developer with a database agnostic persistence API that will proxy CRUD operations to the appropriate persistence plugin. For example, the dk-model-couchdb plugin acts as an adapter between dk-model and dk-couchdb.

All the methods listed below will be available both on the server and browser, as will your custom model methods.

All CRUD operations are asyncronous and require callback functions as their last parameter. The callback functions generally are passed any resulting errors as their first parameter and an object (or array of objects) as the second.

Class Methods

new MyModel(attributes={})

Instances of a model class are initialized using the new constructor and take an object of attributes as the first parameter.

User = dk.model "User"
user = new User firstName: "John", lastName: "Smith"

.all(options, function(err, objects))

Fetches all records based on the options that are passed (options may be different across adapters).

User = dk.model "User"
User.all {}, (err, users) ->
  if err
    console.log "Error fetching users:", err
  else
    for user in users
      console.log "Fetched", user.fullName()

.get(id, function(err, object))

Fetches a single record by its identifier.

User = dk.model "User"
User.get 123, (err, user) ->
  if err
    console.log "Error fetching user:", err
  else
    console.log "Fetched", user.fullName()

.save(attributes, function(err, object))

Attempts to create a new record with the given attributes, or update a record if attributes has an id.

User = dk.model "User"
User.save firstName: "John", lastName: "Smith", (err, user) ->
  if err
    console.log "Error creating user:", err
  else
    console.log "Created", user.fullName()

User.save id: 123, firstName: "Jane", lastName: "Doe", (err, user) ->
  if err
    console.log "Error updating user:", err
  else
    console.log "Updated", user.fullName()

.create(attributes, function(err, object))

Right now this simply aliases save.

.destroy(id, function(err))

Deletes the record with the given id.

User = dk.model "User"
User.destroy 123, (err) ->
  if err
    console.log "Error destroying user:", err
  else
    doSomethingElse()

Instance Methods

save(function(err, object))

Saves the given model object. If it is a new record, then the object passed into the callback will have its new id.

User = dk.model "User"
user = new User firstName: "John"
user.lastName = "Smith"
user.save (err, obj) ->
  if err
    console.log "Error saving user:", err
  else
    console.log "New user's id is", obj.id

destroy(function(err))

Deletes the given model object from persistence (currently the JS object will remain in memory).

User = dk.model "User"
User.get 123, (err, user) ->
  user.destroy (err) ->
    if err
      console.log "Error destroying user:", err
    else
      console.log "Just destroyed", user.fullName()

TODO

This still needs a lot of work and love, including but not limited to:

  • Validation
  • Better error handling
  • Using promises rather than callbacks
  • More adapters

dk-routes

WARNING! This framework is currently in very early development, it may be broken or may break at any time.

This is a DrumKit plugin that adds URL routing on both the server and browser.

Installation

Install dk-routes with npm:

npm install dk-routes

Getting Started

The dk-routes plugin assumes that you have a routes.coffee file that defines all your routes. To use a different file, pass the path option to config:

dk.routes.config path: "#{__dirname}/nonstandard-path.coffee"

Inside this file you can define your routes, which will be available both on the server and on the browser. The routes DSL provides you with the top level methods get, post, put and del (delete). Each of these methods takes three parameters -- a route URL, an optional helper method name and a function. For example:

get "/users", "users", ->
  dk.model("User").all {}, (err, users) =>
    this.render "users", users: users

In the above example, when either the server or the browser receives a request for the url /users, it will fetch all the User objects and use them to render the users view. Also, because "users" was passed as the second parameter to get, the helper method usersPath will be added to all templates.

Note that in the example, the callback passed to the User.all method uses the double arrow => rather than the single ->. This is done to maintain the value of this inside the callback because inside routes, this points to a special RouteContext object.

RouteContext

Inside of any route function, this refers to a RouteContext object. These objects have two purposes:

  1. Make request details available (ex. params)
  2. Provide route actions (ex. rendering, redirects)

Here is the current (limited) API:

params(paramName)

Returns the value of the request param with the given name. This param could be in the URL, the querystring or a POST message body.

get "/users/:id", "user", ->
  dk.model("User").get this.params("id"), (err, user) =>
    this.render "user", user: user

render(templateName, locals)

Renders the template with the given templateName using the given locals.

get "/users/:id", "user", ->
  dk.model("User").get this.params("id"), (err, user) =>
    this.render "user", user: user

redirect(path)

Redirect the user to the given path.

post "/users", ->
  dk.model("User").create this.params("user"), (err, user) =>
    this.redirect "/users/#{user.id}"

title(str)

Sets the value of the page title tag.

get "/users/:id", "user", ->
  dk.model("User").get this.params("id"), (err, user) =>
    this.title "User: #{user.fullName()}"
    this.description "This is a page about #{user.fullName()}"
    this.render "user", user: user

description(str)

Sets the value of the page description meta tag.

get "/users/:id", "user", ->
  dk.model("User").get this.params("id"), (err, user) =>
    this.title "User: #{user.fullName()}"
    this.description "This is a page about #{user.fullName()}"
    this.render "user", user: user

TODO

Tons of work still needed on this, especially:

  • Figure out how to keep browser from overwriting what server generates
  • Build out RouteContext to have more request data and actions
  • Allow routes file to be straight JS
  • More routing features

dk-server

HTTP Server Plugin for DrumKit.js

WARNING! This framework is currently in very early development, it may be broken or may break at any time.

Installation

You can install dk-server using npm:

npm install dk-server

Getting Started

This module is meant to be pretty low-level, so application developers should not need to ever use it directly. If you need to setup URLs and respond to HTTP requests, you should probably be using the dk-routes plugin.

Plugin Developers Guide

The dk-server plugin acts as a Connect compliant server to allow you to respond to requests and wire up middleware. You are given get, post, put, del and use. This module cannot be used on the browser.

dk.server.get "/hello", (req, res) ->
  res.send "Hello there!"

connect = require "connect"
dk.server.use connect.logger(format: ":method :url")

NOTE: If you need to serve asset files (JS, CSS, images), use dk-assets.

dk-template

Server and Browser Templating for DrumKit.js

WARNING! This framework is currently in very early development, it may be broken or may break at any time.

Installation

You can install dk-template using npm:

npm install dk-assets

Getting Started

Out of the box, dk-template assumes that you have a views directory that holds all of your templates. If you need to customize this, you can do so in your app configuration:

dk.template.config dir: "/path/to/my/views"

Currently dk-template supports .eco and .ejs templates. Other rendering engines can easily be added (see Plugin Developers Guide). The render method takes a template name and a context object, returning the rendered template as a string:

<!-- in views/js-user.ejs -->
<p>My name is <%= user.name %> and I like straight JS.</p>

```html
<!-- in views/coffee-user.eco -->
<p>My name is <%= @user.name %> and I prefer CoffeeScript.</p>

```coffeescript
# In my CoffeeScript source

dk.template.render "js-user", user: {name: "John"}
# => returns "<p>My name is John and I like straight JS.</p>"

dk.template.render "coffee-user", user: {name: "Jane"}
# => returns "<p>My name is Jane and I prefer CoffeeScript.</p>"

The `render` method is available both on the server and the browser. Please refer 
to the EJS and ECO projects' documentation for a full explanation of their features.


## View Helper Methods

To add helper methods that will be available to all templates, use the 
`dk.template.helpers.add` method in your `helpers.coffee` file:

```html
<!-- in views/quote.eco -->
<p>Favorite Quote: "<%= @truncate @quote, 10 %>"</p>
# In helpers.coffee
dk.template.helpers.add 
  truncate: (str, len) ->
    if str.length > len
      str.slice(0, len) + '...'
    else
      str
# Elsewhere in the app
dk.template.render "quote", quote: "Four score and seven years ago"
# returns '<p>Favorite Quote: "Four score..."</p>

Helper methods defined in your helpers.coffee file will be made available on both the server and browser. If you want to define your helper methods in a file other than helpers.coffee, you can do so by using the helpersPath config option:

dk.template.config helpersPath: "#{__dirname}/nonstandardHelpersPath.coffee

Also, you can use a helpers.js file instead if you prefer straight JS.

Plugin Developers Guide

Support for .ejs, .eco and .mustache files was added simply using Drumkit plugin extensions, so it is easy to create your own extensions to support other rendering engines. View the following files to see how it is done:

  • lib/dk-template-eco.coffee
  • lib/dk-template-ejs.coffee
  • lib/dk-template-mustache.coffee
  • public/js/dk-template-eco.coffee
  • public/js/dk-template-ejs.coffee
  • public/js/dk-template-mustache.coffee

dk.template.layout

This module is responsible for rendering full page layouts on the server. By default, dk.template.layout uses its own minimal layout, which is at ./views/layout.eco. To use your own custom layout file, use the path option of the config method.

dk.template.layout.config(options)

Available options:

  • path: (String) An absolute path to your custom layout file. Defaults to using a built-in layout.
  • title: (String) A default page title, defaults to "".
  • description: (String) A default page description, defaults to "".
dk.template.layout.config
  path: "#{__dirname}/views/layout.eco"
  title: "My DrumKit App"
  description: "This app was built using DrumKit.js"

dk.template.layout.render(templateName, context)

Renders the template called templateName inside of your layout.

NOTE: The layout has these additional values available in its context:

  • content: The rendered content of the inner view template templateName.
  • title: The page title.
  • description: The page description.
# renders the 'users' template inside of the page layout
dk.template.layout.render "users", users: ["Bill", "Susan"]

dk-websockets

WARNING! This framework is currently in very early development, it may be broken or may break at any time.

The dk-websockets plugin adds Websocket functionality to your DrumKit.js application.

Installation

Install the package with npm:

npm install dk-websockets

Getting Started

For general use you should not use dk-websockets directly -- use the higher-level dk-transport instead.

Plugin Developers Guide

The dk.websockets object is an EventEmitter, so you can listen for the following events:

dk.websockets.on "connection", (client) ->
  # do something
dk.websockets.on "message", (msg) ->
  # do something
dk.websockets.on "disconnect", (client) ->
  # do something
npm loves you