Jade (now Pug) is a great templating engine, but the compilation of the views consume so much resources. Jade is slow. Of course you can use the "cache view" feature of express on production that caches the compiled views, but the compiled views are stored in memory that can consume so much resources. Thanks to Jade, the latest express app that I had developed responded to the first request in more than 800ms, so as I didn't want to change the templating engine, I, just like you, decided to compile the Jade views on my development environment and deploy these files instead of original views.
In order to use the compiled views which are .js
files consisting of a function named template
, you need to use the jade runtime. The runtime generates the attribute values and does other stuff like escaping values. The template
function accepts one argument which is for dynamic data.
Since these functions are compiled for client side, the compiled views depends on a global jade runtime (i.e. window.jade
). In node.js you can populate the GLOBAL
object, i.e. GLOBAL.jade = require('jade/lib/runtime')
but it's not a good idea. I decided to modify the compiled function so:
- We can
require
the compiled view (.js
files) by using module.exports
.
- The function accepts a second argument which is the jade runtime.
The following code snippet uses gulp
, gulp-jade
and gulp-replace
node modules in a .gulpfile
:
gulp.task('compile-jade', () => {
// get all the jade files and compile them for client
return gulp.src([
'../views/**/*.jade'
]).pipe(jade({
client: true
}))
// replace the function definition
.pipe(replace('function template(locals)', 'module.exports = function(locals, jade)'))
.pipe(gulp.dest('../views_js') );
});
Now that we have changed the function declaration we can load the compiled files (.js
files) instead of the .jade
files. But there is another problem. There is no pre-made templating engine (as far as I know) for using these files. So we need to define a new engine. It's pretty easy:
let jade = require('jade/lib/runtime');
app.engine('js', function (filePath, options, callback) { // define the template engine
let data = require(filePath)(options, jade);
callback(null, data);
});
Now we can change the view related settings in express:
app.set('view engine', 'js');
app.set('views', path.join(__dirname, 'views_js'));
Now responding to the first request on startup of the application takes 7ms for me. Just note that require
throws error for files that do not exist so you can consider using try/catch
or promises for handing the possible exceptions.