remove last pieces of connect dependency

- copy over patch.js to shim ServerResponse
- bundle `static` middleware
This commit is contained in:
Roman Shtylman
2014-02-15 20:20:12 -05:00
parent 6a7363e4ae
commit 1396e0855d
30 changed files with 321 additions and 156 deletions

View File

@@ -8,6 +8,7 @@
- `app.router` - is removed
- `req.accepted*` - use `req.accepts*()` instead
- `res.location` - relative URL resolution is removed
- all bundled middleware except `static`
* change:
- `app.route` -> `app.mountpath` when mounting an express app in another express app
- `json spaces` no longer enabled by default in development

View File

@@ -3,7 +3,10 @@
*/
var express = require('../..')
, hash = require('./pass').hash;
, hash = require('./pass').hash
, bodyParser = require('body-parser')
, cookieParser = require('cookie-parser')
, session = require('express-session')
var app = module.exports = express();
@@ -14,9 +17,9 @@ app.set('views', __dirname + '/views');
// middleware
app.use(express.bodyParser());
app.use(express.cookieParser('shhhh, very secret'));
app.use(express.session());
app.use(bodyParser());
app.use(cookieParser('shhhh, very secret'));
app.use(session());
// Session-persisted message middleware

View File

@@ -1,5 +1,6 @@
var express = require('../..')
, logger = require('morgan')
, app = express();
app.set('views', __dirname);
@@ -14,11 +15,11 @@ while (n--) {
pets.push({ name: 'Jane', age: 6, species: 'ferret' });
}
app.use(express.logger('dev'));
app.use(logger('dev'));
app.get('/', function(req, res){
res.render('pets', { pets: pets });
});
app.listen(3000);
console.log('Express listening on port 3000');
console.log('Express listening on port 3000');

View File

@@ -4,17 +4,19 @@
*/
var express = require('../../');
var favicon = require('static-favicon');
var cookie-parser = require('cookie-parser');
var app = module.exports = express();
// ignore GET /favicon.ico
app.use(express.favicon());
app.use(favicon());
// pass a secret to cookieParser() for signed cookies
app.use(express.cookieParser('manny is cool'));
app.use(cookieParser('manny is cool'));
// add req.session cookie support
app.use(express.cookieSession());
app.use(cookieSession());
// do something with the session
app.use(count);
@@ -29,4 +31,4 @@ function count(req, res) {
if (!module.parent) {
app.listen(3000);
console.log('Express server listening on port 3000');
}
}

View File

