How to configure webpack dev server with react router dom v4? - reactjs

This is the code of my webpack configuration:
const compiler = webpack({
entry: ['whatwg-fetch', path.resolve(__dirname, 'js', 'app.js')],
module: {
loaders: [
{
exclude: /node_modules/,
test: /\.js$/,
loader: 'babel',
},
],
},
output: {filename: 'app.js', path: '/'},
});
const app = new WebpackDevServer(compiler, {
contentBase: '/public/',
proxy: {'/graphql': `http://localhost:${GRAPHQL_PORT}`},
publicPath: '/js/',
stats: {colors: true},
});
app.use('/', express.static(path.resolve(__dirname, 'public')));
Works fine, the app runs on localhost:3000/index.html but when I try to implement React Router dom v4. It doesn't work. This is the code:
const About = () => <div> <h1>About</h1> </div>
ReactDOM.render(
<BrowserRouter>
<div>
<Route exact path='/' component={App}/>
<Route path='/about' component={About}/>
</div>
</BrowserRouter>,
mountNode
);
This is the result on localhost:3000/
And on localhost:3000/about. I get an error: Cannot GET /about . Not what I'm expecting, why would this not render? About

I do not think it has anything to do with webpack-config. Here is a basic github repository using react-router-4.0. I have created this example without any specific changes related to react-router-4.0 in webpack config.
Add 'devServer' in your webpack config if not already:
devServer: {
historyApiFallback: true,
}
Two small suggestions in your code, try using 'exact' with the path for 'about' i.e.
<Route exact path='/about' component={About}/>
and, add parenthesis for const about i.e.,
const About = () => (<div> <h1>About</h1> </div>);
Hope, this solves your query. Let me know if you require any other information on this.

In my case I had to remove proxy config, because the webpack server wanted a response from http://localhost:3001.
// proxy: {
// '/': 'http://localhost:3001',
// },

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

White page deploying react app with webpack in IIS Server

I'm trying to deploy a react web application based in microfrontends using ModuleFederationPlugin and webpack, but when I try to deploy one of microfrontends in isolation I get a white page without errors.
My webpack configuration to production:
const { merge } = require('webpack-merge')
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin')
const commonConfig = require('./webpack.common')
const packageJson = require('../package.json')
const prodConfig = {
mode: 'production',
output: {
filename: '[name].[contenthash].js',
publicPath: '/Microfrontends/marketing/'
},
plugins: [
new ModuleFederationPlugin({
name: 'marketing',
filename: 'remoteEntry.js',
exposes: {
'./MarketingModule': './src/bootstrap'
},
shared: packageJson.dependencies
})
]
}
module.exports = merge(commonConfig, prodConfig)
My webpack common with babel:
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
module: {
rules: [
{
test: /\.m?js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-react', '#babel/preset-env'],
plugins: ['#babel/plugin-transform-runtime']
}
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html'
})
]
}
My App.js component with React-Router:
export default function App({ history }) {
return (
<Fragment>
<StylesProvider generateClassName={generateClassName}>
<Router history={history}>
<Switch>
<Route exact path="/Microfrontends/marketing/pricing" component={Pricing} />
<Route path="/Microfrontends/marketing/" component={Landing} />
</Switch>
</Router>
</StylesProvider>
</Fragment>
)
}
When I deploy in server all status requests are 200 and the chrome console hasn't errors
Try adding or changing the homepage attribute in the package.json file.
Set it to be relative to the path by using homepage: '.';.
If you still get a white page after doing this it may be that the basename for your Router is not set:
<Router basename='/name' history={history}>
<Switch>
<Route exact path="/Microfrontends/marketing/pricing" component={Pricing} />
<Route path="/Microfrontends/marketing/" component={Landing} />
</Switch>
</Router>

React Route does not work with nested URLs

I am trying to use a switch that routes different components depending on a URL. This URl should be able to be nested, like courses/:cid/assignments/:aid.
This is how my Switch looks like:
<Switch>
<Route path='/courses/:cid/assignments/:aid' component={Assignment} />
<Route exact path="/" component={Home} />
</Switch>
The app runs fine: I can access the home page. However, when I access for example courses/1/assignments/20, I get the following error:
Loading failed for the <script> with source “http://localhost:8081/courses/1/assignmentsets/bundle.js”.
I fiddled around a bit with the paths, just to see where it went wrong and these are the results:
<Switch>
<Route path='/courses/:cid/assignments/:aid' component={Assignments} /> // Does not work
<Route path="/courses/randomnestedurl" component={Assignments} /> // Does not work
<Route path="/courses" component={Assignments} /> // Works fine
<Route path="/:aid" component={Assignments} /> // Works fine
<Route exact path="/" component={Home} /> // Works fine
</Switch>
Does anyone have an idea what could be wrong? Something with my webpack? Some setting I'm missing?
If more code needs to be provided, please let me know which parts of my application would be required.
EDIT: This is my webpack.config.js:
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
const APP_PATH = path.resolve(__dirname, 'src');
module.exports = {
entry: APP_PATH,
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, '/dist'),
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.json']
},
module: {
rules: [
{ test: /\.(ts|js)x?$/, loader: 'babel-loader', exclude: /node_modules/ },
{ test:/\.(s*)css$/, use:['style-loader','css-loader', 'sass-loader'] },
],
},
devServer: {
historyApiFallback: true,
proxy: {
'/api': {
target: 'http://localhost:8080',
secure: false
}
}
},
plugins: [
new HtmlWebpackPlugin({ inject: true, template: path.join(APP_PATH, 'index.html') }),
new ForkTsCheckerWebpackPlugin(),
]`enter code here`
};
That the browser is trying to load your bundle.js from http://localhost:8081/courses/1/assignmentsets/bundle.js indicates that the bundle.js is written as bundle.js instead of /bundle.js in the src attribute of the script tag in your index.html file.
To fix this you could add a publicPath to your Webpack config.
module.exports = {
entry: APP_PATH,
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, '/dist'),
publicPath: '/'
},
// ...
}
Looks like you have your script in the site like:
<script src="bundle.js"></script>
Edit it to be (/ before filename):
<script src="/bundle.js"></script>

