How can I get Express to output nicely formatted HTML? - node.js

When using Express for Node.js, I noticed that it outputs the HTML code without any newline characters or tabs. Though it may be more efficient to download, it's not very readable during development.
How can I get Express to output nicely formatted HTML?

In your main app.js or what is in it's place:
Express 4.x
if (app.get('env') === 'development') {
app.locals.pretty = true;
}
Express 3.x
app.configure('development', function(){
app.use(express.errorHandler());
app.locals.pretty = true;
});
Express 2.x
app.configure('development', function(){
app.use(express.errorHandler());
app.set('view options', { pretty: true });
});
I put the pretty print in development because you'll want more efficiency with the 'ugly' in production. Make sure to set environment variable NODE_ENV=production when you're deploying in production. This can be done with an sh script you use in the 'script' field of package.json and executed to start.
Express 3 changed this because:
The "view options" setting is no longer necessary, app.locals are the local variables merged with res.render()'s, so [app.locals.pretty = true is the same as passing res.render(view, { pretty: true }).

To "pretty-format" html output in Jade/Express:
app.set('view options', { pretty: true });

There is a "pretty" option in Jade itself:
var jade = require("jade");
var jade_string = [
"!!! 5",
"html",
" body",
" #foo I am a foo div!"
].join("\n");
var fn = jade.compile(jade_string, { pretty: true });
console.log( fn() );
...gets you this:
<!DOCTYPE html>
<html>
<body>
<div id="foo">I am a foo div!
</div>
</body>
</html>
I doesn't seem to be very sophisticated but for what I'm after -- the
ability to actually debug the HTML my views produce -- it's just fine.

In express 4.x, add this to your app.js:
if (app.get('env') === 'development') {
app.locals.pretty = true;
}

If you are using the console to compile, then you can use something like this:
$ jade views/ --out html --pretty

In express 4.x, add this to your app.js:
app.locals.pretty = app.get('env') === 'development';

Do you really need nicely formatted html? Even if you try to output something that looks nice in one editor, it can look weird in another. Granted, I don't know what you need the html for, but I'd try using the chrome development tools or firebug for Firefox. Those tools give you a good view of the DOM instead of the html.
If you really-really need nicely formatted html then try using EJS instead of jade. That would mean you'd have to format the html yourself though.

you can use tidy
take for example this jade file:
foo.jade
h1 MyTitle
p
a(class='button', href='/users/') show users
table
thead
tr
th Name
th Email
tbody
- var items = [{name:'Foo',email:'foo#bar'}, {name:'Bar',email:'bar#bar'}]
- each item in items
tr
td= item.name
td= item.email
now you can process it with node testjade.js foo.jade > output.html:
testjade.js
var jade = require('jade');
var jadeFile = process.argv[2];
jade.renderFile(__dirname + '/' + jadeFile, options, function(err, html){
console.log(html);
});
will give you s.th. like:
output.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html><head><title>My Title</title><link rel="stylesheet" href="/stylesheets/style.css"/><script type="text/javascript" src="../js/jquery-1.4.4.min.js"></script></head><body><div id="main"><div ><h1>MyTitle</h1><p>show users</p><table><thead><tr><th>Name</th><th>Email</th></tr></thead><tbody><tr><td>Foo</td><td>foo#bar</td></tr><tr><td>Bar</td><td>bar#bar</td></tr></tbody></table></div></div></body></html
then running it through tidy with tidy -m output.html will result in:
output.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="generator" content=
"HTML Tidy for Linux (vers 25 March 2009), see www.w3.org" />
<title>My Title</title>
<link rel="stylesheet" href="/stylesheets/style.css" type=
"text/css" />
<script type="text/javascript" src="../js/jquery-1.4.4.min.js">
</script>
</head>
<body>
<div id="main">
<div>
<h1>MyTitle</h1>
<p>show users</p>
<table>
<thead>
<tr>
<th>Name</th>
<th>Email</th>
</tr>
</thead>
<tbody>
<tr>
<td>Foo</td>
<td>foo#bar</td>
</tr>
<tr>
<td>Bar</td>
<td>bar#bar</td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>

