How to serve a static site within keystone? - node.js

I have one keystone based site and a completely static one.
I would like to integrate the static one into the first one.
All the requests to "/" will serve the static one but requests under "/resources" would serve the keystone site.
basically:
"/" would serve the static folder 'site'
"/resources" would serve the keystone app
At the moment my structure is:
public
| - keystone
| - site
And my keystone static option is set on 'public'
'static': 'public'
How would I go to set up these routes?
I was thinking of using a middleware in this way:
app.use("/", express.static(__dirname + "/site"));
app.use("/resources", express.static(__dirname + "/keystone"));
But how would I do it in keystone?

You don't need any extra middleware.
With the option 'static' : 'public', any static content placed in the public folder within your project folder will be served as static content.
It is also possible to define more than one directory by providing an array of directories like this 'static' : ['public','site'] this way everything in the directory site will also be served.
I assume you want some kind of index.html to be loaded when someone hits your sites root. You can achieve tha by adding a redirect to your /routes/index.js.
Simply add keystone.redirect('/', '/index.html'); or whatever the filename is you want to get served. You also have to remove the keystone route to '/'

I achieved this by just editing one line in the routes/index.js file, and adding the directory name in the keystone.init() "static" setting. Now all files in "client" directory get served under the root of my site URL, and Keystone lives at www.yoursite.com/resources
Step 1
Edit routes/index.js:
Change:
app.get('/', routes.views.index);
To:
app.get('/resources', routes.views.index);
Step 2
edit keystone.js:
Change
keystone.init({
...
'static': 'public',
...
To
keystone.init({
...
'static': ['public','client']
...
```
Step 3
Add site files, including index.html, into a new folder called "client".
Keep in mind that Node will also load files that are in the "public" folder. For example, currently keystone has a file called "logo-email.gif" in public/images. This means that www.yoursite.com/images/logo-email.gif will load that image. It turns out that if there is both a file public/images/logo-email.gif and client/images/logo-email.gif, then the image in public takes precedence. If you reverse the 'static' attribute in keystone.init() so that it says ['client','public'] then the image in "client" takes precedence

KeystoneJS v5, I used this way:
module.exports = {
keystone,
apps: [
new GraphQLApp(),
new StaticApp({path:"/", src:'public'}), // for your static site
new StaticApp({path:"/resources", src:'static'}), // Keystone uploaded resources
new AdminUIApp({
enableDefaultRoute: true,
authStrategy,
})
]}

Related

Express static folder does not load properly

I'm having trouble with a Node APP that I am building.
App folder structure:
controllers // controllers
helpers // helpers
config // some config files
public // stores a built angular app
...
App URL 1: www.domain.com
App URL 2: www.another.com/myapps/app1
So this is how I set the static folder to load the assets:
app.use(express.static(__dirname + '/public'));
And this is how I would access the files in the static folder:
URL1: www.domain.com/assets/main.js
URL2: www.another.com/myapps/app1/assets/main.js
Now, the problem is that if I deploy the app on URL1 everything works perfectly. But deploying the app to URL2 gives me some issues.
The static files cannot be accessed on the app on URL2. I get 404 (Cannot GET ...).
www.another.com/myapps/app1/assets/main.js // returns 404
www.domain.com/assets/main.js // returns the JavaScript file.
There are multiple apps running on URL2 that is why I have used contexts to separate the apps.
My initial thoughts are that because of the additional contexts to the url on URL2, express is failing to set the static folder properly.
Could this be because the static folder is not being set properly?
express.static receives data from somewhere and applies this data to the root of your domain.
Actually you can get your files inside another folder by adding some structure.
In your case set app.use(express.static(__dirname + '/public')); and place assets inside app1 and then in myapps folders. All this should be inside public folder

cannot reach a file on server though I exposed using express

In my project I need to store some text files dynamically and end user should be able to download them from browser. I know the best way is using object store like MINIO or S3 but unfortunately the only way I have is to use in memory storage. So what I am trying to do is: I made a public folder and I exposed it using the following code:
var express = require('express');
var app = express();
//setting middleware
app.use(express.static( 'public')); //Serves resources from public folder
var server = app.listen(5000);
it is as simple as that. Then for testing just to make sure I can download and reach a file I created a public folder with t.txt file in it and when I try:
http://localhost:5000/public/t.txt
I get
So why am I not getting it? Also is what I am trying to achieve will be a good match to scenario and is it doable at all?
When you're not specifying a path in app.use(), your app will serve the contents of the directory you're pointing to in express.static() on the root path. Try this:
http://localhost:5000/t.txt
That said, if you want it to be accessible at /public/t.txt, just specify the path:
app.use('/public', express.static('public'))
At first use the following line of code:
app.use(express.static(__dirname+'/public'));
This means that your home directory for static HTML pages is in the "public" folder. Note that the "__dirname" points to the directory of the current js file.
After that, call the following URL from the browser or POSTMAN:
http://localhost:5000/t.txt
As you can see, there is no need to write http://localhost:5000/public/t.txt referring to the "public" folder because you have already specified that in the app.use line.

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

Serve Static content to subdomain with express?

I have an express app, which is just the default blank app. I have then added the line:
app.use(serveStatic('docs/public', {'index': ['index.html', 'index.htm']}))
to serve the contents of my docs/public directory. This works great, but it is being served to the root of my application, so I no longer see the default express index page.
I would like to see the static html (which I am currently seeing as my index) as a subdomain, e.g. blog.mydomain.com. Or at least as mydomain.com/blog. How do I serve the static content to a subdomain?
NB: the static file names and folders can't change, as my ./docs directory is a hexo project and any changes would break the generation of the static content in the docs/public folder.
I have tried to use express-subdomain so I added code like this to my app.js:
var router = express.Router();
router.use(serveStatic('docs/public', {'index': ['index.html', 'index.htm']}))
app.use(subdomain('docs', router));
However, If I run that, I get the express index page at http://localhost:3000/ (not the static one) which is what I want, but if I go to http://docs.localhost:3000/ then I don't get my static content, still the original express index. In fact, if I remove the subdomain code nd run the app, navigate tot he docs subdomain I still get the same result.
I have also tried to use the subdomain module:
app.use(subdomain('docs', serveStatic('docs/public', {'index': ['index.html', 'index.htm']})));
However, that has the same result as above (not serving any static content).
So how can I serve the static content I am currently serving on a subdomain?
#GeorgeEdwards In your example code you've called the static middleware before the subdomain middleware. The order is important... it should be something like this:
app.use(subdomain('docs', express.static('docs/public')));
This means any requests with the docs subdomain will be handled by the express static middleware.

Express JS: how to know if request is for static asset?

I am writing middleware for some specific task, which should not be executed when request is for static assets (from client folder: app.use(express.static(path.join(__dirname, "../client")));)
So how can i know that particular request is for static asset or is being served from "client" folder?
I have below code
app.use(express.static(path.join(__dirname, "../client")));
app.use(someCustomMiddleware());
i am seeing that requests for static assets like for css/js files is still going thru someCustomMiddleware(). My requirement is that someCustomMiddleware() should not process request for static assets.
Just add it before your other routes. If a request is made for a static item then it will go to app.use(express.static(path.join(__dirname, "../client"))); first, and then your routes.
Ex. Let's say your public folder has some css folder with a file style.css in it. Let's say your routes look like this.
app.use(express.static(path.join(__dirname, "../public")));
app.use(someMiddleware);
If you access /css/style.css, it will hit express.static and serve the file, and will not go to that '/' route.

Resources