Problem with filename and path resolve in Webpack with React - javascript

I have following webpack config settings for .css, .js files:
const cssLoaders = (extra) => {
const loaders = [{
loader: MiniCssExtractPlugin.loader,
options: {
hmr: isDev,
reloadAll: true
}
},
{
loader: require.resolve('css-loader'),
options: {
importLoaders: 1,
modules: {
localIdentName: '[path][name]__[local]--[hash:base64:5]',
},
}
},
];
if (extra) {
loaders.push(extra);
}
return loaders;
};
const filename = ext => isDev ? `[name].${ext}` : `[name].[contenthash].${ext}`;
.
.
.
module.exports = {
context: path.resolve(__dirname, 'src'),
mode: 'development',
entry: {
main: ['#babel/polyfill', './index.jsx']
},
output: {
filename: filename('js'),
path: path.resolve(__dirname, 'dist')
},
.
.
.
plugins: [
new MiniCssExtractPlugin({
filename: filename('css'),
})
],
.
.
.
module: {
rules: [
{
test: /\.css$/,
use: cssLoaders()
},
{
test: /\.less$/,
use: cssLoaders('less-loader')
},
{
test: /\.s[ac]ss$/,
use: cssLoaders('sass-loader')
},
.
.
.
The problem is when I add new page (react component) with a new path (/car/model/:id) I see an error that webserver cannot find files:
Can't find http://localhost:4200/cars/model/main.css
Can't find http://localhost:4200/cars/model/main.js
I also have root Application component with following routing code:
class Application extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div className={Styles.container}>
<Switch>
<Route exact path="/" component={Catalogue} />
<Route exact path="/cars/model/:id" component={CarModel} />
<Route path="*" component={NotFound} />
</Switch>
</div>
);
}
}
Everything is ok for the main page, it renders well.
<Route exact path="/" component={Catalogue} />
What should I change to fix it for <Route exact path="/cars/model/:id" component={CarModel} /> ?

Related

React Routing Issue (Without create-react-app)

I have created react app without using CRA command and also installed react router dom v6.
When I have 1 path in url, I don't get any error (like http://localhost:3000 /firstPath ). But, when I have 2 paths in URL (like http://localhost:3000 /firstPath/secondPath ), I get 404 firstPath/main.js not found error. It is searching for main.js inside a folder called firstPath.
In the following code, the index, add and test URLs are working. But the edit URL is not working.
Console Log Image
Sources Tab Image
rootRouter.js code: [BrowserRouter tag is given in the parent file]
import React from "react";
import { Route, Routes } from "react-router-dom";
import Home from "../views/Home";
import Add from "../views/Add";
import Edit from "../views/Edit";
const rootRouter = () => {
return (
<Routes>
<Route exact path="/" element={<Home />} />
<Route path="add" element={<Add />} />
<Route path="edit/:id" element={<Edit />} />
<Route path="test" element={<div>test</div>} />
</Routes>
);
};
export default rootRouter;
webpack.config.js code:
const path = require("path");
const port = process.env.PORT || 3000;
module.exports = {
mode: "development",
entry: "./index.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "main.js",
},
target: "web",
devServer: {
host: "localhost",
port: port,
static: ["./public"],
open: true,
hot: true,
liveReload: true,
historyApiFallback: true,
},
resolve: {
extensions: [".js", ".jsx", ".json", ".ts", ".tsx"],
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ["babel-loader"],
},
{
test: /\.css$/i,
use: ["style-loader", "css-loader"],
},
{
test: /\.png?$/,
use: ["file-loader"],
},
],
},
};

React-router cannot get component when manually modifying url or page refresh [duplicate]

