Pug: accessing bootstrap from node_modules - node.js

I am using pug to output html which I use for later pdf generation with html-pdf.
My controller:
// read file
var source = fs.readFileSync(path.resolve(__dirname, 'templates/pdf.pug'), 'utf-8');
// compile pug template and output html
var template = pug.compile(source);
var html = template(data)
My template
doctype html
html
head
title Merapi Export
link(rel='stylesheet', href='/node_modules/bootstrap/dist/css/bootstrap.min.css')
body
h1 Merapi Export
Is there any way to integrate bootstrap directly from node modules?

Turns out you have to set a base dir to your pug template in the options of html-pdf (used to generate the pdf):
base: 'file:///'+__dirname+'/templates/'
Once this is done you can access bootstrap like this:
link(rel='stylesheet', href='../../../../../../node_modules/bootstrap/dist/css/bootstrap.min.css')

In app.js
app.use(
"/css",
express.static(path.join(_dirname, "node_modules/bootstrap/dist/css"))
)
app.use(
"/js",
express.static(path.join(_dirname, "node_modules/bootstrap/dist/js"))
)
in your pug file
link(rel="stylesheet", href="./css/bootstrap.min.css")
script(src="./js/bootstrap.js", defer)

Related

template layout for PugJs

I used NodeJs with Handlebars and thought about switching to PugJs because some functionality is native - using Handlebars requires some helper functions / partials.
In Handlebars I have to define a layout and pass in the template. In PugJs I created two example routes
First route file:
const express = require('express');
const router = express.Router();
router.get('/', (req, res) => {
res.render('index', {
title: 'Home',
template: 'main'
});
});
module.exports = router;
Second route file:
const express = require('express');
const router = express.Router();
router.get('/', (req, res) => {
res.render('index', {
title: 'Page2',
template: 'pageTwo'
});
});
module.exports = router;
As you can see I always have to render my index file and pass in the desired pug file as a template variable.
index.pug
doctype html
html
include ./header.pug
body
include ./templates/#{template}.pug
header.pug
head
title #{title} template!
main.pug
script(src='./client/main.js')
h1 main content here
pageTwo.pug
p pageTwo
When rendering the pug files I get this error
ENOENT: no such file or directory, open
'...\views\templates\#{template}.pug'
How can I replace #{template} with the correct template variable?
Dynamic template selection isn't a feature of pug, I believe it has something to do with how pug pre-compiles everything into a JavaScript function that stays in-memory inside node.js when it runs. The benefit of that is super-fast page rendering, so we're happy to keep using pug and just work around this.
Speaking of which, you can accomplish what you want to do using conditional logic:
doctype html
html
include ./header.pug
body
if template === 'pageOne'
include ./templates/pageOne.pug
else if template === 'pageTwo'
include ./templates/pageTwo.pug
else
include ./templates/home.pug
You should also look into the extends feature to simplify adding the header into your templates and mixins to resuse code between templates. You might find that these features could provide a better solution to your requirements with some redesign.

Routes and scripts in Express (using Jade) - scripts on layout.jade

