layout.ejs doesn't work on NodeJS app in Heroku - node.js

I have the usual nodejs express app...
var express = require('express');
var app = express.createServer(
express.bodyParser()
);
app.configure( function () {
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.use("/public", express.static(__dirname + '/public'));
});
app.get('/', function (req, res) {
res.render('index');
});
I have a index.ejs and layout.ejs in /views folder:
layout.ejs:
<!doctype html>
<html lang="en" manifest=""><head>
<title>jQuery Plugin Demo</title>
</head>
<body>
<div class="container container-fluid">
<%- body %>
</div>
</body>
</html>
index.ejs:
Hello world
index.ejs only renders the "Hello world" text without the surrounding layout.ejs wrapper. The ejs is working. It's able to find the correct .ejs template, but it's just ignoring the layout. I've also tried explictly adding layout file to app..
app.set('view options', { layout:'layout.ejs' });
All of this works fine locally, but not on Heroku. Here is my package.json:
{
"name": "in1-test",
"version": "0.0.1",
"author": "Iatek",
"dependencies": {
"express": ">=2.5.x",
"ejs": ">=0.7.x"
},
"engines": {
"node": "0.6.x"
}
}
Why no joy on the layout??? Thanks

I'm using express 3.x with ejs-locals and it works well. You just have to specify which layout to use:
login.ejs
<% layout('layout') -%>
<form>...</form>
layout.ejs
<body>
<h1>Hello</h1>
<%- body %>
</body>
https://npmjs.org/package/ejs-locals

When you deploy to Heroku it does an npm install for all your dependencies; because you have stated express >=2.5.x it will install the latest which is 3.0.0_betax. Express 3 does not have support for layouts in ejs (yet).
To fix remove the ">=" and specify the version of express that is in your local version.

As chovy said, ejs-locals can help you handle this if you want to upgrade to Express 3.x. I've got a github repo here that provides a bootstrapped project for Express 3.x, ejs, and twitter bootstrap:
https://github.com/cacois/node-express-twitter-bootstrap
Its a good starting point for a new app, or as an example of how to use ejs layouts with Express 3.x.

Related

Bundler similar to webpack that can compile node.js express and EJS files

