ExpressJS: How to render a EJS file locally - node.js

Excuse me for the novice question.
I want to render a EJS template in a module.
The examples I've seen render them in the main 'app' or they pass the 'app' where the app has the view engine set:
app.set('view engine', 'ejs');
But I want to render an EJS template in another JS file, where app is not available. How do I tell where to find the EJS file? What is the general way of doing this?
Thank you.

Related

Express NodeJS Cannot find module 'html'

I have a Node Server with Express. I get the cannot find module 'html' error even though my code looks like this and should be correct in my opinion:
app.set('views', path.join(__dirname, 'build/views'));
app.use(favicon(path.join(__dirname, "build/favicon.ico")));
app.use('/scripts', express.static(path.join(__dirname, 'node_modules')));
app.use(express.static(path.join(__dirname, 'build')));
app.get('/', function(req, res){
res.render('index.html');
});
You have to set engine for HTML
Include this code in your main file
var engines = require('consolidate');
app.engine('html', engines.mustache);
app.set('view engine', 'html');
If you only want to serve a static file without passing any variables from the server to the client the easiest solution would be:
res.sendFile(path.join(__dirname + '/build/views/index.html'));
Especially when you are using AngularJS for the client side. The problem with the solution above is that mustache uses {{}} as variables recognition. So does AngularJS which might causes errors!
It seems that you are trying to display a static index.html file but you serve it as if it was a template. Probably Express is trying to find a module for html template format, which doesn't exist.
You may try to send the index as a static file instead of with res.render which is for rendering templates.
Some time ago I wrote an example of serving static files with Express. It's available on GitHub:
https://github.com/rsp/node-express-static-example
See also my other answer, where I explain it in more detail.

Structuring a MEAN app so Express can find all the Jade files

I am building out a MEAN app right now that is getting big. I really need to start modularizing the app but right now my Express server is configured to look for Jade views in one folder
app.set('views', path.join(__dirname, '/app/views'));
app.set('view engine', 'jade');
The authors of these posts show the view files scattered about the app in the different module directories.
https://blog.safaribooksonline.com/2014/03/27/13-step-guide-angularjs-modularization/
http://www.johnpapa.net/angular-app-structuring-guidelines/
If I try to do this now, my Express server will not be able to see them. How can I make it so Express will be able to find all the Jade views?
Two solutions :
You can use a base folder named views and create subfolders inside views.
For example, views/menu/, views/header/. To use this, you have to
declare a basedir in Express so Jade will know where to look your
views, by doing app.locals.basedir = __dirname + "/views";. Then,
in your Jade file, use include /header/a.jade, include
/menu/item1.jade etc...
Use Express App submounting feature. This allows you to modularize
your main app into small apps, which all have their own routes, views
etc... You can watch this nice video tutorial by TJ
Holowaychuk to learn more about this.
Does that help you ?
I just start using module prefixes in my render calls and set my views base directory to be the parent directory of my modules. So if I started with:
app/views/page1.jade
app/views/page2.jade
and was doing res.render("page1"), I reorganize to:
app/module1/page1.jade
app/module2/page2.jade
and I do app.set("views", "app") then render with res.render("module1/page1").

Getting Started with express.js, serving a dynamic HTML

I'm writing a single page web application using node.js and express. After going through some online tutorials, I found out this is how express.js serves a client directory with HTML, javascript and css
app.use(express.static(__dirname + '/public'));
This works great except the fact that public directory has to have .html root file which is static. I'd like to know how can I serve a dynamic HTML file with this same approach.
I want to insert some data into the page for example "Hello user_name" at the top. How do I do that for this single file.
I want to only do it once, at the startup, after that my application will make rest API calls and get plain JSON responses which it will then put it in the page.
You cannot use the express static server to serve dynamic files as far as I'm aware. In order to serve a dynamic HTML you need to use a templating engine, such as jade or any of these templating engines.
Jade is pretty straightforward to use and is supported by express by default. To set up jade, include the following lines in your app configuration block:
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
The first line sets your views directory - from which the template files would be served. Since you want to serve only an index file, this directory would contain your index.jade template. The second line sets jade as the templating engine.
Now, instead of using the static server to serve the index.html, you need to create a get route '/' to serve the index file, like so:
app.get('/', function(req, res) {
res.render('index', {user_name: username});
});

Automatically rendering jade file as if it was an html file?

