node.js/express: Sending static files if they exist - node.js

I want to serve html files from a folder if they exist, otherwise fallback to the dynamic app.
currently I use something like:
var express = require('express');
var app = express()
, server = require('http').createServer(app)
, io = require('socket.io').listen(server);
server.listen(4444);
app.use("/", express.static(__dirname + '/../WebContent/index.html'));
app.use("/styles", express.static(__dirname + '/../WebContent/styles'));
app.use("/script", express.static(__dirname + '/../WebContent/script'));
//here I would like to define a rule like this:
//app.use("*.html", express.static(__dirname + '/../WebContent/*html'));
How can I achieve this?
Some tutorials use a module called connect. If it's the most elegant solution to my problem, how can I integrate connect to my current code?

You don't have to do anything special.
i'm assuming the WebContent folder is in the root.
And if all your static content are in the same base folder like you've shown, you don't have to specify it multiple times.
app.use(express.static(__dirname + '/WebContent'));
if you have a file called file.html in the WebContent folder you can now access it via the url i.e. localhost:4444/file.html

You are using a lot of boilerplate. It is easier using routes. Here is an example:
var routes = require('./routes');
app.configure(function () {
...
app.use(express['static'](path.join(__dirname, '/../WebContent')));
app.use(app.router);
});
// Routes
app.get('/', routes.index);
routes/index.js:
exports.index = function (req, res) {
res.render('index');
};
Rendering your webapp root outside your project root is very strange. Feels like bad practice. Is this necessary?

Related

bodyParser middleware not working when adding static route

I'm a newbie on express, and when I was creating a simple server demo I detected that POST requests were not sent. After doing some experiments I discovered that it was the express.static middleware, that somehow was interfering. I supposed it was a common error, but didn't manage to find a clue. My code is the following:
//jshint esversion:6
import express from "express";
import path from "path";
import { fileURLToPath } from "url";
import bodyParser from "body-parser";
import https from "https";
/* jshint ignore:start */
const __filename = fileURLToPath(import.meta.url);
/* jshint ignore:end */
const __dirname = path.dirname(__filename);
const app = express();
const port = 8080;
app.use(express.static(__dirname + "/public"));
app.use("/", bodyParser.urlencoded({ extended: true }));
app.get("/", (req, res) => {
res.sendFile(__dirname + "/index.html");
});
app.post("/", function (req, res) {
let name = req.body.name;
let email = req.body.email;
let message = req.body.message;
res.send("POST request to the homepage");
console.log(req.body);
});
app.listen(port, () => console.log(`Listening on port ${port}!`));
I'll gladly appreciate any answer or commet :)
EDIT: Apparently this error doesn't occur on Firefox, but does on Chrome and Edge
Based on your symptoms of the POST not even being sent from the client when you added the express.static(), I would guess that when you go to the / route in your browser, that express.static() was picking up an index.html from your public directory rather than the index.html that you wanted from here:
app.get("/", (req, res) => {
res.sendFile(__dirname + "/index.html");
});
You can fix that two ways. Either move this app.get("/", ...) route before the express.static() route or tell the express.static route to NOT serve index.html like this:
// set up static file handling, but don't serve index.html for the / request
app.use(express.static(__dirname + "/public", {index: false}));
Ok figured out what was really blocking this.
When adding express.static() it loaded the JS for the front-end, which has the following line:
$(".sendMessageBtn").attr("disabled", "true");
which disables the submit button. Turns out disabling it also means it can't send anything BUT only on chromium browsers. This does not happen on Firefox.
To disable it without causing this mess, you can replace with:
$(".sendMessageBtn").css("pointer-events", "none");
Instead of disabling it through HTML, it uses CSS
So the way express static file serving works is that you put a /path which you want to serve on, and the term express.static(/path/to/static/folder) which will be published to the api.
Otherwise your entire application will be static, due to the fact that everything start with /.
See the docs for more info.
In your case:
app.use("/your-static-endpoint", express.static(__dirname + "/public"));
One more thing about your code. Stuff like static serving, error handling, body parsing are called middlewares, so if you want to apply them through the application, you shouldn't specify a path, because it might interfere with how express handles routing.

Run HTML file on HTTPS local server [duplicate]

