Reputation: 197
I've created a webpage to use it locally. I have a ton of routes like the ones shown below -- 31 .ejs
files and 3 .html
files. (They are all in the same "views" folder).
//app.js - using node and express
app.get('/page1', function(req, res){
res.render('page1');
});
app.get('/page2', function(req, res){
res.sendFile('views/page2.html', { root: __dirname });
});
I use an app.get
for each and every one of these files. I've had a feeling it wasn't DRY code, and so now I'm trying to figure out a more elegant and optimal way to achieve the same result.
I know that many res.sendFile();
could be replaced with a single express.static()
middleware statement. I usually use express.static()
on a "public" folder which I use to save all my css files -- like this app.use(express.static(path.join(__dirname, 'public')));
. But I still don't see how I could use this to simplify all my res.sendFile()
.
As for the many res.render();
routes, I know that if I don't pass any customized data I could probably replace them with a single middleware that handles either a whole directory of template files (and their corresponding routes) or a list of files. I just don't know how I would do that.
Any help is very much appreciated, thanks!!
- richie
- node_modules
- public
- css files, images, etc
- views
- partials
- all partial files
- programmingPublic
- all ejs files from a same topic
- other files (html & other ejs)
- appjs
- packagejson
- package-lockjson
const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const app = express();
// Body Parser Middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
// engine
app.set("view engine", "ejs");
// Set static path
app.use(express.static(path.join(__dirname, 'public')));
const fs = require('fs');
function renderStatic(dir) {
return function(req, res, next) {
let target = path.join(dir, req.path);
fs.access(target, fs.constants.R_OK, function(err) {
if (err) {
// file not found, just move on
next();
} else {
res.render(target);
}
});
}
}
app.use(renderStatic(path.join(__dirname, "views/programmingPublic")));
Below is the format of my side-menu: (all these files are inside "programmingPublic" folder)
<a href="/programming" class="title">Programming</a>
<li><a href="/c">C</a></li>
<li><a href="/cpp">C++</a></li>
<li><a href="/python">Python</a></li>
<li><a href="/javascript">JavaScript</a></li>
<li><a href="/php">PHP</a></li>
Upvotes: 0
Views: 283
Reputation: 707298
If you have a bunch of pages that need to call res.render()
, but aren't passing custom options to each render, then you could isolate all those templates in their own directory and then use some middleware like this:
const path = require('path');
const fs = require('fs');
function renderStatic(dir, options) {
const regex = /^\.|\.\.|\/\.|\\\./;
options = options || {};
return function(req, res, next) {
let target = path.join(dir, req.path);
if (options.ext && !path.extname(target)) {
target = target + options.ext;
}
// don't allow leading dot or double dot anywhere in the path
if (regex.test(target)) {
next();
return;
}
fs.access(target, fs.constants.R_OK, function(err) {
if (err) {
// file not found, just move on
next();
} else {
res.render(target);
}
});
}
}
app.use(renderStatic(path.join(__dirname, "renderPublic"), {ext: ".ejs"}));
Note, you must isolate these template files in their own directory so that other files are not found there.
For safety completeness, this code also needs to filter out .
and ..
items in the path like express.static()
does to prevent an attacker from going up your directory hierarchy to get access to other files than those in the render static directory.
Then, for the routes you are using res.sendFile()
and no other logic, just isolate those HTML files in their own directory and point express.static()
at that directory. Then, the express.static()
middleware will find a matching HTML file in that directory and do res.sendFile()
for you automatically, exactly the same as it does for your CSS files.
Upvotes: 1