Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

combohandler

Package Overview
Dependencies
Maintainers
1
Versions
17
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

combohandler - npm Package Compare versions

Comparing version 0.1.2 to 0.1.3

.gitignore

37

app.js

@@ -1,2 +0,35 @@

var server = require('./lib/server');
module.exports = server(require('./config'));
#!/usr/bin/env node
/**
Cluster initialization file for the site. See the Cluster docs at
<http://learnboost.github.com/cluster/> for details about Cluster.
**/
var cluster = require('cluster'),
server = require('./lib/server');
cluster(server(require('./config')))
.set('title', 'combohandler')
.in('development')
.set('workers', 1)
.use(cluster.pidfiles())
.use(cluster.cli())
.use(cluster.logger('logs', 'debug'))
.use(cluster.reload([
'config.js',
'index.js',
'lib',
], {
extensions: ['.js'],
interval : 1000,
signal : 'SIGQUIT'
}))
.use(cluster.debug())
.listen(8000)
.in('production')
.use(cluster.pidfiles())
.use(cluster.cli())
.use(cluster.logger('logs'))
.listen(8000);
Combo Handler History
=====================
0.1.3 (2011-10-31)
------------------
* Use Cluster instead of Spark2.
0.1.2 (2011-07-11)

@@ -5,0 +11,0 @@ ------------------

119

index.js

@@ -1,118 +0,1 @@

var fs = require('fs'),
path = require('path'),
sys = require('sys'),
// Default set of MIME types supported by the combo handler. Attempts to
// combine one or more files with an extension not in this mapping (or not
// in a custom mapping) will result in a 400 response.
MIME_TYPES = exports.MIME_TYPES = {
'.css' : 'text/css',
'.js' : 'application/javascript',
'.json': 'application/json',
'.txt' : 'text/plain',
'.xml' : 'application/xml'
};
// -- Exported Methods ---------------------------------------------------------
exports.combine = function (config) {
var mimeTypes = config.mimeTypes || MIME_TYPES,
// Intentionally using the sync method because this only runs when the
// middleware is initialized, and we want it to throw if there's an error.
rootPath = fs.realpathSync(config.rootPath);
function getMimeType(filename) {
return mimeTypes[path.extname(filename).toLowerCase()];
}
return function (req, res, next) {
var body = [],
query = parseQuery(req.url),
pending = query.length,
type = pending && getMimeType(query[0]),
lastModified;
function finish() {
if (lastModified) {
res.header('Last-Modified', lastModified.toUTCString());
}
res.header('Content-Type', (type || 'text/plain') + ';charset=utf-8');
res.body = body.join('\n');
next();
}
if (!pending) {
// No files requested.
return next(new BadRequest);
}
query.forEach(function (relativePath, i) {
// Skip empty parameters.
if (!relativePath) {
pending -= 1;
return;
}
fs.realpath(path.normalize(path.join(rootPath, relativePath)), function (err, absolutePath) {
// Bubble up an error if the file can't be found or if the request
// attempts to traverse above the root path.
if (err || !absolutePath || absolutePath.indexOf(rootPath) !== 0) {
return next(new BadRequest);
}
fs.stat(absolutePath, function (err, stats) {
if (err || !stats.isFile()) { return next(new BadRequest); }
var mtime = new Date(stats.mtime);
if (!lastModified || mtime > lastModified) {
lastModified = mtime;
}
fs.readFile(absolutePath, 'utf8', function (err, data) {
if (err) { return next(new BadRequest); }
body[i] = data;
pending -= 1;
if (pending === 0) {
finish();
}
}); // fs.readFile
}); // fs.stat
}); // fs.realpath
}); // forEach
};
};
// BadRequest is used for all filesystem-related errors, including when a
// requested file can't be found (a NotFound error wouldn't be appropriate in
// that case since the route itself exists; it's the request that's at fault).
function BadRequest(message) {
this.name = 'BadRequest';
Error.call(this, message || 'Bad request.');
Error.captureStackTrace(this, arguments.callee);
}
sys.inherits(BadRequest, Error);
exports.BadRequest = BadRequest; // exported to allow instanceof checks
// -- Private Methods ----------------------------------------------------------
function decode(string) {
return decodeURIComponent(string).replace(/\+/g, ' ');
}
// Because querystring.parse() is silly and tries to be too clever.
function parseQuery(url) {
var parsed = [],
query = url.split('?')[1];
if (query) {
query.split('&').forEach(function (item) {
parsed.push(decode(item.split('=')[0]));
});
}
return parsed;
}
module.exports = require('./lib/combohandler');
var connect = require('connect'),
express = require('express'),
combo = require('../index');
combo = require('./combohandler');

