Webpack builded index.html served from express - node.js

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!!

Related

Can Not Get file EJS Under Views Directory

In this problem, I tried to render ejs after update the data from UI. Here is my code,
const express = require("express");
const bodyParse = require("body-parser");
const date = require(__dirname + "/date.js");
const app = express();
const port = 3000;
app.set("view engine", "ejs");
app.use(bodyParse.urlencoded({ extends: true }));
var path = require('path');
let items = ["Buy Food", "Cook Food", "Eat Food"];
let itemWorks = [];
app.get("/", function (req, res) {
let day = date.getDay();
res.render(path.join(__dirname + "/views/list.ejs"), { listTitle: day, listItem: items });
items.pop;
app.post("/", function (req, res) {
let item = req.body.foodservice;
if(res.body.list === "work"){
itemWorks.push(item);
res.redirect("/work");
}else{
items.push(item);
res.redirect("/");
}
items.push(item);
res.redirect("/");
});
});
Here is my list.ejs:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>To Do List</title>
</head>
<body>
<h1><%=listTitle%></h1>
<ul>
<% for(var i = 0; i < listItem.length; i++){ %>
<li><%=listItem[i]%></li>
<% } %>
</ul>
<form action="/" method="post">
<input type="text" name="foodservice" placeholder="New Item" autocomplete="off"/><br /><br />
<button type="submit" name="button" value=<%=listTitle%>>+</button>
</form>
</body>
</html>
Here is my project's structure:
BRANDNEW_PROJECT views /list.ejs app.js data.js
However, when I have executed it=> errors have been displayed as bellow
TypeError: Cannot read properties of undefined (reading 'list')
at E:\WEB DEVELOPMENT\NodeJS\BrandNew_Project\app.js:25:15
I have tried to debug by putting log to check whether it already points to file that I want or not and the path is correct and also to tried set up file path like this:
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
However, the issues have not been resolved.
What can be the reason here? Thanks a lot for your help.
Live working URL : https://stackblitz.com/edit/node-dmtquz?file=index.js
Views folder is default in EJS.
Concept:
when render html pages you must take care path will start for other inside views as root
when render html pages you must take care path will start for other inside views as root.
Not render views/layouts/index use layout/index because,EJS make views (or your directory) as active directory for it.
if you want to change the directory use app.set("views", path.join(path.resolve(), < dir name >)).
Structure:
views
-------- layouts
---------------- index.ejs (this file i rendered as root)
-------- partials
-----------------footer.ejs, header.ejs etc
Hope this will clear up your problem
var express = require("express");
var app = express();
// set the view engine to ejs
// app.set("views", __dirname + "/views");
app.set("view engine", "ejs");
// use res.render to load up an ejs view file
// index page
app.get("/", function (req, res) {
res.render("layouts/index" , {
displayTitle: "items viewer",
item: ["item1", "item2"]
});
});
// about page
app.get("/about", function (req, res) {
res.render("layouts/about");
});
app.listen(8080);
console.log("Server is listening on port 8080");
<!-- root dir, views/layout/list.ejs -->
<!DOCTYPE html>
<html lang="en">
<body>
<%= displayTitle%>
<hr />
<% for (let i of items) { %>
<br />
<%= i %> <% } %>
</body>
</html>
I think you need to use path.resolve instead of path.join like this:
res.render(path.resolve(__dirname + "/views/list.ejs"), { listTitle: day, listItem: items });
You might also need to update your import of the date object at the top to use path.resolve like this:
const date = require(path.resolve(__dirname + "/date.js"));
In my code I use path.resolve anytime I use __dirname

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.

How do I render a page in Node.JS with hogan-express

How do I render a page in node (using a router) which just passes a value to the template engine for me to use?
So for instance (this is the real code):
var apiRouter = express.Router();
apiRouter.get('/myPosts', function(req, res){
userPostsModel.findOne({'profileID':req.session.facebookProfileId}, function(err, userPosts) {
if(userPosts) {
res.json({
posts : userPosts.posts
});
} else {
console.log('You do not have any posts');
}
})
})
And the template engine part (html file):
<!doctype html>
<head>
<meta charset="UTF-8">
<title>My Posts</title>
</head>
<body>
<p>Post 1</p>
<p>Post 2</p>
</body>
</html>
I am expecting this to render the page but instead, I am getting this (on the webpage):
{"posts":["12345667"]}
For my template engine, I am using 'hogan-express', as below:
app.engine('html', require('hogan-express'));
app.set('view engine', 'html');
I know the res.json may be wrong here but I am not getting anywhere with this. The documentation for node and the routers is all over the place!
As #Molda has answered in the comments, below, it should be like this:
res.render('template-name', { posts:userPosts.posts});
Tried it and worked for me.

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

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.

Resources