@@ -4,7 +4,11 @@
*/
var express = require('../../')
, app = module.exports = express();
, app = module.exports = express()
, favicon = require('static-favicon')
, logger = require('morgan')
, cookieParser = require('cookie-parser')
, bodyParser = require('body-parser')
// add favicon() before logger() so
@@ -12,20 +16,20 @@ var express = require('../../')
// logged, because this middleware
// reponds to /favicon.ico and does not
// call next()
app.use(express.favicon());
app.use(favicon());
// custom log format
if ('test' != process.env.NODE_ENV)
app.use(express.logger(':method :url'));
app.use(logger(':method :url'));
// parses request cookies, populating
// req.cookies and req.signedCookies
// when the secret is passed, used
// when the secret is passed, used
// for signing the cookies.
app.use(express.cookieParser('my secret here'));
app.use(cookieParser('my secret here'));
// parses json, x-www-form-urlencoded, and multipart/form-data
app.use(express.bodyParser());
app.use(bodyParser());
app.get('/', function(req, res){
if (req.cookies.remember) {
@@ -51,4 +55,4 @@ app.post('/', function(req, res){
if (!module.parent){
app.listen(3000);
console.log('Express started on port 3000');
}
}

View File

@@ -3,7 +3,9 @@
*/
var express = require('../..')
, logger = require('morgan')
, app = express()
, bodyParser = require('body-parser')
, api = express();
// app middleware
@@ -12,8 +14,8 @@ app.use(express.static(__dirname + '/public'));
// api middleware
api.use(express.logger('dev'));
api.use(express.bodyParser());
api.use(logger('dev'));
api.use(bodyParser());
/**
* CORS support.

View File

@@ -4,6 +4,8 @@
var express = require('../../')
, app = module.exports = express()
, logger = require('morgan')
, favicon = require('static-favicon')
, silent = 'test' == process.env.NODE_ENV;
// general config
@@ -21,9 +23,9 @@ if ('production' == app.settings.env) {
app.disable('verbose errors');
}
app.use(express.favicon());
app.use(favicon());
silent || app.use(express.logger('dev'));
silent || app.use(logger('dev'));
// Routes

View File

@@ -4,10 +4,11 @@
*/
var express = require('../../')
, logger = require('morgan')
, app = module.exports = express()
, test = app.get('env') == 'test';
if (!test) app.use(express.logger('dev'));
if (!test) app.use(logger('dev'));
// error handling middleware have an arity of 4
// instead of the typical (req, res, next),

View File

@@ -1,5 +1,6 @@
var express = require('../..')
, logger = require('morgan')
, app = express();
app.set('view engine', 'jade');
@@ -23,7 +24,7 @@ User.prototype.toJSON = function(){
}
};
app.use(express.logger('dev'));
app.use(logger('dev'));
// earlier on expose an object
// that we can tack properties on.
@@ -57,4 +58,4 @@ app.get('/user', function(req, res){
});
app.listen(3000);
console.log('app listening on port 3000');
console.log('app listening on port 3000');

View File

@@ -1,4 +1,8 @@
var express = require('../..');
var logger = require('morgan');
var session = require('express-session');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var app = module.exports = express();
@@ -25,20 +29,17 @@ app.response.message = function(msg){
};
// log
if (!module.parent) app.use(express.logger('dev'));
if (!module.parent) app.use(logger('dev'));
// serve static files
app.use(express.static(__dirname + '/public'));
// session support
app.use(express.cookieParser('some secret here'));
app.use(express.session());
app.use(cookieParser('some secret here'));
app.use(session());
// parse request bodies (req.body)
app.use(express.bodyParser());
// support _method (PUT in forms etc)
app.use(express.methodOverride());
app.use(bodyParser());
// expose the "messages" local variable when views are rendered
app.use(function(req, res, next){

View File

@@ -5,6 +5,9 @@
var express = require('../..')
, app = express()
, logger = require('morgan')
, cookieParser = require('cookie-parser')
, bodyParser = require('body-parser')
, site = require('./site')
, post = require('./post')
, user = require('./user');
@@ -13,10 +16,9 @@ var express = require('../..')
app.set('view engine', 'jade');
app.set('views', __dirname + '/views');
app.use(express.logger('dev'));
app.use(express.cookieParser());
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(logger('dev'));
app.use(cookieParser());
app.use(bodyParser());
app.use(express.static(__dirname + '/public'));
// General

View File

@@ -7,8 +7,6 @@ var express = require('../..');
var app = express();
app.use(express.logger('dev'));
// Required by session() middleware
// pass the secret for signed cookies
// (required by session())

View File

@@ -1,9 +1,10 @@
var express = require('../..');
var logger = require('morgan');
var app = express();
// log requests
app.use(express.logger('dev'));
app.use(logger('dev'));
// express on its own has no notion
// of a "file". The express.static()
@@ -41,4 +42,4 @@ console.log('listening on port 3000');
console.log('try:');
console.log(' GET /hello.txt');
console.log(' GET /js/app.js');
console.log(' GET /css/style.css');
console.log(' GET /css/style.css');

View File

@@ -3,6 +3,7 @@
*/
var express = require('../..');
var logger = require('morgan');
/*
edit /etc/hosts:
@@ -16,7 +17,7 @@ edit /etc/hosts:
var main = express();
main.use(express.logger('dev'));
main.use(logger('dev'));
main.get('/', function(req, res){
res.send('Hello from main app!')

View File

@@ -6,7 +6,8 @@ var mixin = require('utils-merge')
, escapeHtml = require('escape-html')
, Router = require('./router')
, methods = require('methods')
, middleware = require('./middleware')
, middleware = require('./middleware/init')
, query = require('./middleware/query')
, debug = require('debug')('express:application')
, View = require('./view')
, http = require('http');
@@ -98,7 +99,7 @@ app.lazyrouter = function() {
strict: this.enabled('strict routing')
});
this._router.use(middleware.query());
this._router.use(query());
this._router.use(middleware.init(this));
}
};

View File

@@ -4,8 +4,7 @@
var EventEmitter = require('events').EventEmitter;
var connect = require('connect')
, merge = require('merge-descriptors')
var merge = require('merge-descriptors')
, mixin = require('utils-merge')
var proto = require('./application')
@@ -14,18 +13,15 @@ var proto = require('./application')
, req = require('./request')
, res = require('./response')
// monkey patch ServerResponse methods
require('./patch')
/**
* Expose `createApplication()`.
*/
exports = module.exports = createApplication;
/**
* Expose mime.
*/
exports.mime = connect.mime;
/**
* Create an express application.
*
@@ -47,13 +43,6 @@ function createApplication() {
return app;
}
/**
* Expose connect.middleware as express.*
* for example `express.logger` etc.
*/
merge(exports, connect.middleware);
/**
* Expose the prototypes.
*/
@@ -69,7 +58,8 @@ exports.response = res;
exports.Route = Route;
exports.Router = Router;
// Error handler title
exports.errorHandler.title = 'Express';
/**
* Expose middleware
*/
exports.static = require('./middleware/static');

View File

@@ -1,66 +0,0 @@
/**
* Module dependencies.
*/
var parseUrl = require('./utils').parseUrl;
var qs = require('qs');
/**
* Initialization middleware, exposing the
* request and response to eachother, as well
* as defaulting the X-Powered-By header field.
*
* @param {Function} app
* @return {Function}
* @api private
*/
exports.init = function(app){
return function expressInit(req, res, next){
if (app.enabled('x-powered-by')) res.setHeader('X-Powered-By', 'Express');
req.res = res;
res.req = req;
req.next = next;
req.__proto__ = app.request;
res.__proto__ = app.response;
res.locals = res.locals || Object.create(null);
next();
}
};
/**
* Query:
*
* Automatically parse the query-string when available,
* populating the `req.query` object using
* [qs](https://github.com/visionmedia/node-querystring).
*
* Examples:
*
* .use(connect.query())
* .use(function(req, res){
* res.end(JSON.stringify(req.query));
* });
*
* The `options` passed are provided to qs.parse function.
*
* @param {Object} options
* @return {Function}
* @api public
*/
exports.query = function query(options){
return function query(req, res, next){
if (!req.query) {
req.query = ~req.url.indexOf('?')
? qs.parse(parseUrl(req).query, options)
: {};
}
next();
};
};

26
lib/middleware/init.js Normal file
View File

@@ -0,0 +1,26 @@
/**
* Initialization middleware, exposing the
* request and response to eachother, as well
* as defaulting the X-Powered-By header field.
*
* @param {Function} app
* @return {Function}
* @api private
*/
exports.init = function(app){
return function expressInit(req, res, next){
if (app.enabled('x-powered-by')) res.setHeader('X-Powered-By', 'Express');
req.res = res;
res.req = req;
req.next = next;
req.__proto__ = app.request;
res.__proto__ = app.response;
res.locals = res.locals || Object.create(null);
next();
}
};

35
lib/middleware/query.js Normal file
View File

@@ -0,0 +1,35 @@
var qs = require('qs');
var parseUrl = require('../utils').parseUrl;
/**
* Query:
*
* Automatically parse the query-string when available,
* populating the `req.query` object using
* [qs](https://github.com/visionmedia/node-querystring).
*
* Examples:
*
* .use(connect.query())
* .use(function(req, res){
* res.end(JSON.stringify(req.query));
* });
*
* The `options` passed are provided to qs.parse function.
*
* @param {Object} options
* @return {Function}
* @api public
*/
module.exports = function query(options){
return function query(req, res, next){
if (!req.query) {
req.query = ~req.url.indexOf('?')
? qs.parse(parseUrl(req).query, options)
: {};
}
next();
};
};

87
lib/middleware/static.js Normal file
View File

@@ -0,0 +1,87 @@
/*!
* Connect - static
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var send = require('send')
, utils = require('../utils')
, parse = utils.parseUrl
, url = require('url');
/**
* Static:
*
* Static file server with the given `root` path.
*
* Examples:
*
* var oneDay = 86400000;
*
* connect()
* .use(connect.static(__dirname + '/public'))
*
* connect()
* .use(connect.static(__dirname + '/public', { maxAge: oneDay }))
*
* Options:
*
* - `maxAge` Browser cache maxAge in milliseconds. defaults to 0
* - `hidden` Allow transfer of hidden files. defaults to false
* - `redirect` Redirect to trailing "/" when the pathname is a dir. defaults to true
* - `index` Default file name, defaults to 'index.html'
*
* @param {String} root
* @param {Object} options
* @return {Function}
* @api public
*/
exports = module.exports = function(root, options){
options = options || {};
// root required
if (!root) throw new Error('static() root path required');
// default redirect
var redirect = false !== options.redirect;
return function staticMiddleware(req, res, next) {
if ('GET' != req.method && 'HEAD' != req.method) return next();
var originalUrl = url.parse(req.originalUrl);
var path = parse(req).pathname;
if (path == '/' && originalUrl.pathname[originalUrl.pathname.length - 1] != '/') {
return directory();
}
function directory() {
if (!redirect) return next();
var target;
originalUrl.pathname += '/';
target = url.format(originalUrl);
res.statusCode = 303;
res.setHeader('Location', target);
res.end('Redirecting to ' + utils.escape(target));
}
function error(err) {
if (404 == err.status) return next();
next(err);
}
send(req, path)
.maxage(options.maxAge || 0)
.root(root)
.index(options.index || 'index.html')
.hidden(options.hidden)
.on('error', error)
.on('directory', directory)
.pipe(res);
};
};

79
lib/patch.js Normal file
View File

@@ -0,0 +1,79 @@
/*!
* Connect
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var http = require('http');
var ServerResponse = http.ServerResponse;
// apply only once
if (ServerResponse.prototype._hasConnectPatch) {
return;
}
// original methods
var setHeader = ServerResponse.prototype.setHeader;
var writeHead = ServerResponse.prototype.writeHead;
/**
* Provide a public "header sent" flag
* until node does.
*
* @return {Boolean}
* @api public
*/
ServerResponse.prototype.__defineGetter__('headerSent', function(){
return this._header;
});
/**
* Set header `field` to `val`, special-casing
* the `Set-Cookie` field for multiple support.
*
* @param {String} field
* @param {String} val
* @api public
*/
ServerResponse.prototype.setHeader = function(field, val){
var key = field.toLowerCase()
, prev;
// special-case Set-Cookie
if (this._headers && 'set-cookie' == key) {
if (prev = this.getHeader(field)) {
if (Array.isArray(prev)) {
val = prev.concat(val);
} else if (Array.isArray(val)) {
val = val.concat(prev);
} else {
val = [prev, val];
}
}
// charset
} else if ('content-type' == key && this.charset) {
val += '; charset=' + this.charset;
}
return setHeader.call(this, field, val);
};
ServerResponse.prototype.writeHead = function(statusCode, reasonPhrase, headers){
if (typeof reasonPhrase === 'object') headers = reasonPhrase;
if (typeof headers === 'object') {
Object.keys(headers).forEach(function(key){
this.setHeader(key, headers[key]);
}, this);
}
if (!this._emittedHeader) this.emit('header');
this._emittedHeader = true;
return writeHead.call(this, statusCode, reasonPhrase);
};
ServerResponse.prototype._hasConnectPatch = true;

View File

@@ -7,11 +7,9 @@ var accepts = require('accepts');
var typeis = require('type-is');
var http = require('http')
, utils = require('./utils')
, connect = require('connect')
, fresh = require('fresh')
, parseRange = require('range-parser')
, parse = utils.parseUrl
, mime = connect.mime;
/**
* Request prototype.
@@ -191,7 +189,7 @@ req.range = function(size){
*
* To utilize request bodies, `req.body`
* should be an object. This can be done by using
* the `connect.bodyParser()` middleware.
* the `bodyParser()` middleware.
*
* @param {String} name
* @param {Mixed} [defaultValue]

View File

@@ -4,7 +4,6 @@
var http = require('http')
, path = require('path')
, connect = require('connect')
, mixin = require('utils-merge')
, escapeHtml = require('escape-html')
, sign = require('cookie-signature').sign
@@ -14,10 +13,10 @@ var http = require('http')
, statusCodes = http.STATUS_CODES
, cookie = require('cookie')
, send = require('send')
, mime = connect.mime
, resolve = require('url').resolve
, basename = path.basename
, extname = path.extname;
, extname = path.extname
, mime = send.mime
/**
* Response prototype.
@@ -589,7 +588,7 @@ res.cookie = function(name, val, options){
options = mixin({}, options);
var secret = this.req.secret;
var signed = options.signed;
if (signed && !secret) throw new Error('connect.cookieParser("secret") required for signed cookies');
if (signed && !secret) throw new Error('cookieParser("secret") required for signed cookies');
if ('number' == typeof val) val = val.toString();
if ('object' == typeof val) val = 'j:' + JSON.stringify(val);
if (signed) val = 's:' + sign(val, secret);

View File

@@ -3,9 +3,9 @@
* Module dependencies.
*/
var mime = require('connect').mime
, crc32 = require('buffer-crc32')
, parse = require('url').parse;
var mime = require('send').mime;
var crc32 = require('buffer-crc32');
var parse = require('url').parse;
/**
* toString ref.

View File

@@ -22,7 +22,6 @@
}
],
"dependencies": {
"connect": "2.12.0",
"accepts": "1.0.0",
"type-is": "1.0.0",
"range-parser": "1.0.0",
@@ -47,7 +46,12 @@
"should": "~2.1.1",
"connect-redis": "~1.4.5",
"marked": "0.2.10",
"supertest": "~0.8.1"
"supertest": "~0.8.1",
"body-parser": "1.0.0",
"cookie-parser": "1.0.0",
"static-favicon": "1.0.0",
"express-session": "1.0.1",
"morgan": "1.0.0"
},
"keywords": [
"express",

View File

@@ -9,7 +9,6 @@ var app = express()
, blog = express()
, admin = express();
// app.use(express.logger('dev'))
blog.use('/admin', admin);
app.use('/blog', blog);
app.set('views', __dirname + '/views');

View File

@@ -4,16 +4,6 @@ var express = require('../')
, assert = require('assert');
describe('exports', function(){
it('should expose connect middleware', function(){
express.should.have.property('bodyParser');
express.should.have.property('session');
express.should.have.property('static');
})
it('should expose .mime', function(){
assert(express.mime == require('connect').mime, 'express.mime should be connect.mime');
})
it('should expose Router', function(){
express.Router.should.be.a.Function;
})

View File

@@ -1,6 +1,7 @@
var express = require('../')
, request = require('./support/http');
, request = require('./support/http')
, bodyParser = require('body-parser')
describe('req', function(){
describe('.param(name, default)', function(){
@@ -33,7 +34,7 @@ describe('req', function(){
it('should check req.body', function(done){
var app = express();
app.use(express.bodyParser());
app.use(bodyParser());
app.use(function(req, res){
res.end(req.param('name'));

View File

@@ -1,13 +1,14 @@
var express = require('../')
, request = require('./support/http');
, request = require('./support/http')
, cookieParser = require('cookie-parser')
describe('req', function(){
describe('.signedCookies', function(){
it('should return a signed JSON cookie', function(done){
var app = express();
app.use(express.cookieParser('secret'));
app.use(cookieParser('secret'));
app.use(function(req, res){
if ('/set' == req.path) {

View File

@@ -2,7 +2,8 @@
var express = require('../')
, request = require('./support/http')
, mixin = require('utils-merge')
, cookie = require('cookie');
, cookie = require('cookie')
, cookieParser = require('cookie-parser')
describe('res', function(){
describe('.cookie(name, object)', function(){
@@ -134,7 +135,7 @@ describe('res', function(){
it('should generate a signed JSON cookie', function(done){
var app = express();
app.use(express.cookieParser('foo bar baz'));
app.use(cookieParser('foo bar baz'));
app.use(function(req, res){
res.cookie('user', { name: 'tobi' }, { signed: true }).end();
@@ -155,7 +156,7 @@ describe('res', function(){
it('should set a signed cookie', function(done){
var app = express();
app.use(express.cookieParser('foo bar baz'));
app.use(cookieParser('foo bar baz'));
app.use(function(req, res){
res.cookie('name', 'tobi', { signed: true }).end();