Permalink
Browse files

first pass at routil-static

  • Loading branch information...
0 parents commit 1591cd1c05b670c74ecc3d32f69c64ff9f8d5e0a @Raynos committed Jul 15, 2012
@@ -0,0 +1,3 @@
+node_modules
+*.log
+*.err
@@ -0,0 +1,4 @@
+language: node_js
+node_js:
+ - 0.6
+ - 0.8
@@ -0,0 +1,19 @@
+Copyright (c) 2012 Raynos.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
@@ -0,0 +1,10 @@
+node-test:
+ ./node_modules/.bin/tap --stderr ./test
+
+test:
+ ./node_modules/.bin/testem \
+ --file testem.json \
+ --debuglog testem.log \
+ --debug 2> testem.err
+
+.PHONY: test
@@ -0,0 +1,22 @@
+# routil-static [![build status][1]][2]
+
+Serve static files
+
+## Example
+
+## Installation
+
+`npm install routil-static`
+
+## Tests
+
+`make test`
+
+## Contributors
+
+ - Raynos
+
+## MIT Licenced
+
+ [1]: https://secure.travis-ci.org/Raynos/routil-static.png
+ [2]: http://travis-ci.org/Raynos/routil-static
@@ -0,0 +1,19 @@
+var path = require("path")
+ , $static = require("../..")({
+ uri: path.join(__dirname, "static")
+ })
+ , http = require("http")
+ , router = new require("routes").Router()
+
+router.addRoute("/static/*?", $static)
+
+$static.load("static/**/*.*", function (err) {
+ console.log("oh shit load error")
+})
+
+http.createServer(function (req, res) {
+ var route = router.match(req.url)
+ if (route) {
+ route.fn(req, res, route.params, route.splats)
+ }
+}).listen(8080)
@@ -0,0 +1,3 @@
+body {
+ color: red;
+}
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <script src="/static/example.js"></script>
+ <link rel="stylesheet" type="text/css" href="/static/example.css">
+ </link>
+ </head>
+ <body>
+ <div id="p"></div>
+ <script>
+ document.getElementById("p").textContent = window.global
+ </script>
+ </body>
+</html>
@@ -0,0 +1 @@
+window.global = 42
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <script src="/static/example.js"></script>
+ <link type="text/css" rel="stylesheet" media="all"
+ href="/stylus/example.css"></link>
+ </link>
+ </head>
+ <body>
+ <div id="p"></div>
+ <script>
+ document.getElementById("p").textContent = window.global
+ </script>
+ </body>
+</html>
@@ -0,0 +1 @@
+window.global = 42
@@ -0,0 +1,48 @@
+var path = require("path")
+ , http = require("http")
+ , router = new require("routes").Router()
+ , stylus = require("stylus")
+ , nib = require("nib")
+ , routilStatic = require("../..")
+
+var staticRoute = routilStatic({
+ uri: path.join(__dirname, "static")
+})
+
+staticRoute.load("static/**/*.*", logError)
+
+router.addRoute("/static/*?", staticRoute)
+
+var stylusRoute = routilStatic({
+ uri: path.join(__dirname, "stylus")
+ , mapUri: function (uri) {
+ return uri.replace(/\.css/, '.styl')
+ }
+ , render: function (raw, callback) {
+ var s = stylus(raw.toString())
+ s.use(nib())
+ s.render(function (err, css) {
+ if (err) {
+ return callback(err)
+ }
+
+ callback(null, new Buffer(css))
+ })
+ }
+ , defaultType: "text/css"
+})
+
+stylusRoute.load("stylus/**/*.styl", logError)
+
+router.addRoute("/stylus/*?", stylusRoute)
+
+http.createServer(function (req, res) {
+ var route = router.match(req.url)
+ if (route) {
+ route.fn(req, res, route.params, route.splats)
+ }
+}).listen(8080)
+
+function logError(err) {
+ console.log("oh shit load error", err.toString())
+}
@@ -0,0 +1,3 @@
+body {
+ color: red;
+}
@@ -0,0 +1,146 @@
+var glob = require("glob")
+ , extend = require("xtend")
+ , mimetypes = require("filed/mimetypes.js")
+ , path = require("path")
+ , crypto = require("crypto")
+ , zlib = require("zlib")
+ , fs = require("fs")
+ , Routil = require("routil")
+ , encoding = Routil.encoding
+ , routilErrorPage = Routil.errorPage
+ , cache = {}
+
+module.exports = Static
+
+function Static(options) {
+ var config = extend({
+ uri: path.join(process.cwd(), 'static'),
+ errorPage: routilErrorPage,
+ render: asyncIdentity,
+ mapUri: identity,
+ defaultType: null
+ }, options || {})
+ , errorPage = config.errorPage
+
+ $static.load = load
+
+ return $static
+
+ function render(fileName, raw, callback) {
+ var cached = cache[fileName]
+ if (cached) {
+ return callback(null, cached)
+ }
+ var etag = getETag(raw)
+ config.render(raw, gzipRendered)
+
+ function gzipRendered(err, rendered) {
+ if (err) {
+ return callback(err)
+ }
+
+ zlib.gzip(rendered, cacheRendered)
+
+ function cacheRendered(err, zipped) {
+ if (err) {
+ return callback(err)
+ }
+
+ var ext = path.extname(fileName).substr(1)
+ , type = mimetypes.lookup(ext, config.defaultType)
+
+ var cached = cache[fileName] = [etag, rendered, zipped, type]
+ callback(null, cached)
+ }
+ }
+ }
+
+ function load(uri, callback) {
+ glob.sync(uri).forEach(readFile)
+
+ function readFile(fileName) {
+ fs.readFile(fileName, renderRaw)
+
+ function renderRaw(err, raw) {
+ if (err) {
+ return callback(err)
+ }
+
+ render(fileName, raw, passback)
+ }
+ }
+
+ function passback(err) {
+ if (err) {
+ callback(err)
+ }
+ }
+ }
+
+ function $static(req, res, params, splats) {
+ var fileRequested = path.join("/", splats.join("/"))
+ , uri = config.mapUri(path.join(config.uri, fileRequested))
+ , cached = cache[uri]
+
+ if (cached) {
+ return send(req, res, cached)
+ }
+
+ fs.readFile(uri, handleRaw)
+
+ function handleRaw(err, raw) {
+ if (err) {
+ console.log("could not find", err, uri)
+ return errorPage(req, res, 404)
+ }
+
+ render(uri, raw, sendCachedData)
+ }
+
+ function sendCachedData(err, cached) {
+ if (err) {
+ return errorPage(req, res, [err, 500])
+ }
+
+ send(req, res, cached)
+ }
+ }
+}
+
+function asyncIdentity(raw, callback) {
+ callback(null, raw)
+}
+
+function identity(raw) {
+ return raw
+}
+
+function send(req, res, cache) {
+ var etag = cache[0],
+ raw = cache[1],
+ zipped = cache[2],
+ type = cache[3]
+
+ if (req.headers["If-None-Match"] === etag) {
+ res.statusCode = 304
+ return res.end()
+ }
+
+ res.setHeader('Content-Type', type)
+ res.setHeader('ETag', etag)
+ encoding(req, {
+ gzip: function () {
+ res.setHeader("Content-Encoding", "gzip")
+ res.end(zipped)
+ },
+ default: function () {
+ res.end(raw)
+ }
+ })()
+}
+
+function getETag(str) {
+ var h = crypto.createHash("sha1")
+ h.update(str)
+ return '"' + h.digest('base64') + '"'
+}
@@ -0,0 +1,43 @@
+{
+ "name": "routil-static",
+ "version": "0.0.1",
+ "description": "Serve static files",
+ "keywords": [],
+ "author": "Raynos <raynos2@gmail.com>",
+ "repository": "git://github.com/Raynos/routil-static.git",
+ "main": "index",
+ "homepage": "https://github.com/Raynos/routil-static",
+ "contributors": [
+ {
+ "name": "Jake Verbaten"
+ }
+ ],
+ "bugs": {
+ "url": "https://github.com/Raynos/routil-static/issues",
+ "email": "raynos2@gmail.com"
+ },
+ "dependencies": {
+ "glob": "~3.1.10",
+ "xtend": "~1.0.3",
+ "filed": "0.0.6",
+ "routil": "0.0.13",
+ "routes": "~0.1.1",
+ "stylus": "~0.28.1",
+ "nib": "~0.7.0"
+ },
+ "devDependencies": {
+ "testling": "git://github.com/Raynos/testling#master",
+ "testem": "git://github.com/Raynos/testem#master",
+ "sinon": "git://github.com/Raynos/Sinon.JS.git",
+ "tap": "0.2.5"
+ },
+ "licenses": [
+ {
+ "type": "MIT",
+ "url": "http://github.com/Raynos/routil-static/raw/master/LICENSE"
+ }
+ ],
+ "scripts": {
+ "test": "make node-test"
+ }
+}
@@ -0,0 +1,14 @@
+{
+ "framework": "custom"
+ , "browserify": true
+ , "src_files": [
+ "test/**/*.js"
+ , "node_modules/testem/adapters/testling.js"
+ ]
+ , "watch_files": [
+ "test/**/*.js"
+ , "./index.js"
+ ]
+ , "node": "node_modules/.bin/tap"
+ , "node-args": ["--tap", "test"]
+}

0 comments on commit 1591cd1

Please sign in to comment.