README
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!
Build models with dk-model (see also dk-model-couchdb and dk-couchdb).
Build view templates and helpers with dk-template.
Build routes with dk-routes.
Check out these other DrumKit plugins:
- 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 whetherdk-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:
- Make request details available (ex. params)
- 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 templatetemplateName
.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