Middleware.coffee | |
---|---|
module.exports = class Middleware
constructor: (@options, @compilers, @cache) -> | |
Handles incoming requests. | intercept: (req, res, next) ->
return next() unless req.method is 'GET'
targetPath = path.join @options.src, parse(req.url).pathname
return next() if targetPath.slice(-1) is '/' # ignore directory requests
cachedTarget = @cache[targetPath]
if cachedTarget and (!cachedTarget.mtime) # memory content
{static, str} = cachedTarget
return sendFile(res, next, {static, str, targetPath})
fs.stat targetPath, (err, stats) -> |
if the file exists, serve it | return serveRaw req, res, next, {stats, targetPath} unless err |
if the file doesn't exist, see if it can be compiled | for ext, compiler of compilers
if compiler.match.test targetPath
return serveCompiled req, res, next, {compiler, ext, targetPath} |
otherwise, pass the request up the Connect stack | next()
serveRaw = (req, res, next, {stats, targetPath}) ->
if cache[targetPath]?.mtime
unless stats.mtime > cache[targetPath].mtime
str = cache[targetPath].str
return sendFile res, next, {str, stats, targetPath}
fs.readFile targetPath, 'utf8', sendCallback(res, next, {stats, targetPath})
serveCompiled = (req, res, next, {compiler, ext, targetPath}) ->
srcPath = targetPath.replace(compiler.match, ".#{ext}")
fs.stat srcPath, (err, stats) ->
return next() if err?.code is 'ENOENT' # no file, no problem!
return next err if err
if cache[targetPath]?.mtime
unless stats.mtime > cache[targetPath].mtime
if compiler is compilers.styl # @import-ed files may have changed
cache[targetPath].str = compiler.compileStr cache[srcPath].str, srcPath
str = cache[targetPath].str
return sendFile res, next, {str, stats, targetPath}
compiler.compile srcPath, sendCallback(res, next, {stats, targetPath})
sendCallback = (res, next, {static, stats, targetPath}) ->
(err, str) ->
return next err if err
sendFile res, next, {str, static, stats, targetPath}
sendFile = (res, next, {str, static, stats, targetPath}) ->
if stats then cache[targetPath] = {mtime: stats.mtime, str}
res.setHeader 'Content-Type', mime.lookup(targetPath)
res.setHeader 'Expires', module.exports.FAR_FUTURE_EXPIRES if static
res.end str |
constants | FAR_FUTURE_EXPIRES = "Wed, 01 Feb 2034 12:34:56 GMT"
|