Framework: node.js / express.js / Jade
Question: in production env, when a jade file is rendered by express, jade cache's it so future renders are faster.
When I start node.js app, how can I pre-compile (or) pre-render (like warmup) all the jade files so its already in cache when requests start to come in...
I can use a folder recursion, I just need to know how to pre-compile (or) pre-render.
Is this possible?
Jade has template pre-compiling and caching built in.
http://jade-lang.com/api/
Simply specify cache: true option to jade.compileFile, and iterate through all of your template files.
var options = {cache: true};
// iterate/recurse over your jade template files and compile them
jade.compileFile('./templates/foo.jade', options);
// Jade will load the compiled templates from cache (the file path is the key)
jade.renderFile('./templates/foo.jade');
If you're not using any parameters, you can compile jade templates directly to HTML with grunt or gulp and make it watch for file modifications
Try it from the command-line:
jade view/map-beacons.jade -D
If you do need to use parameters I would use something like in Andrew Lavers answer.
compileFile returns a function which you can use to pass in parameters i.e. fn({ myJsVar: 'someValue' })
There is also a client option in the command-line but I didn't find any use for it :
jade view/map-beacons.jade -cD
i do this solution, this code outside http.createServer function
let cache_index=jade.renderFile('index.jade');
and when return view
res.statusCode = 200;
res.setHeader('Content-Type', 'text/html');
res.end(cache_index);
when use this solution server return index to 1ms
but without solution server return index between 150ms to 400ms
result:
Picture 1 with cache
Picture 2 without cache
Related
I've decided to try out ReactJS. Along with that, I've decided to use Gulp for compiling .jsx to .js, also for the first time.
I can compile it no problem for the client use with browserify. Here's my gulp task:
browserify("./scripts/main.jsx")
.transform(
babelify.configure({
presets: ["react"]
}))
.bundle()
.pipe(source('bundle.js'))
.pipe(gulp.dest('./scripts/'));
But since I use PHP to generate data, I need to get those data to node. If I use browserify, it will prevent me from using process.argv in node. I can save data to file and read that file in node, so I wouldn't need to pass the whole state to node, but I still need to pass the identifying arguments, so the node knows which file to load.
What should I use instead of browserify?
If you need to compile a React module to es5 for use on the server, use Babel itself.
A module that may help with reading and writing files is this one: https://nodejs.org/api/fs.html
Have you considered posting and getting from a database?
Here's how I solved it:
I have learnt that you can create standalone bundles with browserify, so I've compiled all the server code I need (components + rendering) as a standalone bundle. Then I have created small node script which is responsible only for reading arguments, loading data and sending it to the rendering code.
I'm not sure if this is a proper way how it should be done but it works.
Here's code for the "setup" script:
var fs = require('fs');
var Server = require('./server.js');
if (process.argv[2]) {
region = process.argv[2].toLowerCase().replace(/[^a-z0-9]/, '');
if (region != '') {
var data = JSON.parse(fs.readFileSync(__dirname + '/../tmp/' + region + '.json', 'utf8'));
console.log(Server.render(data.deal, data.region));
}
}
This way I only need to deploy two files and I still can easily compile jsx to js.
Background / Need
I am working with a group on a web application using Node.JS and Express. We need to be able to generate reports which can be printed as hard copies and also hard copy forms. Preferably we'd like to dynamically generate PDFs on the server for both reports and hand written forms. We're currently using EJS templates on the server.
Options
I was thinking that it would be convenient to be able to use templates to be able to build forms/reports and generate a PDF from the resulting HTML, however my options to do this appear limited as far as I can find. I have looked at two different possible solutions:
PhantomJS -- (npm node-phantom module)
PDFKit
EDIT: I found another Node.JS module which is able to generate PDFs from HTML called node-wkhtml which relies on wkhtmltopdf. I am now comparing using node-phantom and node-wkhtml. I have been able to generate PDFs on a Node server with both of these and they both appear to be capable of doing what I need.
I have seen some examples of using PhantomJS to render PDF documents from websites, but all of the examples I have seen use a URL and do not feed it a string of HTML. I am not sure if I could make this work with templates in order to dynamically generate PDF reports.
When a request for a report comes in I was hoping to generate HTML from an EJS template, and use that to generate a PDF. Is there anyway for me to use Phantom to dynamically create a page completely on the server without making a request?
My other option is to use PDFkit which allows dynamic generation of PDFs, but it is a canvas-like API and doesn't really support any notion of templates as far as I can tell.
The Question
Does anyone know if I can use PhantomJS with Node to dynamically generate PDFs from HTML generated from a template? Or does anyone know any other solutions I can use to generate and serve printable reports/forms from my Node/Express back-end.
EJS seems to run fine in PhantomJS (after installing the path module). To load a page in PhantomJS given a string of HTML, do page.content = '<html><head>...';.
npm install ejs and npm install path, then:
var ejs = require('ejs'),
page = require('webpage').create();
var html = ejs.render('<h1><%= title %></h1>', {
title: 'wow'
});
page.content = html;
page.render('test.pdf');
phantom.exit();
(Run this script with phantomjs, not node.)
I am going to post an answer for anyone trying to do something similar with node-phantom. Because node-phantom controls the local installation of PhantomJS, it must use asynchronous methods for everything even when the corresponding PhantomJS operation is synchronous. When setting the content for a page to be rendered in PhantomJS you can simply do:
page.content = '<h1>Some Markup</h1>';
page.render('page.pdf');
However, using the node-phantom module within node you must use the page.set method. This is the code I used below.
'use strict';
var phantom = require('node-phantom');
var html = '<!DOCTYPE html><html><head><title>My Webpage</title></head>' +
'<body><h1>My Webpage</h1><p>This is my webpage. I hope you like it' +
'!</body></html>';
phantom.create(function (error, ph) {
ph.createPage(function (error, page) {
page.set('content', html, function (error) {
if (error) {
console.log('Error setting content: %s', error);
} else {
page.render('page.pdf', function (error) {
if (error) console.log('Error rendering PDF: %s', error);
});
}
ph.exit();
});
});
});
A really easy solution to this problem is the node-webshot module - you can put raw html directly in as an argument and it prints the pdf directly.
I am thinking of using Jade templates on client side (with BackboneJS). Seems like I can use jadeify. But was wondering, how does it work? Does it download each template 1 by 1 or compile all templates on serverside then serve a "compiled" templates file to the client? Looking at the source, it looks surprisingly short:
https://github.com/substack/node-jadeify/blob/master/jadeify.js
var views = require('jadeify/views'); ...
module.exports = function (file, vars, opts) {
...
return $(jade.render(views[file], opts));
};
Line 1: can I even require a folder like that? Can I say views is now an array of scripts under that directory? That appear to be the case from Line 5, where views[file] is used.
But it calls jade.render. Won't it be more efficient to call jade.compile and cache it first? Or is it already cached somewhere?
I want to use compiled jade templates on client side. How should I compile them to get javascript files ?
https://github.com/visionmedia/jade
Yes you can! https://github.com/techpines/asset-rack#jadeasset
I just open sourced "asset-rack", a nodejs project that can can precompile jade templates and serve them in the browser as javascript functions.
This means that rendering is blazingly fast, even faster then micro-templates because there is no compilation step in the browser.
First you set it up on the server as follows:
new JadeAsset({
url: '/templates.js',
dirname: __dirname + '/templates'
});
If you template directory looked like this:
templates/
navbar.jade
user.jade
footer.jade
Then all your templates come into the browser under the variable "Templates":
$('body').append(Templates.navbar());
$('body').append(Templates.user({name: 'mike', occupation: 'sailor'});
$('body').append(Templates.footer());
#coffeescript
jade = require 'jade'
data = '#menu'
options =
client: true
compileDebug: false
fn = jade.compile data, options
console.log fn.toString()
Look for proposed solutions in the jade issue 149 discussion. Unfortunately, there is no built-in ready for use option, as I know.
You should probably look at integrating this into a Grunt build task.
See grunt-contrib-jade
Blade is a Jade-like HTML template engine that has a built-in middleware for serving compiled templates to the client. :) Check it out!
This question is a bit dated, but there is a method of compiling Jade templates,
var jade = require('jade');
var fn = jade.compile(jadeTemplate);
var htmlOutput = fn({
maintainer: {
name: 'Forbes Lindesay',
twitter: '#ForbesLindesay',
blog: 'forbeslindesay.co.uk'
}
})
Just got to the tutorial and search for compile, or the API under
jade.compile(source, options)
Be sure to set, compileDebug so you get the source,
Set this to false to disable debugging instrumentation (recommended in production). Set it to true to include the function source in the compiled template for better error messages (sometimes useful in development).
I using express and jade, but when I debug I doesn't want jade compress my html, are there any way to pass an option jade globally and make it does not compress html.
If you use Express 3.x, you can control compression via app.locals.pretty. I usually enable it while development:
app.configure('development', function () {
app.locals.pretty = true;
});
In the time since this answer was written an option has been added to control this behaviour.
app.locals.pretty = true;
At the moment, no. This feature has been discussed here:
https://github.com/visionmedia/jade/pull/205
The html doesn't actually get compressed or minified by default, though. It's just not formatted nicely. The simplest way I've found to make it human-readable is to use Chrome's dev tools, which give you a nice foldable representation of the source.
You can use Jade Comments to annotate your code for viewing in the browser.
//h1
h1 Some Title
//p
p some content
will output
<!--h1-->
<h1>Some Title</h1>
<!--p-->
<p>some content</p>
The template is already compiled once it leaves the server, so if you wanted to view the template in the browser you would have to write a plugin that de-compiles html to jade and than display the decompiled version.
Huh, new to nodejs so maybe missing something here; but in app.js adding app.set('view options', {pretty: true}); was ineffectual (using express 3.0.3).
..doesn't appear to be supported? did find a workaround, e.g. on a per route basis:
exports.index = function(req, res){
res.render('index', {
[... other stuff ...]
pretty: true
});
};
For whom using pug-cli, you need to add --pretty in cmd(terminal). Like the following,
pug --pretty -w -o dist/html/ assets/pug/index.pug