React CRA with SSR configuration throws 404 when using the resulting html - reactjs

I have a react application built using CRA with the default configurations. I wanted to make SSR, so I followed an article something similar to this https://www.vairix.com/tech-blog/server-side-rendering-ssr-of-create-react-app-cra-app-in-2020
Next, I wanted to inline the JS and CSS so that I could hit the URL and copy the resultant HTML page and then use it where ever I want.
For that, I used react-app-rewired plugin which works now I can see the HTML with inline CSS and JS.
The issue is when I copy the generated HTML and save it as .html, and when I open the page, it returns 404 error.
I am trying to copy the HTML that is produced and then use them as individual components in a completely different application.
Am I missing something?
config-overrides.js for react app rewired
const HtmlWebpackPlugin = require("html-webpack-plugin");
const InlineChunkHtmlPlugin = require("react-dev-utils/InlineChunkHtmlPlugin");
const HTMLInlineCSSWebpackPlugin = require("html-inline-css-webpack-plugin").default;
module.exports = {
webpack: function(config, env) {
if (env === "production") {
config.plugins.push(new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/.*/]));
config.plugins.push(new HTMLInlineCSSWebpackPlugin());
}
return config;
}
};
server.js for SSR
import express from "express";
import path from "path";
import renderer from "./react-renderer";
const app = express();
const PORT = 8000;
const routes = ["/custom1/:id","/custom2/:id","/custom3/:id"];
app.get("/*", renderer(routes));
app.use(express.static(path.resolve(__dirname, "../build")));
app.use(express.static(path.resolve(__dirname, "../public")));
app.listen(PORT, () => {
console.log(`App running in the port ${PORT}`);
});

404 is the HTTP code for not found: I don't think the problem is in opening the page but in finding it.
It seems the first route you added in your server is catching all the requests:
app.get("/*", renderer(routes));
you could try moving it as last route
app.use(express.static(path.resolve(__dirname, "../build")));
app.use(express.static(path.resolve(__dirname, "../public")));
app.get("/*", renderer(routes));
More than this you didn't said where you copied the resulting page, I hope in ../build or in ../public directories, otherwise I'm not surprised you can't GET it.

Related

React-router urls don't work when refreshing or writing manually, gives 404 page not found

My production webiste opens normally, but for a user visiting/accessing that link the first time, he gets a 404 Page Not Found. For users that has already visited the website it loads just fine.
This is the url - https://literacycloud.org/readaloudsdetail/546-jennifer-phillips-reads-the-invitation.
Ideally it should redirect to the login page, but there is no api being hit at all.
The issue doesn't get reproduced locally only when deployed to development or to live, getting this issue.
Is it something back-end has to handle from their end?
Any help appreciated.
Set historyApiFallback in your webpack.config.js. Checkout this.
Also, it is a good idea to serve your index.html from a server. The idea is that no matter what url you visit on your domain, the server should always return the index.html as it contains your react code.
Here is a sample code:
const path = require('path');
const express = require('express');
const app = express();
app.use(express.static(path.join(__dirname, 'build')));
app.set('port', process.env.PORT || 8080);
app.get("*", (req, res, next) => {
const filePath = path.join(__dirname, 'build', 'index.html');
res.sendFile(filePath);
});
const server = app.listen(app.get('port'), function () {
console.log('listening on port ', server.address().port);
});

How does express serve index.html for React App and how do I modify it?

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

I would like to alter the way create-react-app builds my app

So I would like to make npm run build to produce local runnable files. Basically, I want it to build index.js with importing assets like ./static/js/chunk.js instead of /static/js/chunk.js. The client I am running this on does not have internet access so I want to serve the app from the file system.
Basically, I want to open index.html in the build folder with chrome and the app just work. Any ideas on how to do this?
Using simple node js and serve it as static is the best way because react router dom need url in the app.
const express = require("express");
const path = require("path");
const app = express();
app.use("/static", express.static());
app.get("*", (req, res) => {
res.sendFile(path.resolve(__dirname, "frontend", "build", "index.html"));
});
app.listen(6000, () => console.log("Listening to port 6000"));
Next to node file index.js, or whatever you name it, make the folder called frontend. Inside it put your build from react so the node can serve index.html in port 6000

ngrok does not work with react-router when deep links are explicitly defined

Context: I'm opening up my React dev environment to external hits using a paid version of the tool ngrok -- I am running WebPack 4.0 with a devServer.
I go to my app's main page:
https://my-example-domain.ngrok.io
Loads fine.
I click one of the links on my app's main page, The router works well and I see the content for:
https://my-example-domain.ngrok.io/my-sub-page
However, if I refresh at this point, ngrok gives out a 404:
Cannot GET /my-sub-page
The reason I suspect is that in a SPA, the internal app's URLs are processed by the front end in React-Router and externally, there is no resource called /my-sub-page
Is there a way to force this to work?
The problem is that the local server doesn't know about your spa routes(react-router). To fix this, you have to create a simple server that will serve your static build and have a fallback route that will enable spa-routing.
Example in express.js:
import express from 'express';
import path from 'path';
// ... other imports
const app = express();
app.use(express.static('build'));
/*
... some route handlers
*/
// * Unknown endpoint
app.use("/*", (_req, res) => {
res.sendFile(path.join(__dirname, "../build/index.html"), (err) => {
if (err) {
res.status(500).send(err);
}
});
});
app.listen(process.env.PORT || 3000 , ()=>{
console.log('server running')
})
This resolved it -- in webpack.config.js
devServer: {
...
...
historyApiFallback: true, // <- inserting this resolved the issue.
}

How do I rewrite all urls to index.html in Heroku?

My Heroku app is using React with React Router. I use Switch to navigate through different components, so the URL changes as well (e.g. /room/4141). However, if I reload the page, it doesn't act like if it was a React app, but instead it searches for the mentioned .html file.
I used this Buildpack: https://github.com/mars/create-react-app-buildpack.git but it seems to do nothing in regards with pages being rewritten to index.html.
Is there a way to prevent this behaviour and rewrite all URLs to index.html?
**EDIT:
I'm not familiar enough with express, but here's how the index.html is served.
const express = require("../../node_modules/express");
const app = express();
const server = require("http").Server(app);
const io = module.exports.io = require('../../node_modules/socket.io/lib')(server)
const path = require("path")
app.use(express.static(path.join(__dirname, '../../build')));
if(process.env.NODE_ENV === 'production') {
app.use(express.static(path.join(__dirname, '../../build')));
console.log("DEBUG HERE", __dirname, path.join(__dirname+'../../build'));
//
app.get('/*', (req, res) => {
res.sendFile(path.join(__dirname+'../../build/index.html'));
})
}
//build mode
app.get('/*', (req, res) => {
res.sendFile(path.join(__dirname+'../../public/index.html'));
})
That buildpack can be configured via a JSON file:
You can configure different options for your static application by writing a static.json in the root folder of your application.
One of the sample routing configurations looks like it does exactly what you want:
When serving a single page app, it's useful to support wildcard URLs that serves the index.html file, while also continuing to serve JS and CSS files correctly. Route ordering allows you to do both:
{
"routes": {
"/assets/*": "/assets/",
"/**": "index.html"
}
}

Resources