Connect 2.0

Connect 2.0 is here with new core middleware, miscellaneous improvements, and some new docs.

var app = connect()
  .use(connect.logger('dev'))
  .use(connect.static('public'))
  .use(function(req, res){
    res.end('hello world\n');
  })

 app.listen(3000);

HTTP and HTTPS

Previously connect.Server inherited from Node’s core net.Server, this made it difficult to provide both HTTP and HTTPS for your application. The result of connect() (formerly connect.createServer()) is now simply a JavaScript Function. This means that you may omit the call to app.listen(), and simply pass app to a Node net.Server as shown here:

var connect = require('connect')
  , http = require('http')
  , https = require('https');

var app = connect()
  .use(connect.logger('dev'))
  .use(connect.static('public'))
  .use(function(req, res){
    res.end('hello world\n');
  })

http.createServer(app).listen(80);
https.createServer(tlsOptions, app).listen(443);

Body parsers

The bodyParser() middleware is now nothing but a short-hand for adding the json(), multipart(), and urlencoded() middleware. Each of these populate req.body with an object containing the parsed values, multipart() provides req.body and req.files for uploads.

Core compression

As of Node 0.6.0 fast, native compression capabilities are available, so now we have the compress() middleware supporting deflate and gzip.

Cookie parser

The cookieParser() middleware now supports signed cookies, and accepts a secret. This replaces the need to pass session({ secret: string }) to the session() middleware. Signed cookies are available via req.signedCookies, and unsigned as req.cookies.

Error delegation

Previously a few of the core middleware would respond to error situations directly, these have been changed to simply next(err)-them along. This change allows you to specify customized behaviour by adding an error-handling middleware:

app.use(function(err, req, res, next){
  if (4 == err.status / 100) {
    // render a client-error page
  } else {
    // render a server-error page
  }
});

Session

As mentioned session() no longer requires a secret. The cookie .maxAge has been defaulted to null, meaning that it will be a browser-session cookie, expiring once the visitor closes their browser.

Third-party middleware

Third-party middleware should remain perfectly functional. This release of Connect is not compatible with Express 2.x, Express 3.0 is coming soon.

Changelog

The following significant changes were made, as well as several others that do not impact public API, such as a full rewrite of the tests using Mocha.

  • Added cookieSession() middleware for cookie-only sessions
  • Added compress() middleware for gzip / deflate support
  • Added session() “proxy” setting to trust X-Forwarded-Proto
  • Added json() middleware to parse “application/json”
  • Added urlencoded() middleware to parse “application/x-www-form-urlencoded”
  • Added multipart() middleware to parse “multipart/form-data”
  • Added cookieParser(secret) support so anything using this middleware may access signed cookies
  • Added signed cookie support to cookieParser()
  • Added support for JSON-serialized cookies to cookieParser()
  • Added err.status support in Connect’s default end-point
  • Added X-Cache MISS / HIT to staticCache()
  • Added public res.headerSent checking nodes res._headerSent until node does
  • Changed basicAuth() req.remoteUser to req.user
  • Changed: default session() to a browser-session cookie. Closes #475
  • Changed: no longer lowercase cookie names
  • Changed bodyParser() to use json(), urlencoded(), and multipart()
  • Changed: errorHandler() is now a development-only middleware
  • Changed middleware to next() errors when possible so applications can unify logging / handling
  • Removed http[s].Server inheritance, now just a function, making it easy to have an app providing both http and https
  • Removed .createServer() (use connect())
  • Removed secret option from session(), use cookieParser(secret)
  • Removed connect.session.ignore array support
  • Removed router() middleware. Closes #262
  • Fixed: set-cookie only once for browser-session cookies
  • Fixed FQDN support. dont add leading “/”
  • Fixed 404 XSS attack vector. Closes #473
  • Fixed HEAD support for 404s and 500s generated by Connect’s end-point

Mocha test coverage

The latest release of Mocha adds two new reporters, now totaling 13 packaged with the library. The two new ones are “json-cov” and “html-cov”, the latter inherits from the former in order to produce a single-page test coverage report.

test coverage example

If you’re curious what a live example looks like, check out this page.

Setup

With Node’s require.paths array out of the picture there’s a bit of boiler-plate involved in setting up test coverage for your project, but it’s pretty minimal. First you’ll want to install the jscoverage executable, this program parses your source code and spits out an instrumented version, effectively a bunch of lines that look like this:

  $_jscoverage[filename][line]++;

This enables libraries like Mocha to execute the code as they normally would, however we can then extract this coverage information and generate fancy reports. jscoverage takes the input directory, and an output directory, I usually calls this “lib-cov”:

 $ jscoverage lib lib-cov

Typically when testing your library you’ll use relative require() calls that look like this: var express = require('../'), and the library entry point is ./index.js. Normally this file might look something like below, or you may not have an ./index.js file at all.

  module.exports = require('./lib/express');

By using ./index.js we can then alter this statement to conditionally export the instrumented version when the EXPRESS_COV environment variable is present:

 module.exports = process.env.EXPRESS_COV
   ? require('./lib-cov/express')
   : require('./lib/express');

