I'd like to use the chrome audits tool on my React app, but it keeps saying that my robots.txt file is invalid. The thing is, the file seems to be perfectly fine, only it doesn't read robots.txt, but rather my index.html file, therefore resulting in this error :
Both files are in my /public folder, so why would it read the index file ?
if your using Node and Express in order to run your React App project in production.
and if your server file code looks like below snippet, this means your are serving same file for all requests(routes). During lighthouse auditing, browser makes a get request to http://localhost:5000/robots.txt and in return it get served with index.html.
app.get('/*', function (req, res) {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
To solve this problem ,you can add route for robots.txt file, before above code snippet as shown below.
app.get('/robots.txt', function (req, res) {
res.sendFile(path.join(__dirname, 'build', 'robots.txt'));
});
app.get('/*', function (req, res) {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
Related
I created a MERN app that has a node.js server.
To host the website on Heroku first I have to create a build folder by it using npm run build. After that, I have to add this to my entry point file in my server
app.use(express.static("./FRONTEND/build"));
if (process.env.NODE_ENV == "production") {
app.get("*", (req, res) => {
res.sendFile(path.resolve(__dirname + './FRONTEND', 'build', 'index.html'));
})
}
I use react-router-dom's BrowserRouter to routing through the webpages. But when I uploaded that site on Heroku I found out that the home page is working perfectly but when I route to other pages an error occurred and it says an error occurred in the application.
I tried searching for it and found methods like adding static.json, using HashRouter, and adding .htaccess. But nothing works on my site.
Then, theoretically, I re-run the backend with my local computer, so the frontend is also hosted. The frontend was connected to the backend by this code.
app.use(express.static("./FRONTEND/build"));
app.get("*", (req, res) => {
res.sendFile(path.resolve(__dirname + './FRONTEND', 'build', 'index.html'));
})
Hence, I was serving the build for the front-end and also found that routing is not working
in the build also. And the error comes here is
ReferenceError: __dirname is not defined
at file:///D:/Yash/React_websites/housedeck-home-services/BACKEND/index.js:26:29
at Layer.handle [as handle_request] (D:\Yash\React_websites\housedeck-home-services\BACKEND\node_modules\express\lib\router\layer.js:95:5)
at next (D:\Yash\React_websites\housedeck-home-services\BACKEND\node_modules\express\lib\router\route.js:137:13)
at Route.dispatch (D:\Yash\React_websites\housedeck-home-services\BACKEND\node_modules\express\lib\router\route.js:112:3)
at Layer.handle [as handle_request] (D:\Yash\React_websites\housedeck-home-services\BACKEND\node_modules\express\lib\router\layer.js:95:5)
at D:\Yash\React_websites\housedeck-home-services\BACKEND\node_modules\express\lib\router\index.js:281:22
at param (D:\Yash\React_websites\housedeck-home-services\BACKEND\node_modules\express\lib\router\index.js:360:14)
at param (D:\Yash\React_websites\housedeck-home-services\BACKEND\node_modules\express\lib\router\index.js:371:14)
at Function.process_params (D:\Yash\React_websites\housedeck-home-services\BACKEND\node_modules\express\lib\router\index.js:416:3)
at next (D:\Yash\React_websites\housedeck-home-services\BACK
So, The routing is not working in the build index.html file. I want it to work any suggestions for that.
I got the same error and I made small change to my code making "/*" instead of "*" and it worked fine for me. And in this case I was using Browser Router and on that it worked fine.
app.use(express.static("./FRONTEND/build"));
if (process.env.NODE_ENV == "production") {
app.get("/*", (req, res) => {
res.sendFile(path.resolve(__dirname + './FRONTEND', 'build', 'index.html'));
})
}
BIG EDIT SINCE I DID SOME MORE RESEARCH
I'm trying to deploy my first Nodejs/React App on a Cloud-Server using Plesk.
That's what I tried first:
I created an .httaccess file with the following contents.
Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.html [QSA,L]
Problem with this was, that I didn't have access to express app.js anymore, since react's index.html file handles everything. So the alternative is to route accordingly out of app.js from express. I have found the following approach and trie to implement it.
Approch:
/api/app.js
app.use('/result', resultRouter);
app.use(express.static(path.join(__dirname, 'build')));
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
app.get('/*', function (req, res) {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
My implementation:
var createError = require('http-errors');
var express = require('express');
const cors = require('cors');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
require('dotenv').config();
var helmet = require('helmet');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var resultRouter = require('./routes/result');
var app = express();
app.use(helmet());
app.use(cors());
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', 'http://localhost:3000');
next();
});
//Set up mongoose connection
var mongoose = require('mongoose');
var mongoDB = 'MYMONGODBURL';
mongoose.connect(mongoDB, { useNewUrlParser: true, useUnifiedTopology: true });
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'MongoDB connection error:'));
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use('/result', resultRouter);
app.use(express.static(path.join(__dirname, 'build')));
app.get('/', function (req, res) {
res.sendFile(path.resolve(__dirname, 'build', 'index.html'));
});
app.get('*', function (req, res) {
res.sendFile(path.resolve(__dirname, 'build', 'index.html'));
});
// catch 404 and forward to error handler
app.use(function (req, res, next) {
next(createError(404));
});
// error handler
app.use(function (err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
While I am sure this is the correct solution in general, I fail to implement it. The app.js file lays in the api folder. Before uploading it to Plesk, I insert the build folder from react inside. So app.js and the build folder are on the same level of the directory.
After the upload via git, I have both the document root as well as the application root set to configurator/api. Configurator is just an empty folder I set up beforehand.
If I set document root to configurator/api/build, the starting page of my react index.html file gets displayed. But routing to any other react component doesnt work.
What do I do wrong here? Also I have enabled "browsing for a domain", but still get a 504 Gateway Timeout Error.
I hope someone can point me in the right direction or has some input as to where I should look next.
Thanks in advance
Found a solution to my problem.
So I know my question is on a real beginner level and in hindsight, I didn't give enough info for someone to help me out here. But I found a solution, that hopefully helps other beginners that are stuck at this point. So I write to share what I learned in the process and also to reflect on it.
2 ways to get react/express running on Plesk
Basically there are two ways to get react/express running on Plesk. Both solutions are viable, but tackle different prerequesites.
Solution 1: You want to render a static site via react, that doesnt perform any backend-requests to nodejs.
In this case, you run Çıpm run build in your react-folder and put the newly created build folder inside your express folder. Inside the build folder, create a .htaccess file with the following content:
Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.html [QSA,L]
I think doing it this way, you don't even need nodejs. But I haven't tried it out. Anyway. Upload the folder (let's call it api) to Plesk via git and set document root to api/build, while application root is just api.
Solution 2: You want to render static react, but you perform backend-requests to express for some business logic or database-requests at any point.
As in solution 1, create the build folder and move it into the api folder. The build folder is everything you need from React for your app to work at the end. In the api folder, create a new Javascript file on the root level. Name it server.js. Inside put the following code:
const app = require('./app');
const http = require('http');
http.createServer(app).listen(process.env.PORT);
As I understood, this starts your server in the first place and without you'll get a 504 Timeout-Error.
Second, you need to tell nodejs, that it redirects to react's index.html file, whenever you hit a route, that is not defined in express. For this, open your app.js file. Go right under the last of your express routes and insert the following:
app.use('/result', resultRouter);
// ^ above is the last route of my express app.
// below tells your server to redirect all other routes to index.html from React
app.use(express.static(path.join(__dirname, 'build')));
app.get('/', function (req, res) {
res.sendFile(path.resolve(__dirname, 'build', 'index.html'));
});
app.get('*', function (req, res) {
res.sendFile(path.resolve(__dirname, 'build', 'index.html'));
});
After modifying and uploading to Plesk, set both your document root and your application root from the Plesk-Nodejs application to api (or whatever your root-folder is). Then, set the application starting file to server.js. Everything should work now.
Troubleshooting
Here are some obstacles I had on the way and you might face also.
Content Security Policy Error: After setting everything up successfully with solution 2, I got a Content Security Policy Error. This was because of the middleware Helmet I use in my express-app. Comment helmet out to test if it's the problem. If it is, there are ways to setup Helmet correctly. You don't need to disable it really.
CORS Error: My backend request failed with the same origin policy being hurt. This was because the axios request from react to express still referred to localhost. Replace all axios request urls in React with the right url from your production-domain.
I'm an express noob here and building a React App with server using express and client using create-react-app.
What I want to do
I want to update the title and meta tag in the index.html.
So browser requests url -> Server gets request and adds the title and tag to the index.html -> return it to the browser.
Listed my code here
...
app.use(bodyParser.json())
app.use(aMiddleware)
app.use("/api/foo", bar)
app.use(express.static('client/build'));
if (process.env.NODE_ENV === 'production') {
const path = require('path');
app.get('/*', (req, res) => {
res.sendFile(path.resolve(__dirname, '../client', 'build', 'index.html'))
})
}
Questions
Code is functioning, but I don't know how to replace the title/tag in the index.html
How do I update/replace index for environment that is not prod?
Fo prod environment, I use path.resolve(__dirname, '../client', 'build', 'index.html'), then where is index.html for dev environment? I see there is an index.html in public folder, is it the one that got rendered for dev environment?
I tried to add this code before app.use(express.static(...))
app.get('/', function(req, res) => {
// maybe replace string in the index.html (though I don't know where is it
// then res.send(...)?
})
but this never got triggered. Why?
Stuck on this for a while, tried many things, any help would be great.
You can use react-helmet for this... Or switch to Nextjs which is server side.
https://www.npmjs.com/package/react-helmet
So I followed the documentation from the creat-react-app-docu and I can not figure out how to serve my react-frontend via express. In the docs it is stated as follows:
const express = require('express');
const path = require('path');
const app = express();
app.use(express.static(path.join(__dirname, 'build')));
app.get('/', function(req, res) {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
app.listen(9000);
But my project structure looks like this:
--root
|
backend
|
src
|
index.ts (My express config)
|
web
|
build (Production build of my react app)
So I had to adapt the config in my index.ts like this:
// Present Frontend view
app.use(express.static(path.join(__dirname, '../../web')));
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname, '../../web/build', 'index.html'));
});
// Start the server
server.listen(3000, () => console.log('BYOD is listening on port 3000!'));
But the error I am getting is that is:
Refused to apply style from 'http://192.168.145.135:3000/BYOD/static/css/main.74ea495e.chunk.css' because its MIME type ('text/html') is not a supported stylesheet MIME type, and strict MIME checking is enabled..
My Question is now: Am I doing something conceptionally wrong? How can I solve this issue?
Update
So I figured out that that the urls in the index.html (within the build folder) has some wrong urls e.g.:
<link rel="shortcut icon" href="/BYOD/favicon.ico"/>
instead of just:
<link rel="shortcut icon" href="/favicon.ico"/>
These urls are automatically inserted by CRA. How can I prevent to load false public-urls into the index.html?
One Solution approach is to add in my frontend dir (react-project) a .env file and set explicitely the following:
PUBLIC_URL=/
My question now is there a better solution or is my project architecture completely messed up? Im extremely curios for advices! Thanks in advance!
I'm sorry I'm reasonably new to node. I've been stuck on this for a couple hours.
server.js
app.use(express.static(__dirname + "/public"));
app.get('/', function(req, res){
res.sendFile(path.resolve(templatesPath + 'index.html'));
});
app.get('*', function(req, res){
res.sendFile(path.resolve(templatesPath + 'index.html'));
});
index.html is an Angular application. I have the first level of routes working fine using Angular's HTML5 routes eg. "http://lh:3000/staff" or "http://lh:3000"
but if I add another level or route parameters, e.g. "http://lh:3000/staff/" or "http://lh:3000/staff/test" Express seems to ignore express.static and instead uses the get wildcard to turn all my files into index.html so my page breaks.
Thanks for your help answerers
In secondary routes, it was loading assets referenced in index.html, relative to the secondary route. My temp solution is to add:
app.use('/files/',express.static(path.join(__dirname + "/public")));
but I realise now it is better to change my solution.
are staff/test, static assets sitting inside your assets folder?
If they are static assets, there must be a file in the path staff/test inside your assets folder.
if they are not static assets and they are dynamic content, consider using express.router,make a router for staff and add it as,
var staff = express.Router();
staff.use('/staff', staff)
//this is route handler for /staff/test
staff.post('/test', function(req, res, next){
res.json(some-json-content)
})
try this:
app.get('*/*', function(req, res){
res.sendFile(path.resolve(templatesPath + 'index.html'));
});