v1.18.x
Julian Lam 11 years ago
parent e5be1d2840
commit 4d73a563c5

@ -5,6 +5,7 @@ var uglifyjs = require('uglify-js'),
async = require('async'), async = require('async'),
fs = require('fs'), fs = require('fs'),
path = require('path'), path = require('path'),
crypto = require('crypto'),
Minifier = { Minifier = {
js: {}, js: {},
@ -28,13 +29,27 @@ Minifier.js.minify = function (scripts, minify, callback) {
} }
try { try {
var minified = uglifyjs.minify(scripts, options); var minified = uglifyjs.minify(scripts, options),
hasher = crypto.createHash('md5'),
hash;
// Calculate js hash
hasher.update(minified.code, 'utf-8');
hash = hasher.digest('hex');
process.send({
type: 'hash',
payload: hash.slice(0, 8)
});
callback({ callback({
js: minified.code, js: minified.code,
map: minified.map map: minified.map
}); });
} catch(err) { } catch(err) {
process.send(err.message); process.send({
type: 'error',
payload: err
});
} }
}; };
@ -43,9 +58,16 @@ process.on('message', function(payload) {
case 'js': case 'js':
Minifier.js.minify(payload.scripts, payload.minify, function(data) { Minifier.js.minify(payload.scripts, payload.minify, function(data) {
process.stdout.write(data.js); process.stdout.write(data.js);
process.send('end.script'); process.send({
type: 'end',
payload: 'script'
});
process.stderr.write(data.map); process.stderr.write(data.map);
process.send('end.mapping'); process.send({
type: 'end',
payload: 'mapping'
});
}); });
break; break;
} }