I can't find an answer to this, despite it seeming rather useful.
I would like to host a site using node.js to serve compiled jade files instead of html files. Currently, I'm using:
app.get('/', function(req, res) {
app.use(express.static(__dirname));
});
How can I get it to find page.jade when someone types in domain.com/page? And furthermore, could I write links that way in the jade file (so a(href='page') link would link to the aforementioned page)?
Set your path as
app.get('/:pageName')
// more code
// then
res.render(req.params.pageName+'.jade')
req.params will contain the last part in property name pageName
Express has a number of possible options for what it calls a "view engine". In order to have it process jade files and serve them as html you must configure it to do so.
One of the easiest ways to do this, if you are starting fresh, is to simply create your project using the express command as mentioned in their guide. The default views engine is jade and the following command sets stylus as the css processor:
express --css stylus myapp
If, instead, you are configuring your own server you need to configure the views engine:
app.configure(function(){
app.set('views', path.join(staticDir,'views'));
app.set('view engine', 'jade');
... the rest of your setup ...
}

Is there any way to use multiple view engines with Express + Node.js

Scenario: I had developed some transactional pages using Node.js, Express + Handlebars as view engine and MongoDB.
Now the issue is during module integration I got some of the pages which are built on Express + Jade as view engine.
Question: How to integrate pages built on Handlebars & some on Jade?
Add both engines and consolidate.js in your package.json
In yourapp.js
var engines = require('consolidate');
app.engine('jade', engines.jade);
app.engine('handlebars', engines.handlebars);
More info here
Express 4.0 and up solution (until it changes again)
NPM install the engines you need.
// some examples
npm install ejs
npm install pug
npm install handlebars
Set the engines to use in your app.js.
app.set('view engine', 'pug');
app.set('view engine', 'ejs');
Render your template, be sure to set the file extension.
// forces usage of the respective render engine by setting the file extension explicitly.
res.render( 'about.ejs', { title: 'About' } );
res.render( 'about.pug', { title: 'About' } );
Documentation for more usage examples.
https://expressjs.com/en/guide/using-template-engines.html
EDIT
After discussing with Amol M Kulkarni below comments, I came back and analyzed these again.
And turns out, it was fairly easier than I thought that I have to get back here and share my solution. Using consolidate, do it like this:
First do the require.
var engines = require('consolidate');
Then you can either remove or set engine and view engine...
I have tried removing all app.engine and app.set('view engine', '...'); and it did work. However, setting it other than 'html' will only work for one engine. So I just have set it to be sure.
I have set it like so:
app.engine('html', engines.swig); // take note, using 'html', not 'ejs' or 'pug'..
app.set('view engine', 'html'); // also 'html' here.
And then later on when you do the app.render, just make sure it has the file extension and it will just work nicely.
res.render( 'theme.ejs', {}); // will render with ejs
res.render( 'theme.pug', {}); // will render with pug
Just make sure have these engines (pug, ejs, etc..) are installed and consolidate will do the rest.
Old answer.
with relation to #Sergii answer, it did not work for me 100%.
There are times when an error is raised in the templates I'm using. But with a wrong error message that says failed to look up this template in this directory.
I tried #azariah solution but still did not work.
app.set('view engine', 'pug'); // does not make sense.
app.set('view engine', 'ejs'); // overriding the last .set()
what worked for me is using consolodate.js as mentioned.
Added app.set('view engine', 'pug'); as usual.
And then, in every time I will call render, I set the 'view engine'.
like so:
req.app.set('view engine', 'ejs');
res.render( 'theme', theme );
My worries with this is that when more simultaneous users will visit page with different engines, not sure if this will collide and be back with the error look up that I'm having.
But I guess that the render is so fast, that it should be done by the time another req.app.set is called.
I found this as more accurate and this is my personal practice.
We should have a default template engine set, so that all all views should process through at-least one template engine, it will save the file from being exposed to end user, in case you have html as default engine.
therefore, start with installing consolidate.js to the directory.
npm install consolidate
Later, we need to add the installed module to the application file.
var consoengines = require('consolidate');
Now setting the default view engine, (choosing pug because of its popularity)
app.set('view engine', 'pug');
After setting the default template engine. now I need to install the additional template engine, for my case, I mostly need EJS, because it allows almost all Javascript, which comes handy, to make anything in template. but you are good to choose any template engine.
All you would have to do is, install your template engine
npm install ejs
Now add this to consolidate instance and then put back to main template engines list.
app.engine('ejs', engines.ejs);
Now each time, you render a template, if you don't give extension in your router, this will call it with the default set template engine (here it is PUG), otherwise it will call the template engine according to the extension mentioned in the router call.

Resources