Use Benchpress (#5901)

* Use Benchpress

* Use Benchpress.compileParse

* Error for template load failure

* Use benchpressjs package

* Compile templates on demand

* Fix user settings page

* Fix admin search to exclude `.jst` files

* Fix 500-embed

So ajaxify can still show an error if the server goes down
v1.18.x
Peter Jaszkowiak 8 years ago committed by Barış Soner Uşaklı
parent 864321f727
commit abffc29128

@ -99,7 +99,7 @@ module.exports = function (grunt) {
'public/src/**/*.js',
'node_modules/nodebb-*/**/*.js',
'!node_modules/nodebb-*/node_modules/**',
'node_modules/templates.js/lib/templates.js',
'node_modules/benchpressjs/build/benchpress.js',
'!node_modules/nodebb-*/.git/**',
],
options: {

@ -9,6 +9,8 @@ var less = require('less');
var async = require('async');
var uglify = require('uglify-js');
var nconf = require('nconf');
var Benchpress = require('benchpressjs');
var app = express();
var server;
@ -35,7 +37,7 @@ web.install = function (port) {
winston.info('Launching web installer on port', port);
app.use(express.static('public', {}));
app.engine('tpl', require('templates.js').__express);
app.engine('tpl', Benchpress.__express);
app.set('view engine', 'tpl');
app.set('views', path.join(__dirname, '../src/views'));
app.use(bodyParser.urlencoded({

@ -21,6 +21,7 @@
"async": "2.4.1",
"autoprefixer": "7.1.1",
"bcryptjs": "2.4.3",
"benchpressjs": "^1.0.1",
"body-parser": "^1.9.0",
"bootstrap": "^3.3.7",
"chart.js": "^2.4.0",
@ -93,7 +94,6 @@
"socketio-wildcard": "2.0.0",
"spdx-license-list": "^3.0.1",
"string": "^3.0.0",
"templates.js": "0.3.11",
"toobusy-js": "^0.5.1",
"uglify-js": "^3.0.11",
"validator": "7.0.0",

@ -328,20 +328,10 @@ $(document).ready(function () {
};
ajaxify.loadTemplate = function (template, callback) {
if (templates.cache[template]) {
callback(templates.cache[template]);
} else {
$.ajax({
url: config.relative_path + '/assets/templates/' + template + '.tpl?' + config['cache-buster'],
type: 'GET',
success: function (data) {
callback(data.toString());
},
error: function (error) {
throw new Error('Unable to load template: ' + template + ' (' + error.statusText + ')');
},
require([config.relative_path + '/assets/templates/' + template + '.jst'], callback, function (err) {
console.error('Unable to load template: ' + template);
throw err;
});
}
};
function ajaxifyAnchors() {
@ -424,7 +414,9 @@ $(document).ready(function () {
});
}
templates.registerLoader(ajaxify.loadTemplate);
require(['benchpress'], function (Benchpress) {
Benchpress.registerLoader(ajaxify.loadTemplate);
});
if (window.history && window.history.pushState) {
// Progressive Enhancement, ajaxify available only to modern browsers
@ -432,9 +424,4 @@ $(document).ready(function () {
}
app.load();
$('[type="text/tpl"][data-template]').each(function () {
templates.cache[$(this).attr('data-template')] = $('<div/>').html($(this).html()).text();
$(this).parent().remove();
});
});

@ -11,7 +11,21 @@ app.cacheBuster = null;
(function () {
var showWelcomeMessage = !!utils.params().loggedin;
templates.setGlobal('config', config);
require(['benchpress'], function (Benchpress) {
Benchpress.setGlobal('config', config);
if (Object.defineProperty) {
Object.defineProperty(window, 'templates', {
configurable: true,
enumerable: true,
get: function () {
console.warn('[deprecated] Accessing benchpress (formerly know as templates.js) globally is deprecated. Use `require(["benchpress"], function (Benchpress) { ... })` instead');
return Benchpress;
},
});
} else {
window.templates = Benchpress;
}
});
app.cacheBuster = config['cache-buster'];

@ -3,15 +3,15 @@
(function (factory) {
if (typeof module === 'object' && module.exports) {
var relative_path = require('nconf').get('relative_path');
module.exports = factory(require('../utils'), require('templates.js'), require('string'), relative_path);
module.exports = factory(require('../utils'), require('benchpressjs'), require('string'), relative_path);
} else if (typeof define === 'function' && define.amd) {
define('helpers', ['string'], function (string) {
return factory(utils, templates, string, config.relative_path);
define('helpers', ['benchpress', 'string'], function (Benchpress, string) {
return factory(utils, Benchpress, string, config.relative_path);
});
} else {
window.helpers = factory(utils, templates, window.String, config.relative_path);
}
}(function (utils, templates, S, relative_path) {
}(function (utils, Benchpress, S, relative_path) {
var helpers = {
displayMenuItem: displayMenuItem,
buildMetaTag: buildMetaTag,
@ -30,8 +30,13 @@
renderDigestAvatar: renderDigestAvatar,
userAgentIcons: userAgentIcons,
register: register,
__escape: identity,
};
function identity(str) {
return str;
}
function displayMenuItem(data, index) {
var item = data.navigation[index];
if (!item) {
@ -270,7 +275,7 @@
function register() {
Object.keys(helpers).forEach(function (helperName) {
templates.registerHelper(helperName, helpers[helperName]);
Benchpress.registerHelper(helperName, helpers[helperName]);
});
}

@ -14,10 +14,12 @@ function filterDirectories(directories) {
// get the relative path
return dir.replace(/^.*(admin.*?).tpl$/, '$1');
}).filter(function (dir) {
// exclude .jst files
// exclude partials
// only include subpaths
// exclude category.tpl, group.tpl, category-analytics.tpl
return !dir.includes('/partials/') &&
return !dir.endsWith('.jst') &&
!dir.includes('/partials/') &&
/\/.*\//.test(dir) &&
!/manage\/(category|group|category-analytics)$/.test(dir);
});

@ -3,7 +3,7 @@
var async = require('async');
var winston = require('winston');
var nconf = require('nconf');
var templates = require('templates.js');
var Benchpress = require('benchpressjs');
var nodemailer = require('nodemailer');
var sendmailTransport = require('nodemailer-sendmail-transport');
var smtpTransport = require('nodemailer-smtp-transport');
@ -173,9 +173,9 @@ Emailer.sendViaFallback = function (data, callback) {
};
function render(tpl, params, next) {
if (meta.config['email:custom:' + tpl.replace('emails/', '')]) {
var text = templates.parse(meta.config['email:custom:' + tpl.replace('emails/', '')], params);
next(null, text);
var customTemplate = meta.config['email:custom:' + tpl.replace('emails/', '')];
if (customTemplate) {
Benchpress.compileParse(customTemplate, params, next);
} else {
app.render(tpl, params, next);
}

@ -29,7 +29,7 @@ JS.scripts = {
'public/vendor/tinycon/tinycon.js',
'public/vendor/xregexp/xregexp.js',
'public/vendor/xregexp/unicode/unicode-base.js',
'node_modules/templates.js/lib/templates.js',
'node_modules/benchpressjs/build/benchpress.js',
'public/src/utils.js',
'public/src/sockets.js',
'public/src/app.js',

@ -11,6 +11,8 @@ var nconf = require('nconf');
var plugins = require('../plugins');
var file = require('../file');
var viewsPath = nconf.get('views_dir');
var Templates = module.exports;
Templates.compile = function (callback) {
@ -18,7 +20,6 @@ Templates.compile = function (callback) {
var themeConfig = require(nconf.get('theme_config'));
var baseTemplatesPaths = themeConfig.baseTheme ? getBaseTemplates(themeConfig.baseTheme) : [nconf.get('base_templates_path')];
var viewsPath = nconf.get('views_dir');
function processImports(paths, relativePath, source, callback) {
var regex = /<!-- IMPORT (.+?) -->/;
@ -63,9 +64,9 @@ Templates.compile = function (callback) {
var source = file.toString();
processImports(paths, relativePath, source, next);
},
function (compiled, next) {
function (source, next) {
mkdirp(path.join(viewsPath, path.dirname(relativePath)), function (err) {
next(err, compiled);
next(err, source);
});
},
function (compiled, next) {
@ -74,6 +75,9 @@ Templates.compile = function (callback) {
], next);
}, next);
},
function (next) {
rimraf(path.join(viewsPath, '*.jst'), next);
},
function (next) {
winston.verbose('[meta/templates] Successfully compiled templates.');
next();
@ -99,7 +103,6 @@ function getBaseTemplates(theme) {
function preparePaths(baseTemplatesPaths, callback) {
var coreTemplatesPath = nconf.get('core_templates_path');
var viewsPath = nconf.get('views_dir');
var pluginTemplates;
async.waterfall([
function (next) {

@ -2,11 +2,13 @@
var async = require('async');
var path = require('path');
var fs = require('fs');
var csrf = require('csurf');
var validator = require('validator');
var nconf = require('nconf');
var ensureLoggedIn = require('connect-ensure-login');
var toobusy = require('toobusy-js');
var Benchpress = require('benchpressjs');
var plugins = require('../plugins');
var meta = require('../meta');
@ -186,3 +188,33 @@ middleware.delayLoading = function (req, res, next) {
// Introduces an artificial delay during load so that brute force attacks are effectively mitigated
setTimeout(next, 1000);
};
var viewsDir = nconf.get('views_dir');
middleware.templatesOnDemand = function (req, res, next) {
var filePath = req.filePath || path.join(viewsDir, req.path);
if (!filePath.endsWith('.jst')) {
return next();
}
async.waterfall([
function (cb) {
file.exists(filePath, cb);
},
function (exists, cb) {
if (exists) {
return next();
}
fs.readFile(filePath.replace(/\.jst$/, '.tpl'), cb);
},
function (source, cb) {
Benchpress.precompile({
source: source.toString(),
minify: global.env !== 'development',
}, cb);
},
function (compiled, cb) {
fs.writeFile(filePath, compiled, cb);
},
], next);
};

@ -4,11 +4,12 @@ var nconf = require('nconf');
var winston = require('winston');
var path = require('path');
var async = require('async');
var express = require('express');
var meta = require('../meta');
var controllers = require('../controllers');
var plugins = require('../plugins');
var user = require('../user');
var express = require('express');
var accountRoutes = require('./accounts');
var metaRoutes = require('./meta');
@ -147,6 +148,7 @@ module.exports = function (app, middleware, hotswapIds, callback) {
}
app.use(middleware.privateUploads);
app.use(relativePath + '/assets/templates', middleware.templatesOnDemand);
var statics = [
{ route: '/assets', path: path.join(__dirname, '../../build/public') },

@ -1,8 +1,12 @@
<script type="text/tpl" data-template="500">
&#x3C;div class=&#x22;alert alert-danger&#x22;&#x3E;
&#x9;&#x3C;strong&#x3E;[[global:500.title]]&#x3C;/strong&#x3E;
&#x9;&#x3C;p&#x3E;[[global:500.message]]&#x3C;/p&#x3E;
&#x9;&#x3C;p&#x3E;{path}&#x3C;/p&#x3E;
&#x9;&#x3C;!-- IF error --&#x3E;&#x3C;p&#x3E;{error}&#x3C;/p&#x3E;&#x3C;!-- ENDIF error --&#x3E;
&#x3C;/div&#x3E;
<script>
define('/assets/templates/500.jst', function () {
function compiled(helpers, context, get, iter, helper) {
return '<div class="alert alert-danger">\n\t<strong>[[global:500.title]]</strong>\n\t<p>[[global:500.message]]</p>\n\t<p>' +
helpers.__escape(get(context && context['path'])) + '</p>\n\t' +
(get(context && context['error']) ? '<p>' + helpers.__escape(get(context && context['error'])) + '</p>' : '') + '\n\n\t' +
(get(context && context['returnLink']) ? '\n\t<p>[[error:goback]]</p>\n\t' : '') + '\n</div>\n';
}
return compiled;
});
</script>

@ -27,7 +27,7 @@ var plugins = require('./plugins');
var flags = require('./flags');
var routes = require('./routes');
var auth = require('./routes/authentication');
var templates = require('templates.js');
var Benchpress = require('benchpressjs');
var helpers = require('../public/src/modules/helpers');
@ -119,11 +119,24 @@ function setupExpressApp(app, callback) {
var middleware = require('./middleware');
var relativePath = nconf.get('relative_path');
var viewsDir = nconf.get('views_dir');
app.engine('tpl', templates.__express);
app.engine('tpl', function (filepath, data, next) {
filepath = filepath.replace(/\.tpl$/, '.jst');
middleware.templatesOnDemand({
filePath: filepath,
}, null, function (err) {
if (err) {
return next(err);
}
Benchpress.__express(filepath, data, next);
});
});
app.set('view engine', 'tpl');
app.set('views', nconf.get('views_dir'));
app.set('json spaces', process.env.NODE_ENV === 'development' ? 4 : 0);
app.set('views', viewsDir);
app.set('json spaces', global.env === 'development' ? 4 : 0);
app.use(flash());
app.enable('view cache');

@ -2,8 +2,8 @@
var async = require('async');
var winston = require('winston');
var templates = require('templates.js');
var _ = require('lodash');
var Benchpress = require('benchpressjs');
var plugins = require('../plugins');
var translator = require('../translator');
@ -93,12 +93,12 @@ function renderWidget(widget, uid, options, callback) {
if (widget.data.container && widget.data.container.match('{body}')) {
translator.translate(widget.data.title, function (title) {
html = templates.parse(widget.data.container, {
Benchpress.compileParse(widget.data.container, {
title: title,
body: html,
}, function (err, html) {
next(err, { html: html });
});
next(null, { html: html });
});
} else {
next(null, { html: html });

@ -14,6 +14,15 @@ describe('admin search', function () {
]);
done();
});
it('should exclude .jst files', function (done) {
assert.deepEqual(search.filterDirectories([
'hfjksfd/fdsgagag/admin/gdhgfsdg/sggag.tpl',
'dfahdfsgf/admin/hgkfds/fdhsdfh.jst',
]), [
'admin/gdhgfsdg/sggag',
]);
done();
});
it('should exclude partials', function (done) {
assert.deepEqual(search.filterDirectories([
'hfjksfd/fdsgagag/admin/gdhgfsdg/sggag.tpl',

Loading…
Cancel
Save