Express JS serve public folder via GET endpoint - node.js

I have a folder called my-folder, and inside it, many other folders. I'm trying to serve HTML and assets like JS and CSS when I go to a route using Express JS. I'm trying:
router.get('/serve/test', (req, res) => {
app.use(express.static(path.join(__dirname, 'my-folder/test/public')))
})
Inside of my-folder is various folders, and in each of those is again different folders, and I'd like to be able to serve the folder's public directory from any folder within my-folder in order to link to JS, HTML and CSS when going to: http://example.com/serve/test
Right now, I've hard-coded a folder of test, but this would be changed via a param...
Any thoughts as to why this doesn't work?

If you know the parent folders beforehand. You could use multiple express.static outside router.get. Like this:
app.use(express.static(path.join(__dirname, 'my-folder/test/public')))
app.use(express.static(path.join(__dirname, 'my-folder/test2/public')))
...
app.get(...)
If you don't know the folder names beforehand then you will need to build it as a route and return files with res.sendFile:
app.get('/my-folder/:uid/*', function(req, res){
var uid = req.params.uid, path = req.params[0] ? req.params[0] : 'index.html';
res.sendFile(path, {root: `./my-folder/${uid}/public/`});
});
The example above will serve the requested path file or "index.html" if no path is provided.

Related

How to make every file accessible without a express route assigned to it

Is it to possible to make every single file accessible without a express route assigned to it? For example with a normal static website you are able to create an html file and have it accessible at domain.com/blah.html but with express I have to actually create a route to be able to see the html view.
Put them in a folder at the root level of the project and serve them.
Let say you made a folder called public, in your app.js file (where app here is the express instance) add this line.
app.use(express.static('public'))
Now anything you have in there will be accessible if you go to domain.com/blah.html
Serving Static files might help.
When using express i.e. a js package as backend, you will need to define a route to access the frontend files. It's like an address, you don't have the address, the program can't find the file and hence can't display it. For example:
app.get("/", function(req, res) {
res.sendFile(__dirname + "/index.html");
});
This is when you need to access the root route to access your index.html file. Another example, where you need to access the "about" page:
app.get("/about", function(req, res) {
res.sendFile(__dirname + "/about.html");
});
Note that each time I have defined a relative path to access the files.

Express App Serving Unwanted Static Files

I have a react app that is served by express. The entire app is included in public/index.html.
Right now my server.js looks like this:
1 const express = require('express');
2 const path = require('path');
3 const port = process.env.PORT || 8080;
4 const app = express();
5
6 // the __dirname is the current directory from where the script is running
7 app.use(express.static(__dirname));
8
9 app.get('*', (req, res) => {
10 res.sendFile(path.resolve(__dirname, 'public/index.html'));
11 });
12
13 app.listen(port);
However, somehow, files like package.json and /.ssh/known_hosts are being served, things that obviously shouldn't be avaialible.
I'm not sure why app.get('*', (req, res)... isn't catching all requests, and why app.use(express.static(__dirname)); seems to be the only configuration that allows my app to server ANY static files.
I haven't had any luck with app.use(express.static(__dirname+'/public')); or
app.use( '/', express.static(__dirname + '/public'));
or anything else I can find.
EDIT---
My project directory looks like:
/myproject
package.json
server.js
/public
index.html
I want ALL requests to simply serve index.html
What I'm still not understanding is why
app.use('*', express.static(path.resolve(__dirname,'/public/index.html')));
does not serve anything.
Also, why in the above example, res.sendFile() does nothing without first having called express.static(). If I delete line 7, then nothing is served.
So, never ever do this:
app.use(express.static(__dirname));
in your main server directory. That exposes ALL your server files to be viewed.
When using express.static() to serve a whole directory, you should create a directory that contains ONLY files intended for public consumption and then point express.static() at that.
I'm not sure why app.get('*', (req, res)... isn't catching all requests
Because that app.get('*', ...) is AFTER your express.static() so if the express.static() finds a matching file, the app.get('*', ...) never even sees the request. It's already handled and routing doesn't continue any more.
As always with express.static() to advise on exactly what you should do, we need to know the precise configuration you have. Where are the public files in your file system relative to your main server directory and what URLs are you intending to use in the client to refer to those publicly available files.
Here's a theoretical example (since you haven't provided your specifics):
Let's suppose you have files like this:
/myproject
app.js
/public
main.css
And, suppose you want to be able to use /main.css as the URL from the client. For that, you would just do this from within app.js:
app.use(express.static(path.join(__dirname, "public")));
In this first example, where you're serving these static files at the top level path, then you have to make sure there are no naming conflicts between these top level resources and any actual routes you want to serve.
If you wanted the client-side URLs to be /assets/main.css, then you would do this:
app.use("/assets", express.static(path.join(__dirname, "public")));
In this example, you must make sure that the /public sub-directory (and any sub-directories it might have) contains only files intended to be publicly accessible.
Adding a path to the public URL such as /assets removes the chance of a naming conflict between your static assets and your top level routes. This can be a good thing because in any multi-person project, it's not uncommon that the person working on the static assets (like CSS files) is different than the person working on server routes so the two main not be directly aware of what names each other is using. In a single person project, you would certainly just keep it all in your head and avoid accidental naming conflicts that way.
FYI, my preference for folder organization is more like this:
/myproject
/server
app.js
/public
main.css
Where it's 100% obvious which are server files and which are public files. Then, to serve the public files from within app.js with a URL of /assets/main.css, I'd do this:
app.use("/assets", express.static(path.join(__dirname, "../public")));
From your comments:
I just want to serve public/index.html for all ('*') GET requests. All other data comes from separate apis. it seems that res.sendFile() doesn't work without first using express.static. The above code resides in server.js
If all you want to do is to serve public/index.html for all requests (where public is a sub-directory below where app.js is located), then remove the express.static() middleware entirely.
Just use this from app.js:
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'public/index.html'));
});
remove app.use(express.static(__dirname));
as that tells express to load all files that exist
app.use(express.static(__dirname)); will make your app insecure.
Always print out the URLs in the console like path.resolve(__dirname, 'public/index.html') to find out if there is something wrong in it. Seems aiming to the root directory for static files makes problem. Put them in the conventional public directory then try it out again

