Browse Source

added transform feature

master
mortie 7 years ago
parent
commit
2047333b1a
3 changed files with 139 additions and 4 deletions
  1. 32
    0
      README.md
  2. 37
    1
      index.js
  3. 70
    3
      js/static.js

+ 32
- 0
README.md View File

* `app.get("^/static/.*", webframe.static("web", "/static"))` will serve all * `app.get("^/static/.*", webframe.static("web", "/static"))` will serve all
files in the `web` directory under `/static`, so `/static/script.js` will files in the `web` directory under `/static`, so `/static/script.js` will
serve `web/script.js`. serve `web/script.js`.

### Transformations - app.transform(extension, mime, function)

Webframe has a way to transform files of one file type to an other, for example
transforming typescript into javascript, or sass into CSS.

Example (assumes you have the node-sass module installed):

```
var sass = require("node-sass");

app.transform("sass", "text/css", (path, writeStream) => {
try {
var str = fs.readFileSync(path, "utf8");
} catch (err) {
ws.status = 404;
return ws.error(err);
}

try {
var result = sass.renderSync({ data: str });
writeStream.end(result.css);
} catch (err) {
writeStream.error(err);
}
});
```

Now, any .sass file served with `webframe.static` will be compiled into CSS,
and sent with the browser with the MIME type "text/css". The result is also
cached, so the expensive sass compilation will only happen the first time the
file is requested. The result will not be cached if you call writeStream.error.

+ 37
- 1
index.js View File



this._routeMap = {}; this._routeMap = {};
this._routes = []; this._routes = [];
this._transforms = {};


// Add scripts // Add scripts
if (options.client_utils) { if (options.client_utils) {
* Args: * Args:
* method: "GET", "POST", "PUT", "DELETE", "ALL" * method: "GET", "POST", "PUT", "DELETE", "ALL"
* path: path, * path: path,
* func: function
* func: function(request, response)
*/ */
route(method, path, middleware, func) { route(method, path, middleware, func) {
if (method !== "GET" && method !== "POST" && method !== "PUT" && if (method !== "GET" && method !== "POST" && method !== "PUT" &&
} }
} }


/*
* Add a transform.
* Args:
* ext: What extension to transform
* mime: The mime-type the transformed code should be sent as
* func: function(path, writeStream)
*
* writeStream: {
* status: status code (should only be modified before write() or end())
* headers: HTTP headers (should only be modified before write() or end())
* write: function(data) - write data
* end: function(data) - write data and end response
* error: function(err) - end response and log error
* }
*/
transform(ext, mime, func) {
if (typeof ext !== "string")
throw new Error("Expected ext to be string, got "+(typeof ext)+".");
if (typeof func !== "function")
throw new Error("Expected func to be function, got "+(typeof func)+".");
if (this._transforms[ext])
throw new Error("Extension "+ext+" already has a transform.");

this._transforms[ext] = {
func: func,
mime: mime
};
}

/* /*
* Add code to be served as /webframe.js * Add code to be served as /webframe.js
*/ */
*/ */
template(tmpl, args) { return template(tmpl, args); } template(tmpl, args) { return template(tmpl, args); }


/*
* Utility methods for GET/POST/PUT/DELETE/ALL
*/
get(path, middleware, func) { this.route("GET", path, middleware, func); } get(path, middleware, func) { this.route("GET", path, middleware, func); }
post(path, middleware, func) { this.route("POST", path, middleware, func); } post(path, middleware, func) { this.route("POST", path, middleware, func); }
put(path, middleware, func) { this.route("PUT", path, middleware, func); } put(path, middleware, func) { this.route("PUT", path, middleware, func); }
delete(path, middleware, func) { this.route("DELETE", path, middleware, func); } delete(path, middleware, func) { this.route("DELETE", path, middleware, func); }
all(path, middleware, func) { this.route("ALL", path, middleware, func); } all(path, middleware, func) { this.route("ALL", path, middleware, func); }


/*
* Logging
*/
info(str) { info(str) {
console.log("Info: "+str); console.log("Info: "+str);
} }

+ 70
- 3
js/static.js View File

}); });
} }


var transformCache = {};
function handleTransform(path, req, res, app) {
var ext = pathlib.extname(req.url).substring(1);
if (ext === "")
return false;

var transform = app._transforms[ext];
if (!transform)
return false;

if (transformCache[path]) {
var c = transformCache[path];
res.writeHead(c.status, c.headers);
res.end(c.content);
return true;
}

var data = { content: "", headers: null, status: null };

var writeStream = {
headersSent: false,
status: 200,
headers: {
"content-type": transform.mime
},

write: function(d) {
if (!writeStream.headersSent) {
res.writeHead(writeStream.status, writeStream.headers);
writeStream.headersSent = true;
}
if (d != null) {
data.content += d;
res.write(d);
}
},

end: function(d, nocache) {
writeStream.write(d);

res.end();

if (!nocache) {
data.status = writeStream.status;
data.headers = writeStream.headers;
transformCache[path] = data;
}
},

error: function(err) {
if (writeStream.status === 200)
writeStream.status = 500;

app.warning("Transform for "+path+": "+err.toString());
writeStream.end(null, true);
}
}

transform.func(path, writeStream);
return true;
}

module.exports = function(root, before) { module.exports = function(root, before) {
return function(req, res, app) { return function(req, res, app) {
// `req.urlobj.pathname` is too long.
var pn = req.urlobj.pathname; var pn = req.urlobj.pathname;


// Join the web root with the request's path name
var path = pathlib.join(root, pn.replace(before, ""));

// If there's a transform, let that handle it
if (handleTransform(path, req, res, app))
return;

// Send a file // Send a file
function send(path) { function send(path) {
sendfile(path, app, pn, req, res); sendfile(path, app, pn, req, res);
return; return;
} }


// Join the web root with the request's path name
var path = pathlib.join(root, pn.replace(before, ""));

fs.stat(path, (err, stat) => { fs.stat(path, (err, stat) => {


// If there's an error stat'ing, just error // If there's an error stat'ing, just error

Loading…
Cancel
Save