How can I render a react application compiled in a bundle.js? - reactjs

So I have a React application that was compiled into a bundle.js file. The index.tsx file of the React application shows that the App component will be rendered in a DOM element with ID "scheduleSitesGrid2" as showed on this picture:
I have been able to bundle this react app and host the bundle on Azure Storage. In fact, if I create a simple HTML file that only contains a div and a script with a src pointing to the azure url, I am able to see the bundle.js in Chrome DevTools:
When I open the dummy index.html, I cannot see the React App component. There are no errors on the console as well.
I also tried to add breakpoints in the App component and they are triggered when the page loads. I am just wondering where the index.html page is blank even if I inserted a div with the valid ID.
Here is my App.tsx file:
import React, {Component} from 'react';
import '#progress/kendo-theme-default/dist/all.css';
import './App.css';
import jobs from './jobs.json';
import { Grid, GridColumn } from '#progress/kendo-react-grid';
import { DropDownListChangeEvent } from '#progress/kendo-react-dropdowns';
import EditIconComponent from "./components/editicon.component";
import UploadIconComponent from "./components/uploadicon.component";
export default class App extends Component {
handleDropDownChange = (e: DropDownListChangeEvent) => {
this.setState({
dropdownlistCategory: e.target.value.CategoryID
});
}
state = { skip: 0, take: 5 }
pageChange = (event: any) => {
this.setState({
skip: event.page.skip,
take: event.page.take
});
}
render() {
return (
<div className="App">
<Grid
resizable={true}
pageable={true}
skip={this.state.skip}
take={this.state.take}
total={jobs.length}
onPageChange={this.pageChange}
data={jobs.slice(this.state.skip, this.state.take + this.state.skip)}>
<GridColumn field="null" title=" " cell={EditIconComponent} resizable={false} width="50px"/>
<GridColumn field="null" title=" " cell={UploadIconComponent} resizable={false} width="50px"/>
<GridColumn field="technology" title="Technology" />
<GridColumn field="marketcost" title="Market/Cost"/>
<GridColumn field="num" title="Job #" />
<GridColumn field="locationCode" title="Location Code" />
<GridColumn field="siteName" title="Site Name" />
<GridColumn field="pin" title="PIN" />
<GridColumn field="status" title="Job Status" />
</Grid>
</div>
);
}
}
Here is the entire index.tsx file:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(<App />, document.getElementById('scheduleSitesGrid2'));
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: .....
serviceWorker.unregister();
And here is my package.json
{
"name": "kendo-grid-test",
"version": "0.1.0",
"private": true,
"dependencies": {
"#progress/kendo-data-query": "^1.5.2",
"#progress/kendo-drawing": "^1.6.0",
"#progress/kendo-react-dateinputs": "^3.6.0",
"#progress/kendo-react-dialogs": "^3.6.0",
"#progress/kendo-react-dropdowns": "^3.6.0",
"#progress/kendo-react-grid": "^3.6.0",
"#progress/kendo-react-inputs": "^3.6.0",
"#progress/kendo-react-intl": "^3.6.0",
"#progress/kendo-theme-default": "^4.5.2",
"#types/jest": "24.0.19",
"#types/node": "12.11.6",
"#types/react-dom": "16.9.2",
"react": "^16.11.0",
"react-dom": "^16.11.0",
"react-scripts": "3.2.0"
},
"scripts": {
"start": "react-scripts start",
"build": "./node_modules/.bin/webpack",
"pack": "webpack --config webpack.config.js",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"#babel/core": "^7.6.4",
"#babel/preset-env": "^7.6.3",
"#babel/preset-react": "^7.6.3",
"#types/react": "^16.9.9",
"babel-loader": "^8.0.6",
"glob": "^7.1.5",
"source-map-loader": "^0.2.4",
"ts-loader": "^6.2.1",
"typescript": "^3.6.4",
"uglifyjs-webpack-plugin": "^2.2.0",
"webpack-cli": "^3.3.10"
}
}
UPDATE
When I created the bundle, public/index.html was an empty file. If I add some basic html code and include the div with id scheduleSitesGrid2, I see that App component is working fine:
Thank you!