After trying to set up webpack5 + express + ejs to no avail, I'm looking for some kind of "bundler" that will optimize my server code (files) so those will be automatically minified/uglified/obfuscated/bundled/converted to ES5/ etc. when there is any code change. It must support server side EJS partials (cause I have almost finished project that use EJS from scratch), has option to modify (for example bundle/not bundle) or leave intact specific files.
I know what bundlers there are on the market but I did not try them - I don't know which one is best suited for my needs (if any, besides webpack ofcourse - cause I'm to stupid to properly set it up, cause of How do I serve Webpack bundles with EJS templates? or
Webpack 5 + express + EJS templates ...).
Ejs render loaders seems to require that you pass in your inline variables in the config file, rather than in your Express routes, which doesn't make much sense to me.
webpack: 5.38.1
express": 4.17.1
ejs-render-loader: 1.0.0*
I have difficulties configuring Webpack 5 to properly use EJS template files. Setup looks like this:
INDEX.JS
var express = require('express');
var app = express();
var page1 = require('./routes/page1.js');
var page2 = require('./routes/page2.js');
app.set('view engine', 'ejs');
app.set('views', __dirname + '/ejs');
var server = https.createServer(options, app).listen(port, host, function()
{
console.log('server is running!');
}
app.use('/page1', page1);
app.use('/page2', page2);
// + bla bla bla
PAGE1.JS
router.get('/', function(req, res, next)
{
res.render('page1', {data : data}); // here we render ejs file
res.end();
}
router.post('/page2', function(req, res, next)
{
// + bla bla bla
res.render('page2', {data : data}); // here we render ejs file
res.end();
}
PAGE1.EJS
<!DOCTYPE html>
<html>
<head>
<title>PAGE1</title>
<%- include ('head.ejs'); %>
</head>
<body>
<%- include ('header.ejs'); %>
<%- include ('menu.ejs'); %>
<div class="errors">
<% if (typeof errors == "undefined") { %>
<% } else { %>
<%- errors %>
<% } %>
</div>
</body>
</html>
PAGE2.JS
router.get('/', function(req, res, next)
{
res.render('page1', {data : data}); // here we render ejs file
res.end();
}
PAGE2.EJS
<!DOCTYPE html>
<html>
<head>
<title>PAGE2</title>
<%- include ('head.ejs'); %>
</head>
<body>
<%- include ('container.ejs'); %>
</body>
</html>
WEBPACK.CONFIG.JS
module.exports = {
target: "node",
entry: {
main: './SRC/index.js'
},
externalsPresets: {node: true},
externals: [webpackNodeExternals()],
module: {
rules: [
{
test: /\.ejs$/,
use: {
loader: 'ejs-render-loader'
}
}
]
}
}
Can somebody who has working config, show his settings, so I can adjust mine? Cause now EJS files are not bundled - seems webpack has problem with included data inside those files. Thanks!

rendering in nodejs using express to html

I'm trying to get values from nodejs into HTML. I've seen lot of answers, but none of them is working.
here what I've done so far:
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<title>Page Title</title>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<link rel='stylesheet' type='text/css' media='screen' href='main.css'>
</head>
<body>
<div>
<a id="test" name="test"> <%=name%></a>
</div>
</body>
</html>
app.js
const express =require('express')
const app = express();
var os = require( 'os' );
var path = require('path')
const PORT = process.env.PORT ||2000;
app.engine('html', require('ejs').renderFile);
app.get('/',(req,res)=>{
res.sendFile(path.join(__dirname+'/index.html'))
})
app.get('/test', (req, res)=> {
var name = 454;
res.render( "/index.html", {name:name});
});
app.listen(2001)
I don't get what I'm doing wrong. but it doesn't work as expected.
any idea how may I solve this ?
thanks in advance !
First, create a folder views and put your index.ejs right there (though, I am not sure, the extension have to be .ejs).
Then set the engine with:
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
And change your routing to:
app.get('/', (req,res) => {
res.render('index', { name: 'Test' });
});
Edit: I have used the express application generator and also checked Using template engines with Express.
Edit: According to the extension .ejs:
One thing to note is that all files in which ejs syntax are used in
must be saved with a .ejs extension [...]
Taken from Using EJS as a Template Engine in your Express App, not from the official docs.

Webpack builded index.html served from express

I had configured express to use swig as template engine and /public as views directory and in static middleware this way:
app.engine('html', engines.swig);
app.set('view engine', 'html');
app.set('views', __dirname + '/public');
app.use(express.static('public'));
Then i configured express app to listen for requests this way:
app.use('/',(req,res)=>{
res.render('index', {
title: 'ciao'
});
})
In my template i have something like
<!DOCTYPE html>
<html lang="en">
<head>
<% for (var chunk in htmlWebpackPlugin.files.css) { %>
<link rel="preload" href="<%= htmlWebpackPlugin.files.css[chunk] %>" as="style">
<% } %>
<% for (var chunk in htmlWebpackPlugin.files.chunks) { %>
<link rel="preload" href="<%= htmlWebpackPlugin.files.chunks[chunk].entry %>" as="script">
<% } %>
</head>
<body>
<h1>{{ title }}</h1>
</body>
</html>
But "title" is not replaced by "ciao" and is rendered as is.
This should be a common scenario so probably i'm missing something.
Thx for your help!!!! ;)
SOLUTION:
!!! Be careful, this solution with expose your template to public access. (mysite.com/index.html will return your template) Btw this can be patched easily.
Remove this:
app.engine('html', engines.swig);
app.set('view engine', 'html');
app.set('views', __dirname + '/public');
Set index in static middleware:
app.use('',express.static('public',{
index: '_',
}));
Instead res.render use:
app.use('/',(req,res)=>{
return engines.swig(__dirname + '/public/index.html', {
title: "Ciao",
cache: true
}).then((html)=>{
return res.send(html);
}).catch((err) => {
throw err
})
})
You need to install npm i --save consolidate
Basically you use index.html as a template and swig function mix swig template + data and return html.
I will investigate further if this solution impact on performance but should not!!

Issue with partials using EJS in express

Just to preface: I've recently been transitioning my web development skills from PHP + HTML/CSS to Nodejs, but have been having trouble with templating.
I'm using Express, and after some research tried to use Pug.js, but found that too complicated for what I'm trying to achieve at the moment, so I moved to ejs as it seemed to be more simple.
What I'm trying to get is to be able to reuse HTML that I have already written for multiple pages on the site - which from what I've found is called 'partials'?
Now to the code I've written so far:
server.js:
var express = require('express');
app = express();
publicFolder = __dirname + '/public';
app.set('view engine', 'ejs');
app.use(express.static(publicFolder, {
extensions: ['html']
}));
app.listen(80, () => {
console.log('Server is online on port 80')
});
index.html: (/public/index.html)
<html>
<body>
<% include ../views/header.ejs %>
</body>
</html>
header.ejs: (/views/header.ejs)
<h1>Test header</h1>
I understand I may be on the completely wrong track, but any help would be greatly appreciated.
Regards
EDIT: I've double checked to make sure it's not a path issue
It might be easier for you to store all your view files as ejs in the same folder and user the path module to set your static files.
server.js:
var express = require('express');
var path = require('path')
app = express();
app.use(express.static(path.join(__dirname, 'public')));
app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'ejs')
app.listen(80, () => {
console.log('Server is online on port 80')
});
index.ejs
<html>
<body>
<% include header %>
</body>
</html>
Just a consideration. Hope it helps!

Why does my swig template not render in my MEAN web app?

I am trying to learn the MEAN stack along with Swig templates. I’m coding from scratch, as I tried a MEAN framework but it generated a lot of files and it was too much for me to begin with.
Currently my Swig template index.html does not render the HTML. This is the output I am getting:
{% include 'header.html' %}
<br>Welcome to my test website
where as I am expecting following
This is coming from Header
<br>Welcome to my test website
Why is it not rendering?
Following is my folder structure:
--config
-config.js
--node_modules
-* //modules installed via npm link
--public
-header.html
-index.html
-package.json
-routes.js
-server.js
Below is the content of each file
config.js
var port = process.env.PORT || 8080;
module.exports = {
dburl: 'mongodb://localhost/test',
port: port,
templateEngine: 'swig'
}
header.html
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<p> This is coming from Header</p>
index.html
{% include 'header.html' %}
<p>Welcome to my test website</p>
</body>
package.json
{
"name": "test",
"version": "0.0.1",
"author": "Rukmaj Chandavar",
"dependencies": {
"express": "*",
"mongoose": "*",
"angular": "*",
"swig": "*",
"consolidate": "*"
}
}
routes.js
module.exports = function(app){
app.get('*',function(req, res){
res.send('index.html');
});
}
server.js
var express = require("express");
var app = express();
var mongoose = require("mongoose");
var config = require('./config/config');
var swig = require('swig');
var cons = require('consolidate');
mongoose.connect(config.dburl);
app.use(express.static(__dirname + '/public'));
app.set('views', __dirname + '/public');
app.engine('html', cons.swig);
app.set('view engine', 'html');
require('./routes') (app);
app.listen(config.port);
console.log('MeriDawat running on port ' + config.port)
Following are the version numbers of installed node modules
angular#1.2.18
consolidate#0.10.0
express#4.4.3
mongoose#3.8.12
passport#0.2.0
swig#1.3.2
I would appreciate any help in troubleshooting this to help me move forward. Thanks in advance.
I think this is the offending line, in routes.js:
res.send('index.html');
res.send() just sends the contents of the file back in the HTTP response.
To render a template and send the rendered results back, you want res.render() instead:
res.render('index.html')

Resources