I am new to Node, Express, and Jade, and have a question about how to structure my script files.
In my layout I have jquery listed at the bottom. In another file, on another route, I wanted to add a script that uses jquery, so I wanted to add it below the jquery script tag on layout.jade when using that particular route.
layout.jade:
doctype html
html
head
title= title
link(rel='stylesheet', href='/stylesheets/happy.css')
link(rel='stylesheet', href='/stylesheets/fonts.css')
link(href='https://fonts.googleapis.com/css?family=Open+Sans:400,300,600', rel='stylesheet', type='text/css')
link(href='https://fonts.googleapis.com/css?family=Open+Sans:400,300,600', rel='stylesheet', type='text/css')
link(href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet")
link(rel="icon" href="/favicon.png" sizes="16x16" type="image/png")
body
block content
script(src='https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js')
script(src="/javascripts/script.js")
I want this file added to the bottom of my scripts on the layout page when visting the /about route:
script(src="/javascripts/scroll.js")
/routes/about.js:
var express = require('express');
var router = express.Router();
router.get('/', function(req, res) {
res.render('about');
});
module.exports = router;
from app.js:
app.use('/about', about);
You can use multiple layouts one with the script and one without
you set layouts like this
res.render('about', { layout: 'layoutwithscript.jade' });
Credit to #alessioalex in this post

node express how to render handlebars html page to file

I want to convert some html page to pdf via wkhtmltopdf. However, the html page I want to convert to pdf is dynamically generated using handlebars.
So I think one solution maybe to generate the html page via handlebars but to a file (html file). Then, convert that file to pdf using hkhtmltopdf, then allow the user to, somehow, download the pdf.
So, my question is: how can I render the (handlebars) dynamically generated html page to a file?
Thanks and bye ...
Simple example for create file.
var Handlebars = require('handlebars');
var source = "<p>Hello, my name is {{name}}. I am from {{hometown}}. I have " +
"{{kids.length}} kids:</p>" +
"<ul>{{#kids}}<li>{{name}} is {{age}}</li>{{/kids}}</ul>";
var template = Handlebars.compile(source);
var data = { "name": "Alan", "hometown": "Somewhere, TX",
"kids": [{"name": "Jimmy", "age": "12"}, {"name": "Sally", "age": "4"}]};
var result = template(data);
var fs = require('fs');
fs.writeFile("test.html", result, function(err) {
if(err) {
return console.log(err);
}
});
Using express-handlebars, you should use the advanced mode and create an instance of it like in this example.
The proper way would be to create a view file (like you probably already have per you question) and use the express handlebars instance to render it:
// init code
var exphbs = require('express-handlebars');
var hbs = exphbs.create({
defaultLayout: 'your-layout-name',
helpers: require("path-to-your-helpers-if-any"),
});
app.engine('.file-extention-you-use', hbs.engine);
app.set('view engine', '.file-extention-you-use');
// ...then, in the router
hbs.render('full-path-to-view',conext, options).then(function(hbsTemplate){
// hbsTemplate contains the rendered html, do something with it...
});
HTH
Code above from Alex works perfect. However, my confusion was: I was using 'express-handlebars' and not 'handlebars'. Now, what I can understand is Express-Handlebars is an implementation of Handlebars for an Express application, which I´m using. I just didn't find a way to use the 'compile()' method in Express-Handlebars, so I ended up installing Handlebars (standalone) and used it to compile my (html) template and save the result to disk, just as Alex explained above.
In summary:
1) I know Express-Handlebars is Handlebars for Express app.
2) I don't know how to use "compile()" method just from express-handlebars, so I ended up installing Handlebars (from npm) and using it on the server to produce my html file (from template) and save it to disk.
3) Of course I installed and use Express-Handlebars everywhere to serve my pages in my Express app; just installed Handlebars to produce my html (in the server) with "compile()" method and save the result to disk.
Hope this is understandable. Thanks again and bye ...

NodeJS, Express - Render EJS view to a download file

I have a NodeJS, Express 3 app that uses EJS templating. I have a route that enables 'preview' of some form fields containing HTML and CSS that are posted. It simply plugs them in and renders my preview.ejs template like this..
app.post('/preview', function(req, res){
var htm = req.body.htm;
var css = req.body.css;
res.render('preview',{_layoutFile:'', htm:htm, css:css});
});
What I'd like to do now is a similar route that forces download of the file instead..
app.post('/download', function(req, res){
var htm = req.body.htm;
var css = req.body.css;
// res.download or res.sendfile here ??
});
I see that there is a res.sendfile() and res.download(), but how can I use these with my EJS 'preview' view template?
P.S. - I'm also using Mikeal's request is this same app. I wonder if there is a way I could use pipe to fs (filesystem) and then force download of the saved file?
See: http://expressjs.com/api.html#res.attachment
res.attachment() sets Content-Disposition: attachment header which tells the browser to treat the response as a download.
app.post('/download', function(req, res){
var htm = req.body.htm;
var css = req.body.css;
res.attachment();
res.render('preview',{_layoutFile:'', htm:htm, css:css});
});

Jade template inheritance without Express

I would like to use Jade block inheritance but I'm not sure how to do that if I'm not using Express. According to the Jade doc, I can use block inheritance in Express by simply adding app.set('view options', { layout: false });. How can I achieve this without Express?
https://github.com/visionmedia/jade
You don't need Express at all to use Jade's Template inheritance; you only need Jade:
// app.js
var jade = require('jade');
var options = { pretty: true, locals: {} };
jade.renderFile(__dirname + '/home.jade', options, function (err, html) {
console.log(html);
});
// home.jade
extends core
block body
h1 Home
// core.jade
doctype html
html
head
meta(charset='utf-8')
title Foo
body
block body
Another example can be found in the repository:
examples/extend.js
examples/extend.jade
examples/extend-layout.jade.
The reason the Jade docs mention setting the 'view options' for Express 2.x is because Express' own (and now defunct in 3.x) layouts are a competing feature that should be disabled to prevent conflicts when using Jade's inheritance.

Resources