@@ -5,0 +5,0 @@ module.exports = function (config, baseApp) {

{
"name" : "combohandler",
"description": "Simple Yahoo!-style combo handler.",
"version" : "0.1.2",
"keywords" : ["combo", "combine", "cdn", "yui", "yui3", "js", "css", "performance"],
"version" : "0.1.3",
"keywords" : [
"combo", "combohandler", "combohandle", "combine", "cdn", "yui", "yui3",
"yui 3", "js", "css", "performance"
],
"homepage" : "https://github.com/rgrove/combohandler",

@@ -21,6 +24,7 @@

"node >=0.4.0",
"npm >=0.3.1"
"npm >=1.0.0"
],
"dependencies": {
"cluster": "~0.7.7",
"connect": ">=1.3.0 <2.0.0",

@@ -35,2 +39,3 @@ "express": ">=2.2.0 <3.0.0"

"files": [
"lib/combohandler.js",
"lib/server.js",

@@ -37,0 +42,0 @@ "HISTORY.md",

@@ -8,3 +8,3 @@ Combo Handler

The combo handler is compatible with the [YUI 3][] Loader, so you can use it to
The combo handler is compatible with the [YUI][] Loader, so you can use it to
host YUI, or you can use it with any other JavaScript or CSS if you're willing

@@ -20,3 +20,3 @@ to construct the combo URLs yourself.

[Nginx]: http://nginx.org/
[YUI 3]: http://developer.yahoo.com/yui/3/
[YUI]: http://yuilibrary.com/

@@ -53,10 +53,14 @@

var combo = require('combohandler');
app.use(combo.combine({rootPath: '/local/path/to/files'}));
```js
var combo = require('combohandler');
app.use(combo.combine({rootPath: '/local/path/to/files'}));
```
Or as route middleware for a specific route:
app.get('/foo', combo.combine({rootPath: '/local/path/to/foo'}), function (req, res) {
res.send(res.body, 200);
});
```js
app.get('/foo', combo.combine({rootPath: '/local/path/to/foo'}), function (req, res) {
res.send(res.body, 200);
});
```

@@ -81,42 +85,43 @@ In either case, the middleware will perform combo handling for files under the

var combo = require('combohandler'),
express = require('express'),
```js
var combo = require('combohandler'),
express = require('express'),
app = express.createServer();
app = express.createServer();
app.configure(function () {
app.use(express.conditionalGet());
app.use(express.errorHandler());
});
app.configure(function () {
app.use(express.conditionalGet());
app.use(express.errorHandler());
});
// Return a 400 response if the combo handler generates a BadRequest error.
app.error(function (err, req, res, next) {
if (err instanceof combo.BadRequest) {
res.send('Bad request.', {'Content-Type': 'text/plain'}, 400);
} else {
next();
}
});
// Return a 400 response if the combo handler generates a BadRequest error.
app.error(function (err, req, res, next) {
if (err instanceof combo.BadRequest) {
res.send('Bad request.', {'Content-Type': 'text/plain'}, 400);
} else {
next();
}
});
// Given a root path that points to a YUI 2 root folder, this route will
// handle URLs like:
//
// http://example.com/yui2?build/yahoo/yahoo-min.js&build/yuiloader/yuiloader-min.js
//
app.get('/yui2', combo.combine({rootPath: '/local/path/to/yui2'}), function (req, res) {
res.send(res.body, 200);
});
// Given a root path that points to a YUI 2 root folder, this route will
// handle URLs like:
//
// http://example.com/yui2?build/yahoo/yahoo-min.js&build/yuiloader/yuiloader-min.js
//
app.get('/yui2', combo.combine({rootPath: '/local/path/to/yui2'}), function (req, res) {
res.send(res.body, 200);
});
// Given a root path that points to a YUI 3 root folder, this route will
// handle URLs like:
//
// http://example.com/yui3?build/yui/yui-min.js&build/loader/loader-min.js
//
app.get('/yui3', combo.combine({rootPath: '/local/path/to/yui3'}), function (req, res) {
res.send(res.body, 200);
});
// Given a root path that points to a YUI 3 root folder, this route will
// handle URLs like:
//
// http://example.com/yui3?build/yui/yui-min.js&build/loader/loader-min.js
//
app.get('/yui3', combo.combine({rootPath: '/local/path/to/yui3'}), function (req, res) {
res.send(res.body, 200);
});
app.listen(3000);
app.listen(3000);
```
### Creating a server

@@ -129,15 +134,16 @@

var comboServer = require('combohandler/lib/server'),
app;
```js
var comboServer = require('combohandler/lib/server'),
app;
app = comboServer({
roots: {
'/yui2': '/local/path/to/yui2',
'/yui3': '/local/path/to/yui3'
}
});
app = comboServer({
roots: {
'/yui2': '/local/path/to/yui2',
'/yui3': '/local/path/to/yui3'
}
});
app.listen(3000);
app.listen(3000);
```
### Augmenting an existing server

@@ -149,31 +155,34 @@

var comboServer = require('combohandler/lib/server');
```js
var comboServer = require('combohandler/lib/server');
comboServer({
roots: {
'/yui2': '/local/path/to/yui2',
'/yui3': '/local/path/to/yui3'
}
}, myApp); // Assuming `myApp` is a pre-existing Express server instance.
comboServer({
roots: {
'/yui2': '/local/path/to/yui2',
'/yui3': '/local/path/to/yui3'
}
}, myApp); // Assuming `myApp` is a pre-existing Express server instance.
```
### Running the included standalone server
If you clone (or download) the GitHub repo, you can rename `config.sample.js` to
`config.js`, edit it to your liking, and then simply use [Spark][] or [Spark2][]
to run `app.js` as a standalone server.
If you clone or download the GitHub repo, you can rename `config.sample.js` to
`config.js`, edit it to your liking, and then simply run `app.js` to start a
standalone server in development mode.
npm install -g spark2
git clone git://github.com/rgrove/combohandler.git
cd combohandler
spark2 -v
mv config.sample.js config.js
./app.js
[Spark]: https://github.com/senchalabs/spark
[Spark2]: https://github.com/davglass/spark2
To run the standalone server in production mode, set the `NODE_ENV` variable to
`production` before running it:
NODE_ENV=production ./app.js
Using as a YUI 3 combo handler
------------------------------
With a tiny bit of configuration, you can tell YUI 3 to use your custom combo
With a tiny bit of configuration, you can tell YUI to use your custom combo
handler instead of the Yahoo! combo handler. Here's a working example that uses

@@ -183,12 +192,14 @@ a live combo handler instance running on fuji.jetpants.com to serve the latest

<script src="http://fuji.jetpants.com/yui/combo/yui3?build/yui/yui-min.js"></script>
<script>
var Y = YUI({
comboBase: 'http://fuji.jetpants.com/yui/combo/yui3?',
combine : true,
root : 'build/'
}).use('node', function (Y) {
// YUI will now automatically load modules from the custom combo handler.
});
</script>
```js
<script src="http://fuji.jetpants.com/yui/combo/yui3?build/yui/yui-min.js"></script>
<script>
var Y = YUI({
comboBase: 'http://fuji.jetpants.com/yui/combo/yui3?',
combine : true,
root : 'build/'
}).use('node', function (Y) {
// YUI will now automatically load modules from the custom combo handler.
});
</script>
```

@@ -195,0 +206,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc