Why am I getting Uncaught ReferenceError: React is not defined? - javascript

I am setting up webpack and react in a SpringMVC webapp and I'm getting this error when hitting my /index page.
The relevant controller method is here
#RequestMapping("/index")
public ModelAndView index(final HttpServletRequest request) {
return new ModelAndView("index");
}
The template at src/main/resource/templates/index.html looks like this
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Webpack App</title>
</head>
<body>
<span>React Content Below:</span>
<div id="content"/>
</body>
<script type="text/javascript" src="http://localhost:3000/dist/app.js">
</script>
</html>
Now onto the meat. My webpack.config.js looks like this
// Generated using webpack-cli http://github.com/webpack-cli
const path = require('path');
const webpack = require("webpack");
module.exports = {
mode: 'development',
entry: './src-js/app.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'app.js',
},
devServer: {
open: true,
host: 'localhost',
port:3000
},
externals: {
'react': 'React'
},
module: {
rules: [
{
test: /\.js|jsx$/,
loader: 'babel-loader',
options: {
presets: [
'#babel/preset-env',
'#babel/preset-react',
]
}
},
{
test: /\.css$/i,
use: ['style-loader','css-loader'],
},
{
test: /\.s[ac]ss$/i,
use: ['style-loader', 'css-loader', 'sass-loader'],
},
{
test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif)$/,
type: 'asset',
},
// Add your rules for custom modules here
// Learn more about loaders from https://webpack.js.org/loaders/
],
},
};
and my ./src-js/app.js looks like this.
import * as ReactDOM from "react-dom";
ReactDOM.render(<h1>Hello, world</h1>, document.getElementById('content'));
I later ammended app.js to look like this
import * as React from 'react';
import * as ReactDOM from 'react-dom'
class Component extends React.PureComponent {
constructor(props) {
super(props);
}
render() {
return <h1>Hello, world</h1>
}
}
ReactDOM.render(<Component/>, document.getElementById('content'));
This works for now but long term I would prefer to not need to import React from this file and wrap everything in a Component.
Adding import React from 'react' to the top of app.js has no effect and neither does var React = require('react'). I'm assuming I'm just missing something in my webpack config but I can't seem to find what, anyone know why this is happening?

In the webpack documentation (https://webpack.js.org/configuration/externals/) it looks like there are no quotes before the colon:
externals: {
react: 'React'
},
A few lines below (https://webpack.js.org/configuration/externals/#object) you can find react in lowerCase:
externals: {
react: 'react'
},

Related

React not rendering components

I am dealing with an electron BrowserWindow that should render an HTML file filled with some react components. However the React components are not showing.
I have an html file which is:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="Content-Security-Policy" content="script-src 'self'" />
</head>
<body>
<div id='QA_Dialog'></div>
<script src="../js/index.js"></script>
</body>
</html>
My script source file "../js/index.js" contains some easy React rendering:
import ReactDOM from 'react-dom';
import QAWindow from './QAWindow';
document.body.style.overflow = "hidden";
document.body.style.borderRadius = "5px";
ReactDOM.render(<QAWindow />, document.getElementById('QA_Dialog'))
Where QAWindow is :
import React from 'react';
import { electron } from 'webpack';
import { CloseButton, StyledButton} from '../templates/style';
const useState = React.useState
function QuestionForm() {
const [question, setQuestion] = useState()
function handleSubmit(e) {
e.preventDefault()
electron.QandA.askQuestionSignal(question);
}
function handleClose(e){
e.preventDefault()
electron.QandA.closeWindowSignal('Dio')
}
return (
<>
<CloseButton onClick={handleClose}>
<img src="../templates/close.svg" />
</CloseButton>
<form onSubmit={handleSubmit}>
<input value={question} onChange={e => setQuestion(e.target.value)} placeholder="Ask a question..." />
<span>
<StyledButton>Find Answer</StyledButton>
</span>
</form>
</>
)
}
export default function QAWindow() {
return(
<>
<QuestionForm />
</>
)
}
If I change the above file to only export a simple element it doesn't work anyways. So I assume that the problem is not in QAWindow.
These files are copied in the build/ folder, and there, the reference '../js/index.js' is still valid (the structure of the files dosn't change).
../js/index.js got compiled by web-pack using a babel-loader.
Why does this render a white page???
EDIT:
To better debug this, I am also providing my webpack.config.js:
// This first configuration bundles the script that renders the react components
const QandAExtension= {
mode: 'development',
entry: './src/preloads/QandA/js/index.js', // This entry point match the correct react script that needs to be bundled.
devtool: 'inline-source-map',
target: 'electron-renderer',
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [[
'#babel/preset-env', {
targets: {
esmodules: true
}
}],
'#babel/preset-react']
}
}
},
{
test: [/\.s[ac]ss$/i, /\.css$/i],
use: [
// Creates `style` nodes from JS strings
'style-loader',
// Translates CSS into CommonJS
'css-loader',
// Compiles Sass to CSS
'sass-loader',
],
},
{
test: /\.svg$/,
use: [
{
loader: 'svg-url-loader',
options: {
limit: 10000,
},
},
],
}
]
},
resolve: {
extensions: ['.js'],
},
output: {
filename: 'index.js',
path: path.resolve(__dirname, 'build', 'QandA', 'js'),
},
};
// This second configuration copies the folder containing the HTML file
// into the build/ folder of this app.
const preloadConfig = getConfig({
target: 'electron-renderer',
devtool: false,
watch: dev,
entry: {
'view-preload': './src/preloads/view-preload',
},
// Here in plugin you can specify what you want to copy in the build/ folder.
plugins: [
new CopyPlugin({
patterns: [
{
from: join(__dirname, "src", "preloads", "QandA", "templates"),
to: "QandA/templates",
toType: "dir",
}
],
}),
],
},);
module.exports = [preloadConfig, QandAExtension];
You need to import React's Javascript bundles, which React does through the command line react-scripts start (and isn't explicitly defined in the index.html file).
e.g.
<script src="/static/js/bundle.js"></script>
<script src="/static/js/0.chunk.js"></script>
<script src="/static/js/main.chunk.js"></script>
are imports on functioning index.html React pages.

