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>
Related
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
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
I'm building a React application without using create-react-app, but using webpack to build it and webpack-dev-server to serve it.
My directory structure is:
myApp
|
|---docs/
| |
| |---dist/
| | |
| | |---bundle.js
| |---index.html
|---src/
|---package.json
|---package-lock.json
|---README.md
|---webpack.config.js
and my webpack.config.js is:
module.exports = {
entry: __dirname + '/src/index.js',
output: {
filename: 'bundle.js',
path: __dirname + '/docs/dist'
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ['babel-loader']
},
{
test: [/.css$|.scss$/],
use: [
'style-loader',
'css-loader',
'sass-loader'
]
},
{
test: /\.(jpg|jpeg|png|jpg|gif)$/,
loader: 'file-loader?limit=10000&name=../assets/images/[name].[ext]'
},
{
test: /\.(woff|woff2|eot|ttf|svg)$/,
loader: 'url-loader?limit=100000&name=../assets/fonts/[name].[ext]'
}
]
},
resolve: {
extensions: ['*', '.js', '.jsx']
},
devServer: {
contentBase: './docs',
compress: true,
port: 9000,
historyApiFallback: true
}
};
The Webpack documentation about historyApiFallback says this configuration historyApiFallback: true will redirect all 404 responses to index.html.
It happens that I am using react-router-dom and I have the following routes:
<BrowserRouter>
<Switch>
<Route exact path="/" component={Homepage} />
<Route path="/about" component={About} />
<Route path="/article/:id/show" component={Article} />
<Route path="/donate" component={Donate} />
</Switch>
</BrowserRouter>
Everything is fine with /, /about and /donate, but when I try the route /article/<something>/show I still get a 404 error message, as the image below shows.
It says it can't find the bundle.jsfile. But then, it is not redirecting my route to index.html in the first place. If it were doing so, it would find the bundle.jsfile, as it does in the other routes.
How may I do this work?
EDIT
Setting publicPath to /, as suggested, won't solve the problem. First of all, / is not my asset's path.
Setting it /docs/dist, my real public asset's path, work to some extent. But the solution comes only if you use an absolute path when loading the resources.
You need to specify the publicPath in the output object like so:
output: {
filename: 'bundle.js',
path: __dirname + '/docs/dist',
publicPath: '/'
},
You can read the doc for more insight.
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>).
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.