I am trying to use react router to have dynamic profile pages, preferably having it in slashes rather than like a ? parameter wildcard in the URL. I'm looking for like /profile/{username}/
rather than /profile?user={username}
if that makes sense.
Here's the route that I'm using to try and achieve this;
<Route path="/profile/:name/" ponent={Profile}/>
But when I try and go to this route as in `/profile/jeff/' or anything it returns a bundle.js (webpack'd) that is a blank HTML template, which is unexpected to be in the bundle.js and throws an error. Any idea's how I can fix this? Thanks.
Here is the bundle.js that gets returned;
<html>
<body style="margin:0px; padding: 0px;">
<link rel="stylesheet" href="styles.css">
<link href="" rel="stylesheet">
<div id = "root" style="margin:0px; padding: 0px;"></div>
<script src="bundle.js"></script>
</body>
Profile ponent;
import React from 'react';
import styles from './profile.scss';
import astyles from './allpages.scss';
export default class Profile extends React.Component{
render(){
console.log("hello!");
const { match, location, history } = this.props
console.log(location);
console.log(match);
console.log(history);
return(
<div className = {styles.borderContainer}>
<p> {this.props.param.name} </p>
</div>
)
}
}
Webpack config;
var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var path = require('path');
require('style-loader');
require('css-loader');
const loaders = {
css: {
loader: 'css-loader'
},
postcss: {
loader: 'postcss-loader',
options: {
plugins: (loader) => [
autoprefixer({
browsers: ['last 2 versions']
})
]
}
},
sass: {
loader: 'sass-loader',
options: {
indentedSyntax: true,
includePaths: [path.resolve(__dirname, './src/app')]
}
}
}
module.exports = {
context: __dirname,
entry: './src/app/index.js',
output: {
path: __dirname + '/dist/',
filename: 'bundle.js',
libraryTarget: 'umd'
},
devtool: "sourceMap",
module: {
loaders: [
{
test: /\.jsx?$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.css$/,
exclude: /node_modules/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
// Could also be write as follow:
// use: 'css-loader?modules&localIdentName=[name]__[local]___[hash:base64:5]!postcss-loader'
use: [
{
loader: 'css-loader',
query: {
modules: true,
localIdentName: '[name]__[local]___[hash:base64:5]'
}
},
'postcss-loader'
]
}),
},
{
test: /\.scss$/,
exclude: /node_modules/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
// Could also be write as follow:
// use: 'css-loader?modules&importLoader=2&sourceMap&localIdentName=[name]__[local]___[hash:base64:5]!sass-loader'
use: [
{
loader: 'css-loader',
query: {
modules: true,
sourceMap: true,
importLoaders: 2,
localIdentName: '[name]__[local]___[hash:base64:5]'
}
},
'sass-loader'
]
}),
},
],
},
plugins: [
new ExtractTextPlugin('styles.css'),
],
}
I am trying to use react router to have dynamic profile pages, preferably having it in slashes rather than like a ? parameter wildcard in the URL. I'm looking for like /profile/{username}/
rather than /profile?user={username}
if that makes sense.
Here's the route that I'm using to try and achieve this;
<Route path="/profile/:name/" ponent={Profile}/>
But when I try and go to this route as in `/profile/jeff/' or anything it returns a bundle.js (webpack'd) that is a blank HTML template, which is unexpected to be in the bundle.js and throws an error. Any idea's how I can fix this? Thanks.
Here is the bundle.js that gets returned;
<html>
<body style="margin:0px; padding: 0px;">
<link rel="stylesheet" href="styles.css">
<link href="https://fonts.googleapis./css?family=Ubuntu" rel="stylesheet">
<div id = "root" style="margin:0px; padding: 0px;"></div>
<script src="bundle.js"></script>
</body>
Profile ponent;
import React from 'react';
import styles from './profile.scss';
import astyles from './allpages.scss';
export default class Profile extends React.Component{
render(){
console.log("hello!");
const { match, location, history } = this.props
console.log(location);
console.log(match);
console.log(history);
return(
<div className = {styles.borderContainer}>
<p> {this.props.param.name} </p>
</div>
)
}
}
Webpack config;
var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var path = require('path');
require('style-loader');
require('css-loader');
const loaders = {
css: {
loader: 'css-loader'
},
postcss: {
loader: 'postcss-loader',
options: {
plugins: (loader) => [
autoprefixer({
browsers: ['last 2 versions']
})
]
}
},
sass: {
loader: 'sass-loader',
options: {
indentedSyntax: true,
includePaths: [path.resolve(__dirname, './src/app')]
}
}
}
module.exports = {
context: __dirname,
entry: './src/app/index.js',
output: {
path: __dirname + '/dist/',
filename: 'bundle.js',
libraryTarget: 'umd'
},
devtool: "sourceMap",
module: {
loaders: [
{
test: /\.jsx?$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.css$/,
exclude: /node_modules/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
// Could also be write as follow:
// use: 'css-loader?modules&localIdentName=[name]__[local]___[hash:base64:5]!postcss-loader'
use: [
{
loader: 'css-loader',
query: {
modules: true,
localIdentName: '[name]__[local]___[hash:base64:5]'
}
},
'postcss-loader'
]
}),
},
{
test: /\.scss$/,
exclude: /node_modules/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
// Could also be write as follow:
// use: 'css-loader?modules&importLoader=2&sourceMap&localIdentName=[name]__[local]___[hash:base64:5]!sass-loader'
use: [
{
loader: 'css-loader',
query: {
modules: true,
sourceMap: true,
importLoaders: 2,
localIdentName: '[name]__[local]___[hash:base64:5]'
}
},
'sass-loader'
]
}),
},
],
},
plugins: [
new ExtractTextPlugin('styles.css'),
],
}
Share
Improve this question
edited Nov 14, 2017 at 18:19
Michael Jungo
33.1k4 gold badges95 silver badges87 bronze badges
asked Nov 14, 2017 at 17:52
Intoxicated PenguinIntoxicated Penguin
3644 silver badges18 bronze badges
7
- Please share the error – Dhaval Jardosh Commented Nov 14, 2017 at 17:55
-
Uncaught SyntaxError: Unexpected token <
– Intoxicated Penguin Commented Nov 14, 2017 at 18:00 - Can you share the Profile ponent code? – Maluen Commented Nov 14, 2017 at 18:04
- can you share webpack.config.js ? – Aaqib Commented Nov 14, 2017 at 18:10
- I added both webpack.config.js & the profile ponent. – Intoxicated Penguin Commented Nov 14, 2017 at 18:15
3 Answers
Reset to default 6When you request /profile/jeff/
you serve the index.html
you posted, and presumably that is done for every resource that doesn't exist on your server (as a fallback). In the index.html
you have the following script tag:
<script src="bundle.js"></script>
This is a relative path. You are actually requesting /profile/jeff/bundle.js
at this point and because that doesn't exist, you end up serving the index.html
as the bundle, which is problematic because it's not valid JavaScript.
You should always use /bundle.js
regardless of the current URL. Similarly you'd always want /styles.css
for your CSS.
<link rel="stylesheet" href="/styles.css">
<script src="/bundle.js"></script>
I don't have a better source for this, but the development server needs to be configured to handle React Routers dynamic routes because it should always serve the same html file (index.html) because it's an SPA.
https://redux.js/docs/advanced/UsageWithReactRouter.html
Edit:
Particularly, I think you are missing this in your webpack config
devServer: {
historyApiFallback: true
}
Edit 2:
For ExpressJS you would need something like this,
app.get('/*', (req, res) => {
res.sendFile(path.join(__dirname, 'index.html'))
})
It looks like it's your stylesheet inclusion. My understanding is that you should be using a babel import statement in your ponent, not link tags, or they will 404 causing the error you are seeing.