I found the issue. I had an issue in my Webpack.config.js file. I set the entry to src/App.tsx, but I changed it to src/index.tsx.
Thank you so much everyone for your help!
Have a good day
Here is my Webpack.config if someone needs it:
"use strict"
const path = require('path');
module.exports = {
entry: './src/index.tsx',
output: {
filename: "bundle.js",
path: path.resolve(__dirname, 'dist')
},
devServer: {
publicPath: "/",
contentBase: "./public",
hot: true
},
resolve: {
extensions: ['.ts', '.tsx', '.js']
},
devtool: "inline-source-map",
module: {
rules: [{
test: /\.(ts|tsx)$/,
use: 'ts-loader',
exclude: /node_modules/
},
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
}]
}
};

Related

Uncaught TypeError: Cannot read properties of null (reading 'useContext')

so no where in my react code do I use the useContext property. I have a npm package which has a compiled webpack file that has a component in there. when i try to use the component in my react app it throw the error Uncaught TypeError: Cannot read properties of null (reading 'useContext'). the component function is there and outputs a react object. it just breaks the page when using it. now I looked into what useContext is and I believe it has something to do with state.
so below is my input component that I will be using in my react App
import React from 'react';
import {TextField} from '#mui/material';
class Input extends React.Component {
constructor(props){
super(props)
}
render(){
return (
<div className="input" style={{position:"relative",left:this.props.tabOver? this.props.tabOver.toString()+"px":"0px"}}>
<label style={{display:"block", width:"100%",position:"relative", margin: "5px"}}> {this.props.labelName}</label>
<TextField
size="small"
onChange={(e)=>{this.props.update(e.target.value)}}
value={this.props.value}
label={this.props.label? this.props.label:"type here"}
error={this.props.error? this.props.error:false}
required={this.props.required? this.props.required:false}
disabled={this.props.disabled? this.props.disabled:false}
helperText={this.props.helperText? this.props.helperText:""}
InputProps={{ style: { fontSize: this.props.InputProps? this.props.InputProp:10 } }}
InputLabelProps={{ style: { fontSize: (this.props.InputLabelProps? this.props.InputLabelProps:12) } }}
style={{background:'white', "borderLeft":"20px solid "+this.props.border,"borderRadius": "10px",width: this.props.width !== undefined ? this.props.width.toString()+"px":"100px"}}
id="filled-basic"
variant="filled" />
</div>
);
}
}
export default Input;
and here is my react Application that uses Input
// import logo from './logo.svg';
import './App.scss';
import React from 'react';
import {Breadcrumbs,Link,Typography} from '#mui/material';
import {Input} from '#zenaby/something';
class App extends React.Component {
constructor(props){
super(props)
}
render(){
return (
<div className="App">
<ul className="header">
<li> logo </li>
<li> login </li>
</ul>
<div className="formCt">
<Input />
</div>
</div>
);
}
}
export default App;
I compiled this input with this webpack file
const path = require('path');
module.exports = {
entry: "./compile/index.js",
mode:"production",
output: {
path: path.resolve(__dirname, 'dist'),
filename: "index.js",
libraryTarget: "commonjs2"
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ["#babel/preset-react",
"#babel/preset-env"],
plugins: ["#babel/plugin-proposal-class-properties"]
}
}
}
]
},
target: 'node'
};
also my package json is here
{
"name": "somename",
"version": "0.1.0",
"private": false,
"babel": {
"presets": [
"#babel/preset-react"
]
},
"main":"dist/header.js",
"dependencies": {
"#testing-library/jest-dom": "^5.16.4",
"#testing-library/react": "^13.2.0",
"#testing-library/user-event": "^13.5.0",
"react-dom": "^18.1.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"pp": "babel .components -d ./dist --ignore 'node_modules'",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"description": "This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).",
"author": "grant",
"license": "ISC",
"peerDependencies": {
"react": "^18.1.0"
},
"devDependencies": {
"#babel/cli": "^7.17.10",
"#babel/plugin-syntax-jsx": "^7.17.12",
"#babel/preset-react": "^7.17.12"
}
}
I wish this was an easy answer but being on this issue for hours I don't have any juice left in me to figure it out. in fact this answer could be helpful to alot of people who are new making components for npmjs. anyways thank you for looking at it any feedback is great :).
This often happens if the packages are installed in different levels.
The mistake
app
|node_modules <-- some packages installed here
|package.json
node_modules
package.json <-- some packages installed here
Correct Way
app
|node_modules
|package.json <-- install all the packages at the same heirarchy
the answer was i had forgot to delete my node_modules in my other package and react was duplicated also throwing the error saying react hooks error. React hooks duplicate react package
January 2023:
I also had this error Cannot read properties of null (reading 'useContext')
I solved it by adding 'rollup-plugin-peer-deps-external' to my rollup.config.mjs
import resolve from '#rollup/plugin-node-resolve';
import commonjs from '#rollup/plugin-commonjs';
import typescript from '#rollup/plugin-typescript';
import dts from 'rollup-plugin-dts';
import PeerDepsExternalPlugin from 'rollup-plugin-peer-deps-external'; //<--- THIS
import packageJson from "./package.json" assert {type: 'json'};
export default [
{
input: "src/index.ts",
output: [
{
file: packageJson.main,
format: "cjs",
sourcemap: true,
},
{
file: packageJson.module,
format: "esm",
sourcemap: true,
},
],
plugins: [
PeerDepsExternalPlugin(), //<--- THIS
resolve(),
commonjs(),
typescript({ tsconfig: "./tsconfig.json" }),
],
},
{
input: "dist/esm/types/index.d.ts",
output: [{ file: "dist/index.d.ts", format: "esm" }],
plugins: [dts()],
},
];

