Different ways to render static assets using express middleware - node.js

Which of the following method is preferable to render the static assets. Consider that only helpPage.html is the only file exist in the public directory
Method 1:
app.use(express.static(__dirname + '/public'))
Method2:
app.use((req, res) => {
res.render(__dirname + '/public/helpPage.html');
})

If helpPage.html is the only static file you will deliver, I propose a third option:
app.get('/helpPage.html', (req, res)=>{
res.sendFile( __dirname + '/public/helpPage.html');
});
I don't see the purpose of using app.use here.
Additionally you may want to use path.join:
const path = require('path');
app.get('/helpPage.html', (req, res)=>{
res.sendFile( path.join(__dirname, '/public/helpPage.html') );
});
This ensures that the paths are properly joined regardless of what machine you are running on.

Related

EJS file not loading after using express.static

I have some plain HTML/CSS files in my frontend folder and the ejs files in the views folder and every other ejs file loads perfectly but the index.ejs file
I don't know what I am doing wrong here
This is my server.js: (this is a basic version of my server file)
const app = express();
app.set('views', __dirname + '/views');
app.set("view engine", "ejs");
app.use(express.static(__dirname + "/frontend"));
app.get("/", (req, res) => {
res.render("index");
});
//The below file loads perfectly. (requireAuth is a authentication middleware)
app.get("/create", requireAuth, (req, res) => {
res.render("create");
});
Also both the files index.ejs and create.ejs are very similar
If anyone requires any extra details then they can comment down.
You've defined static middleware for / (root path) and the index page is also defined for root path, but because static middleware is defined early, express tries to find and return static file instead of rendering index page.
You have two variants here:
Define static middleware for some path different than root:
app.use("/public", express.static(__dirname + "/frontend"));
Don't use root path for index page: app.get("/index", (req, res)...

Cannot Get/ when express app is deployed on heroku

my dir structure
/src
--/public
--/server.ts
--package.json
--package-lock.json
above is my director structure
app.use(express.static(__dirname + "/public/"));
// app.use(express.static("/public/"));
const path = require("path");
app.get("/", (req, res, next) => {
// res.sendFile(path.join(__dirname, + "public", 'index.html'));
res.sendFile(__dirname , "index.html");
//res.send('Testing one two');
});
const port = process.env.PORT || '5005';
app.listen(port, () => console.log("Server running on port 5005"));
when I run the above code, it works well on my local machine but won't work when it is deployed to Heroku,
I tried just passing a string like this and it worked, but when I want to render a static file like the HTML file it wont work on heroku, any help? i think the problem is my directory structure
app.get("/", (req, res, next) => {
res.send('Testing one two');
});
If I recall correctly, express.static middleware is separate from res.sendFile. In other words, even if you set express.static to public, it will not do anything to res.sendFile, as it takes the first parameter as a path.
In my humble opinion, it would be better if you were to use an absolute path, like the following snippet below.
const path = require('path');
/** Code here... **/
app.get("/", (req, res, next) => {
res.sendFile(path.join(__dirname, 'public', 'index.html'));
});
Explanations:
path.join is an utility to join path segments into one path. It is cross-platform compatible.
__dirname will get the current directory that the script is running from.
Further reading: Express methods.
You just need to give the address of the index.html file in the path for the code mentioned below and paste this code at the end of the inside of the express file and everything will work perfectly fine and you are good to go.
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, './public/index.html'));
});

Express.js "path must be absolute or specify root to res.sendFile" error

