Webpack React error: You should not use <Switch> outside a <Router> - reactjs

so i'm trying to setup server side rendering with my React app and I have solved every problem so far but I have run into this one which I cannot solve after a few days of trying.
I'm using the latest of everything included and I run into this error: Error: Invariant failed: You should not use <Switch> outside a <Router>
Below is the react app index
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { BrowserRouter } from 'react-router-dom';
const SSR = (
<BrowserRouter>
<App/>
</BrowserRouter>
);
if(typeof document === "undefined") {
module.exports = SSR;
} else {
ReactDOM.hydrate(SSR, document.getElementById("app"));
}
And the component
import React from 'react';
import { Route, Switch } from 'react-router-dom'
import Home from './components/index'
const NavRoute = ({exact, path, component: Component}) => (
<Route exact={exact} path={path} render={(props) => (
<React.Fragment>
<Navbar/>
<Component {...props}/>
</React.Fragment>
)}/>
)
export default class App extends React.Component {
render() {
return (
<Switch>
<NavRoute exact={true} path="/" component={Home}/>
</Switch>
);
}
}
And my webpack config
const path = require('path');
const webpack = require('webpack');
const nodeExternals = require('webpack-node-externals');
module.exports = [
{
entry: {
client: './server/index.js',
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: "[name].js",
publicPath: '/',
},
target: 'node',
externals: [nodeExternals()],
module: {
rules: [
{ test: /\.jsx?/, loader: "babel-loader"}
]
},
},
{
entry: {
bundle: './src/App.js'
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: "[name].js",
publicPath: '/',
libraryTarget: "umd",
globalObject: "this",
},
module: {
rules: [
{ test: /\.jsx?/, loader: "babel-loader"}
]
},
plugins: [
new webpack.DefinePlugin({
'process.env.BROWSER': JSON.stringify(true),
}),
]
}
]
any help is appreciated let me know if I missed any info out, thank you.

Related

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 cannot GET any specified routes, except the root /

Here's my App.jsx that's first mounted to the DOM:
import React, { Component } from 'react';
import Home from './Home.jsx';
import Representatives from './Representatives.jsx';
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
export default class App extends Component {
constructor() {
super();
this.state = {value: ''};
}
render() {
return (
<Router>
<div>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/representatives" component={Representatives} />
</Switch>
</div>
</Router>
)
}
}
And here's the representative's component:
import React, { Component } from 'react';
export default class Representatives extends Component {
constructor() {
super();
this.state = {value: ''};
}
render() {
return (
<div>
Hello World!
</div>
)
}
}
It looks exactly like examples I've seen and my webpack config looks like other's I've seen in similar posts. Any help would be greatly appreciated, I'm at 4+ hours wracking my brain
Here's my webpack config:
const path = require('path');
const SRC_DIR = path.resolve(__dirname, './src');
const BUILD_DIR = path.resolve(__dirname, './public/');
module.exports = {
mode: 'development',
entry: path.resolve(SRC_DIR, 'index.jsx'),
output: {
filename: 'bundle.js',
path: BUILD_DIR,
publicPath: '/'
},
devServer: {
historyApiFallback: true,
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: [/node_modules/],
use: [{
loader: 'babel-loader',
options: { "presets": [
"#babel/env",
"#babel/react"
] }
}],
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
]
}
}
I added the historyApiFallback: true, and publicPath: '/'
as recommended by another post here.
Here is the index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App/App.jsx';
ReactDOM.render(<App />, document.getElementById('root'));

react-router v4 browserRouter is not working

