React App giving 404 on main js and css - node.js

I built a react app using "react-scripts". The application runs perfectly on my local development server but when I deploy to my actual server the applications seems to not find the main JS and CSS files being compiled. I get 404 on both.
Following is the information that might help.
The files on the server are located at
ads/build/static/js and ads/build/static/css || respectively
The 404s I am getting are on the following files:
https://www.example.com/ads/build/static/css/main.41938fe2.css
https://www.example.com/ads/build/static/js/main.74995495.js
Here is how my server is configured:
const express = require('express');
const path = require('path');
const app = express();
const favicon = require('serve-favicon');
//favicon
app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.get('/ads', function (req, res) {
app.use(express.static(path.join(__dirname, 'build/static')));
console.log(path.join(__dirname, 'build'));
res.sendFile(path.join(__dirname, '/build/index.html'));
});
app.listen(9000);
In my package.json I have also included the homepage parameter as:
"homepage" : "https://www.example.com/ads
UPDATE
When I run the app on the server itself with the following path:
dedicated-server-host:9000/static/js/main.74995495.js that renders the JS file correctly
Is there some configuration that I am missing, the routing doesn't seem to be working. Please advise.

Use some indentation so you will see error like this:
app.get('/ads', function (req, res) {
app.use(express.static(path.join(__dirname, 'build/static')));
console.log(path.join(__dirname, 'build'));
res.sendFile(path.join(__dirname, '/build/index.html'));
});
You are setting the static route inside of the /ads handler, will add a new express.static route handler on every GET /ads request.
This will set the static route on server startup:
app.use(express.static(path.join(__dirname, 'build/static')));
app.get('/ads', function (req, res) {
console.log(path.join(__dirname, 'build'));
res.sendFile(path.join(__dirname, '/build/index.html'));
});
or:
app.get('/ads', function (req, res) {
console.log(path.join(__dirname, 'build'));
res.sendFile(path.join(__dirname, '/build/index.html'));
});
app.use(express.static(path.join(__dirname, 'build/static')));
But make sure that you get the path right - for example you may need:
app.use('/ads/build/static', express.static(path.join(__dirname, 'build/static')));
if you want the URL in your question to work.
To make it much simpler, you could use just this single handler to make express.static handle both the css/js and index.html at the same time:
app.use('/ads', express.static(path.join(__dirname, 'build')));
and change your index.html to use:
https://www.example.com/ads/static/css/main.41938fe2.css
https://www.example.com/ads/static/js/main.74995495.js
instead of:
https://www.example.com/ads/build/static/css/main.41938fe2.css
https://www.example.com/ads/build/static/js/main.74995495.js
Sometimes getting your paths structure right in the first place can make your route handlers much easier.

Related

Unable to send response using app.use in node js

code is used to set up server and calling a html page
const express =require('express')
const path=require('path')
const app=express()
const ppath=path.join(__dirname,'../public/index.htm')
app.use(express.static(ppath))
app.listen(3000,()=>
{**strong text**
console.log("HEy")
})
Try this.
app.get('/', function(req, res) {
res.sendFile(path.join(__dirname, '..', 'public', 'index.htm'));
});
You pass express.static() a directory and it looks for requested files in that directory. You don't pass express.static() a path to a single file. That will not work.
If you actually want other static files in the same directory to be served, you could point express.static() at the parent directory.
Of, if you just want that one file served, then you just set up a route for that one file:
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname,'../public/index.htm'));
});
For an further help with express.static(), we also need to know exactly what the incoming URL is that you want to serve index.htm with.

Express static serves index.html How to deny it?