building off of oliver's suggestion, heres a quick and dirty way to view beautified html
1) download tidy
2) add this to your .bashrc
function tidyme() {
curl $1 | tidy -indent -quiet -output tidy.html ; open -a 'google chrome' tidy.html
}
3) run
$ tidyme localhost:3000/path
the open command only works on macs. hope that helps!

Related

hbs rendered site with handlebars.js in the script - nodejs

I use hbs to render my pages with partials for navigation and footers.
router.get('/test', function (req, res) {
return res.render('test');
});
On one page I have template that uses mustache.js. This template doesn't work as it should as the {{}} seems to be picked up on the hbs render. Below is a basic example that illustrates the error. If I load this as a static page with express I get "Joe is a Web Developer", if I render it with hbs I get "is a".
Are there any work arounds that wont involve me changing how all my pages are rendered?
<!doctype html>
<html lang="en">
<head>
<title>Mustache.js Inline Method</title>
<script type="text/javascript" src="js/libs/mustache.js" ></script>
<script>
var view = {
name : "Joe",
occupation : "Web Developer"
};
function loadtemp(){
var output = Mustache.render("{{name}} is a {{occupation}}", view);
document.getElementById('person').innerHTML = output;
}
</script>
</head>
<body onload="loadtemp()" >
<p id="person"></p>
</body>
</html>
It was simple enough. I just had to escape the brackets with a \
So all it took was
\{{name}}

html-pdf npm library gives different output on windows & ubuntu

I'm using https://www.npmjs.com/package/html-pdf library which is based on Phantom JS which internally uses webkit. I'm pasting the dummy HTML & JS code(keep these files in 1 folder) and also attaching the output screenshot.
The issue I'm facing is that on windows the PDF is generated with some extra space at top(empty space above red) which I can't get rid of.
Here is a forum(outdated) discussing similar issues, https://groups.google.com/forum/#!topic/phantomjs/YQIyxLWhmr0 .
input.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<div id="pageHeader" style="border-style: solid;border-width: 2px;color:red;">
header <br/> header <br/> header <br/> header
</div>
<div id="pageContent" style="border-style: solid;border-width: 2px;color:green;">
<div>
body <br/> body <br/> body
</div>
</div>
JS
(You require path, fs, handlebars, html-pdf npm packages)
var path = require('path');
var fs = require('fs');
var handlebars = require('handlebars');
var pdf = require('html-pdf');
saveHtml();
function saveHtml() {
fs.readFile('input.html', 'utf-8', {
flag: 'w'
}, function(error, source) {
handlebars.registerHelper('custom_title', function(title) {
return title;
})
var template = handlebars.compile(source);
var data = {};
var html = template(data);
var options = {
'format': 'A4',
'base': "file://",
/* You can give more options like height, width, border */
};
pdf.create(html, options).toFile('./output.pdf', function(err, res) {
if (err) {
console.log('err pdf');
return;
} else {
console.log('no err pdf');
return;
}
});
});
}
Output on ubuntu
Output on windows
Extra space at top(empty space above red) in Windows is the issue.
THINGS that didn't work
1. Adding
"border": {
"top": "0px" // or mm, cm, in
}
to options in JS file
https://www.npmjs.com/package/html-pdf#options
Giving fixed "height": "10.5in" & "width": "8in" in options in JS file
Making margin-top & padding-top to 0px/-50px to pageHeader div.
Overriding margin-top & padding of body to 0px/-20px in #media print in bootstrap.css
Giving fixed height to header
Any help will be greatly appreciated. Thanks.
You can manually set the CSS property to html tag. In my case I was having problems developing the template in Windows and deploying it to Linux (Heroku).
I put zoom: 0.7 in the label html and now both views look the same.
html{zoom: 0.7;}
I was able to get more consistent results by removing the ID's so that it treated everything as content rather than separate header and content areas.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<div style="border-style: solid;border-width: 2px;color:red;">
header
</div>
<div style="border-style: solid;border-width: 2px;color:green;">
<div>
body
</div>
</div>
</body>
</html>
If you need an ID for styling, use something other than pageHeader / pageFooter to avoid the special treatment associated with those IDs.
Have you tried using a normalize style sheet to compensate for cross platform differences?
https://necolas.github.io/normalize.css/

