subdirs in url breaks react route with custom webpack setup - reactjs

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

Related

Route Component dose not render even though url changes. with custom webpack

code repository url
below is my file structure
and webpack.config.js looks like something like below
const path = require("path");
const HtmlWebPackPlugin = require("html-webpack-plugin");
const entryPoint = path.join(__dirname, "src", "index.js");
module.exports = {
entry: entryPoint,
output: {
path: path.join(__dirname, "public"),
filename: "bundle.js",
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
},
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"],
},
],
},
plugins: [
new HtmlWebPackPlugin({
template: path.join(__dirname, "public", "index.html"),
filename: "./index.html",
}),
],
devServer: {
contentBase: path.join(__dirname, "public"),
historyApiFallback: true,
// publicPath: "/dist/",
},
devtool: "source-map",
stats: {
errorDetails: true,
},
};
i don't know why is it still not working eventhough i have give historyApiFallback
below is my app.js
when i click on the /home route the content is not changing.
could any one please explain me what more i have to add
and my index.js
You need to add exact to your / route otherwise it will match anything starting with / and since it is in a Switch it will be the only one to be matched.
<Switch>
<Route exact path="/" component={() => <div>i am in home</div>} />
<Route exact path="/home" component={() => <div> i am user</div>} />
</Switch>
If the url is not parameterized, i would add exact to /home as well
See: https://reactrouter.com/web/api/Route/exact-bool

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>

accessing resources within nested react-routes using webpack file-loader

I have recently switched my routing using react-router from hashHistory to browserHistory. There is a problem though. Everytime I access a nested route and try and refresh the page, public resources such as my logo can't be found as it uses the first part of the nested route as the root for the resource.
In my index.js I require the image as follows:
require('./images/logo-icon.png');
I am using a logo in my Navigation Bar component as follows:
<Link to="/" className="gc-padding-none">
<img alt="Get Cooked" className="gc-logo-default" src="images/logo-icon.png" />
</Link>
and here are my routes:
<Route path="/" component={NavigationBar}>
<IndexRoute component={Home} />
<Route path="/chefs" component={ProfileList} />
<Route exact path="register" component={Register} redirect />
<Route path="chef">
<Route path="register" component={RegisterChef} />
</Route>
</Route>
and here is my webpack config:
var HtmlWebpackPlugin = require('html-webpack-plugin');
var HTMLWebpackPluginConfig = new HtmlWebpackPlugin({
template: __dirname + '/client/index.html',
filename: 'index.html',
inject: 'body'
});
module.exports = {
entry: [
'./client/index.js'
],
output: {
path: __dirname + '/dist',
filename: 'index_bundle.js',
publicPath: '/'
},
devServer: {
historyApiFallback: true,
inline: true,
contentBase: './client',
port: 8080,
proxy: { '/api/**': { target: 'http://localhost:3000', secure: false } }
},
module: {
loaders: [
{test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader', query: {presets: ['es2015','react'], plugins: ['transform-es2015-destructuring', 'transform-object-rest-spread']}},
{test: /\.jpe?g$|\.gif$|\.svg$|\.png$/i, loader: 'file-loader?name=/images/[name].[ext]'},
{test: /\.css$/, loaders: ['style-loader', 'css-loader', 'postcss-loader', 'sass-loader','resolve-url-loader']},
{test: /\.scss$/, loaders: ['style-loader', 'css-loader','postcss-loader', 'sass-loader','resolve-url-loader']}
]
},
plugins: [HTMLWebpackPluginConfig]
};
Every time I go to '/' or '/chefs' everything loads fine, however, when I access a nested route such as '/chef/register' and refresh my browser the logo cannot be found in the Navigation Bar component.
The error below is presented:
logo-icon.png:1 GET http://localhost:8080/chef/images/logo-icon.png 404 (Not Found)
As you can see the logo is trying to be fetched from a location which includes the first part of my route '/chef'.
I have tried removing the publicPath configuration in my webpack, however, that affects the rendering of nested components on refresh.
Any ideas on why this is happening?
To explain elmeister's comment,
images/logo-icon.png is a relative path making it dependent upon the current path.
So the request for images/logo-icon.png from url http://localhost:8080/chef/ results in a request for http://localhost:8080/chef/images/logo-icon.png.
/images/logo-icon.png is an absolute path ensuring the path is always based upon the root of the site, no matter what the current path might be.
So a request for /images/logo-icon.png from url http://localhost:8080/chef/ will result in a request for http://localhost:8080/images/logo-icon.png.

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

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',
// },

React router cannot get my entry js

Hello i have a problem with react-router, my code
ReactDOM.render(
<Provider store={store}>
<Router history={browserHistory}>
<Route path="/" component={App}>
<IndexRoute component={StartPage}/>
<Route path="/matches" component={MatchesPage} />
<Route path="/sector/:idparam" component={SectorsPage} />
</Route>
</Router>
</Provider>,
app);
When I call /matches everything is OK, but when i try GET /sector/15 app failed try to load http://localhost:8080/sector/client.min.js but normally will load from default path (/)
Webpack:
var debug = process.env.NODE_ENV !== "production";
var webpack = require('webpack');
var path = require('path');
module.exports = {
context: path.join(__dirname, "src"),
devtool: debug ? "inline-sourcemap" : null,
entry: "./js/client.js",
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
loader: 'babel',
query: {
presets: ['react', 'es2015', 'stage-0'],
plugins: ['react-html-attrs', 'transform-decorators-legacy', 'transform-class-properties'],
}
}
]
},
output: {
path: __dirname + "/src/",
filename: "client.min.js"
},
plugins: debug ? [] : [
new webpack.optimize.DedupePlugin(),
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin({mangle: false, sourcemap: false}),
],
devServer: {
historyApiFallback: true,
contentBase: './',
hot: true
},
};
I don't think the issue is with react router, or even webpack. I think your issue is related to how you are requiring your client js file, although since you didn't include that section of code I cannot confirm.
It looks like you are including the script relative to your path
(<script src="client.min.js"></script> no leading slash) instead of an absolute path (<script src="/client.min.js"></script>).

Resources