I have the following webpack config file:
var webpack = require('webpack');
var path = require('path');
var BUILD_DIR = path.resolve(__dirname, 'src/client/public');
var APP_DIR = path.resolve(__dirname, 'src/client/app');
var config = {
entry: [
APP_DIR + '/config/routes.jsx',
'webpack/hot/dev-server',
'webpack-dev-server/client?http://localhost:8080'
],
output: {
publicPath: 'http://localhost:8080/src/client/public/'
},
module : {
loaders : [
{
test: /\.jsx?$/,
loader: 'babel-loader',
include: APP_DIR,
exclude: /node_modules/,
query: {
presets: ['es2015']
}
},
{
test: /\.scss$/,
loaders: [ 'style', 'css', 'sass' ]
},
{
test: /\.json$/,
loader: "json-loader"
}
]
}
};
module.exports = config;
all I am trying to do is run my app on localhost, however when I hit: "http://localhost:8080/src/client/home" (as per my routes.jsx and after running webpack-dev-server)
import React from 'react';
import { Route, Router, browserHistory } from 'react-router';
import ReactDOM from 'react-dom';
import Wrapper from './../components/wrapper.jsx';
import Home from './../components/home.jsx';
import Projects from './../components/projects.jsx';
import SingleProject from './../components/projectContent/singleProject.jsx';
import About from './../components/aboutUs.jsx'
ReactDOM.render((
<Router history={browserHistory} >
<Route path="/" component={Wrapper} >
<Route path="home" component={Home} />
<Route path="projects" component={Projects} />
<Route path="projects/:id" component={SingleProject} />
<Route path="about" component={About} />
</Route>
</Router>
), document.getElementById('app'));
I get
"Cannot GET /src/client/home".
First thing you have mentioned in your routes as the home component to have path /home. So you need to visit http://localhost:8080/home. Also if you try to access this url directly, it will give you this error since you are using browserHistory. If you want you can use hashHistory or HashRouter in react-router v4, in which case you will need to visit http://localhost:8080/#/home. If you want to continue using browserHistory or BrowserRouter as in react-router v4, then you will need to add historyApiFallback: true in you webpack
var webpack = require('webpack');
var path = require('path');
var BUILD_DIR = path.resolve(__dirname, 'src/client/public');
var APP_DIR = path.resolve(__dirname, 'src/client/app');
var config = {
entry: [
APP_DIR + '/config/routes.jsx',
'webpack/hot/dev-server',
'webpack-dev-server/client?http://localhost:8080'
],
output: {
publicPath: 'http://localhost:8080/src/client/public/'
},
devServer: {
historyApiFallback: true
},
module : {
loaders : [
{
test: /\.jsx?$/,
loader: 'babel-loader',
include: APP_DIR,
exclude: /node_modules/,
query: {
presets: ['es2015']
}
},
{
test: /\.scss$/,
loaders: [ 'style', 'css', 'sass' ]
},
{
test: /\.json$/,
loader: "json-loader"
}
]
}
};
module.exports = config;
You need to add this in your webpack settings:
devServer: {
historyApiFallback: true,
},
And start your server like this:
webpack-dev-server --config webpack.config.js
Because you want React-Route to handle the route instead of your server. So no matter what the url is it should goes to index.html.

React Route not displaying component on production

I am developing a React Webapp and I am using webpack for automating some tasks. The development mode works fine, I can see all components showing up, but when I open index.html from /dist folder where I have bundle.js and bundle.css same directory the webapp does not show the components.
I tried to upload on a apache web server whole /dist folder and tried to access like localhost/dist still I cannot see the comopnents.
Any idea how to make it so the files within dist folder I can use, in fact that's why I am using webpack to automate tasks so I can use this folder for production.
Webpack:
const HtmlWebPackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CleanWebpackPlugin = require('clean-webpack-plugin');
const webpack = require('webpack');
const path = require('path');
module.exports = (env, argv) => {
console.log("ENV DETECTED: " + argv.mode);
return {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
//publicPath: '/', // Remove this when running in production
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.html$/,
use: [
{
loader: "html-loader",
options: {
minimize: true
}
}
]
},
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
// 'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
minimize: true
}
},
{
loader: 'postcss-loader',
options: {
config: {
path: './postcss.config.js'
}
}
}
]
},
{
test: /\.scss$/,
use: [
argv.mode !== 'production' ? 'style-loader' : MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
importLoaders: 1,
minimize: true
}
},
{
loader: 'postcss-loader',
options: {
config: {
path: './postcss.config.js'
}
}
},
"sass-loader"
]
}
],
},
devServer: {
historyApiFallback: true,
},
plugins: [
new CleanWebpackPlugin('dist', {}),
new HtmlWebPackPlugin({
template: "src/index.html",
filename: "./index.html"
}),
new MiniCssExtractPlugin({
filename: "bundle.css",
chunkFilename: "bundle.css"
}),
require('autoprefixer'),
]
}
};
Routes:
import React from "react";
import { Switch, Route } from 'react-router-dom';
import Helloworld from './components/helloworld/helloworld.component';
import SecondView from './components/secondview/secondview.component';
import ThirdView from "./components/thirdview/thirdview.component";
const AppRoutes = () => (
<main>
<Switch>
<Route exact path='/' component={Helloworld}/>
<Route path='/secondview' component={SecondView}/>
<Route path='/thirdview' component={ThirdView}/>
<Route path='/thirdview/:number' component={ThirdView}/>
</Switch>
</main>
);
export default AppRoutes;
Helloworld component:
import React from 'react';
import HelloworldApi from './helloworld.api';
import { Link , withRouter } from 'react-router-dom';
require('./helloworld.style.scss');
class Helloworld extends React.Component {
constructor(props) {
super(props);
this.state = {
persons: [],
};
}
componentDidMount() {
console.log("I am being called helloworld component...");
HelloworldApi.getAll().then(response => {
if (response.data) {
console.log(response.data);
const persons = response.data;
this.setState({persons});
} else {
console.log(response);
}
});
}
render() {
return (
<div className={"boxDiv"}>
<p>Helloworld components</p>
<h1>Hello World</h1>
<h3>Web pack and React aree awesome together!!! test</h3>
{this.state.persons.map(person => <li>{person.name}</li>)}
<Link to='/secondview'>go to secondview</Link>
</div>
);
}
}
export default withRouter(Helloworld);