Node Express EJS Dynamic template render

Hi I am trying to create dynamic template system in express, where I will get dynamic content from database and then render output in single index.ejs file.
Here is my index.js
router.get('/', function(req, res, next) {
var dataFrmDB = {
pageContent: "<%= data.pageTitle %>",
pageTitle: "home"
};
res.render('index', {data:dataFrmDB} );
});
And index.ejs contains:
<%= data.pageContent %>
What I should do so that I can render "home" as output. Is this possible?
I was working on something similar when we migrated from drupal to nodejs, I used ect for rendering instead of jade, its faster and much easier to deal with, However, its much better to use design pattern if you have a big dynamic website
js controller file
model.homepage(function(data)
{
res.render("homepage.ect",data,function(err,html)
{
// Do something before you send the response such as minification, or error handling
res.send(html);
});
});
ECT file
<html xmlns="http://www.w3.org/1999/xhtml" lang="ar" xml:lang="ar">
<head>
<%- #page.title.body %>
<%- #page.headerScript.body %>
<style type="text/css">#homepage-container{min-height:300px;color:#353535;float:right;width:100%}</style>
</head>
<body>
<% include 'upper_bar.ect' %>
<%- #page.headerAd.ads %>
<%- #page.notifications.body %>
<%- #page.autocomplete.body %>
<%- #page.redirect.body %>
<%- #page.navigation.body %>
<%- #page.overlayAd.ads %>
</body>
</html>
why bother so much?
You can easily do this using templatesjs
without any template engine.
let me show you how your work can be done using templatesjs
html file
<html>
<head>
<title> <%title%> </title>
</head>
<body>
your content goes here
</body>
</html>
now use templatesjs in you node.js file
var tjs = require("templatsjs");
router.get('/', function(req, res, next) {
var data = fs.readFileSync("./index.html");
tjs.set(data); // invoke templatesjs
var output = tjs.render("title","home");
/* this will replace the <%title%> tag
in the html page with actual title*/
res.write(output);
res.end()
});
i have used fs.readFileSync to keep simplicity of code you can use the asynchronus function if you want (fs.readFile).
a good referrence can be found here
Installation :
$ npm install templatesjs

Node.js and swig template engine - including template inside template

I trying to create main page (part of node.js and mongoDB application) that includes login form.
To add view part I included js files with function that returns HTML, but as I can see much better is using template engine.
Everything is OK until I including one compiled swig part inside another one.
The output of main page is OK, but login part outputs like text on the page.
How is possible to output the login HTML as HTML instead of plain text?
Does more information needed to understand the issue?
Thank you in advance.
var swig = require('swig');
var mainPage_tpl = swig.compileFile(__dirname+'/../views/mainpage_tpl.html');
var formLogin_tpl = swig.compileFile(__dirname+'/../views/login_tpl.html');
var loginOutput = formLogin_tpl();
var mainPageOutput = mainPage_tpl({
title: 'Sometitle',
pagetitle: 'Somepagetitle',
content: loginOutput
});
exports.get = function(req, res){
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(mainPageOutput);
res.end();
}
mainpage_tpl.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>{{title}}</title>
<link rel="stylesheet" href="/assets/reset.css" />
<link rel="stylesheet" href="/assets/style.css" />
<script type="text/javascript" src="/assets/jquery-2.0.0.js"></script>
<script type="text/javascript" src="/assets/script.js"></script>
</head>
<body id="login_page">
<h1>{{pagetitle}}</h1>
<div id="content">{{content}}</div>
</body>
</html>
If you want to include literal HTML, you need to tell Swig to not escape it using the safe filter:
...
<div id="content">{{ content|safe }}</div>
...

is there a way to add CSS/JS later using EJS with nodejs/express

