React router 4 url issue - reactjs

import React from 'react';
import { Router, Route, Switch } from 'react-router-dom';
import { history } from './history';
import Login from './components/Login';
import Home from './components/Home';
import NotFound from './presentation/NotFound';
import MainContent from './components/MainContent';
import Overview from './components/Overview';
export default () => {
return(
<Router history ={history}>
<Switch>
<Route path="/" component={Login} exact />
<Home>
<Route path="/main" exact component={MainContent} />
<Route path="/admin/:id" exact component={Overview} />
</Home>
<Route component={ NotFound } />
</Switch>
</Router>
);
}
my webpack config is
const path = require('path');
var webpack = require('webpack');
module.exports = {
entry: './src/main.js',
output: {
path: path.join(__dirname, 'public'),
filename: 'bundle.js'
},
module: {
rules: [{
loader: 'babel-loader',test: /\.js$/,exclude: /node_modules/},
{
test: /\.s?css$/,
use: [
'style-loader',
'css-loader',
'sass-loader'
]
}, {
test: /\.(png|jpg|gif)$/,
use: [
'file-loader',
],
},{
test: /\.svg$/,
use: ['#svgr/webpack'],
}, {
test: /\.ttf$/,
loader: "file-loader?limit=10000"
}
]
},
devtool: 'cheap-module-eval-source-map',
devServer: {
contentBase: path.join(__dirname, 'public'),
historyApiFallback: true
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.DefinePlugin({
__CLIENT__: JSON.stringify(true),
__DEVELOPMENT__: true,
__DEVTOOLS__: true
}),
],
optimization:{}
};
So when i land on /main i.e. MainContent component it renders a ViewComponent which renders a list of admins and on click of an individual element of the list it gives the detailed view of the that element on the /admin/:id route which works fine.
but if i refresh or hit the url directly from the address bar, the
fonts' and the images' network request that were being rendered initially
from localhost:8080/somerandomid.ttf are now retrieved from
localhost:8080/admin/somerandomid.ttf throws a 400 bad request error and the styles change.
can anybody suggest how to rectify this error. i am calling a function and passing the id on click of an element from the list.
this.props.history.push('/admin/' + id);
and that ViewComponent is which renders the admin list is connected as export default withRouter(ViewComponent); to get this.props.history.push.
same goes with the image url too. localhost:8080/otherandomid.png is replaced and tried to get > from localhost:8080/admin/otherandomid.png and throws a 400 bad request error with no image
displaying.

You need to set up a base URL.
It can be done with HtmlWebpackPlugin:
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.DefinePlugin({
__CLIENT__: JSON.stringify(true),
__DEVELOPMENT__: true,
__DEVTOOLS__: true
}),
new webpack.HtmlWebpackPlugin({
base: '/'
}),
],
Or directly in the <head> of your index.html file:
<base href="/">

Related

subdirs in url breaks react route with custom webpack setup

I have a simple UI where I display a list of objects and then a form to add one.
The default page shows the list of objects with a menu to add a new one. When I click on the new link, I get a 404
When I click on New Company I get a blank screen and a 404 because it cannot find the main.js
Wondering what the hell is main.js I was looking through my code and see I have it defined in my webpack config;
module.exports = {
mode: "development",
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "public"),
filename: "main.js"
},
target: "node",
devServer: {
port: "9000",
contentBase: ["./public"],
open: true,
historyApiFallback: true
},
resolve: {
extensions: [".js", ".jsx", ".json"]
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
include: /src/,
use: {
loader: "babel-loader"
}
},
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader
},
'css-loader',
'postcss-loader'
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: "styles.css"
}),
new HtmlWebpackPlugin({
template: "public/index.html" //source html
}),
]
}
I thought I had my webpack setup correctly but I think I must be missing something?
Running more tests I added a simple about page that just displayed a heading and had it at /about
const CompanyBox = () => (
<>
<Menu/>
<Switch>
<Route exact path="/">
<CompanyList/>
</Route>
<Route exact path="/companies/new">
<CompanyForm/>
</Route>
<Route path="/companies/:companyId">
<CompanyDetails/>
</Route>
<RolesRoute path="/secret" roles={['admin']}>
<SecretCompanies/>
</RolesRoute>
<Route path="/about">
<About />
</Route>
<Route path="*">
<NoMatch/>
</Route>
</Switch>
</>
)
function About() {
return (
<div>
<h2>About</h2>
</div>
);
}
I also added it to the links in the menu. When I go to the URL directly or via the link it both works
But when I change the url to something like /about/new, I get the error on the console that it can't find the main.js
Not sure why the routes doesn't work when I go 2 levels deep in the url directories
Found the answer here.
I knew it was a webpack config issue, but turns out I had the path to the html file set relatively and not absolute

React router dom is not working in the main app

