diff --git a/lib/middlewares/route.js b/lib/middlewares/route.js index 8ae70e0..ab63f3f 100644 --- a/lib/middlewares/route.js +++ b/lib/middlewares/route.js @@ -1,22 +1,47 @@ 'use strict'; -const pathFn = require('path'); -const mime = require('mime'); +// arguments: +// `--cache [bytes]` enables the cache, the optinal bytes are the size of the cache (default `10485760` 10MB) +// `--cache-filter [regex]` set a filter of which files should be cached (default `\.(css|js)$` for .css an .js) + +var pathFn = require('path'); +var mime = require('mime'); +var LRU = require('lru-cache'); +var stream = require('stream'); module.exports = function(app) { - const { config, route } = this; - const { args = {} } = this.env; - const { root } = config; + var config = this.config; + var args = this.env.args || {}; + var root = config.root; + var route = this.route; if (args.s || args.static) return; - app.use(root, (req, res, next) => { - const { method } = req; + var cache = new LRU({ + max: (args.cache === true) ? 10485760 : args.cache || 0, + length: function (value, key) { + return value.byteLength; + } + }); + var cacheFilterRegExp = new RegExp(args.cacheFilter || '\.(css|js)$'); + + // Reset cache if source-files are modified + this.addListener('generateAfter', function() { + cache.reset(); + }); + + app.use(root, function(req, res, next) { + var method = req.method; if (method !== 'GET' && method !== 'HEAD') return next(); - let url = route.format(decodeURIComponent(req.url)); - const data = route.get(url); - const extname = pathFn.extname(url); + var url = route.format(decodeURIComponent(req.url)); + var data; + if (args.cache && cache.has(url)) { + data = cache.get(url); + } else { + data = route.get(url); + } + var extname = pathFn.extname(url); // When the URL is `foo/index.html` but users access `foo`, redirect to `foo/`. if (!data) { @@ -24,7 +49,7 @@ module.exports = function(app) { url = encodeURI(url); res.statusCode = 302; - res.setHeader('Location', `${root + url}/`); + res.setHeader('Location', root + url + '/'); res.end('Redirecting'); return; } @@ -32,7 +57,30 @@ module.exports = function(app) { res.setHeader('Content-Type', extname ? mime.lookup(extname) : 'application/octet-stream'); if (method === 'GET') { - data.pipe(res).on('error', next); + if (args.cache && url.search(cacheFilterRegExp) !== -1) { + if (cache.has(url)) { + // load from cache + var cacheStream = new stream.Readable(); + cacheStream.push(cache.get(url)); + cacheStream.push(null); + cacheStream.pipe(res).on('error', next); + } else { + // save to cache + var cacheStream = stream.PassThrough(); + cacheStream.on('data', function(data) { + if (!cache.has(url)) { + cache.set(url, Buffer.from(data)); + } else { + cache.set(url, cache.get(url).data.concat(data) ); + } + }); + + data.pipe(cacheStream).pipe(res).on('error', next); + } + } else { + // stream from hexo + data.pipe(res).on('error', next); + } } else { res.end(); } diff --git a/package.json b/package.json index 72c09b8..3c44974 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "chalk": "^2.4.1", "compression": "^1.7.3", "connect": "^3.6.6", + "lru-cache": "^5.1.1", "mime": "^1.6.0", "morgan": "^1.9.0", "opn": "^5.3.0",