Browse Source

browser prefixes in CSS, proper Content-Type headers, caching and compressing favicon

master
mort 8 years ago
parent
commit
caf908c107
8 changed files with 74 additions and 37 deletions
  1. 2
    2
      conf.json.example
  2. 28
    15
      lib/loader.js
  3. 1
    0
      package.json
  4. 8
    4
      server.js
  5. 4
    4
      templates/head.html
  6. 25
    9
      web/favicon.node.js
  7. 3
    3
      web/global.css
  8. 3
    0
      web/index/style.css

+ 2
- 2
conf.json.example View File

{ {
"title": "Spus", "title": "Spus",
"base_url": "http://example.com", "base_url": "http://example.com",
"webroot": "web",
"port": 8081, "port": 8081,
"db": { "db": {
"host": "localhost", "host": "localhost",
"minify": true, "minify": true,
"session_timeout": 1800000, "session_timeout": 1800000,
"dir": { "dir": {
"imgs": "imgs"
"imgs": "imgs",
"web": "web
}, },
"debug": false, "debug": false,
"max_runs": 9999, "max_runs": 9999,

+ 28
- 15
lib/loader.js View File

var fs = require("fs"); var fs = require("fs");
var zlib = require("zlib"); var zlib = require("zlib");
var browserPrefix = require("browser-prefix");
var minify = require("./minify.js"); var minify = require("./minify.js");
var includeHtml = require("./includeHtml.js"); var includeHtml = require("./includeHtml.js");




//Prepare endpoints //Prepare endpoints
var errs = false; var errs = false;
Object.keys(endpoints).forEach(function(i) {
var ep = endpoints[i];
var eps = Object.keys(endpoints).map(function(i) {
var ep = {
path: endpoints[i],
url: i
}

try { try {


//The endpoint is a function if the file ends with .node.js //The endpoint is a function if the file ends with .node.js
if (/\.node\.js$/.test(ep)) {
res.endpoints[i] = require("../"+conf.webroot+"/"+ep);
if (/\.node\.js$/.test(ep.path)) {
ep.func = require("../"+conf.dir.web+"/"+ep.path);
return ep;


//If it doesn't end with .node.js, it's a regular text file and will //If it doesn't end with .node.js, it's a regular text file and will
//just be served as is //just be served as is
} else { } else {
var str = fs.readFileSync(conf.webroot+"/"+ep, "utf8");
ep.str = fs.readFileSync(conf.dir.web+"/"+ep.path, "utf8");


//If it's an HTML file, we minify it
if (!conf.minify) {
//Don't minify unless the conf tells us to
} else if (/\.html$/.test(ep)) {
str = minify.html(str);
} else if (/\.js$/.test(ep)) {
str = minify.js(str);
} else if (/\.css$/.test(ep)) {
str = minify.css(str);
//Add browser prefixes
if (/\.css$/.test(ep.path)) {
ep.str = browserPrefix(ep.str);
ep.mimeType = "text/css";
if (conf.minify) ep.str = minify.css(ep.str);
} else if (/\.html$/.test(ep.path)) {
ep.mimeType = "text/html";
if (conf.minify) ep.str = minify.html(ep.str);
} else if (/\.js$/.test(ep.path)) {
ep.mimeType = "application/javascript";
if (conf.minify) ep.str = minify.js(ep.str);
} }


res.endpoints[i] = str;
return ep;
} }


//Errors will usually be because an endpoint doesn't exist //Errors will usually be because an endpoint doesn't exist
//No need to proceed if some endpoints don't exist //No need to proceed if some endpoints don't exist
if (errs) process.exit(); if (errs) process.exit();


eps.forEach(function(ep) {
res.endpoints[ep.url] = ep;
});


//Prepare all templates //Prepare all templates
var templates = {}; var templates = {};
fs.readdirSync("templates").forEach(function(f) { fs.readdirSync("templates").forEach(function(f) {

+ 1
- 0
package.json View File

}, },
"license": "GPLv2", "license": "GPLv2",
"dependencies": { "dependencies": {
"browser-prefix": "^0.1.0",
"formidable": "^1.0.17", "formidable": "^1.0.17",
"html-minifier": "^0.7.2", "html-minifier": "^0.7.2",
"pg": "^4.4.0", "pg": "^4.4.0",

+ 8
- 4
server.js View File

} }


//Execute if it's a .node.js, or just respond with the contents of the file //Execute if it's a .node.js, or just respond with the contents of the file
if (typeof ep == "function") {
ep(ctx);
if (ep.func) {
ep.func(ctx);
} else { } else {


//Cache content for a while //Cache content for a while
ctx.setHeader("Cache-Control", "public, max-age="+conf.cache_max_age); ctx.setHeader("Cache-Control", "public, max-age="+conf.cache_max_age);


//Set appropriate content-type headers
if (ep.mimeType)
ctx.setHeader("Content-Type", ep.mimeType);

//Gzip and such //Gzip and such
if (ctx.shouldGzip && gzipCache[req.url]) { if (ctx.shouldGzip && gzipCache[req.url]) {
ctx.end(gzipCache[req.url], true); ctx.end(gzipCache[req.url], true);
} else if (ctx.shouldGzip) { } else if (ctx.shouldGzip) {
zlib.gzip(ep, function(err, res) {
zlib.gzip(ep.str, function(err, res) {
gzipCache[req.url] = res; gzipCache[req.url] = res;
ctx.end(res, true); ctx.end(res, true);
}); });
} else { } else {
ctx.end(ep);
ctx.end(ep.str);
} }
} }
} }

+ 4
- 4
templates/head.html View File

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<link rel="stylesheet" href="/{{env#view}}/style.css?{{conf#current_run}}"> <link rel="stylesheet" href="/{{env#view}}/style.css?{{conf#current_run}}">


<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script src="/global.js?{{conf#current_run}}"></script>
<script src="/{{env#view}}/script.js?{{conf#current_run}}"></script>
<script src="https://code.jquery.com/jquery-2.1.4.min.js" defer></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js" defer></script>
<script src="/global.js?{{conf#current_run}}" defer></script>
<script src="/{{env#view}}/script.js?{{conf#current_run}}" defer></script>

+ 25
- 9
web/favicon.node.js View File

var fs = require("fs"); var fs = require("fs");
var zlib = require("zlib");

var gzipped;

var favicon = fs.readFileSync("favicon.ico");

zlib.gzip(favicon, function(err, res) {
gzipped = res;
});


module.exports = function(ctx) { module.exports = function(ctx) {
var readStream = fs.createReadStream("favicon.ico");
readStream.pipe(ctx.res);

readStream.on("error", function(err) {
if (err.code === "ENOENT")
ctx.end(ctx.view("404"));
else
ctx.end(err.toString());
});
if (favicon) {
ctx.res.setHeader(
"Cache-Control",
"public, max-age="+ctx.conf.cache_max_age
);
}

if (gzipped && ctx.shouldGzip) {
ctx.res.setHeader("Content-Encoding", "gzip");
ctx.res.end(gzipped);
} else if (favicon) {
ctx.res.end(favicon);
} else {
ctx.res.writeHead(404);
ctx.end(ctx.view("404"));
}
} }

+ 3
- 3
web/global.css View File

} }


#notify-box { #notify-box {
transition: max-height 0.2s;
@prefix transition: max-height 0.2s;
max-height: 0px; max-height: 0px;


background-color: #F8F8F8; background-color: #F8F8F8;
position: fixed; position: fixed;
bottom: 0px; bottom: 0px;
width: 100%; width: 100%;
box-sizing: content-box;
@prefix box-sizing: content-box;
} }


#notify-box .close { #notify-box .close {
max-height: 48px; max-height: 48px;
} }
#notify-box.active:hover { #notify-box.active:hover {
transition: max-height 0.6s;
@prefix transition: max-height 0.6s;
max-height: 200px; max-height: 200px;
} }

+ 3
- 0
web/index/style.css View File

border-radius: 4px; border-radius: 4px;
padding: 6px 12px; padding: 6px 12px;
} }
#uploader-select-files, #uploader-collection-name, #uploader-upload {
height: 34px;
}

Loading…
Cancel
Save