@ -44,6 +44,8 @@ apiController.getConfig = function(req, res, next) {
config.environment = process.env.NODE_ENV; config.environment = process.env.NODE_ENV;
config.loggedIn = !!req.user; config.loggedIn = !!req.user;
config['cache-buster'] = meta.config['cache-buster'] || ''; config['cache-buster'] = meta.config['cache-buster'] || '';
config['script-buster'] = meta.js.hash;
config['css-buster'] = meta.css.hash;
config.requireEmailConfirmation = parseInt(meta.config.requireEmailConfirmation, 10) === 1; config.requireEmailConfirmation = parseInt(meta.config.requireEmailConfirmation, 10) === 1;
config.topicPostSort = meta.config.topicPostSort || 'oldest_to_newest'; config.topicPostSort = meta.config.topicPostSort || 'oldest_to_newest';

@ -5,6 +5,7 @@ var winston = require('winston'),
fs = require('fs'), fs = require('fs'),
path = require('path'), path = require('path'),
less = require('less'), less = require('less'),
crypto = require('crypto'),
plugins = require('../plugins'), plugins = require('../plugins'),
emitter = require('../emitter'), emitter = require('../emitter'),
@ -12,7 +13,9 @@ var winston = require('winston'),
module.exports = function(Meta) { module.exports = function(Meta) {
Meta.css = {}; Meta.css = {
'css-buster': +new Date()
};
Meta.css.cache = undefined; Meta.css.cache = undefined;
Meta.css.branding = {}; Meta.css.branding = {};
Meta.css.defaultBranding = {}; Meta.css.defaultBranding = {};
@ -57,15 +60,22 @@ module.exports = function(Meta) {
try { try {
var css = tree.toCSS({ var css = tree.toCSS({
cleancss: true cleancss: true
}); });
} catch (err) { } catch (err) {
winston.error('[meta/css] Syntax Error: ' + err.message + ' - ' + path.basename(err.filename) + ' on line ' + err.line); winston.error('[meta/css] Syntax Error: ' + err.message + ' - ' + path.basename(err.filename) + ' on line ' + err.line);
return; return;
} }
Meta.css.cache = css; Meta.css.cache = css;
// Calculate css buster
var hasher = crypto.createHash('md5'),
hash;
hasher.update(css, 'utf-8');
hash = hasher.digest('hex').slice(0, 8);
Meta.css.hash = hash;
var re = /.brand-([\S]*?)[ ]*?{[\s\S]*?color:([\S\s]*?)}/gi, var re = /.brand-([\S]*?)[ ]*?{[\s\S]*?color:([\S\s]*?)}/gi,
match = re.exec(css); match = re.exec(css);

@ -16,6 +16,7 @@ module.exports = function(Meta) {
Meta.js = { Meta.js = {
cache: '', cache: '',
map: '', map: '',
hash: +new Date(),
prepared: false, prepared: false,
minFile: 'nodebb.min.js', minFile: 'nodebb.min.js',
scripts: [ scripts: [
@ -160,19 +161,22 @@ module.exports = function(Meta) {
Meta.js.map += buffer.toString(); Meta.js.map += buffer.toString();
}); });
minifier.on('message', function(payload) { minifier.on('message', function(message) {
switch(payload) { switch(message.type) {
case 'end.script': case 'end':
winston.info('[meta/js] Successfully minified.'); if (message.payload === 'script') {
onComplete(); winston.info('[meta/js] Successfully minified.');
onComplete();
} else if (message.payload === 'mapping') {
winston.info('[meta/js] Retrieved Mapping.');
onComplete();
}
break; break;
case 'end.mapping': case 'hash':
winston.info('[meta/js] Retrieved Mapping.'); Meta.js.hash = message.payload;
onComplete();
break; break;
case 'error':
default: winston.error('[meta/js] Could not compile client-side scripts! ' + message.payload.message);
winston.error('[meta/js] Could not compile client-side scripts! ' + payload);
minifier.kill(); minifier.kill();
process.exit(); process.exit();
break; break;

@ -425,6 +425,15 @@ middleware.routeTouchIcon = function(req, res) {
} }
}; };
middleware.addExpiresHeaders = function(req, res, next) {
if (app.enabled('cache')) {
res.setHeader("Cache-Control", "public, max-age=5184000");
res.setHeader("Expires", new Date(Date.now() + 5184000000).toUTCString());
}
next();
};
module.exports = function(webserver) { module.exports = function(webserver) {
app = webserver; app = webserver;
middleware.admin = require('./admin')(webserver); middleware.admin = require('./admin')(webserver);

@ -6,6 +6,7 @@ var path = require('path'),
meta = require('../meta'), meta = require('../meta'),
db = require('../database'), db = require('../database'),
plugins = require('../plugins'), plugins = require('../plugins'),
middleware = require('../middleware'),
minificationEnabled = false; minificationEnabled = false;
@ -46,13 +47,13 @@ function setupPluginSourceMapping(app) {
} }
module.exports = function(app, middleware, controllers) { module.exports = function(app, middleware, controllers) {
app.get('/stylesheet.css', sendStylesheet); app.get('/stylesheet.css', middleware.addExpiresHeaders, sendStylesheet);
app.get('/nodebb.min.js', sendMinifiedJS); app.get('/nodebb.min.js', middleware.addExpiresHeaders, sendMinifiedJS);
app.get('/sitemap.xml', controllers.sitemap); app.get('/sitemap.xml', controllers.sitemap);
app.get('/robots.txt', controllers.robots); app.get('/robots.txt', controllers.robots);
if (!minificationEnabled) { if (!minificationEnabled) {
app.get('/nodebb.min.js.map', sendSourceMap); app.get('/nodebb.min.js.map', middleware.addExpiresHeaders, sendSourceMap);
setupPluginSourceMapping(app); setupPluginSourceMapping(app);
} }
}; };

@ -14,7 +14,7 @@ var _ = require('underscore'),
module.exports = function(app, middleware, controllers) { module.exports = function(app, middleware, controllers) {
// Static Assets // Static Assets
app.get('/plugins/:id/*', function(req, res) { app.get('/plugins/:id/*', middleware.addExpiresHeaders, function(req, res) {
var relPath = req._parsedUrl.pathname.replace('/plugins/', ''), var relPath = req._parsedUrl.pathname.replace('/plugins/', ''),
matches = _.map(plugins.staticDirs, function(realPath, mappedPath) { matches = _.map(plugins.staticDirs, function(realPath, mappedPath) {
if (relPath.match(mappedPath)) { if (relPath.match(mappedPath)) {

Loading…
Cancel
Save