React Universal Webpack App Crashes After ReactDOMServer.renderToString(<App />) - javascript

I'm new to universal rendering. I have a wildcard route in express that should catch anything that's not prepended with /api.
It looks like this:
module.exports = function(req, res){
const location = createLocation(req.url);
const store = configureStore();
match({routes, location}, (err, redirectLocation, renderProps) => {
if (err) {
console.error('Error!', err);
return res.status(500).end('Internal server error');
}
if (!renderProps) return res.status(404).end('Not found.');
const InitialComponent = (
<div style={{ width: '80%' }}>
<Provider store={store}>
<RoutingContext {...renderProps} />
</Provider>
</div>
);
const initialState = store.getState();
// | | | | | | | |
// v v v v running this will cause server to crash v v v v
const componentHTML = ReactDOMServer.renderToString(InitialComponent);
console.log('Component html? ', componentHTML);
const html = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<base href="/" />
<title>rūh collective: server</title>
</head>
<body>
<div id="react-app">${html}</div>
<script src="bundle.js"></script>
</body>
</html>
`
res.send(html);
});
}
This successfully sends to the server, because I see that the title has the ruh:server included.
Right after the page loads, the server crashes saying pointing to events.js:82
If I comment out the ReactDOMServer.renderToString and I remove the reference in the html the server loads and does not crash.
If I run ReactDOMServer.renderToString and DO NOT EVEN REFERENCE IT, the server still crashes on load. Commenting out will allow the server to live.
Here is my webpack config:
var webpack = require('webpack');
var path = require('path');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
const commonLoaders = [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'react-hot',
}, {
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
stage: 0,
}
},
{
test: /\.jsx$/,
loader: 'babel-loader',
query: {
stage: 0,
}
},
{ test: /\.css$/, loader: "style-loader!css-loader" },
{
test: /\.html$/,
loader: 'file?name=[name].[ext]',
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
loaders: [
'file?hash=sha512&digest=hex&name=[hash].[ext]',
'image-webpack?bypassOnDebug&optimizationLevel=7&interlaced=false',
]
}
];
//const assetsPath = path.join(__dirname, 'dist');
const publicPath = path.join(__dirname, 'dist');
module.exports =
{
name: 'browser',
entry: [
'webpack-dev-server/client?http://localhost:8080',
'webpack/hot/only-dev-server',
'./browser/js/main.js',
],
output: {
filename: 'bundle.js',
path: __dirname + '/dist',
publicPath: 'http://localhost:8080/',
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
],
module: {
loaders: commonLoaders.concat([
{test: /\.scss$/, loader: 'style!css!sass?sourceMap'},
])
}
}
If I comment out the line const componentHTML etc, the server will run, but it's not rendering universally. I can try to replicate the issue if anyone is interested

Related

Why is webpack processing my node_modules folder?

... despite my configuration file telling it not to. It is a simple file only handling a few file types as seen below. I am using webpack 5.7.0, the current latest version.
const jsx = {
test: /\.jsx?/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-react']
}
}
};
const file_types = {
rules: [
jsx
]
};
const entry = '/Users/c/top/tiny/index.jsx';
const output = {
filename: 'bundle.js',
path: '/Users/c/top/tiny/dist'
};
const config_obj = {
entry: entry,
output: output,
module: file_types
};
module.exports = (env) => {
return config_obj;
};

React router 404 error when refreshing page with url params

I'm trying to use Url params in react router 5.2.0, something like
<Switch>
<Route path="/home" component={ Home } />
<Route path="/user/:id" component={ User } />
</Switch >
It's working but when the I'm on a user's page (localhost:8080/user/1) and I refresh the page it'll trigger a 404.
I think the issue may come from my webpack config.
If I add publicPath: '/' in the output it'll work but the app is not able to load images anymore, it'll try to access //assets/images/... instead of /assets/images/....
Here is my webpack config:
const HtmlWebPackPlugin = require('html-webpack-plugin')
const ReactIntlPlugin = require('react-intl-webpack-plugin')
const getPublicUrlOrPath = require('react-dev-utils/getPublicUrlOrPath')
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin')
const fs = require('fs')
const path = require('path')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const appDirectory = fs.realpathSync(process.cwd())
const resolveApp = relativePath => path.resolve(appDirectory, relativePath)
const publicPath = getPublicUrlOrPath(
process.env.NODE_ENV === 'development',
require(resolveApp('package.json')).homepage,
process.env.PUBLIC_URL
)
const publicUrl = process.env.NODE_ENV === 'development' ? publicPath + "public/assets" : ""
module.exports = {
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env']
}
}
},
{
test: /\.html$/,
use: [
{
loader: "html-loader"
}
]
},
{
test: /\.(png|jpg|gif|svg|ico)$/i,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[contenthash].[ext]',
outputPath: 'assets/img/'
}
},
],
},
{
test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
exclude: [/images/],
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'assets/fonts/'
}
},
],
},
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
}
]
},
output:{
filename: 'main.[contenthash].js',
publicPath: '/' //now I can refresh the page but assets folder is not accessible anymore
},
plugins: [
new HtmlWebPackPlugin({
template: "./public/index.html",
filename: "./index.html",
favicon: "./public/assets/favicon.ico"
}),
new ReactIntlPlugin(),
new InterpolateHtmlPlugin(HtmlWebPackPlugin, {
PUBLIC_URL: publicUrl,
}),
new CleanWebpackPlugin()
],
devServer: {
historyApiFallback: true
}
}
Thanks for your help
I fixed it.
So the solution to make the refresh working was to add webpackConfig.output.publicPath = '/' as I tried but the reason why the images were not loading anymore was because in my code I access the images this way:
import Image from '../../images/image.png'
<img src={`/${Image }`} alt="Image"/>
So I just removed the / from src={`/${Image }`} and now it's working and now the images url looks like /assets/images/... instead of //assets/images/...
It was kind of an easy one but I missed it.

ReactJS buttons or submit functions created by webpack isn't working

so I'm creating a ReactJS app and configuring webpack for it.
below's my webpack config:
webpack.config.js
const webpack = require('webpack');
const HtmlWebPackPlugin = require( 'html-webpack-plugin' );
const path = require( 'path' );
const dotenv = require('dotenv');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const env = dotenv.config().parsed;
const envKeys = Object.keys(env).reduce((prev, next) => {
prev[`process.env.${next}`] = JSON.stringify(env[next]);
return prev;
}, {});
module.exports = {
context: __dirname,
entry: ['./src/js/index.js','./src/sass/index.scss'],
output: {
path: path.resolve( __dirname, 'dist' ),
filename: 'main.js',
publicPath: '/',
},
devtool: 'eval-source-map',
devServer: {
historyApiFallback: true,
contentBase: path.join(__dirname, 'dist'),
},
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
exclude: [/node_modules/],
query: {
presets: ['#babel/react', "#babel/preset-env"]
}
},
{
test: /\.jsx?$/,
loader: 'babel-loader',
exclude: [/node_modules/],
query: {
presets: ['#babel/react', "#babel/preset-env"]
}
},
{
test: /\.scss$/,
use: ["style-loader", "css-loader", "sass-loader"]
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.(gif|png|jpe?g|svg|webp)$/i,
use: [
'file-loader',
{
loader: 'image-webpack-loader',
options: {
bypassOnDebug: true, // webpack#1.x
disable: true, // webpack#2.x and newer
},
},
],
}
]
},
plugins: [
new HtmlWebPackPlugin({
template: path.resolve( __dirname, 'public/index.html' ),
filename: 'index.html',
}),
new webpack.ProvidePlugin({
"React": "react",
}),
new CopyWebpackPlugin({
patterns: [
{ from: 'public/assets' }
]
}),
new webpack.DefinePlugin(envKeys),
]
};
It was all going well until I realized that all my buttons aren't working, I checked all the functions and the syntax to make sure if I get it wrong, but turns out I am making no mistake about it
here's the function to my button:
const submitMail = e => {
console.log('here')
alert('here')
e.preventDefault()
e.stopPropagation()
e.nativeEvent.stopImmediatePropagation();
console.log('test')
}
I tried to call it in my test button, but it wouldn't work, it sent no alert, it won't even log all my console.logs
<button onClick={e => submitMail(e)}>test</button>
I also tried to put them in my form to trigger it at onSubmit along with another button inside just to see if it triggers the "console.log" which is also not working:
<form onSubmit={e => submitMail(e)}>
<input id="banner-text-input-email-input-wrapper-email-input" placeholder="Enter your email here"/>
<input id="banner-text-input-email-input-wrapper-submit-input" onClick={()=>console.log('hi')} type="button" value="Button Value"/>
</form>
NOTE:
I've tried to run the normal react app:
react-script start
and all the buttons are working!! at this point, I can only think that the reason it's not working is because of my webpack config, here's also my webpack command just in case:
webpack serve --open --mode=development --config=webpack.config.js
--hot
Instead of
<button onClick={e => submitMail(e)}>test</button>
did you try to use
<button onClick={submitMail}>test</button>
It will implicitly send the event if I'm not mistaken...
okay, it turns out, I'm very silly at this thing, I'm very new to webpacks, so I thought I needed to put
<script type="text/javascript" src="main.js"></script>
in my public/index.html file
after I deleted that part, it all went well.

Why does my React app only load on refresh without cache?

Seems this would be more straightforward, but I am stumped. My React app is being served with Webpack and if I open up the localhost in an Incognito browser (or refresh a regular tab without cache) the content appears. But otherwise I get these errors in my inspector:
src/index.js and public/index.html files are like a basic Create React App config, like so:
src/index.js:
import React from 'react';
import ReactDOM from "react-dom";
import App from "./components/App";
ReactDOM.render(<App />, document.getElementById('root'));
public/index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Index</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
and the Webpack is as follows:
const Dotenv = require('dotenv-webpack')
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const config = {
entry: './src/index.js',
output: {
filename: 'bundle.js'
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx', '.css']
},
module: {
rules: [
{
test: /\.(tsx?|jsx?)$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
rootMode: 'upward'
}
}
]
},
{
enforce: 'pre',
test: /\.js$/,
exclude: /node_modules/,
loader: 'source-map-loader'
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
{
loader: 'url-loader'
}
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: ['file-loader']
}
]
},
node: {
fs: 'empty'
},
plugins: [
new Dotenv({
path: './.env',
systemvars: true
}),
new ForkTsCheckerWebpackPlugin({ eslint: true })
]
}
module.exports = env => {
const styleRule = {
test: /\.(scss|css)$/,
use: ['style-loader', 'css-loader', 'sass-loader']
}
const htmlPluginConfig = { template: 'public/index.html', inject: true }
config.module.rules.push(styleRule)
config.plugins.push(new HtmlWebpackPlugin(htmlPluginConfig))
config.devtool = 'inline-source-map'
config.devServer = {
contentBase: './src',
overlay: true,
port: 8080
}
return config
}
I know something is jacked, but can't put my finger on it.

Javascript File Not Found in Browser but Compiles Correctly

I went through a React Introduction found on Microsoft Virtual Academy and downloaded the code found in the associated GitHub repo. At this point I'm just trying to have my simple Index.html page create an empty React Div Tag.
However i'm having trouble establishing my environmentI installed node.js, downloaded the start code from github, did my npm install and upon compile got the error "Breaking Change: Its's not longer allowed to omit the '-loader' when using loaders. You need to specify the file-loader instead of file. I fixed this error by changing the webpack.config.js .html loader under module from "file?name=[name].[ext]" to "file-loader?name=[name].[ext]".
However upon doing that I received an error stating "Conflict: Multiple assets emit to the same filename" error when compiling. I fixed this error by changing the output filename in the webpack.config.js from bundle.js to [name].js.
Then it compiled fine but when looking at it in the browser I noticed that there was an error stating "the server has not found anything matching the requested URI" and mentions app.js.
I have tried changing the call in my Index.html to app.js but also get the same error. I have tried clearing out the code in my app.js so it is completely empty and still get the requested URI error. Below is my very simple code...
webpackag.config.js`var path = require('path');
var webpack = require('webpack');
module.exports = {
context: path.join(__dirname, 'app'),
entry: {
javascript: './app.js',
html: './index.html'
},
  output: {
path: path.join(__dirname, 'dist'),
filename: '[name].js'
},
  module: {
    loaders: [
{
test: /.js?$/,
loader: 'babel-loader',
exclude: /node_modules/,
query: {
presets: ['es2015', 'react']
}
},
{
test: /\.html$/,
loader: "file-loader?name=[name].[ext]",
},
{
test: /\.css$/,
loader: "style-loader!css-loader"
},
{
test: /\.png$/,
loader: "url-loader?limit=100000"
},
{
test: /\.jpg$/,
loader: "file-loader"
}
]
  },
devServer: {
historyApiFallback: true
}
};
Code for Index.html...`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Pizza Bot Manager</title>
<link rel="stylesheet" href="/app/app.css">
</head>
<body>
<div id="main">
</div>
<script src="./app.js"></script>
</body>
</html>
App.Js code below...
var React = require('react');
var ReactDom = require('react-dom');
var App = React.createClass({
render: function() {
return (
<div>
</div>
)
}
});
ReactDOM.render(<App />, Document.getElementById("main"));
`
Very new to React so if anyone has any suggestions on how to resolve this error I would really appreciate it
Error as it appears in the Browser Console
HTTP404: NOT FOUND - The server has not found anything matching the requested URI (Uniform Resource Identifier).
GET - http://localhost:8080/app.js
OK looks like adding brackets around my input files in the webpack.config.js seemed to resolve the 404 error. See updated "entry" code below for resolution to help others who may have this issue...
var path = require('path');
var webpack = require('webpack');
module.exports = {
context: path.join(__dirname, 'app'),
/*entry: {
html: './index.html',
javascript: './app.js'
},*/
entry: ['./index.html','./app.js'],
  output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js'
},
  module: {
    loaders: [
{
test: /.js?$/,
loader: 'babel-loader',
exclude: /node_modules/,
query: {
presets: ['es2015', 'react']
}
},
{
test: /\.html$/,
loader: "file-loader?name=[name].[ext]",
},
{
test: /\.css$/,
loader: "style-loader!css-loader"
},
{
test: /\.png$/,
loader: "url-loader?limit=100000"
},
{
test: /\.jpg$/,
loader: "file-loader"
}
]
  },
devServer: {
historyApiFallback: true
}
};

Categories

Resources