Upgrading Express 2.0 to 3.0 project - node.js

I am somewhat new to node programming and trying to follow some tutorials. They're almost all written for 2.5.x. I've read the migration page for Express but there are no clear working examples for a newbie. My question is addressing the following areas:
req.flash()
layouts and partials
dynamicHelpers
for 'old way' vs. 'new way' examples and not just snippets or additional modules to make the older version code still work as I'd like to work with the new style of working with Express. Thanks in advance.

As you found the old-way examples already, here are the 'new' ways:
'new' req.flash:
// insert in app.js as middleware, after express.static
app.use(function(req, res, next) {
var msgs = req.session.messages || [];
res.locals({
messages: msgs,
hasMessages: !! msgs.length
});
req.session.messages = [];
next();
});
// save a message
res.message('error', 'message');
// output
<% if (hasMessages) { %>
<ul id="messages">
<% messages.forEach(function(msg){ %>
<li class="<%= msg.type %>"><%= msg.msg %></li>
<% }) %>
</ul>
<% } %>
'new partials':
// install
npm install express-partials
// app.js
var partials = require('express-partials');
app.use(partials());
// usage
<%- body %>
'new' dynamicHelpers:
// middleware
app.use(function(req, res, next) {
res.locals.user = req.user;
next();
});
// usage
<%= user %>

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!

Why is mypartial.ejs not showing?

I am trying to learn node.js with the help the book "Get programming with node.js" by Jonathan Wrexler. In chapter 10 the use of partials is explained very briefly and I am not getting it to work.
I made a nav.ejs in the partials-folder that looks like this:
<ul>
<li>One</li>
<li>Two</li>
<li>Three</li>
</ul>
The layout.ejs-example in the book looks like this:
<body>
<header>Header</header>
<nav>
<% include partials/nav %>
</nav>
<%- body %>
<footer>Footer</footer>
</body>
But this gives me a syntax-error:
SyntaxError: Unexpected identifier in C:\node-projects\wandelverhalen\views\layout.ejs while compiling ejs
With the help of stackoverflow I changed the include template to:
<% include ("partials/nav"); %>
This solved the error, but it does not show the nav when I run it. And the page source shows a <nav>-tag that is empty.
I would appreciate any help.
For the sake of completeness, this is my index.js:
"use strict";
const port = 3000;
const express = require("express");
const app = express();
const homeController = require("./controllers/homeController");
const layouts = require("express-ejs-layouts");
app
.set("view engine", "ejs")
.use(
express.urlencoded({
extended: false
})
)
.use(express.json())
.use(layouts)
.use((req, res, next) => {
console.log(`Request made to ${req.url}`);
next();
})
.get("/", homeController.sendReqParam)
.get("/:myname", homeController.sendReqParam)
.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
You want to use <%- include ("partials/nav"); %> to render your partial. The <% is just for scripting and control-flow and produces no output, thus you are not seeing anything added to the page. Adding a - after <% will cause it to output the unescaped value of include ("partials/nav").

Can monk return a json of data directly instead of a promise?