i don't know what is diffrence in my code.
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const AsyncChunkNames = require('webpack-async-chunk-names-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',
chunkFilename: '[name].bundle.js',
publicPath: '/', // 헐랭이.. 이 게 뭐길래...
},
mode: process.env.NODE_ENV || 'development',
resolve: {
alias: {
'luna-rocket': lunaRocketModulesPath
},
extensions: [
'.js',
],
},
devServer: {
contentBase: path.join(__dirname,'src'),
disableHostCheck: true,
historyApiFallback: true
},
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',
}
},
{
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'),
inject: 'body',
}),
// new AsyncChunkNames()
],
optimization: {
splitChunks:{
cacheGroups: {
default: false,
vendors: false,
vendor: {
name: 'vender',
chunks: "all",
test: "/node_module/",
priority: 20
},
common: {
name: 'common',
minChunks: 2,
chunks: "all",
priority: 10,
reuseExistingChunk: true,
enforce: true
}
}
}
}
};
app.js
import React, { Suspense, lazy } from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter as Router, Route, Switch, HashRouter, withRouter, useRouterHistory , Redirect} from 'react-router-dom'
import Home from './Home';
import RocketComponent from './RocketComponent';
const Loading = () => <div>loading...</div>
ReactDOM.render(
<Router>
<div className="app">
<div className="container">
<Suspense fallback={<Loading />}>
<Route exact path="/" component={Home} />
<Route path="/rocket" component={RocketComponent} />
</Suspense>
</div>
</div>
</Router>,
document.getElementById('app')
);
RocketComponent.js
import HeaderNew from "./HeaderNew";
import React, {lazy, Suspense} from 'react';
import RocketMenuNew from "./RocketMenuNew";
import {Route, Switch} from "react-router-dom";
function scrollToTop() {
document.body.scrollTop = 0
}
const menuData = [
{
title: "LUXAccordion",
path: "/rocket/LUXAccordion",
component: "./Documents/LUXAccordion/AccordionDocument"
},
{
title: "LUXActionBar",
path: "/rocket/LUXActionBar",
component: "./Documents/LUXActionBar/ActionBarDocument"
},
{
title: "LUXBadge",
path: "/rocket/LUXBadge",
component: "./Documents/LUXBadge/BadgeDocument"
},
{
title: "LUXButton",
path: "/rocket/LUXButton",
component: "./Documents/LUXButton/ButtonDocument"
}
]
function DynamicLoader(props) {
// console.log("title", `./Documents/${title.title}/${title.title.substring(3)}Document`)
// const LazyComponent = React.lazy(() => import(`./Documents/${title.title}/${title.title.substring(3)}Document`));
const LazyComponent = lazy(() => import(`${props.component}`));
console.log("LazyComponent", LazyComponent)
return (
<LazyComponent />
);
}
class RocketComponent extends React.Component {
render() {
console.log("this.props.match.path", this.props.match.path)
return (
<div className="documents-new">
<HeaderNew />
<RocketMenuNew />
<Switch>
{menuData.map((props, i) => {
return <Route path={props.path} render={() => <DynamicLoader component={props.component}/>} key={i}/>
})}
</Switch>
</div>
);
}
}
export default RocketComponent
this code is working.
but RocketComponent.js moves to the route directory. is not working.
i don't know why??
RocketComponent.js --> path: app/router/RocketComponent.js
import HeaderNew from "./../HeaderNew";
import React, {lazy, Suspense} from 'react';
import RocketMenuNew from "./../RocketMenuNew";
import {Route, Switch} from "react-router-dom";
function scrollToTop() {
document.body.scrollTop = 0
}
const menuData = [
{
title: "LUXAccordion",
path: "/rocket/LUXAccordion",
component: "./../Documents/LUXAccordion/AccordionDocument"
},
{
title: "LUXActionBar",
path: "/rocket/LUXActionBar",
component: "./../Documents/LUXActionBar/ActionBarDocument"
},
{
title: "LUXBadge",
path: "/rocket/LUXBadge",
component: "./../Documents/LUXBadge/BadgeDocument"
},
{
title: "LUXButton",
path: "/rocket/LUXButton",
component: "./../Documents/LUXButton/ButtonDocument"
}
]
function DynamicLoader(props) {
const LazyComponent = lazy(() => import(`${props.component}`));
return (
<LazyComponent />
);
}
class RocketComponent extends React.Component {
render() {
return (
<div className="documents-new">
<HeaderNew />
<RocketMenuNew />
<Switch>
{menuData.map((props, i) => {
return <Route path={props.path} render={() => <DynamicLoader component={props.component}/>} key={i}/>
})}
</Switch>
</div>
);
}
}
export default RocketComponent
i modify the component path and app.js modify RocketComponent path right.
but is not working
the error is
why is not working, the path is right, please help me .
my webpack is 4, babel 7

Can't load JS bundle on route in React