When I serve my angular 5 app from node express I face this issue as express static serves index.html when I visit domain.com but I when I visit domain.com/something it works correctly can some help how do I solve this
app.use(express.static(path.join(__dirname, 'dist'))); //This line serves index.html how to deny it
app.use("/api", routes);
app.get('*', function(req, res) { //The reason it needs to be * so that it works with angular routes or it wont work
//This is never called when i visit domain.com. but it does when i visit domain.com/somthing
console.log("i was serverd");
res.sendFile(path.join(__dirname, 'dist/index.html'));
});
Thanks in advance :)
Found a solution
var options = {
index: false
}
app.use(express.static(path.join(__dirname, 'dist'), options));
index : Sends the specified directory index file. Set to false to disable directory indexing.
Refer: http://expressjs.com/en/api.html
I have found a workaround for your prooblem
app.use('/',(req,res,next)=>{
if(req.path!='/')
next();
console.log('ii');
res.sendFile(path.join(__dirname,'dist/index.html'));
},express.static(path.join(__dirname, 'dist')));
app.get('*',(req,res,next)=>{
console.log('ii');
res.sendFile(path.join(__dirname,'dist/index.html'));
});
This will cover for all your requests. But in this way you would have to write same code in 2 routes
Replace * with /.
This should be registered before the app.use(express.static call. (Thank you jfriend00)
Ex :
app.get('/', function(req, res) { //see, no asterix
//This is never called when i visit domain.com. but it does when i visit domain.com/somthing
console.log("i was serverd");
res.sendFile(path.join(__dirname, 'dist/index.html'));
});
app.use(express.static(path.join(__dirname, 'dist')));

Serving multiple react apps with client-side routing in Express

I have different software products for one single service, which needs to be deployed to a single server. The clients are built with react, with a build setup by create-react-app, while the server runs Node.js and Express.
When I serve a single application from the server it is done the following way:
// App.js
// ...
// Entry point for data routes (API)
app.use('/data', indexRoute);
if(process.env.NODE_ENV !== 'development') {
app.use(express.static(path.join(__dirname, 'build-client')));
app.get('/*', function(req, res) {
return res.sendFile(path.resolve( __dirname, 'build-client' , 'index.html'));
});
}
I want to be able to serve multiple apps from the server. How should I do that?
What I tried is to wire in different static paths for the assets and separate the clients with different names, although it did not work. Like this:
// App.js
// ...
// Entry point for data routes (API)
app.use('/data', indexRoute);
if(process.env.NODE_ENV !== 'development') {
app.use(express.static(path.join(__dirname, 'build-client')));
app.use(express.static(path.join(__dirname, 'build-admin')));
app.get('/client/*', function(req, res) {
return res.sendFile(path.resolve( __dirname, 'build-client' , 'index.html'));
});
app.get('/admin/*', function(req, res) {
return res.sendFile(path.resolve( __dirname, 'build-client' , 'index.html'));
});
}
I have also tried to do it this way, but Express throw Error: No default engine was specified and no extension was provided:
if(process.env.NODE_ENV !== 'development') {
// Admin paths
app.use('/admin', express.static(path.join(__dirname, 'build-admin')));
app.get('/admin/*', function(req, res) {
return res.sendFile(path.resolve( __dirname, 'build-admin' , 'index.html'));
});
// Site paths
app.use('/', express.static(path.join(__dirname, 'build-client')));
app.get('/*', function(req, res) {
return res.sendFile(path.resolve( __dirname, 'build-client' , 'index.html'));
});
}
How could I accomplish this or something similar?
After some tinkering I was able to achieve this without using virtual hosts. I used the first idea you gave in the question, except I left the main app at the root (i.e. /).
// when going to `/app2`, serve the files at app2/build/* as static files
app.use('/app2', express.static(path.join(__dirname, 'app2/build')))
// when going to `/`, serve the files at mainApp/build/* as static files
app.use(express.static(path.join(__dirname, 'mainApp/build')))
// These are necessary for routing within react
app.get('app2/*', (req, res) => {
res.sendFile(path.join(__dirname + '/app2/build/index.html'))
})
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname + '/mainApp/build/index.html'));
});
After this, I went into mainApp/package.json and added
"proxy": "http://localhost:4141"
:4141 is the port that the express server is running on. This line will make calls to fetch('/some/route') go back to the server instead of into your react app itself.
Finally, we go to app2/package.json and add
"proxy": "http://localhost:4141/app2",
"homepage": "/app2"
I believe that the key here is the "homepage" key. The way I understand it, when react starts it searches for some static files at its homepage, and without the "homepage" piece I was only able to get either a blank white screen or the mainApp.
I hope this helps someone out there!
EDIT
I have since changed from serving my create-react-apps through my express server to serving them through netlify. Now I don't need to worry about this express setup, or the homepage key in package.json. The express server lives by itself, and the react apps can still both use the same api, and deployment is much easier. Setup with netlify is trivial.
After struggling for a while with this problem I've found a possible solution without compromising the original setup.
We used Express vhost package to setup handling of requests through virtual domains.
When you create your app instance, you should initialize as many apps with express as you want to expose separately (in our case its three separate apps plus the original app instance)
// Create an express instance
const app = express();
const appAdmin = express();
const appClient = express();
const appVendor = express();
After that you need to install vhost and import it. Then with specifying the static folder for each app you can handle serving the static files separately, while the remaining part deals with handling the request for the given subdomains respectively.
appAdmin.use(express.static(path.join(__dirname, 'build-admin')));
appClient.use(express.static(path.join(__dirname, 'build-client')));
appVendor.use(express.static(path.join(__dirname, 'build-vendor')));
appAdmin.use((req, res, next) => {
return res.sendFile(path.resolve( __dirname, 'build-admin' , 'index.html'));
});
appClient.use((req, res, next) => {
return res.sendFile(path.resolve( __dirname, 'build-client' , 'index.html'));
});
appVendor.use((req, res, next) => {
return res.sendFile(path.resolve( __dirname, 'build-vendor' , 'index.html'));
});
app.use(vhost('domain.com', appClient));
app.use(vhost('www.domain.com', appClient));
app.use(vhost('a.domain.com', appAdmin));
app.use(vhost('b.domain.com', appVendor));
Don't forget to add the desired subdomains in your domain's DNS registry. Example:
...records
CNAME vendor #
CNAME admin #

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.

Intercept request for a static file in express.js

I have a node server, that serves static files in a PUBLIC folder like this:
var app = express();
app.listen(port);
app.use(compression());
app.use(express.static(__dirname + '/PUBLIC'));
There is a json file, let's say important.json that is located in /PUBLIC folder. This is being served as a static file
Now, I want to intercept request for this /PUBLIC/important.json, so that I can programatically return a random json structure instead.
None of the followings works:
app.get('/PUBLIC/important.json', function(req, res) {
console.log("caught1!")
});
app.get(__dirname + '/PUBLIC/important.json', function(req, res) {
console.log("caught2!")
});
app.get('important.json', function(req, res) {
console.log("caught3!")
});
How can I intercept request for that partically static file?
As the express.static middleware does not call the next middleware using next(), the definition order is important. You have to define your own middleware before using express.static.
app.get('/PUBLIC/important.json', (req, res, next) => {
console.log('caught');
next();
});
app.use(express.static(__dirname + '/PUBLIC'));
Could you tell us a bit more about your stack ?
Are you using nginx / apache to proxy_pass the traffic to your nodejs server ?
Are you just running your app with "node app.js"
Let's try to add this simple route in your application :
app.get('/', function (req, res) {
res.send('Hello World!');
});
And try to access it by removing URI parameters ? Does the "Hello world" show up ?
I just want to be sure the traffic is actually treated by your node app.
Your route definition is supposed to work for your actual request.

Resources