I learning express recently,and want to make a tiny blog with express+mongodb+monk+ejs,below is the code I writed:
model are some js exports function to handle data:
var db = require('../model/public').db;
var contentCollection = db.get('contentcollection');
exports.getContent = function (fn) {
contentCollection.find({},{},function(err,data){
fn(data);
});
};
controller is deal with route:
var express = require('express');
var router = express.Router();
var $data = require('../model/core').$content;
var $ = require('../controller/util');
router.get('/', function(req, res, next){
$data.getContent(function(data){
res.render('content', $.extend(req.staticRes, {
article: data
}));
});
});
module.exports = router;
(in this code,"$" is a util function include a method to extend double object just like jQuery.extend do.)
view is page that be controller render:
<% include ./public/head %>
<%include ./public/header%>
<%for(var i = 0;i<article.length;i++){%>
<div class="article">
<div class="title">
<%= article[i]["title"]%>
</div>
<div class="content">
<%= article[i]["content"]%>
</div>
</div>
<%}%>
<script src="/js/content.js"></script>
<% include ./public/footer %>
what confused me is the part of model,i only can access data in a method named
xxx.find({},{},function(data){
//some handle with data
})
that result in that i only use the getContnet function like that:
router.get('/', function(req, res, next){
$data.getContent(function(data){
res.render('content', $.extend(req.staticRes, {
article: data
}));
});
});
but i only want to handle the data query from database like below's form,so I can use some function that query data form different collection:
router.get('/', function(req, res, next){
res.render('content', {
article: $data.getContent('some arguments here to query from content collection'),
user: $data.getUser('some arguments here to query from user collection')
});
});
my vocabulary is poor,thanks to google translate ;-)
anyone help?
add:
var s = contentCollection.find({},{},function(err,data){
fn(data);
});
console.log(s);
is a Promise when i console it.
OK,I find the solution by myself.
After research my colleague'code whom project based on Koa,I find the different between my code with him:it's not the fault of monk which make me confuse that i mentioned above,it's the blame of Express!
below is Koa's code style for route to render page:
yield this.render('index', {
topics: $Topic.getTopicsByTab(tab, p),
items: $Scrape.getAllTopics(tab,p)
});
and below is express's(if I'm not wrong):
router.get('/',function(){
$data.getUserInfo(function(user){
$data.getContent(function(content){
res.render('index',{
userinfo:user,
content:content
})
})
})
})
see the differenent?
Express is callback,callback,callback!
and my solution is got a dependenies named "co-express",it's said that koa also based on it,below is the code after I use co-express:
router.get('/', wrap(function *(req,res,next){
res.render('content',$.extend(req.staticRes,{
content: yield $data.getContent(),
userinfo: yield $data.getUserInfo()
}))
}));
it's looks great.
thanks myself :-)

How do I inject a variable into an EJS template with Node.js + Express3?

I'd like to be able to use Underscore.js from within my EJS templates, like this:
<% _.each(articles, function(article){ %>
<section>
<h2><%= title %></h2>
<%= body %>
</section>
<hr/>
<% }) %>
I could inject it for every single route like so...
var _ = require('underscore');
exports.index = function(req, res){
res.render('index', { _: _, articles: app.allArticles() });
};
But that's tedious and prone to human error. Is there a general solution for this, to inject it for all views, all of the time?
You can do this whith app.locals.
var _ = require('underscore');
var express = require('express');
var app = express();
app.locals._ = _;
// some code
app.listen(3000);

Render a non-specific amount of results with express/ejs

I'm trying to create a basic blog platform to help me get my feet wet with node. I'm using Express as a framework and ejs as my rendering engine. On my homepage, I'd like to display the last ten blogs. So far, I have:
"use strict";
var mongo = require("mongodb")
, server = new mongo.Server("localhost", mongo.Connection.DEFAULT_PORT, {auto_reconnect: true, safe:true})
, mdb = new mongo.Db("blog", server)
, querystring = require("querystring")
, express = require('express')
, app = express();
app.configure(function() {
app.set('view engine', 'ejs');
});
module.exports = {
home: function home(req, res) {
var blogs;
//Load blogs from db
mdb.open(function(err, db) {
db.collection("blogs", function(err, collection) {
var stream = collection.find({}, {"limit": 10, "sort": {"created": -1}}).stream();
stream.on("data", function(item) {
app.render('blogItem', {title: item.title, content: item.content}, function(err, html) {
if(err) { console.error(err); return; }
blogs += html;
});
});
//Render the finished page
stream.on("end", function() {
res.render('home', {title: "AwesomeBlog", content: blogs});
db.close();
});
});
});
}
};
ejs files:
home.ejs
<!DOCTYPE html>
<head>
<title><%= title %></title>
</head>
<body>
<h1><%= title %>!</h1>
<%= content %>
Admin section
</body>
blogItem.ejs
<h4><%= title %></h4>
<p><%= content %></p>
While this technically "works", the rendered HTML per-blog is interpreted as plain text, resulting in
AwesomeBlog!
<h4>Hi</h4> <p>test 123</p> <h4>Awesome title</h4> <p>Awesome text</p> <h4>FIRST</h4> <p>POST!</p> Admin section
How can I fix this in this case?
What's the best practice for what I'm trying to do?
That's a safety feature built-into EJS. It stops your users from embedding html that contains javascript exploits (XSS) in your pages. (They can still submit unsafe strings in form requests, etc, but your template escapes it to prevent browser exploits.)
To turn it off (for HTML content you can trust):
Escapes html by default with <%= code %>
Unescaped buffering with <%- code %>
Simply switch the tags in your template like this:
<h4><%= title %></h4>
<p><%- content %></p>

Resources