React-Router Broken after changing from hashLocation to browserLocation - reactjs

I can't figure out why after changing from hashLocation to now using browserLocation that after I am able to click the link below to navigate to (render the interview) the interview, but now for some reason once I'm at the interview (I am redirected to the interview component that renders), if I refresh my browser and try to hit interviews/companies/:companyId again when I'm on that same page already, it instead hits my page not found in my express.js implementation.
So again, summarizing this: first time around when I click the link from my main landing page which is where that <Link> resides..when i first load the website, when I click that...it's able to hit interviews/companies/:companyId and render the interview component. All is good, until after you try to hit refresh, it bombs out. Not sure why
server.js
'use strict';
var express = require('express'),
app = module.exports = express(),
port = process.env.PORT || 3000,
path = require('path');
app.use(express.static('client'));
app.use(function (req, res) {
res.send('Sorry, Page Not Found');
});
console.log("port we're about to run on: " + port);
app.listen(port, function () {
console.log('Ready on port %d', port);
}).on('error', function (err) {
console.log(err);
});
On my main landing page, I click a link that's defined like this in one of my React Components:
<Link to={`/interviews/companies/${company.id}`}
params={{id: company.id}}
className="ft-company"
ref="link">
{company.name}
</Link>
which initially works fine. I am sent to /interviews/companies/6 for example and it renders my interview component just fine
Here's my route definitions:
const App = Component({
render() {
return (
<Router history={browserHistory} onUpdate={() => window.scrollTo(0, 0)}>
<Route path="/">
<IndexRoute component={HomePage}/>
<Route name="interview" path="interviews/companies/:companyId" component={Interview}/>
</Route>
<Route path="/" component={Container}></Route>
</Router>
);
}
})

You need to add entry in your webserver to serve the index.html for every get html request .
Import the library:
var history = require('connect-history-api-fallback');
Now you only need to add the middleware to your application like so:
var connect = require('connect');
var app = connect()
.use(history())
.listen(3000);
Of course you can also use this piece of middleware with express:
var express = require('express');
var app = express();
app.use(history());
https://github.com/bripkens/connect-history-api-fallback

Related

Client side routing with react-router and expressJS only works one level deep

I'm trying to use react-router to enable client side routing, but I can only get the routing to behave as expected at one level deep past "/". (i.e. localhost:8080/ works, localhost:8080/{id} works, but localhost:8080/vote/{id} does not)
Additionally, I am trying to develop locally using webpack-dev-server, and deploy to heroku using webpack -p and an expressjs server. My express server is set to have all routes default to index.html.
app.get('/*', (req, res) => {
res.sendFile(path.resolve(__dirname, './dist/index.html'));
});
When using npm start (express server) and I try to navigate to localhost:8080/vote/{id} the console says: SyntaxError: expected expression, got '<' meaning I have a situation like this issue. However, when using webpack-dev-server, I get a different error in the console that says: Loading failed for the with source “http://localhost:8080/vote/bundle.js”. I believe what I'm seeing is two different outputs for the same core problem, the difference being my environment or differences in how express/webpack-dev-server are serving up the content.
Here is my full expressJS server:
const express = require('express');
const path = require('path');
const port = process.env.PORT || 8080;
app = express();
// the __dirname is the current directory from where the script is running
app.use('/', express.static(path.resolve(__dirname, 'dist')));
// send the user to index html page inspite of the url
app.get('/*', (req, res) => {
res.sendFile(path.resolve(__dirname, './dist/index.html'));
});
app.listen(port);
console.log("server started on port " + port);
Here are the relevant parts of my webpack.config.js:
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
publicPath: "/"
},
devServer: {
contentBase: path.resolve(__dirname, "dist"),
historyApiFallback: true
}
And here is my App.js with relevant routes (Home, RealtimeView, PollVote being custom React components):
export default class App extends Component {
render() {
return (
<BrowserRouter history={browserHistory}>
<div>
<Route exact path="/" component={Home} />
<Route exact path="/:id" component={RealtimeView} />
<Route exact path="/vote/:id" component={PollVote}/>
</div>
</BrowserRouter>
);
}
}
With this configuration, I can reliably get localhost:8080/ to work and localhost:8080/{whatever} to work but localhost:8080/vote/{id} or any route more complicated than localhost:8080/{something} fails with the errors I mentioned earlier depending on if I'm using webpack-dev-server or my expressjs server.
FWIW I'm relatively new to webdev (my experience so far is that it's a cluster-fck) and I can't go with a totally isomorphic app because my back-end is in java/spring and I'm not re-writing my whole back-end. I found this post to be helpful but it doesnt solve my problem. Please help this is making me crazy.
Try setting fallback file explicitly:
historyApiFallback:{
index: 'index.html'
}