I have a React app, using webpack. I have added React Router 3 and when trying to visit a route in my app, I get a 404 on the .JS files when on anything but the initial route.
My application is also using a basename as I must prepend the application path.
Routes
import React from 'react'
import Loadable from 'react-loadable'
import { Router, Route, IndexRoute, IndexRedirect } from 'react-router'
import App from './components/App'
const AsyncRoute = loader =>
Loadable({
loader,
loading: () => <h3>Loading...</h3>,
delay: 300,
})
const LandingPage = AsyncRoute(() => import(/* webpackPrefetch: true, webpackChunkName: "landingPage" */ './containers/LandingPage'))
export default ({ history }) => (
<Router history={history}>
<Route path="/:tenant" component={App}>
<IndexRoute component={LandingPage} />
<Route path="foo" component={LandingPage} />
</Route>
</Router>
)
Index
import React, { Fragment } from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import { useRouterHistory } from 'react-router'
import { syncHistoryWithStore } from 'react-router-redux'
import createBrowserHistory from 'history/lib/createBrowserHistory'
import store from './store'
import Router from './routes'
const historyConfig = { basename: '/content-manager' }
const browserHistory = useRouterHistory(createBrowserHistory)(historyConfig)
const history = syncHistoryWithStore(browserHistory, store)
render(
<Provider store={store}>
<Fragment>
<Router history={history} />
</Fragment>
</Provider>,
document.getElementById('root')
)
Webpack.dev
const PORT = process.env.SERVER_PORT || 3000
const HOST = process.env.SERVER_HOST || '127.0.0.1'
module.exports = {
devtool: 'inline-source-map',
mode: 'development',
output: {
filename: '[name].[hash].js',
publicPath: '',
},
devServer: {
host: 'localhost',
port: process.env.PORT || 3200,
historyApiFallback: true,
hot: false,
open: true,
proxy: {
'/api/**': {
target: `http://${HOST}:${PORT}`,
pathRewrite: { '^/api': '' },
secure: false,
logLevel: 'debug',
},
},
},
}
Webpack.common
const commonPaths = require('../common-paths');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CompressionPlugin = require('compression-webpack-plugin');
const Dotenv = require('dotenv-webpack');
module.exports = {
context: commonPaths.appPath,
entry: ['babel-polyfill', './index.jsx'],
resolve: {
extensions: ['.js', '.jsx'],
},
module: {
rules: [
{ test: /\.(jsx?)$/, exclude: /node_modules/, use: ['babel-loader'] },
],
},
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
chunks: 'initial',
test: 'vendor',
name: 'vendor',
enforce: true,
},
},
},
},
plugins: [
new HtmlWebpackPlugin({
title: 'Web App',
template: commonPaths.projectRoot + '/public/index.html',
inject: 'body',
}),
new CompressionPlugin({
algorithm: 'gzip',
test: /\.js$|\.css$/,
threshold: 10240,
minRatio: 0.8,
deleteOriginalAssets: process.env.NODE_ENV === 'prod',
}),
new Dotenv(),
],
};
If I visit http://app.local/content-manager/foo in the browser, the landing page will load.
If I then trying and navigate to http://app.local/content-manager/foo/edit the application does not load and I see the following in the console
GET http://app.local/content-manager/foo/main.fdb34ff55bc02a8cd347.js 404 (Not Found)
edit:1 Refused to execute script from 'http://app.local/content-manager/foo/main.fdb34ff55bc02a8cd347.js' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled.
I believe on the initial route, it is trying to find the js bundle at http://app.local/content-manager but then when I move to a sub route it is looking in http://app.local/content-manager/foo
So I have added
<base href="/content-manager/" />
into my index.html and now it seems to work....

React Router error

hey guys having trouble with react-router, i keep getting this unexpected token you may need an appropriate loader to handle this file type on the line with <Router history={browserHistory}>. im not sure what is going on here any help would be appreciated!
thanks
import React from 'react'
import ReactDOM from 'react-dom'
import { Router, Route, browserHistory } from 'react-router'
import Products from './Products'
import Home from './Home'
document.addEventListener('DOMContentLoaded', function() {
ReactDOM.render(
<Router history={browserHistory}>
<Route path="/" component={Home} />
<Route path="/" component={Products} />
</Router>, document.getElementById('mount')
);
});
webpack.config
var path = require('path');
var config = {
context: path.join(__dirname, 'src/js'),
entry: [
'./main.js',
],
output: {
path: path.join(__dirname, 'www'),
filename: 'bundle.js',
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loaders: ['babel'],
},
],
},
resolve: {
root: [
path.join(__dirname, 'node_modules'),
],
},
};
module.exports = config;
.babelrc
{
"presets": ["es2015", "react"]
}
This isn't a React Router issue but instead is an issue with your JSX transpilation. Check your webpack.config.js file or your .babelrc file.

Resources