Good morning,
I am having an issue when working with React router dom using my own webpack configuracion. I know using create-react-app will solve (almost) any issues and is friendly to use, but we would like to have more flexibility.
This is my main application:
import React from 'react'
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'
import Login from '../pages/Login'
import { AppContextProvider } from '../context/AppContext'
const MainApp = () => {
return (
<AppContextProvider>
<Router basename={'nynweb'}>
<Switch>
<Route exact path='/' component={Login} />
<Route exact path='/login' component={Login} />
</Switch>
</Router>
</AppContextProvider>
)
}
export default MainApp
As you can see, it´s very simple. If I use localhost:3000/nynweb in the browser, it works perfectly and the router redirects to the login page. Then, If I type localhost:3000/nynweb/login, it should do exactly the same (at list to my understanding), but it doesn´t. I have the Cannot GET /nynweb/login response instead.
Internally the routing is working, though. I mean, when in the components I use the useHistory push method, it redirects properly (history.push('/login')).
What am I missing? Below I am posting my webpack configuration. Maybe the problem lies there:
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const BabelRules = {
test: /\.(js)$/,
use: ['babel-loader'],
exclude: /node_modules/,
}
const CSSRules = {
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
}
const ImageRules = {
test: /\.(woff(2)?|ttf|otf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'static/fonts/',
},
},
],
}
module.exports = {
entry: './src/index.js',
output: {
path: path.join(__dirname, '/dist'),
filename: 'bundle.js',
publicPath: '/nynweb/',
clean: true,
},
optimization: {
minimize: true,
},
devServer: {
port: 3000,
historyApiFallback: true,
},
module: {
rules: [BabelRules, CSSRules, ImageRules],
},
resolve: {
extensions: ['.js'],
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
}),
],
}
Below I have included a screenshot with the applicacion tree, so that you can see where the static folder is located (all the assets lie there)
As the documentation of Webpack states, the publicPath option allows to serve assets, like images, SVGs etc. What's probably going on is Webpack searching for an asset with the name 'login', but can't find it.
I'd advise you to change this string to your public folder where you store assets (typically, /public).
Also, the example in React-Router documentation adds a forward slash before the basename string.
Clarifications
You set your publicPath variable to /nynweb/, and what Webpack understands is that everything under the '/nynweb/*' path is to be served as an asset.
Change it to, let's say, /nynweb/public/, and now, everything under the '/nynweb/public/*' path is to be served as an asset.
Routes that are not '/nynweb/public/some_route' will now work as expected.

Navigate to a specific page by url in React

How do I navigate to a specific page with url in React?
I realized I've used CRA in the past and haven't really tackled this specifically.
Currently I'm rendering ReactDOM with BrowserRouter and Switch with exact path in Routes
// index.jsx
/* eslint-disable import/extensions */
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import store from './store';
import App from './app/App.jsx';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root'),
);
// App.jsx
import React from 'react';
import { BrowserRouter, Switch, Route } from 'react-router-dom';
import Header from '../components/Header';
import HomePage from '../pages/Home';
import PlansPage from '../pages/Plans';
import NotFoundPage from '../pages/NotFound';
const App = () => (
<BrowserRouter>
<Header />
<Switch>
<Route exact path="/" component={HomePage} />
<Route exact path="/plans" component={PlansPage} />
<Route component={NotFoundPage} />
</Switch>
</BrowserRouter>
);
export default App;
// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
const webpack = require('webpack');
module.exports = {
devtool: false,
module: {
rules: [
{
test: /\.m?(js|jsx)$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
},
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.scss$/,
use: [{
loader: 'style-loader',
options: {
sourceMap: true,
},
}, {
loader: 'css-loader',
options: {
sourceMap: true,
},
}, {
loader: 'sass-loader',
options: {
sourceMap: true,
},
}],
},
],
},
entry: './src/index.jsx',
output: {
path: path.resolve(__dirname, './dist'),
filename: 'index_bundle.js',
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
filename: './index.html',
}),
new webpack.SourceMapDevToolPlugin({}),
],
};
Navigating to http://localhost:8080/plans leads to a page with Cannot GET /plans. However, clicking on a Link element navigates to that plans page without an issue.
Yeah since you're using webpack Dev Server all you have to do is add historyApiFallback=true and it'll fix you issue. You're essentially telling all routes to fall back to your index.html file. Hope that helped.

react-router-dom v4 router is not working