How to embed React component on other sites?

I've created React application and I need to generate embed code to other websites. It's large app where I want to do only one component as a widget for other domains. I have read Writing embeddable Javascript plugin with React & Webpack and How to embed react component on other domains?. I set my webpack, but still can't render the widget on another domain.
This widget should:
be available via <script> tag, not iframe
show only one part of the app (path /referral), but not all app
The widget is a button and popup, which displays by click on the button.
Here is my webpack.config.js in client folder:
const path = require('path');
const bundleOutputDir = './referral';
const env = require('yargs').argv.env;
module.exports = env => {
const isDevBuild = !(env && env.prod);
if (env === 'build') {
mode = 'production';
} else {
mode = 'development';
}
return [
{
mode: mode,
entry: './src/components/early-referrals/Referral.js',
output: {
filename: 'widget.js',
path: path.resolve(bundleOutputDir),
library: 'Referral',
libraryTarget: 'umd',
umdNamedDefine: true
},
devServer: {
contentBase: bundleOutputDir
},
module: {
rules: [
{ test: /\.html$/i, use: 'html-loader' },
{
test: /\.css$/i,
use: [
'style-loader',
'css-loader' + (isDevBuild ? '' : '?minimize')
]
},
{
test: /\.(png|jpe?g|gif)$/i,
use: [
{
loader: 'file-loader'
}
]
},
{
test: /(\.jsx|\.js)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
[
'#babel/env',
{
targets: {
browsers: ['ie 6', 'safari 7']
}
}
]
]
}
}
}
]
}
}
];
};
Here is component RegisterReferral.js, which is entry point in webpack:
import PopupRef from '../popup/PopupRef';
const RegisterReferral = ({
...
}) => {
const [...] = useState();
useEffect(() => {
...
}, []);
return (
<div>
// some styles for button that displays popup
<PopupRef />
</div>
);
};
const mapStateToProps = state => ({
...
});
export default connect(
mapStateToProps,
{ ... }
)(RegisterReferral);
PopupRef.js is a component with popup, which should displays on other websites within the button.
In the App.js, I have the route for this component that I want to create as an embeddable:
<Route exact path="/referral" component={RegisterReferral} />
And this is a way how I paste the code on another domain:
// the URL in script is an URL of bundle file from webpack
<html>
<head>
<script src="http://example.com/client/referral/widget.js" type="text/javascript"></script>
</head>
<body>
<p>Another website</p>
<div id='app'></div>
</body>
</html>
Also, I've tried to do entry point in webpack.config.js with Referral.js. And here is this component:
// Referral.js
import React from 'react';
import { render } from 'react-dom';
import App from './RegisterReferral.js';
render(<App />, document.getElementById('app'));
// At this case, webpack.config.js has 2 changes:
entry: './src/components/early-referrals/Referral.js',
output: {
...
library: 'Referral',
},
Nothing works. My component doesn't display on other websites.
Please help me to figure out what's wrong and how to embed one component (not all app) from React app on other websites.
Assume that you correctly config your webpack to bundle react js code
This is how I render the component in any page I want
Assume that I have this component
import React, {Component} from "react";
import {render} from "react-dom";
class LoginForm extends Component { }
render(<LoginForm/>, document.getElementById("loginForm")); // use render method
Edit:
Just saw your code I think you need also change the id in index.html
<div id="root"></div>
to
<div id="referral"></div>