I want to serve index.html and /media subdirectory as static files. The index file should be served both at /index.html and / URLs.
I have
web_server.use("/media", express.static(__dirname + '/media'));
web_server.use("/", express.static(__dirname));
but the second line apparently serves the entire __dirname, including all files in it (not just index.html and media), which I don't want.
I also tried
web_server.use("/", express.static(__dirname + '/index.html'));
but accessing the base URL / then leads to a request to web_server/index.html/index.html (double index.html component), which of course fails.
Any ideas?
By the way, I could find absolutely no documentation in Express on this topic (static() + its params)... frustrating. A doc link is also welcome.
If you have this setup
/app
/public/index.html
/media
Then this should get what you wanted
var express = require('express');
//var server = express.createServer();
// express.createServer() is deprecated.
var server = express(); // better instead
server.configure(function(){
server.use('/media', express.static(__dirname + '/media'));
server.use(express.static(__dirname + '/public'));
});
server.listen(3000);
The trick is leaving this line as last fallback
server.use(express.static(__dirname + '/public'));
As for documentation, since Express uses connect middleware, I found it easier to just look at the connect source code directly.
For example this line shows that index.html is supported
https://github.com/senchalabs/connect/blob/2.3.3/lib/middleware/static.js#L140
In the newest version of express the "createServer" is deprecated. This example works for me:
var express = require('express');
var app = express();
var path = require('path');
//app.use(express.static(__dirname)); // Current directory is root
app.use(express.static(path.join(__dirname, 'public'))); // "public" off of current is root
app.listen(80);
console.log('Listening on port 80');
express.static() expects the first parameter to be a path of a directory, not a filename. I would suggest creating another subdirectory to contain your index.html and use that.
Serving static files in Express documentation, or more detailed serve-static documentation, including the default behavior of serving index.html:
By default this module will send “index.html” files in response to a request on a directory. To disable this set false or to supply a new index pass a string or an array in preferred order.
res.sendFile & express.static both will work for this
var express = require('express');
var app = express();
var path = require('path');
var public = path.join(__dirname, 'public');
// viewed at http://localhost:8080
app.get('/', function(req, res) {
res.sendFile(path.join(public, 'index.html'));
});
app.use('/', express.static(public));
app.listen(8080);
Where public is the folder in which the client side code is
As suggested by #ATOzTOA and clarified by #Vozzie, path.join takes the paths to join as arguments, the + passes a single argument to path.
const path = require('path');
const express = require('express');
const app = new express();
app.use(express.static('/media'));
app.get('/', (req, res) => {
res.sendFile(path.resolve(__dirname, 'media/page/', 'index.html'));
});
app.listen(4000, () => {
console.log('App listening on port 4000')
})
If you have a complicated folder structure, such as
- application
- assets
- images
- profile.jpg
- web
- server
- index.js
If you want to serve assets/images from index.js
app.use('/images', express.static(path.join(__dirname, '..', 'assets', 'images')))
To view from your browser
http://localhost:4000/images/profile.jpg
If you need more clarification comment, I'll elaborate.
use below inside your app.js
app.use(express.static('folderName'));
(folderName is folder which has files) - remember these assets are accessed direct through server path (i.e. http://localhost:3000/abc.png (where as abc.png is inside folderName folder)
npm install serve-index
var express = require('express')
var serveIndex = require('serve-index')
var path = require('path')
var serveStatic = require('serve-static')
var app = express()
var port = process.env.PORT || 3000;
/**for files */
app.use(serveStatic(path.join(__dirname, 'public')));
/**for directory */
app.use('/', express.static('public'), serveIndex('public', {'icons': true}))
// Listen
app.listen(port, function () {
console.log('listening on port:',+ port );
})
I would add something that is on the express docs, and it's sometimes misread in tutorials or others.
app.use(mountpoint, middleware)
mountpoint is a virtual path, it is not in the filesystem (even if it actually exists). The mountpoint for the middleware is the app.js folder.
Now
app.use('/static', express.static('public')`
will send files with path /static/hell/meow/a.js to /public/hell/meow/a.js
This is the error in my case when I provide links to HTML files.
before:
<link rel="stylesheet" href="/public/style.css">
After:
<link rel="stylesheet" href="/style.css">
I just removed the static directory path from the link and the error is gone. This solves my error one thing more don't forget to put this line where you are creating the server.
var path = require('path');
app.use(serveStatic(path.join(__dirname, 'public')));
You can achieve this by just passing the second parameter express.static() method to specify index files in the folder
const express = require('express');
const app = new express();
app.use(express.static('/media'), { index: 'whatever.html' })

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)...

how to access images on disk on localhost and access via url on website [duplicate]

I want to serve index.html and /media subdirectory as static files. The index file should be served both at /index.html and / URLs.
I have
web_server.use("/media", express.static(__dirname + '/media'));
web_server.use("/", express.static(__dirname));
but the second line apparently serves the entire __dirname, including all files in it (not just index.html and media), which I don't want.
I also tried
web_server.use("/", express.static(__dirname + '/index.html'));
but accessing the base URL / then leads to a request to web_server/index.html/index.html (double index.html component), which of course fails.
Any ideas?
By the way, I could find absolutely no documentation in Express on this topic (static() + its params)... frustrating. A doc link is also welcome.
If you have this setup
/app
/public/index.html
/media
Then this should get what you wanted
var express = require('express');
//var server = express.createServer();
// express.createServer() is deprecated.
var server = express(); // better instead
server.configure(function(){
server.use('/media', express.static(__dirname + '/media'));
server.use(express.static(__dirname + '/public'));
});
server.listen(3000);
The trick is leaving this line as last fallback
server.use(express.static(__dirname + '/public'));
As for documentation, since Express uses connect middleware, I found it easier to just look at the connect source code directly.
For example this line shows that index.html is supported
https://github.com/senchalabs/connect/blob/2.3.3/lib/middleware/static.js#L140
In the newest version of express the "createServer" is deprecated. This example works for me:
var express = require('express');
var app = express();
var path = require('path');
//app.use(express.static(__dirname)); // Current directory is root
app.use(express.static(path.join(__dirname, 'public'))); // "public" off of current is root
app.listen(80);
console.log('Listening on port 80');
express.static() expects the first parameter to be a path of a directory, not a filename. I would suggest creating another subdirectory to contain your index.html and use that.
Serving static files in Express documentation, or more detailed serve-static documentation, including the default behavior of serving index.html:
By default this module will send “index.html” files in response to a request on a directory. To disable this set false or to supply a new index pass a string or an array in preferred order.
res.sendFile & express.static both will work for this
var express = require('express');
var app = express();
var path = require('path');
var public = path.join(__dirname, 'public');
// viewed at http://localhost:8080
app.get('/', function(req, res) {
res.sendFile(path.join(public, 'index.html'));
});
app.use('/', express.static(public));
app.listen(8080);
Where public is the folder in which the client side code is
As suggested by #ATOzTOA and clarified by #Vozzie, path.join takes the paths to join as arguments, the + passes a single argument to path.
const path = require('path');
const express = require('express');
const app = new express();
app.use(express.static('/media'));
app.get('/', (req, res) => {
res.sendFile(path.resolve(__dirname, 'media/page/', 'index.html'));
});
app.listen(4000, () => {
console.log('App listening on port 4000')
})
If you have a complicated folder structure, such as
- application
- assets
- images
- profile.jpg
- web
- server
- index.js
If you want to serve assets/images from index.js
app.use('/images', express.static(path.join(__dirname, '..', 'assets', 'images')))
To view from your browser
http://localhost:4000/images/profile.jpg
If you need more clarification comment, I'll elaborate.
use below inside your app.js
app.use(express.static('folderName'));
(folderName is folder which has files) - remember these assets are accessed direct through server path (i.e. http://localhost:3000/abc.png (where as abc.png is inside folderName folder)
npm install serve-index
var express = require('express')
var serveIndex = require('serve-index')
var path = require('path')
var serveStatic = require('serve-static')
var app = express()
var port = process.env.PORT || 3000;
/**for files */
app.use(serveStatic(path.join(__dirname, 'public')));
/**for directory */
app.use('/', express.static('public'), serveIndex('public', {'icons': true}))
// Listen
app.listen(port, function () {
console.log('listening on port:',+ port );
})
I would add something that is on the express docs, and it's sometimes misread in tutorials or others.
app.use(mountpoint, middleware)
mountpoint is a virtual path, it is not in the filesystem (even if it actually exists). The mountpoint for the middleware is the app.js folder.
Now
app.use('/static', express.static('public')`
will send files with path /static/hell/meow/a.js to /public/hell/meow/a.js
This is the error in my case when I provide links to HTML files.
before:
<link rel="stylesheet" href="/public/style.css">
After:
<link rel="stylesheet" href="/style.css">
I just removed the static directory path from the link and the error is gone. This solves my error one thing more don't forget to put this line where you are creating the server.
var path = require('path');
app.use(serveStatic(path.join(__dirname, 'public')));
You can achieve this by just passing the second parameter express.static() method to specify index files in the folder
const express = require('express');
const app = new express();
app.use(express.static('/media'), { index: 'whatever.html' })

Node.js + Express: What do I have to serve the specific folder's path to express.static?

I wrote the following code:
var express = require('express');
var app = express();
app.use('/', express.static(__dirname ));
app.get('/', function (req, res) {
res.sendFile('./dist/index.html');
});
app.listen(3000, function() {
console.log("Listening on port 3000");
});
which doesn't work. When open the browser and go to "localhost:3000" I get the error:
path must be absolute or specify root to res.sendFile
Of course the once I fix the line that starts with "app.use..." to:
app.use('/', express.static(__dirname + "./dist"));
then everything works right.
Can you please explain why? What's wrong with giving "express.static" a path of a parent folder of the direct folder of the file sent?
Try changing the order. Instead of:
app.use('/', express.static(__dirname ));
app.get('/', function (req, res) {
res.sendFile('./dist/index.html');
});
Try:
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname, './dist/index.html'));
});
app.use('/', express.static(__dirname));
// OR:
app.use('/', express.static(path.join(__dirname, 'dist')));
Plus use path.join() to join paths. You need to require path first:
var path = require('path');
See this answer for more info on serving static files and why path.join is important:
How to serve an image using nodejs
Now, your problem was not about express.static but about res.sendFile. When you changed express.static path to a different one, then the file you previously wanted to send with res.sendFile was probably found by express.static and the handler with res.sendFile was not run at all. Before the change, the express.static wasn't finding the index.html file and was passing the request to the next handler - which had a bad res.sendFile invocation. That's why it appeared to solve the problem with the error, because the code causing the error was no longer called.

Resources