Problem using a NPM Package builded with Rollup

I am creating a npm package with react components, providers, and other utilities. The idea is use this npm package in other projects. I configured rollup to create the builds but when I try to use it in another project I got a "React is not defined" error.
Here is my code and the error in detail:
package.json:
{
"name": "myapp",
"version": "0.1.14",
"description": "Npm package.",
"main": "lib/index.cjs.js",
"module": "lib/index.esm.js",
"files": [
"dist",
"README.md"
],
"scripts": {
"start": "react-scripts start",
"build": "npx rollup -c",
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": ""
},
"author": "",
"license": "ISC",
"dependencies": {
"#babel/polyfill": "^7.12.1",
"#fluentui/react": "8.52.2",
"#rjsf/core": "4.2.0",
"#rjsf/fluent-ui": "4.2.0",
"#types/node": "^17.0.21",
"#types/react": "^17.0.40",
"#types/react-dom": "^17.0.13",
"axios": "^0.25.0",
"office-ui-fabric-core": "^11.0.0",
"react-query": "^3.34.19",
"react-simple-resizer": "^2.1.0"
},
"peerDependencies": {
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
"#fluentui/react": "8.52.2"
},
"devDependencies": {
"#babel/cli": "^7.17.0",
"#babel/core": "^7.17.0",
"#babel/preset-env": "^7.16.11",
"#babel/preset-react": "^7.16.7",
"#fluentui/example-data": "^8.4.0",
"#rollup/plugin-babel": "^5.3.0",
"#rollup/plugin-commonjs": "^21.0.1",
"#rollup/plugin-node-resolve": "^13.1.3",
"#rollup/plugin-replace": "^4.0.0",
"#rollup/plugin-typescript": "^8.3.1",
"react-scripts": "^5.0.0",
"rollup": "^2.67.1",
"rollup-plugin-import-css": "^3.0.3",
"rollup-plugin-includepaths": "^0.2.4",
"rollup-plugin-peer-deps-external": "^2.2.4",
"rollup-plugin-terser": "^7.0.2",
"typescript": "^4.6.2",
"react": "^17.0.2",
"react-dom": "^17.0.2"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
rollup.config.js:
import babel from "#rollup/plugin-babel";
import resolve from "#rollup/plugin-node-resolve";
import commonjs from "#rollup/plugin-commonjs";
import includePaths from "rollup-plugin-includepaths";
import peerDepsExternal from "rollup-plugin-peer-deps-external";
import { terser } from "rollup-plugin-terser";
import pkg from "./package.json";
import typescript from "#rollup/plugin-typescript";
import css from "rollup-plugin-import-css";
import replace from "#rollup/plugin-replace";
const outputs = [
{
file: pkg.main,
format: "umd",
},
{
file: pkg.module,
format: "es",
}
]
const external = [
...Object.keys(pkg.peerDependencies || {})
].map(name => RegExp(`^${name}($|/)`))
const config = outputs.map(({ file, format }) => ({
input: "src/lib/index.js",
output: {
file,
format,
name: "ReactPackage",
globals: {
react: "React",
"react-dom": "ReactDOM",
"#fluentui/react": "FluentUI",
}
},
external,
plugins: [
typescript(),
peerDepsExternal(),
includePaths({
include: {},
paths: ["src/lib"],
external: Object.keys(pkg.dependencies),
extensions: ['.js', '.json', '.html', '.tsx', '.ts']
}),
css(),
babel({
babelHelpers: "bundled",
exclude: "node_modules/**",
configFile: "./babel.config.rollup.js",
}),
resolve({
browser: true
}),
commonjs(),
terser(),
replace({
preventAssignment: true,
'process.env.NODE_ENV': JSON.stringify('production')
})
],
}));
export default config;
Babel:
const pkg = require('./package.json');
module.exports = {
presets: [
[
'#babel/preset-env',
{
modules: false,
targets: pkg.browserslist.production,
},
],
[
'#babel/preset-react',
{
"runtime": "automatic"
}
]
],
ignore: ['node_modules/**'],
};
The provider that I am trying to use but I get an "React is not defined" error:
Provider.ts:
import PContext from "../contexts/pContext";
import { QueryClient, QueryClientProvider } from "react-query";
import React, { useState } from "react";
const queryClient = new QueryClient();
const PProvider = ({ children, url }) => {
const [active, setActive] = useState(null);
return (
<PContext.Provider
value={{
url,
active,
setActive
}}
>
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
</PContext.Provider>
);
};
export default PProvider;

React + Redux + Typescript Chrome Extension Popup Script - Redux Devtools Shows "No Store Found"

I am creating a chrome extension that is mainly served in a popup script.
Manifest.json
// public/manifest.json
{
"manifest_version": 3,
"version": "3.0.0",
"name": "__MSG_appName__",
"description": "__MSG_appDesc__",
"default_locale": "en",
"author": "lbragile",
"homepage_url": "some_url_not_relevant_to_question_at_hand",
"permissions": ["tabs", "storage"],
"optional_permissions": ["contextMenus", "alarms", "downloads", "downloads.shelf"],
"icons": {
"16": "images/logo16.png",
"48": "images/logo48.png",
"128": "images/logo128.png"
},
"action": {
"default_icon": {
"16": "images/logo16.png",
"48": "images/logo48.png",
"128": "images/logo128.png"
},
"default_popup": "index.html",
"default_title": "title"
},
"background": {
"service_worker": "background.js"
},
"incognito": "split"
}
Package.json
// package.json
{
"name": "name",
"version": "0.0.1",
"description": "description",
"author": "lbragile",
"private": true,
"dependencies": {
"nanoid": "^3.1.30",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-redux": "^7.2.5",
"react-router-dom": "^5.3.0",
"react-scripts": "4.0.3",
"redux": "^4.1.1"
},
"devDependencies": {
"#babel/core": "^7.13.14",
"#babel/preset-env": "^7.13.12",
"#babel/preset-react": "^7.13.13",
"#fortawesome/fontawesome-svg-core": "^1.2.36",
"#fortawesome/free-regular-svg-icons": "^5.15.4",
"#fortawesome/free-solid-svg-icons": "^5.15.4",
"#fortawesome/react-fontawesome": "^0.1.15",
"#types/chrome": "0.0.159",
"#types/express": "^4.17.13",
"#types/node": "^16.10.3",
"#types/react": "^17.0.15",
"#types/react-dom": "^17.0.9",
"#types/react-redux": "^7.1.19",
"#types/react-router-dom": "^5.1.8",
"#types/redux-immutable-state-invariant": "^2.1.2",
"#types/remote-redux-devtools": "^0.5.5",
"#types/styled-components": "^5.1.12",
"#typescript-eslint/eslint-plugin": "^5.0.0",
"#typescript-eslint/parser": "^5.0.0",
"babel-loader": "^8.2.3",
"babel-plugin-styled-components": "^1.13.2",
"copy-webpack-plugin": "^9.0.1",
"eslint": "^7.11.0",
"eslint-plugin-react": "^7.24.0",
"eslint-plugin-react-hooks": "^4.2.0",
"eslint-plugin-styled-components-a11y": "0.0.34",
"redux-devtools-extension": "^2.13.9",
"styled-components": "^5.3.0",
"stylelint": "^13.13.1",
"stylelint-config-standard": "^22.0.0",
"ts-loader": "^9.2.6",
"typescript": "^4.3.5",
"url-loader": "^4.1.1",
"webpack": "^5.59.1",
"webpack-cli": "^4.9.1"
},
"scripts": {
"lint": "npx eslint {src,public}/**/**/*.[jt]s -c config/.eslintrc.js --ignore-path .gitignore .",
"lint:style": "npx stylelint {src,public}/**/**/*.css --config config/.stylelintrc.json",
"start": "webpack --config config/webpack.config.js --watch --progress"
},
"babel": {
"extends": "./config/.babelrc.json"
},
"eslintConfig": {
"extends": "./config/.eslintrc.js"
},
"stylelint": {
"extends": "./config/.stylelintrc.json"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
Webpack
// config/webpack.config.js
const path = require("path");
const CopyPlugin = require("copy-webpack-plugin");
module.exports = {
entry: {
popup: path.resolve(__dirname, "../src/index.tsx"),
background: path.resolve(__dirname, "../src/background.ts"),
},
plugins: [
new CopyPlugin({
patterns: [{ from: "public", to: "." }],
}),
],
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: "babel-loader",
exclude: /node_modules/,
},
{
test: /\.ts(x)?$/,
loader: "ts-loader",
exclude: /node_modules/,
},
{
test: /\.png$/,
use: [
{
loader: "url-loader",
options: {
mimetype: "image/png",
},
},
],
},
],
},
resolve: {
extensions: [".js", ".jsx", ".ts", ".tsx"],
},
mode: "production",
output: {
path: path.resolve(__dirname, `../dist`),
filename: "[name].js",
},
};
Problem
I've tried redux-devtools-extension:
// src/index.tsx
import React from "react";
import ReactDOM from "react-dom";
import App from "./components/App";
import { Provider } from "react-redux";
import { createStore } from "redux";
import { composeWithDevTools } from "redux-devtools-extension";
import rootReducer from "./store/reducers";
export const store = createStore(rootReducer, composeWithDevTools());
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById("root")
);
which shows:
I've also tried using remote-redux-devtools:
// src/index.tsx
import React from "react";
import ReactDOM from "react-dom";
import App from "./components/App";
import { Provider } from "react-redux";
import { createStore } from "redux";
import devToolsEnhancer from "remote-redux-devtools";
import rootReducer from "./store/reducers";
export const store = createStore(rootReducer, devToolsEnhancer());
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById("root")
);
which seems more promising, but has no data in the store:
When I run in the browser, using npm start (react-scripts start), I do see the store in the Redux DevTools extension, so I am not sure what the problem is.
Possible Idea
When I build with React (react-scripts build), I can see the store just fine. The issue is that I cannot use react as it's build times are too slow and using webpack seems like the most logical alternative. Here is the build output:
Any ideas?
Note: this answer was originally added by OP as an edit to their original question, I have just reposted it as an answer.
A server needs to be running and remote redux devtools should be used rather than redux devtools extension.
The best approach would be the following:
Install npmjs.com/package/remotedev-server
Add "remotedev": "remotedev --hostname=localhost --port=8080" npm script
Run the above script to start a server
Right click on popup, Redux DevTools > Open Remote DevTools (not inspect)
Settings > Use Custom Local Server > Type in the hostname and port specified in the npm script.
Here is what my store looks like:
import { createStore } from "redux";
import { composeWithDevTools } from "remote-redux-devtools";
import rootReducer from "./store/reducers";
const composeEnhancers = composeWithDevTools({
realtime: true,
hostname: "localhost",
port: 8080
});
export const store = createStore(rootReducer, composeEnhancers());
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById("root")
);
I think the problem is with webpack uglifying __REDUX_DEVTOOLS_EXTENSION_COMPOSE__ in the following code
You can try the following:
import { createStore, compose } from 'redux'
//same code as original but with bracket notation
const composeWithDevTools = (
typeof window !== 'undefined' && window["__REDUX_DEVTOOLS_EXTENSION_COMPOSE__"] ?
window["__REDUX_DEVTOOLS_EXTENSION_COMPOSE__"] :
function() {
if (arguments.length === 0) return undefined;
if (typeof arguments[0] === 'object') return compose;
return compose.apply(null, arguments);
}
);
//your original code but using your composeWithDevTools
export const store = createStore(rootReducer, composeWithDevTools());
You don't need to import composeWithDevTools from redux-devtools-extension as you've created it yourself but if this solves the problem you should create an issue requesting for bracket notation so uglify won't break the code.
To see what the compiled code is you can add a console log before your createStore: console.log("creating store") then you can disable source maps in chrome devtools (Command+Shift+P or Control+Shift+P) and then search for the console text creating store shortcut is: command+alt+f or control+shift+f)