i'm using the EJS template engine with nodejs/express and i'm wondering if it's possible to add another css or js file in e.g the index.ejs (not the layout.ejs)
layout.ejs
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
<link rel='stylesheet' href='/stylesheets/style.css' />
<link rel='stylesheet' href='/stylesheets/smoothness/jquery-ui-1.8.14.custom.css' />
</head>
<body>
<%- body %>
</body>
</html>
index.ejs
<h1><%= title %></h1>
<p>Welcome to <%= title %></p>
i don't want to add the second css file in every template but only the index.ejs - is there any way i can do that?
found a solution here: Node.js with Express: Importing client-side javascript using script tags in Jade views?
it's using jade instead of EJS but works all the same.
here are some code-snippets for express 2.4.0.
you have to add the following "helpers" to your app.js
app.helpers({
renderScriptsTags: function (all) {
if (all != undefined) {
return all.map(function(script) {
return '<script src="/javascripts/' + script + '"></script>';
}).join('\n ');
}
else {
return '';
}
}
});
app.dynamicHelpers({
scripts: function(req, res) {
return ['jquery-1.5.1.min.js'];
}
});
the layout.ejs looks sth like this:
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
<link rel='stylesheet' href='/stylesheets/style.css' />
<%- renderScriptsTags(scripts) %>
</head>
<body>
<%- body %>
</body>
</html>
if you don't add any scripts to the scripts-array, only 'jquery-1.5.1.min.js' will be included - if you want to add files to a subpage you can do this like so:
test.ejs
<% scripts.push('jquery-ui-1.8.14.custom.min.js', 'jquery.validate.min.js') %>
<h1><%= title %></h1>
<p>I'm a template with 3 js files in the header</p>
that's it.
As helpers and dynamicHelpers are gone in Express > 3, I rewrote pkyeck code so it works in Express 3.
So in app.js have this instead of the helpers / dynamicHelpers. Leave everything else as is.
app.locals({
scripts: [],
renderScriptsTags: function (all) {
app.locals.scripts = [];
if (all != undefined) {
return all.map(function(script) {
return '<script src="/javascripts/' + script + '"></script>';
}).join('\n ');
}
else {
return '';
}
},
getScripts: function(req, res) {
return scripts;
}
});
In app.js add line:
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.use(express.static(__dirname + '/public')); // This line.
In layout.ejs:
<!DOCTYPE html>
<html>
<head>
<title>Authentication Example</title>
<link rel="stylesheet" href="/stylesheets/style.css"/>
<script src="/javascripts/jquery.js"></script>
</head>
<body>
<%- body %>
</body>
</html>
In index.ejs or login.ejs:
<h1>Login</h1>
<form method="post" action="/login">
<p>
<label>Username:</label>
<input type="text" name="username">
</p>
<p>
<label>Password:</label>
<input type="text" name="password">
</p>
<p>
<input type="submit" value="Login">
</p>
</form>
<script src="/javascripts/test.js"></script> <!-- Second Script -->
In test.js:
$(document).ready(function() {
try{
alert("Hi!!!");
}catch(e)
{
alert("Error");
}
});
Regards.
Thanks #asprotte for providing this for express 4.x. Did you tested this?
Because it does not appears to be working for me. So I have made some changes to your code here are they:
Put this in app.js file
app.locals.scripts = [];
app.locals.addScripts=function (all) {
app.locals.scripts = [];
if (all != undefined) {
app.locals.scripts = all.map(function(script) {
console.log(script);
return "<script src='/js/" + script + "'></script>";
}).join('\n ');
}
};
app.locals.getScripts = function(req, res) {
return app.locals.scripts;
};
then in template file put (I am using ejs template here) :
<% addScripts(['cart.js']) %>
Then in the layout file we need these to append at the bottom of the page get the scripts
<%- getScripts() %>
I have tested it and its working for me. Please correct me if I am wrong.
Thanks,
Thanks for illustrating this option pkyeck!
In express 4.x app.locals is an object. Here's pkyeck's answer rewritten to work in express 4.x:
app.locals.scripts = [];
app.locals.addScripts=function (all) {
app.locals.scripts = [];
if (all != undefined) {
return all.map(function(script) {
return "<script src='/javascripts/" + script + "'></script>";
}).join('\n ');
}
else {
return '';
}
};
app.locals.getScripts = function(req, res) {
return scripts;
};

Resources