404 Not Found nginx React

I have a react app and i serve it using express. It work well locally but when i deploy it to heroku i get this error 404 Not Found.
The error is when i open for example this link stand alone on a separate browser window :
http://localhost:9000/projects/5a0df094c27078039346fee2
it works very well. But if i deploy to heroku and then i try the same call i get 404.
If i navigate internally i don't get 404 but this happen only if i open it on a separate window in the browser and its the heroku one .
http://www.mywebsite.website/projects/5a0df05dc27078039346fedf
In my express server i have this code:
// server/app.js
const express = require('express');
const morgan = require('morgan');
const path = require('path');
const app = express();
// Setup logger
app.use(morgan(':remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] :response-time ms'));
// Serve static assets
app.use(express.static(path.resolve(__dirname, '..', 'build')));
app.get('/projects/:ProjectId', (req, res) => {
res.sendFile(path.resolve(__dirname, '..', 'build', 'index.html'));
});
app.get('/projects/', (req, res) => {
res.sendFile(path.resolve(__dirname, '..', 'build', 'index.html'));
});
// Always return the main index.html, so react-router render the route in the client
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, '..', 'build', 'index.html'));
});
app.use(function(req, res, next){
res.status(404);
// respond with html page
if (req.accepts('html')) {
res.render('404', { url: req.url });
return;
}
// respond with json
if (req.accepts('json')) {
res.send({ error: 'Not found' });
return;
}
// default to plain-text. send()
res.type('txt').send('Not found');
});
module.exports = app;
And for my react app i have this code.
<Switch>
<AppliedRoute path="/" exact component={AsyncHome} props={childProps} />
<AppliedRoute
path="/projects/:ProjectId"
exact
component={AsyncSingleProject}
props={childProps}
/>
{/* Finally, catch all unmatched routes */}
<Route component={AsyncNotFound} />
</Switch>
dont know about deployment in heroku, but i have tried deploying in public ip and got the same issue, I think its because routing is working properly in localhost but not working during deployment with nginx.
I have edited the "default" file which is in /etc/nginx/sites-available/default in my machine nginx/1.4.6 (Ubuntu)
sudo gedit /etc/nginx/sites-available/default
Inside the server you can find location, edit that and change to
server{
.......
location / {
try_files $uri /index.html;
}
........
}
Its simple. This worked for me. Hope this will help someone.
Thanks

How to access Node JS route Url in Angular JS site

I am working on a site which is in Angular JS language. Now for website, I have to generate dynamic sitemaps and for this I used Node JS and created a xml.js route in node and wrote hello world.
Now the problem is, I am not able to use access this xml.js in angular site. Here is xml.js code :
var express = require("express");
var router = express.Router();
router.get("/test", function() {
console.log("hello world");
});
module.exports = router;
Here is server.js code :
var express=require('express');
var xml = require("./xml");
var app=express();
app.use('/xml',xml);
app.use('/',express.static('app'));
app.listen(9000) ;
Now whenever I try to access http://192.168.0.19:9000/xml/test I am being redirected to home page always.
Can someone help me out ?
You can try this code.This code work for me
You need to pass req and res parameter.
router.get('/', function (req, res) {
res.send('home page')
})
router.get("/test", function (req, res) {
console.log("hello world");
res.send('test page')
})