NOTE : This is NOT a duplicate question, I've already tried other answers to similar questions.
I'm trying to render html files (Angular) but I'm having an issue.
This works.
app.get('/randomlink', function(req, res) {
res.sendFile( __dirname + "/views/" + "test2.html" );
});
But I don't want to copy and paste dirname thingy over and over, so I tried this in order to not to be repetitive with urls:
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'views')));
app.get('/randomlink', function(req, res) {
res.sendFile('test2.html'); // test2.html exists in the views folder
});
Here's the error.
My express version is 4.13
path must be absolute or specify root to res.sendFile
If you look into the express code for sendFile, then it checks for this condition:
if (!opts.root && !isAbsolute(path)) {
throw new TypeError('path must be absolute or specify root to res.sendFile');
}
So You must need to pass Absolute path or relative path with providing root key.
res.sendFile('test2.html', { root: '/home/xyz/code/'});
And if you want to use relative path and then you can make use path.resolve to make it absolute path.
var path = require('path');
res.sendFile(path.resolve('test2.html'));
You can't go against official documentation of res.sendFile()
Unless the root option is set in the options object, path must be an absolute path to the file.
But I understand that you don't want to copy smth like __dirname every time, and so for your purpose I think you can define your own middleware:
function sendViewMiddleware(req, res, next) {
res.sendView = function(view) {
return res.sendFile(__dirname + "/views/" + view);
}
next();
}
After that you can easily use this middleware like this
app.use(sendViewMiddleware);
app.get('/randomlink', function(req, res) {
res.sendView('test2.html');
});
Easiest way is to specify the root:
res.sendFile('index.html', { root: __dirname });
I was facing the same problem then i solved my issue as follows.
const path = require("path")
app.get('/', (req, res)=>{
res.sendFile(path.resolve("index.html"))
}
Good Luck
the issue happened to me when I was providing subpaths. I set static path and had this route:
const public = path.join(__dirname, "..", "live", "public");
app.get("*", (_, res) => {
res.sendFile("index.html");
});
Visiting "/" path worked but "/anyOtherPath" did not work. So I change the route:
app.get("*", (_, res) => {
res.sendFile(public + "/index.html");
});

Serve Static Files on a Dynamic Route using Express

I want to serve static files as is commonly done with express.static(static_path) but on a dynamic
route as is commonly done with
app.get('/my/dynamic/:route', function(req, res){
// serve stuff here
});
A solution is hinted at in this comment by one of the developers but it isn't immediately clear to me what he means.
Okay. I found an example in the source code for Express' response object. This is a slightly modified version of that example.
app.get('/user/:uid/files/*', function(req, res){
var uid = req.params.uid,
path = req.params[0] ? req.params[0] : 'index.html';
res.sendFile(path, {root: './public'});
});
It uses the res.sendFile method.
NOTE: security changes to sendFile require the use of the root option.
I use below code to serve the same static files requested by different urls:
server.use(express.static(__dirname + '/client/www'));
server.use('/en', express.static(__dirname + '/client/www'));
server.use('/zh', express.static(__dirname + '/client/www'));
Although this is not your case, it may help others who got here.
You can use res.sendfile or you could still utilize express.static:
const path = require('path');
const express = require('express');
const app = express();
// Dynamic path, but only match asset at specific segment.
app.use('/website/:foo/:bar/:asset', (req, res, next) => {
req.url = req.params.asset; // <-- programmatically update url yourself
express.static(__dirname + '/static')(req, res, next);
});
// Or just the asset.
app.use('/website/*', (req, res, next) => {
req.url = path.basename(req.originalUrl);
express.static(__dirname + '/static')(req, res, next);
});
This should work:
app.use('/my/dynamic/:route', express.static('/static'));
app.get('/my/dynamic/:route', function(req, res){
// serve stuff here
});
Documentation states that dynamic routes with app.use() works.
See https://expressjs.com/en/guide/routing.html

Node/Express.js - Overriding where to look for the 'Views' folder for each request

In my Node/Express.js project I can set the views folder globally like so:
app.configure(function() {
app.set('views', __dirname + '/views');
.... snip ....
});
...and all my view templates go into the views folder.
Is it possible to override where Express looks for views on a request by request basis? For instance, something like the following:
app.get('/', function(req, res) {
res.render('index', { viewFolder: 'otherViews' });
});
The reason I ask is I'm trying to replicate Microsoft ASP.NET MVC's Areas functionality where each Area gets it's own views folder.
The 'views' setting is the root directory, so you should be able to specify a sub-folder in the hierarchy:
app.get('/', function(req, res) {
res.render('areaName/viewName');
});
It means your 'areas' need to be sub-folders, but it allows you to accomplish the separation you are looking for.
As a more modular solution, I did something like this in sails.js.
Just over-ride the render function for the given request in your middleware. :)
var curRender = res.render;
res.render = function(path, locals, func) {
var args = [res.locals.explicitPath + '/' + path, locals, func];
curRender.apply(this, args);
};
Full path works too
app.get('/', function(req, res) {
res.render(path.join(__dirname, 'view.jade'));
});

Resources