Node Js Express Static File fails when URL get

I am new to Node Js and doing some practice examples. Static files doesn't serve properly when sending get request as url id.
app.use(express.static('public'));
// It works. Static files loaded properly from http://localhost:3000/themify-icons.css
app.get('/about', (req,res) => {
res.render('about', {
title: 'About'
});
});
// It opens productdetail.ejs but Static files failed here.
// When I check the 'css' from view page source, Its locating to http://localhost:3000/product/themify-icons.css
app.get('/product/:id',(req,res) => {
// console.log(req.params.id);
res.render('productdetail', {
title:'Product Details'
});
});
app.listen(3000);
app('/product/:id') opens productdetail.ejs but Static files failed here. When I check the 'css' from view page source, Its locating to http://localhost:3000/product/themify-icons.css.
I understand its adding 'product' in the path. How do I resolve this even in this url id get method also?
If the browser is requesting http://localhost:3000/product/themify-icons.css, but you want it to just request http://localhost:3000/themify-icons.css, then change the url in the tag to have a leading /. So, instead of
"themify-icons.css"
use:
"/themeify-icons.css"
In your <style> or <link> tag. This should be true for all static resources that you don't want the path from the page URL to be added to.
When you have only a filename, the browser takes the path from the page URL and adds that to the filename. When you have a leading /, then the browser just takes the protocol, host and port from the page URL, not the path.
If your 'public' folder is directly in the project root, write
app.use(express.static(path.join(__dirname, 'public')));
instead of
app.use(express.static('public'));
to get the correct path relative from the project root.
__dirname will refer to the folder in wich your current script is executed.
Note: you need to require the "path" module:
let path = require('path');

How to modify static file content with express.static?

I am using express.static to serve some static files. I want to modify some files content before return to the client. Below is the source code for static resources under /public path.
app.use('/public', express.static(path.join(__dirname, 'public')))
There are some html files under the public directory and I want to modify the html files before responsing to the client.
How can I do that with static? I know I can add customized middlewares but not sure how. Is there a middleware pattern I can use?
You don't use express.static() for files you want to modify - that's not what it does.
Instead, you create routes for the specific URLs you want to do modification on, then you read the file from disk, make your modification and send it back to the client. There are dozens of template systems for the Express eco-system (such as EJS, Jade, Handlebars, etc...) that are specifically designed to solve this problem. Or, if you really want to write your own, you can just load the file yourself, make whatever modifications you want and then send it.
app.get("/public/somefile", function(req, res) {
fs.readFile(path.join(__dirname, 'public', 'somefile'), function(err, data) {
if (err) {
res.sendStatus(404);
} else {
// modify the data here, then send it
res.send(data);
}
});
});
// put express.static after your other routes that serve from the public
// directory so those other routes are matched first
app.use('/public', express.static(path.join(__dirname, 'public')));

Access to mountpath variable from inside a template using express

Is there a clean, recomended way to access the mountpath from inside a template, so an express app can be run both standalone and as a part of another app (by means of app.use), with the paths pointing to the correct destination either way?
Something like:
{{mountpath}}route/to/file
So in the case that the app is running standalone, mountpath will be /, and in case is running as a submodule, mountpath could be /foo/
Note: I'm using handlebars.
express.static middleware is responsible for serving the static assets of an Express application.
How it works:
Serve static content for the app from the "public" directory in the application directory
// GET /style.css etc
app.use(express.static(__dirname + '/public'));
Mount the middleware at "/static" to serve static content only when their request path is prefixed with "/static"
// GET /static/style.css etc.
app.use('/static', express.static(__dirname + '/public'));
Serve static files from multiple directories, but give precedence to "./public" over the others
app.use(express.static(__dirname + '/public'));
app.use(express.static(__dirname + '/files'));
app.use(express.static(__dirname + '/uploads'));
In your case you can use the second case i.e.; mounting files on path '/static', so whatever files are under the folder public can be accesses with src='/static/filename.xyz'
Create a folder name public with sub folders css, js, images
Or if you want your css to be mounted on path /css then you do :
app.use('/css',express.static(path.join(__dirname, 'module1/css')));
Now you can use all your css files in your entire application as :
<link href="css/style.css" rel="stylesheet">
There is an event that is fired after the module is mounted, so I can do:
app.locals.modulePath = "/";
app.on('mount', function (parent) {
app.locals.modulePath = app.mountpath;
});
The locals are directly accessible from inside all the views, so this will be accessible like {{modulePath}}
I had the same issue - needed to use mountpath from inside a template.
Solution that works for me is based on 2 facts
mountpath is available in request - req.baseUrl
response locals object gets exported to the template - res.locals
First, create a one-line middleware - this will apply to all routes inside the module/subapp
router.use(function (req, res, next) {
res.locals.baseUrl = req.baseUrl;
next();
});
Then inside the template use #{baseUrl}/some/route - note that this is jade syntax, but I suppose it works the same way with handlebars.

Resources