Then all you need to do is invoke mocha with --reporter html-cov and redirect the stdout to a file such as coverage.html. Line 25 the test-cov target of the Express Makefile illustrates how I typically handle this but depending on your setup it may vary.

That’s it! remember to add “coverage.html” to your .npmignore and .gitignore files ;)

Stylus gets @extend

@extend is a great little feature which originated in SASS, and now finds a home in Stylus. If you’ve ever written CSS like this, you know it can become quite the pain to maintain large lists of selectors:

.message,
.warning,
.error {
  font-size: 14px;
  padding: 5px 10px;
  border: 1px solid #eee;
  border-radius: 5px;
}

.warning {
  color: yellow;
}

.error {
  color: red;
}

@extend makes this process flow naturally, and even supports inheritance. In Stylus you may use @extend or @extends, I prefer the latter personally but that’s up to you! Using this feature you would define .message on it’s own, and simply __@extend_ it from within the other rulesets:

.message {
  font-size: 14px;
  padding: 5px 10px;
  border: 1px solid #eee;
  border-radius: 5px;
}

.warning {
  @extends .message;
  color: yellow;
}

.error {
  @extends .message;
  color: red;
}

Taking this even further with inheritance:

.fatal-error {
  @extends .error;
  font-weight: bold
}

Would yield the following CSS:

.message,
.warning,
.error,
.fatal-error {
  font-size: 14px;
  padding: 5px 10px;
  border: 1px solid #eee;
  border-radius: 5px;
}
.warning {
  color: #ff0;
}
.error,
.fatal-error {
  color: #f00;
}
.fatal-error {
  font-weight: bold;
}

Here’s another example:

form
  button
    padding: 10px
    border: 1px solid #eee
    border-radius: 5px

ul
  li a
    @extends form button

Yielding:

form button,
ul li a {
  padding: 10px;
  border: 1px solid #eee;
  border-radius: 5px;
}

And of course you may utilize the alternative Stylus syntax if you prefer:

.message
  font-size: 14px
  padding: 5px 10px
  border: 1px solid #eee
  border-radius: 5px

.warning
  @extends .message
  color: yellow

.error
  @extends .message
  color: red

.fatal-error
  @extends .error
  font-weight: bold

Grab Stylus 0.22.4 for these goodies!

Connect 1.8.0 - multipart support

Connect 1.8.0 is a tiny but substantial release because it adds multipart/form-data support via Felix Geisendörfer’s fantastic multipart parser formidable, it’s great and chances are you’re already using it!

The bodyParser() middleware now unifies multipart, json, and x-www-form-urlencoded parsing, providing the req.body object containing the parsed data. For security purposes the files are placed in a separate object, req.files, however just as accessible. A constant struggle that I’ve seen in the community is the concept of “missing” request data events so this will prevent further confusion. The downside to this is that if you wish to report upload progress, or access files and fields as the request is streamed, you will have to use formidable directly.

Before this addition your use of formidable might look something like the following (with Express):

  app.post('/someform', function(req, res, next){
    var form = new formidable.IncomingForm;
    form.parse(req, function(err, fields, files){
      if (err) return next(err);
      // do something with files.image etc
    });
  });

With the new bodyParser() all you need is:

  app.use(express.bodyParser());

  app.post('/some-form', function(req, res){
    // do something with req.files.image
  })

The middleware takes the same options that are mentioned on formidable’s GitHub repo page, so you can specify things like size limits, retaining extensions, the upload directory etc.

  app.use(express.bodyParser({
    uploadDir: '/tmp/uploads'
  }));

That’s it! but I think this will cover well above the 80% use-case and prevent a lot of headaches that people have with the previous the inconsistencies.

Stylus 0.15.1 - new property reference & @keyframes fabrication features

Stylus 0.15.x adds a bunch of cool new functionality as well as some important bug fixes.

@keyframes fabrication

The new keyframes fabrication support automatically duplicates your @keyframes definitions to support vendor prefixes. Note that this is only a default, as shown below:

@-moz-keyframes foo {
  0% {
    color: #000;
  }

  100% {
    color: #fff;
  }
}
@-webkit-keyframes foo {
  0% {
    color: #000;
  }

  100% {
    color: #fff;
  }
}
@keyframes foo {
  0% {
    color: #000;
  }

  100% {
    color: #fff;
  }
}

one can tweak this functionality using the vendors list as shown in the following snippet which will only expand to the -webkit- vendor prefix.

vendors = moz official

@keyframes foo {
  from {
    color: black
  }
  to {
    color: white
  }
}

The vendors property may be utilized more in the future, and perhaps in frameworks like “nib” to unify configuration.

Property reference

The syntax @<property> has been introduced to reference values of existing properties. For example if you want to re-use values, you may typically do something like below instead of typing the value several times, also allowing you to use functions with w.

.button
  width: w = 50px
  height: w

The new property reference syntax allows you to treat properties as variables, which can also be accessed within mixins:

.button
  width: 50px
  height: @width

Comment compilation

When the compress option is true Stylus will not output single-line nor multi-line comments, which are commonly found used for licensing in stylesheet frameworks etc, so it’s useful to strip these out however you can now force output with the ! character /*!.

New built-in functions

The math functions cos() and sin() were added, as well as exposing PI.

Bug fixes

  • Fixed @import on windows