router is not working.
localhost:3000/, localhost:3000/#/, localhost:3000/#/aa ==> all moves in home page.
index.js
import ReactDOM from 'react-dom'
import { BrowserRouter, Route, Switch } from 'react-router-dom'
ReactDOM.render(
<BrowserRouter>
<div>
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/aa" component={Main}/>
</Switch>
</div>
</BrowserRouter>,
document.getElementById('app')
);
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const lunaRocketModulesPath = path.resolve(__dirname, 'luna-rocket');
module.exports = {
entry: [
'#babel/polyfill',
path.join(__dirname,'src/app','app.js')
],
output: {
path: path.join(__dirname,'build'),
filename: 'index.bundle.js'
},
mode: process.env.NODE_ENV || 'development',
resolve: {
alias: {
},
extensions: [
'.js',
],
},
devServer: {
contentBase: path.join(__dirname,'src')
},
module: {
rules: [
{
// this is so that we can compile any React,
// ES6 and above into normal ES5 syntax
test: /\.(js)$/,
// we do not want anything from node_modules to be compiled
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env']
}
}
},
{
test: /\.(css|scss)$/,
use: [
"style-loader", // creates style nodes from JS strings
"css-loader", // translates CSS into CommonJS
"sass-loader" // compiles Sass to CSS, using Node Sass by default
]
},
{
test: /\.(jpg|jpeg|png|gif|mp3|svg)$/,
loaders: ['file-loader']
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname,'src','index.html')
}),
]
};
how to move aa??? please help me.
i don't why router is not working.
and url in # is what is meaning in react??
if localhost:3000/aa--> devServer is working
if localhost:3000/#/aa ==> Home page
(React 16, babel7, wepack4)
I can't really identify was wrong here, but try removing the <Switch></Switch> around the routes and also <Route exact path="/aa" component={Main}/>
without exact this also matches the first route
Actually with /#/aa you are just routing towards / because # specifies an "Anchor", or a position on the page, and allows you to "jump" or "scroll" to that position on the page.
your Main will be available at localhost:3000/aa

Cannot GET "/About" with react-router v4 (Production Help)

I've been reading over all the docs for react-router-dom (v4), and tons of Stack Overflow questions with my same error, but A) They leave a lot of unanswered holes and B) They seem to all be suggesting a development only fix, so I'm hoping to see what people are actually doing in PRODUCTION for this simple scenario and C) I'm probably doing something stupid and the answers aren't working for me, with the error "Cannot GET /about" rendering with no errors in the console.
I'm using Express, React, Node and using Webpack for compiling. I can successfully reach my homepage, and clicking any links takes me to the appropriate components, but manually typing in the URL breaks this, as discussed here and the reasons for this error discussed here.
Most answers suggest adding devServer.historyApiFallback = true and output.publicPath = '/' in the webpack.config.js file, which implies I also need to run npm install --save-dev webpack-dev-server and run it using node_modules/.bin/webpack-dev-server as suggested in the docs. Doing all of this, nothing happens. In fact, it's worse now because I also can't access my home route of '/'.
So before dropping my current config here, 1) What can I do to fix this? 2) Does it even matter? The webpack-dev-server is obviously for development only so what about production?
My webpack.config.js file:
var webpack = require('webpack');
var path = require('path');
var envFile = require('node-env-file');
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
try {
envFile(path.join(__dirname, 'config/' + process.env.NODE_ENV + '.env'))
} catch (e) {
}
module.exports = {
devServer: {
historyApiFallback: true,
},
entry: [
'script-loader!foundation-sites/dist/js/foundation.min.js',
'./app/app.jsx'
],
plugins: [
new webpack.DefinePlugin({
'process.env': {
//you don't get to see this
}
})
],
output: {
path: __dirname,
filename: './public/bundle.js',
publicPath: '/'
},
resolve: {
modules: [
__dirname,
'node_modules',
'./app/components',
'./app/api'
],
alias: {
app: 'app',
applicationStyles: 'app/styles/app.scss',
actions: 'app/actions/actions.jsx',
configureStore: 'app/store/configureStore.jsx',
reducers: 'app/reducers/reducers.jsx'
),
},
extensions: ['.js', '.jsx']
},
module: {
rules: [
{
loader: 'babel-loader',
query: {
presets: ['react', 'es2015', 'stage-0']
},
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/
},
{
loader: 'url-loader?limit=100000',
test: /\.(jpg|png|woff|woff2|eot|ttf|svg)$/
},
{
loader: 'sass-loader',
test: /\.scss$/,
options: {
includePaths: [
path.resolve(__dirname, './node_modules/foundation-sites/scss')
]
}
}
]
},
devtool: process.env.NODE_ENV === 'production' ? false : 'source-map'
};
My app.jsx:
var React = require('react');
var ReactDOM = require('react-dom');
import {Provider} from 'react-redux';
import {BrowserRouter as Router, Route, Switch, Link, HashRouter} from 'react-router-dom';
import Home from 'Home';
import Watch from 'Watch';
import About from 'About';
import AddShow from 'AddShow';
var store = require('configureStore').configure();
import firebase from 'app/firebase/';
// Load Foundation
$(document).foundation();
// App css
require('style-loader!css-loader!sass-loader!applicationStyles');
ReactDOM.render(
<Provider store={store}>
<Router>
<div>
<Route exact path="/" component={Home}/>
<Route path="/watch" component={Watch}/>
<Route path="/about" component={About}/>
<Route path="/addshow" component={AddShow}/>
</div>
</Router>
</Provider>,
document.getElementById('app')
);
You have to set up your web server (the one that serves index.html with the react app) to redirect all requests to the url of your index.html so that react-router can do its job. That's what the suggested change to webpack.config.js is doing for webpack-dev-server
In your webpack.config.js you need to enable the html plugin so webpack knows where your index.html is:
plugins: [
new webpack.DefinePlugin({
'process.env': {
//you don't get to see this
}
}),
new HtmlWebpackPlugin({
template: 'public/index.html' //or wherever your index.html is
})
],

Resources