React do not render new components, new webpack setup

Today I was setting up my first Webpack Bebel React project and I got some strange case here.I don't know why, but every single Component that I make is not recognized by React. I can see it directly in the inspector, and It seems like it's not getting compiled. All standard HTML elements are getting rendered. Even console.log inside of constructor function of a component that I have created is not called. I run Hot mode with webpack -p
Here is my Webpack config:
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const webpack = require('webpack')
const path = require('path')
const isProduction = process.env.NODE_ENV === 'production'
const cssDeveloperLoaders = ['style-loader', 'css-loader', 'sass-loader']
const cssProduction = ExtractTextPlugin.extract({
fallback: 'style-loader',
loader: ['css-loader', 'sass-loader'],
publicPath: '/dist'
})
const cssConfig = isProduction ? cssProduction : cssDeveloperLoaders
module.exports = {
entry: {
app: './src/app.jsx'
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].bundle.js'
},
module: {
rules: [
{
test: /\.scss$/,
use: cssConfig
},
{
test: /\.jsx$/,
exclude: path.resolve(__dirname + '/node_modules/'),
use: 'babel-loader',
query: {
presents: ['es2015','react']
}
}
]
},
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true,
hot: true,
open: true,
openPage: '' //Fix to webpack version 3.0.0 after removing redirection to /undefined
},
plugins: [
new ExtractTextPlugin({
filename: 'app.css',
disable: !isProduction, //So if production is running it will generate file otherwise not
allChunks: true
}),
new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin()
]
}
My .bablerc
{
"presets": [
"es2015",
"react"
]
}
App.jsx:
import './app.scss'
import React from 'react';
import { render } from 'react-dom';
import engine from './engine.jsx'
render(
<engine/>,
document.getElementById('root')
);
engine.jsx
import React from 'react';
class engine extends React.Component{
constructor(){
super();
console.log('Component has been constructed ')
}
render(){
return(
<div>xD</div>
)
}
}
export default engine;
The picture of React Chrome extension.
Please notice, console.log is not been called.
My html is empty, I see only engine element (Not compiled.)
Any suggestions about this problem?
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="root"></div>
<script src="app.bundle.js"></script>
</body>
</html>
In your webpack config file add
resolve : {
extensions: [".js", ".jsx"]
}
So that you won't need to import your jsx file with extenstion.
Class names should start with Capital letters otherwise methods in react components will not be invoked and also no error will be thrown.
engine.jsx
class Engine extends React.Component{
constructor(){
super();
console.log('Component has been constructed ')
}
render(){
return(
<div>xD</div>
)
}
}
export default Engine;
App.jsx
import Engine from './engine'
render(
<Engine/>,
document.getElementById('root')
);
Please verify https://codesandbox.io/s/D9rpvWWG6
Also you can refer https://github.com/facebook/react/issues/4695

React Component from jsx is not rendering to html

I am new to react and webpack configuration just trying with basic program.
I am not able to see any exception while running in localhost:8080 but not able to see the data in return statement of Render Component too. Please help me:
My React Component:
import React from 'react';
import ReactDOM from 'react-dom';
import SearchBar from '../search/search_bar';
export default class Index extends React.Component{
render()
{
return (<div>Hi Its me</div>);
}
}
html Page:
React Component is here:
<Index/>
<script src="bundle.js"></script>
webpack.config.js:
var path = require('path');
webpack = require('webpack');
var BUILD_DIR = path.resolve(__dirname, './src/client/public');
var APP_DIR = path.resolve(__dirname, './src/client/app');
module.exports = {
entry: APP_DIR + '/index.jsx',
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: '/public/'
},
module: {
loaders: [
{
test: /\.jsx?$/,
loader: 'babel-loader',
exclude: /node_modules/,
query: {
presets: ['es2015', 'react']
}
}
]
},
resolve: {
extensions: ['', '.js', '.jsx'],
}
};
You can't render the component in an HTML file, so this:
<Index/>
<script src="bundle.js"></script>
is invalid. You need to render the application in your entry file index.js using the ReactDOM.render method, like this:
ReactDOM.render(
<Index />,
document.getElementById('#app'),
)
Then create that tag in your html file like this:
<div id="app"></div>
<script src="bundle.js"></script>
The principle of JSX is that it allows you to render HTML inside the JavaScript using a familiar syntax. All your components will always need to be rendered from inside your JS files.

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