React Router cannot GET /route only after deployed to Heroku

I have a simple web-app made with create-react-app and express.
All of the pages made with react router work fine locally, as well as online on my own machine once deployed to Heroku.
But, after testing online on other machines, I can't access these pages - whenever I click the links to them it displays Cannot GET /*route*
I still have the *name*.herokuapp.com domain if that affects it in any way
The redirect code I use is as follows: (I use firebase and react-bootstrap as well)
class App extends Component {
render() {
return (
<div>
<MyNavbar/>
<Switch>
<Route exact path="/" component={Home}/>
<Route exact path="/eateries" component={Eateries}/>
<Route exact path="/thank-you" component={ThankYou}/>
</Switch>
</div>
);
}
Redirecting to /thank-you:
componentWillMount() {
firebase.auth().onAuthStateChanged((user) => {
if (user) {
window.location = "thank-you"
}
})
}
So essentially when a user signs in through a modal component it should take them to /thank-you
Redirecting to /eateries:
<NavItem href="/eateries">
For Eateries
</NavItem>
Is there something wrong with the way I'm redirecting users or using react router in general?
It's hard to know without seeing your server code - but in order to support react-router's rendering mechanism, you need to use a wild card route in your server code:
app.get('*', (req, res) => res.sendFile(path.resolve('build', 'index.html'));
This basically means "for any route not already matched, send the index.html file", which will then load your webapp, which in turn will handle routing. Note that you need to add the static middleware serving your assets before this - that's a gotcha I've forgotten many times. Most of your server file would then look like this:
const express = require('express');
const app = express();
app.use(express.static('build'));
app.get('*', (req, res) => res.sendFile(path.resolve('build', 'index.html'));
app.listen(process.env.PORT, () => console.log('listening for connections'));
Now, this would seem to work either way locally, since your web app is already loaded, and handles routing for you.
However, I've noticed that you're using window.location when redirecting your user. This makes some browsers at least (probably all) request the new page from the server, instead of letting the app deal with it. Instead, use the provided history property, which contains a push method.
componentWillMount() {
firebase.auth().onAuthStateChanged((user) => {
if (user) {
this.props.history.push('/thank-you');
}
});
}
This adds a new entry to the history stack. If you want a regular redirect, you should use .replace instead.
Hope this helps!

Refreshing site with parameters doesn't work in React.js

When I try to refresh the site when the url have a parameter I get a blank page.
My routes.js file is as follows :
const routes = (
<Route path="/" component={App}>
<IndexRoute component={HomePage}/>
<Route path="registration/:id" component={hideIfLoggedIn(Registration)}/>
<Route path="registration" component={hideIfLoggedIn(Registration)}/>
<Route path="reset-password" component={PasswordReset} />
<Route path="portal" component={requireAuth(UserPage)} />
</Route>
);
When I'm on http://localhost:8001/registration everything works perfect. If I refresh the page it works without problems.
But the problem is when I'm on http://localhost:8001/registration/step-one . First time when it loads it works good, but when I try to refresh the site I get a blank page.
EDIT
gulp.task('connect', ['watch'], function () {
connect.server({
root: ['dist'],
port: config.port,
base: config.devBaseUrl,
livereload: true,
fallback: 'dist/index.html'
})
});
You have to configure your server to serve index html for any other route .
Browser request /registration/step-one , it does not found index.html at this path hence fails
Use connect-history-api-fallback.
The middleware is available through NPM and can easily be added.
npm install --save connect-history-api-fallback.
Import the library
var history = require('connect-history-api-fallback');
Now you only need to add the middleware to your application like so
var connect = require('connect');
var app = connect()
.use(history())
.listen(3000);
Of course you can also use this piece of middleware with express:
var express = require('express');
var app = express();
app.use(history());

Resources