react-router-dom 4 routing questions

I'm trying to use react-router-dom 4, But am unable to navigate directly to a route.
Here's a sample of my code:
let Test = (props) => (<div>This is a test component</div>);
let About = (props) => (<div>About us</div>);
class App extends Component {
render () {
return (
<Router>
<div>
<nav>
<NavLink to="/about" activeClassName="selected">About</NavLink>
<NavLink to="/" activeClassName="selected">Test</NavLink>
</nav>
<Route exact path="/" component={Test} />
<Route exact path="/about" component={About} />
</div>
</Router>
)
}
}
When i try to just go to localhost:3000/about, i get Not Found in the browser. But when i go to just localhost:3000, then click on the About link, i get redirected just fine.
in my Console, i get
Uncaught Error: uBlock Origin: aborting content scripts for http://localhost:3000/about
at contentscript.js:90
I'm assuming you're using Webpack. If so, adding a few things to your webpack config should solve the issue. Specifically, output.publicPath = '/' and devServer.historyApiFallback = true. Here's an example webpack config below which uses both of ^ and fixes the refresh issue for me. If you're curious "why", this will help.
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './app/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index_bundle.js',
publicPath: '/'
},
module: {
rules: [
{ test: /\.(js)$/, use: 'babel-loader' },
{ test: /\.css$/, use: [ 'style-loader', 'css-loader' ]}
]
},
devServer: {
historyApiFallback: true,
},
plugins: [
new HtmlWebpackPlugin({
template: 'app/index.html'
})
]
};
when you go to localhost:3000/about,it's run server-side route,and the you don't set server-side route,so you got 404;when you go to just localhost:3000, then click on the About link,now, you run the client route that you have setted. In other word,it's run react-router-dom,so you can got the page

React Router not behaving as I would like it to

I have a webpack, react, flux, react router setup. I have these two routes:
ReactDOM.render((
<Router history={hashHistory}>
<Route path="/" component={Photos} onEnter={someAuthCheck}>
<Route path="/login" component={Login}></Route>
</Route>
</Router>
),document.getElementById('app'));
When I write http://localhost:8080/login in the browser I get:
Cannot GET /login
rather than my login dialog
I am running on the webpack dev server. What am I not doing right?
My webpack config:
var webpack = require('webpack');
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require("extract-text-webpack-plugin");
var BUILD_DIR = path.resolve(__dirname, 'src/client/public');
var APP_DIR = path.resolve(__dirname, 'src/client/app');
var config = {
resolve: {
alias: {
jquery: "jquery/src/jquery"
}
},
entry: {
main: APP_DIR + '/index.jsx',
},
output: {
publicPath: "/src/client/public/",
path: BUILD_DIR,
filename: '[name].js'
},
module : {
loaders : [
{ test : /\.jsx?/, include : APP_DIR, loader : 'babel-loader' },
{ test: /.(woff|woff2|eot|ttf)$/, loader:"url-loader?prefix=font/&limit=5000" },
{test: /\.(scss|css)$/, loader: ExtractTextPlugin.extract('css-loader!sass-loader')}
]
},
plugins: [
new ExtractTextPlugin("[name].css"),
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery"
}),
new HtmlWebpackPlugin({
title: 'PhotoTank',
template: 'src/client/app/html-template.ejs',
filename: '../index.html'
})
],
devServer: {
//publicPath: "/src/client/public/",
//historyApiFallBack: true,
// progress: true,
//hot: true,
//inline: true,
// https: true,
//port: 8081,
contentBase: path.resolve(__dirname, 'src/client'),
proxy: {
"/api": {
target: "http://localhost:5000",
pathRewrite: {"^/api" : ""}
}
}
},
};
module.exports = config;
Usually, if you encounter Cannot GET error, it is an issue with webpack-dev-server. From the docs:
To prepare, make sure you have a index.html file that points to your bundle. Assuming that output.filename is bundle.js:
<script src="/bundle.js"></script>
So, you will have to use webpack to generate an index.html file first, usually called npm run build if you are using some boilerplate, or you have to create a separate webpack config for production build to do so.
Alternatively, just create an empty index.html file as instructed above.
There are also some problems with your react-router configuration:
<Route path="/login" component={Login}></Route>
should be
<Route path="login" component={Login}></Route>
There shouldn't be preceding slashes in children routes.
Also, you should be using browserHistory instead of hashHistory if you want to access the page at /login.
You are using hashHistory, so instead of
http://localhost:8080/login
open this:
http://localhost:8080/#/login it will work.
From Doc:
Hash history uses the hash (#) portion of the URL, creating routes
that look like example.com/#/some/path.
Read the difference between hashHistory and browserHistory.

Resources