ReactJS error when accessing page using Server-side Rendering

I get this error when I load my ReactJS page
Error: Invariant failed: You should not use <Switch> outside a <Router>
at invariant (/home/user/Documents/Development/hmuweb/room/node_modules/tiny-invariant/dist/tiny-invariant.cjs.js:13:11)
at Object.children (/home/user/Documents/Development/hmuweb/room/node_modules/react-router/cjs/react-router.js:685:19)
at ReactDOMServerRenderer.render (/home/user/Documents/Development/hmuweb/room/node_modules/react-dom/cjs/react-dom-server.node.development.js:3635:55)
at ReactDOMServerRenderer.read (/home/user/Documents/Development/hmuweb/room/node_modules/react-dom/cjs/react-dom-server.node.development.js:3373:29)
at Object.renderToString (/home/user/Documents/Development/hmuweb/room/node_modules/react-dom/cjs/react-dom-server.node.development.js:3988:27)
at ./server/index.js.app.get (/home/user/Documents/Development/hmuweb/room/server-build/index.js:215:71)
at Layer.handle [as handle_request] (/home/user/Documents/Development/hmuweb/room/node_modules/express/lib/router/layer.js:95:5)
at next (/home/user/Documents/Development/hmuweb/room/node_modules/express/lib/router/route.js:137:13)
at Route.dispatch (/home/user/Documents/Development/hmuweb/room/node_modules/express/lib/router/route.js:112:3)
at Layer.handle [as handle_request] (/home/user/Documents/Development/hmuweb/room/node_modules/express/lib/router/layer.js:95:5)
I am assuming this error message is coming from my App.js file but I cannot seem to find where the error is occurring exactly. I tried re-structuring my App.js but when I do this, I receive another error saying the prop history is marked as required in the Router but its value is undefined. Also, that it cannot read property 'location' of undefined. Any idea how I can fix this issue? It started when I implemented SSR (Server Side Rendering).
import React, { Component } from 'react';
import { Route, Switch, BrowserRouter as Router } from 'react-router-dom';
import './App.css';
import Room from './App/pages/Room'
import Content from './App/pages/content';
class App extends Component {
render() {
return (
<div>
<Switch>
<Route exact={true} path="/" component={Room} />
<Route path="/watch" component={Content} />
</Switch>
</div>
);
}
}
export default App;
webpack.server.js file incase needed
const path = require('path');
const nodeExternals = require('webpack-node-externals');
module.exports = {
devtool: 'source-map',
entry: './server/index.js',
target: 'node',
externals: [nodeExternals()],
module: {
rules: [
{
test: /\.js$/,
use: ["babel-loader"],
exclude: /node_modules/,
},
{ test: /\.css$/, loader: "css-loader" },
{ test: /\.(jpg|png|svg)$/, use: 'file-loader'}
]
},
resolve: {
alias: {
'react-router-dom': path.join('./node_modules/react-router-dom')
}
},
output: {
path: path.resolve('server-build'),
filename: 'index.js'
},
};
package.json file incase needed
{
"name": "room",
"version": "0.1.0",
"private": true,
"dependencies": {
"#babel/plugin-proposal-class-properties": "^7.8.3",
"axios": "^0.19.2",
"babel-preset-es2015": "^6.24.1",
"bootstrap": "^3.4.1",
"branca": "^0.3.0",
"cors": "^2.8.5",
"express": "^4.17.1",
"hls.js": "^0.13.2",
"html-react-parser": "^0.10.3",
"jquery": "^3.5.1",
"jsonwebtoken": "^8.5.1",
"object-encrypt-decrypt": "^1.0.2",
"path": "^0.12.7",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-helmet": "^6.0.0",
"react-router-dom": "^5.2.0",
"react-router-redux": "^4.0.8",
"react-scripts": "3.2.0"
},
"scripts": {
"start": "node ./server/index.js | react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"dev:build-server": "NODE_ENV=development webpack --config webpack.server.js --mode=development -w",
"dev:start": "nodemon ./server-build/index.js",
"dev": "npm-run-all --parallel build dev:*"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"proxy": "http://localhost:5000",
"devDependencies": {
"babel-core": "^6.26.3",
"babel-preset-env": "^1.7.0",
"babel-preset-react-app": "^9.1.2",
"nodemon": "^2.0.4",
"npm-run-all": "^4.1.5",
"webpack-cli": "^3.3.11",
"webpack-node-externals": "^1.7.2"
},
"babel": {
"presets": [
"#babel/preset-env",
"#babel/preset-react"
],
"plugins": [
"#babel/plugin-proposal-class-properties"
]
}
}
Index.js
import path from 'path';
import fs from 'fs';
import express from 'express';
import React from 'react'
import ReactDOMServer from 'react-dom/server';
import { StaticRouter } from 'react-router-dom';
import App from '../src/App';
const PORT = process.env.PORT || 5000;
const app = express();
app.use(express.static(path.join(__dirname, '../build')));
app.get('/*', (req, res) => {
const context = {};
const app = ReactDOMServer.renderToString(
<StaticRouter location={req.url} context={context}>
<App />
</StaticRouter>
);
const indexFile = path.join(__dirname + '../build/index.html');
fs.readFile(indexFile, 'utf8', (err, data) => {
if (err) {
console.error('Something went wrong:', err);
return res.status(500).send('Oops, better luck next time!');
}
if (context.status === 404) {
res.status(404);
}
return res.send(
data.replace('<div id="root"></div>', `<div id="root">${app}</div>`)
);
});
});
app.listen(PORT, () => {
console.log(`😎 Server is listening on port ${PORT}`);
});
After hours of troubleshooting, I have finally fixed this issue.
Instead of passing the directly inside the renderToString function, you have to nest it inside of a StaticRouter tag.
This answer helped me out: https://github.com/jaredpalmer/razzle/issues/1157#issuecomment-553044993
Also, I had to nest my Switch tag inside a Router tag like this:
<Router>
<Switch>
<Route exact={true} path="/" component={Room} />
<Route path="/watch" component={Content} />
</Switch>
</Router>
After doing this I received another issue where my build index.html wasn't found. To fix this issue I had to tweak my project:
In ReactJS index.js file I had to switch my ReactDOM.render to ReactDOM.hydrate instead.
Created a server.js file inside my server folder where I moved my index.js code inside.
Inside my old server/index.js, I implemented my server-side support for JSX using #babel.
Here is my code:
server/index.js
import path from 'path';
import fs from 'fs';
import express from 'express';
import React from 'react'
import ReactDOMServer from 'react-dom/server';
import { StaticRouter } from 'react-router-dom';
import App from '../src/App';
const PORT = process.env.PORT || 5000;
const app = express();
app.get('^/$', (req, res) => {
const context = {};
const app = ReactDOMServer.renderToString(
<StaticRouter location={req.url} context={context}>
<App />
</StaticRouter>
);
const indexFile = path.resolve('./build/index.html');
fs.readFile(indexFile, 'utf8', (err, data) => {
if (err) {
console.error('Something went wrong:', err);
return res.status(500).send('Oops, better luck next time!');
}
if (context.status === 404) {
res.status(404);
}
return res.send(
data.replace('<div id="root"></div>', `<div id="root">${app}</div>`)
);
});
});
app.use(express.static(path.resolve(__dirname, '..', 'build')));
app.listen(PORT, () => {
console.log(`😎 Server is listening on port ${PORT}`);
});
server/index.js
require('ignore-styles')
require('#babel/register')({
ignore: [/(node_module)/],
presets: ['#babel/preset-env', '#babel/preset-react'],
plugins: ['#babel/plugin-proposal-class-properties']
})
require('./server');
package.json
{
"name": "room",
"version": "0.1.0",
"private": true,
"homepage": "https://hmutv.com/",
"dependencies": {
"#babel/plugin-proposal-class-properties": "^7.8.3",
"#babel/preset-react": "^7.9.4",
"#babel/register": "^7.9.0",
"axios": "^0.19.2",
"babel-preset-es2015": "^6.24.1",
"bootstrap": "^3.4.1",
"branca": "^0.3.0",
"cors": "^2.8.5",
"express": "^4.17.1",
"history": "^4.10.1",
"hls.js": "^0.13.2",
"html-react-parser": "^0.10.3",
"ignore-styles": "^5.0.1",
"jquery": "^3.5.1",
"jsonwebtoken": "^8.5.1",
"next": "^9.4.0",
"object-encrypt-decrypt": "^1.0.2",
"path": "^0.12.7",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-helmet": "^6.0.0",
"react-router-dom": "^5.2.0",
"react-router-redux": "^4.0.8",
"react-scripts": "3.2.0"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"ssr": "node server/index.js"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"proxy": "http://localhost:5000",
"devDependencies": {
"babel-core": "^6.26.3",
"babel-preset-env": "^1.7.0",
"babel-preset-react-app": "^9.1.2",
"nodemon": "^2.0.4",
"npm-run-all": "^4.1.5",
"webpack-cli": "^3.3.11",
"webpack-node-externals": "^1.7.2"
}
}

React not rendering custom elements (babel + webpack)

I created an app using create-react-app and started to use webpack and babel.
What I get from this code is that I cannot render my components (example, <App />).
I can only render elements like h1 or h2, even if I import App in index.js (and don't use it), I cannot see anything.
I run with npm run dev-server.
webpack.config.js:
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.join(__dirname, 'public'),
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
presets: ['#babel/react']
}
}
]
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
},
devtool: 'cheap-module-eval-source-map',
devServer: {
contentBase: path.join(__dirname, 'public')
}
};
index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import './style.css';
ReactDOM.render(
<App />,
document.getElementById('root')
);
App.js:
import React, { Component } from 'react';
class App extends Component {
render() {
return (
<div className="mainContainer">
<h1>Test h1</h1>
<h2>Test h2</h2>
<p>Test p</p>
</div>
);
}
}
export default App;
package.json:
{
"name": "smartpharma-front",
"version": "0.0.1",
"private": true,
"dependencies": {
"axios": "^0.19.0",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-scripts": "^3.3.0"
},
"scripts": {
"start": "webpack --mode=development",
"build": "webpack --mode=production",
"dev-server": "webpack-dev-server",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"engines": {
"node": "13.3.0",
"npm": "6.13.1"
},
"devDependencies": {
"#babel/core": "^7.7.7",
"#babel/preset-env": "^7.7.7",
"#babel/preset-react": "^7.7.4",
"babel-loader": "^8.0.6",
"css-loader": "^3.4.0",
"style-loader": "^1.1.1",
"webpack": "^4.41.4",
"webpack-cli": "^3.3.10"
},
"description": "SmartPharma Frontend",
"main": "webpack.config.js",
"repository": {
"type": "git",
"url": "git+https://github.com/vfeder6/smartpharma-front.git"
},
"keywords": [],
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/vfeder6/smartpharma-front/issues"
},
"homepage": "https://github.com/vfeder6/smartpharma-front#readme"
}

Resources