Fail to improve site first time loading performance

I am creating a site using HTML5, JavaScript and React.
I am using Google Chrome Lighthouse to check the performance of the site first load.
This is the Lighthouse Runtime environment:
User agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36
Device Emulation Nexus 5X: Enabled
Network Throttling 562.5ms RTT, 1.4Mbps down, 0.7Mbps up: Enabled
CPU Throttling 4x slowdown: Enabled
After many iteration and fixes these are the scores I have on Lighthouse so far:
Performance 57
Progressive Web App 100
Accessibility 100
Best Practices 88
SEO 100
The best Practices is not at 100 because:
the host I have does not provide HTTP/2 (I might change if that's really an issue)
I have Google Ads script with has document.write() (can't change anything about that)
My big problem is with the Performance Metrics.
I have a white blank screen for more than 3.3s and the is fully showing after 8.3s!
The First meaningful paint is at 5,750ms, the first Interactive is at 6,720ms (same for Consistent Interactive)
The Perceptual Speed Index is 4,228 (score 64)
And the Estimated Input Latency is 16ms (score 100)
This is the Critical Chain Request:
This is the Network overview:
This is what I have done/tried so far:
Moved all components in the start page to async load using react-code-splitting
Optimized the images to use the new J2P, JXR and WEBP format, and made them the correct size so the browser does not have to resize them.
Moved the content of App.js into index.js (before the loading would get index.js and vendor.js in parallel, then a js file with all the css files inside and app.js, and after that it would load in parallel the components that are used inside app.js
Moved some css import to the components they are associated with.
Used webpack-bundle-analyzer to try to find common libraries and how they are splitted. As you can see in the following screenshot there are a lot of duplicated modules in my bundles that I cannot find how to extract for efficiency. (lodash, react-overlays,...)
This is my webpack.config.js
const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ChunkManifestPlugin = require('chunk-manifest-webpack-plugin');
const WebpackChunkHash = require('webpack-chunk-hash');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
//var SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin');
const OfflinePlugin = require('offline-plugin');
// To handle the regeneratorRuntime exception
require('babel-polyfill');
require('file-loader');
require('css-loader');
require('style-loader');
require('html-webpack-template');
/* Shared Dev & Production */
const config = {
context: path.resolve(__dirname, 'src'),
entry: {
index: [
// To handle the regeneratorRuntime exception
'babel-polyfill',
'./index.js'
],
vendor: ['offline-plugin/runtime', 'react', 'react-dom', 'react-router', 'react-redux', 'history', 'react-router-dom', 'redux', 'react-router-redux', 'redux-form', 'lodash'],
},
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader',
exclude: /node_modules/,
},
{
test: /\.(ico|jpg|png|gif|eot|otf|jp2|jxr|webp|svg|ttf|woff|woff2)(\?.*)?$/,
exclude: /\/favicon.ico$/,
use: [
{
loader: 'file-loader',
query: {
name: '[path][name][hash].[ext]',
publicPath: '/'
}
}
]
},
{
test: /\.css$/,
include: path.join(__dirname, 'src/style'),
use: [
'style-loader',
{
loader: 'css-loader',
options: {
minimize: true
}
}
]
},
{
test: /\.(ico)(\?.*)?$/,
exclude: /node_modules/,
use: {
loader: 'file-loader',
options: { name: '[name].[ext]' },
},
},
{
test: /\.xml/,
use: {
loader: 'file-loader',
options: { name: '[name].[ext]' },
},
},
],
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].bundle.js',
publicPath: '/',
},
resolve: {
extensions: ['.js'],
modules: [path.resolve(__dirname, 'src'), 'node_modules'],
},
plugins: [
// New moment.js optimization
new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /en/),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: 2
}),
new webpack.optimize.ModuleConcatenationPlugin(),
new HtmlWebpackPlugin({
appMountId: 'app-root',
inlineManifestWebpackName: 'webpackManifest',
template: 'templateIndex.html',
title: 'Our Site',
}),
new OfflinePlugin({
AppCache: false,
ServiceWorker: { events: true },
}),
new BundleAnalyzerPlugin({analyzerMode: 'static'}),
],
devServer: {
historyApiFallback: true,
},
};
//if (process.env.NODE_ENV === 'production') {
config.output.filename = '[name].[chunkhash].js';
config.plugins = [
...config.plugins,
new webpack.HashedModuleIdsPlugin(),
new WebpackChunkHash(),
/*new ChunkManifestPlugin({
filename: 'chunk-manifest.json',
manifestVariable: 'webpackManifest',
inlineManifest: true,
}),*/
];
//}
module.exports = config;
my .babelrc
{
"presets": [
[
"env",
{ "modules": false }
],
"react",
"stage-0",
"stage-2"
],
"plugins": [ "syntax-dynamic-import", "transform-react-jsx", "transform-decorators-legacy" ]
}
And my index.js
import React from 'react';
import { render } from 'react-dom';
import { BrowserRouter } from "react-router-dom";
import {Redirect, Route, Switch, withRouter} from 'react-router';
import { Provider } from 'react-redux';
import Async from 'react-code-splitting';
const TopBar = () => (<Async load={import('./containers/TopBar/TopBarAsync')} />);
const NavBar = () => (<Async load={import('./containers/NavBar/NavBarAsync')} />);
const BottomBar = () => (<Async load={import('./containers/BottomBar/BottomBarAsync')} />);
const UserHelpers = (props) => <Async load={import('./containers/UserHelpers')} componentProps={props} />
const Main = () => (<Async load={import('./containers/Main')} />);
const Blog = () => (<Async load={import('./containers/Blog')} />);
const PublicPage = () => (<Async load={import('./containers/PublicPage')} />);
import configureStore from './store/store';
const store = configureStore();
import './styles/font-awesome.min.css';
import './styles/app.css';
import './styles/TeamBrowser.css';
let googleTracking = null;
if(process.env.NODE_ENV==='production') {
// https://web-design-weekly.com/2016/07/08/adding-google-analytics-react-application/
ReactGA.initialize([my key here]);
googleTracking = function fireTracking() {
let page=window.location.pathname+window.location.search;
ReactGA.set({ page: page });
ReactGA.pageview(page);
}
const runtime=require('offline-plugin/runtime');
runtime.install({
onUpdateReady() {
runtime.applyUpdate();
},
onUpdated() {
window.location.reload();
},
});
}
render((
<Provider
store={store}>
<BrowserRouter
onUpdate={googleTracking}>
<div className="body">
<header>
<TopBar/>
<NavBar />
</header>
<main>
<Switch>
<Route path="/" exact component={Main} />
<Route path="/main" component={Main} />
<Route path="/Feed" component={Blog} />
<Route path="/Blog" component={Blog} />
<Route path="/:id" component={PublicPage} />
<Redirect to="/" />
</Switch>
</main>
<footer
className="footer">
<BottomBar />
</footer>
<UserHelpers />
</div>
</BrowserRouter>
</Provider>),
document.getElementById('app'));
Right now I am out of ideas about how to improve the loading speed to get a better Lighthouse score.
Can anyone spot anything that I do not know about?
To me it looks like chunk-manifest-webpack-plugin is not doing its job properly because it is not extracting all the common modules.
And second, the index.[hash].js bundle contains files that it should not (ex: utils.js, files under the 'actions' folder,... These are my own files, but they are not referenced in my index.js so why does it put them there?

React static site with webpack

I'm trying to create a static site following this tutorial http://jxnblk.com/writing/posts/static-site-generation-with-react-and-webpack/
I'm currently getting this error: ERROR in ReferenceError: document is not defined
This is my app.jsx file:
import React from 'react';
import ReactDOM from 'react-dom';
import { Router } from 'react-router';
import routes from './config/routes';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
}
}
render() {
return (
<Router>{routes}</Router>
);
}
}
export default App;
module.exports = function render(locals, callback) {
var html = React.renderToStaticMarkup(React.createElement(App, locals))
callback(null, '<!DOCTYPE html>' + html)
}
Routes:
import React from 'react';
import { Route, IndexRoute } from 'react-router';
import Layout from '../components/layout';
import Home from '../components/home';
export default (
<Route path="/" component={Layout}>
<IndexRoute component={Home} />
</Route>
);
layout.jsx component:
import React from 'react';
import Nav from './nav';
import Footer from './footer';
import Styles from '../styles.scss';
class Layout extends React.Component {
constructor(props) {
super(props);
this.state = {
}
}
render() {
return (
<div id="layout" className={Styles.main}>
<Nav />
{this.props.children}
<Footer />
</div>
)
}
}
Layout.PropTypes = {
children: React.PropTypes.object.isRequired
}
export default Layout;
and my webpack.config.js file:
/* eslint-disable */
var path = require('path'),
webpack = require('webpack'),
autoprefixer = require('autoprefixer'),
OpenBrowserPlugin = require('open-browser-webpack-plugin');
StaticSiteGeneratorPlugin = require('static-site-generator-webpack-plugin');
data = require('./data');
var configServe = {
port: 9100,
};
module.exports = {
devServer: {
hot: true,
inline: true,
historyApiFallback: true,
progress: true,
port: configServe.port,
},
entry: [
'webpack/hot/dev-server',
'webpack-dev-server/client?http://localhost:' + configServe.port,
path.resolve(__dirname, './src/app.jsx'),
],
output: {
path: __dirname,
filename: './dist/bundle.js',
libraryTarget: 'umd'
},
module: {
loaders: [
{
// JSX files :
test: /\.js[x]?$/,
include: path.resolve(__dirname, 'src'),
exclude: /node_modules/,
loader: 'babel-loader?presets[]=es2015&presets[]=react',
},
{
// CSS files :
test: /\.css?$/,
include: path.resolve(__dirname, 'src'),
loader: 'style-loader!css-loader!postcss-loader',
},
{
// SCSS files :
test: /\.scss?$/,
include: path.resolve(__dirname, 'src'),
loader: 'style-loader!css-loader!postcss-loader!sass',
},
{
test: /\.(png|jpg)$/,
include: path.resolve(__dirname, 'src'),
loader: 'file-loader'
},
{
test: /\.svg$/,
loader: 'svg-inline'
}
],
},
postcss: [
autoprefixer({ browsers: ['last 3 versions'] }),
],
plugins: [
// Avoid publishing files when compilation fails
new StaticSiteGeneratorPlugin('./dist/bundle.js', data.routes, data),
new webpack.NoErrorsPlugin(),
new webpack.HotModuleReplacementPlugin(),
new OpenBrowserPlugin({ url: 'http://localhost:' + configServe.port }),
],
resolve: {
extensions: ['', '.js', '.jsx'],
},
stats: {
// Nice colored output
colors: true,
},
// Create Sourcemaps for the bundle
devtool: 'source-map',
};
Hopefully someone can help me figure this out. I'd like to eventually bundle this all in a non-opinionated way of creating static webpages with React and posting on github.
I guess this line is causing error:
var html = React.renderToStaticMarkup(React.createElement(Root, locals))
There you are using some Root component, but concluding from your code it is not defined. Also it is defined in tutorial (you have pointed out) by this line: var Root = require('./components/Root.jsx')

Categories

Resources