Browse files

package.json: Updated description.

  • Loading branch information...
0 parents commit c6d1821a9affd6086943c994518f29ca192bf003 @papandreou committed Oct 2, 2012
Showing with 226 additions and 0 deletions.
  1. +1 −0 .gitignore
  2. +28 −0 LICENSE
  3. +35 −0 README.md
  4. +57 −0 lib/index.js
  5. +32 −0 package.json
  6. +60 −0 test/compiless.js
  7. +1 −0 test/root/importerror.less
  8. +3 −0 test/root/imports/a.less
  9. +1 −0 test/root/something.txt
  10. +7 −0 test/root/stylesheet.less
  11. +1 −0 test/root/syntaxerror.less
1 .gitignore
@@ -0,0 +1 @@
+/node_modules/
28 LICENSE
@@ -0,0 +1,28 @@
+Copyright (c) 2012, Andreas Lind Petersen
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of the author nor the names of contributors may
+ be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 README.md
@@ -0,0 +1,35 @@
+express-compiless
+=================
+
+Middleware that compiles less to css on-the-fly. Intended to be used
+in a development setting with the `connect.static` middleware, but
+should work with any middleware further down the stack, as long as a
+`text/less` response is served. Or if the `Content-Type` of the
+response is `application/octet-stream` and the request url ends in
+`.less`.
+
+Installation
+------------
+
+Make sure you have node.js and npm installed, then run:
+
+ npm install express-compiless
+
+Example usage
+-------------
+
+```javascript
+var express = require('express'),
+ compiless = require('express-compiless'),
+ root = '/path/to/my/static/files';
+
+express.createServer()
+ .use(compiless({root: root}))
+ .use(express.static(root))
+ .listen(1337, done);
+```
+
+License
+-------
+
+3-clause BSD license -- see the `LICENSE` file for details.
57 lib/index.js
@@ -0,0 +1,57 @@
+var Path = require('path'),
+ less = require('less');
+
+require('express-hijackresponse');
+
+module.exports = function compiless(options) {
+ if (!options || !options.root) {
+ throw new Error('options.root is mandatory');
+ }
+ return function (req, res, next) {
+ if (req.accepts('text/css')) {
+ res.hijack(function (err, res) {
+ if (res.statusCode !== 200) {
+ return res.unhijack(true);
+ }
+ var contentType = res.getHeader('Content-Type'),
+ matchContentType = contentType && contentType.match(/^text\/less(?:;\s*charset=([a-z0-9\-]+))?$/i);
+ // The mime module doesn't support less yet, so we fall back:
+ if (matchContentType || contentType === 'application/octet-stream' && /\.less(?:\?.*)?$/.test(req.url)) {
+ // If there's an ETag, make sure it's different from the original one so the downstream middleware
+ // won't reply with a false positive 304 on the same URL after compiless has been enabled or disabled:
+ var etag = res.getHeader('ETag');
+ if (etag) {
+ res.setHeader('ETag', '"' + etag.replace(/^"|"$/g, '') + '-compiless"');
+ }
+ delete req.headers['if-modified-since']; // Prevent false positive conditional GETs after enabling compiless
+
+ var chunks = [];
+ res.on('error', function () {
+ res.unhijack();
+ next();
+ }).on('data', function (chunk) {
+ chunks.push(chunk);
+ }).on('end', function () {
+ var lessText = Buffer.concat(chunks).toString('utf-8'), // No other charsets are really relevant, right?
+ baseDir = Path.resolve(options.root, req.url.replace(/\/[^\/]*(?:\?.*)?$/, '/').substr(1)),
+ hasResponded = false;
+
+ // Unfortunately less.render throws errors in async code instead of passing it to our callback.
+ // Hopefully the solution for https://github.com/cloudhead/less.js/issues/462 will remedy this.
+ less.render(lessText, {paths: [baseDir]}, function (err, cssText) {
+ if (err) {
+ return res.send(500);
+ }
+ res.setHeader('Content-Type', 'text/css');
+ res.setHeader('Content-Length', Buffer.byteLength(cssText));
+ res.end(cssText);
+ });
+ });
+ } else {
+ res.unhijack(true);
+ }
+ });
+ next();
+ }
+ };
+};
32 package.json
@@ -0,0 +1,32 @@
+{
+ "name": "express-compiless",
+ "version": "0.0.1",
+ "description": "Express middleware that compiles less files to css on the way out.",
+ "main": "lib/index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/papandreou/express-compiless"
+ },
+ "keywords": [
+ "less",
+ "css",
+ "express",
+ "compiler",
+ "middleware"
+ ],
+ "author": "Andreas Lind Petersen <andreas@one.com>",
+ "license": "BSD",
+ "dependencies": {
+ "express-hijackresponse": "=0.0.7",
+ "less": "=1.3.0",
+ "passerror": "=0.0.1"
+ },
+ "devDependencies": {
+ "express": "=2.5.11",
+ "mocha": "=1.5.0",
+ "request": "=2.11.4"
+ }
+}
60 test/compiless.js
@@ -0,0 +1,60 @@
+var express = require('express'),
+ Path = require('path'),
+ request = require('request'),
+ passError = require('passerror'),
+ expect = require('expect.js'),
+ compiless = require('../lib/');
+
+describe('test server', function () {
+ var root = Path.resolve(__dirname, 'root'),
+ // Pick a random TCP port above 10000 (.listen(0) doesn't work anymore?)
+ portNumber = 10000 + Math.floor(55536 * Math.random()),
+ baseUrl = 'http://127.0.0.1:' + portNumber,
+ server;
+
+ before(function (done) {
+ server = express.createServer()
+ .use(compiless({root: root}))
+ .use(express.static(root))
+ .listen(portNumber, done);
+ });
+
+ after(function () {
+ server.close();
+ });
+
+ it('request for non-less file', function (done) {
+ request(baseUrl + '/something.txt', passError(done, function (response, body) {
+ expect(body).to.equal("foo\n");
+ expect(response.headers['content-type']).to.equal('text/plain; charset=UTF-8');
+ done();
+ }));
+ });
+
+ it('request for less file with @import', function (done) {
+ request(baseUrl + '/stylesheet.less', passError(done, function (response, body) {
+ expect(body).to.equal('body {\n width: 100%;\n}\n#foo #bar {\n color: red;\n}\n');
+ expect(response.headers['content-type']).to.equal('text/css');
+ done();
+ }));
+ });
+
+ // Unfortunately less.render throws instead of passing the error to our callback.
+ // Hopefully the solution for https://github.com/cloudhead/less.js/issues/462 will remedy this.
+
+ /*
+ it('request for less file with syntax error', function (done) {
+ request(baseUrl + '/syntaxerror.less', passError(done, function (response, body) {
+ expect(response.statusCode).to.equal(500);
+ done();
+ }));
+ });
+
+ it('request for less file with @import error', function (done) {
+ request(baseUrl + '/importerror.less', passError(done, function (response, body) {
+ expect(response.statusCode).to.equal(500);
+ done();
+ }));
+ });
+ */
+});
1 test/root/importerror.less
@@ -0,0 +1 @@
+@import "notfound.less";
3 test/root/imports/a.less
@@ -0,0 +1,3 @@
+body {
+ width: 100%;
+}
1 test/root/something.txt
@@ -0,0 +1 @@
+foo
7 test/root/stylesheet.less
@@ -0,0 +1,7 @@
+@import "imports/a.less";
+
+#foo {
+ #bar {
+ color: red;
+ }
+}
1 test/root/syntaxerror.less
@@ -0,0 +1 @@
+body {

0 comments on commit c6d1821

Please sign in to comment.