Why does this basic webpack hot module replacement work? - javascript

I tried the very basic HMR(without react-hot-loader) using webpack after reading this Medium post by Dan Abramov.
Entry index.js
import React from 'react';
import { render } from 'react-dom';
import App from './App';
if(module.hot) {
// Basic HMR for React without using react-loader
// module.hot.accept('./App', () => {
// const UpdatedApp = require('./App').default;
//
// render(<UpdatedApp />, document.getElementById('app'));
// });
// Why does this work as well?
module.hot.accept();
}
render(<App />, document.getElementById('app'));
The webpack config
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
module.exports = {
entry: [
'webpack-dev-server/client?http://localhost:8081',
'webpack/hot/only-dev-server',
'./src/js/index.js'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: [{ loader: 'babel-loader' }]
}
]
},
plugins: [
new HtmlWebpackPlugin({ template: 'src/index.html' }),
new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin()
],
devServer: {
hot: true
}
}
My question is that, why does HMR for React app works with just module.hot.accept()?
As per my understanding, webpack's HMR only provides a simple API to detect changes in files. How to handle those changes depends on the loaders. The style-loader handles .css files. And, in context of a React app, the changes to .js modules might be managed by react-hot-loader.
Or, as per the Medium post, one can manage them like this:
render(<UpdatedApp />, document.getElementById('app'))
So why just doing module.hot.accept() gives same result as doing render(<UpdatedApp />, document.getElementById('app'))?
Package verisons
"webpack": "^3.10.0",
"webpack-dev-server": "^2.9.7"

Related

React doesn't render

I am begining with React using Webpack to make the configuration. I made all step by step. No error message on console or browser but the h1 that I want to insert doesn't appear.
I know that React is v.18 but I am using React v.17
App.jsx
import React from 'react'
const App = () => {
return (
<h1>Holaaa</h1>
);
}
export default App;
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/app.jsx';
ReactDOM.render (<App/>, document.getElementById ("Hello"))
webpack.config.js
const path = require ("path");
const HtmlWebpackPlugin = require ('html-webpack-plugin')
const MiniCssExtractPlugin = require ('mini-css-extract-plugin')
module.exports = {
entry: "./src/index.js",
output: {
path: path.resolve (__dirname, 'dist'),
filename: "bundle.js"
},
mode: "development",
resolve: {
extensions: ['.js', '.jsx']
},
module: {
rules: [
{test: /\.(js|jsx)$/,
exclude: "/node_modules",
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env', '#babel/preset-react']
}
}},
{test: /\html$/,
use: [
{loader: 'html-loader'}
] },
{test: /\.sa[ac]ss$/,
use: ['css-loader',
'style-loader',
'sass-loader']}
]
},
plugins: [
new HtmlWebpackPlugin ({
inject: true,
template: "./public/index.html",
filename: '/menu.html'
}), new MiniCssExtractPlugin ({
filename: "[name].css"
})
]
}
index.html
<title>Document</title>
</head>
<body>
<div id="Hello"> </div>
</body>
</html>
I found the solution. It was the filename config. Was /menu.html. So when localhost was with /menu.html, React render the h1 element.
So, to make render I only have to change /menu.html for index.html in the filename config, refresh and was done!

webpack inline-source-map is mapping to the wrong file

I would prefer to use inline source maps in my webpack config as it sources to the actual original file.
my webpack config is...
const paths = {
src: './widgets/src/scripts/index.js',
dest: '/src/main/content/jcr_root/etc/designs/universal-template-abloyalty/clientlib/js'
};
module.exports = (env, argv) => {
return {
devtool: argv.mode === 'production' ? 'source-map' : 'inline-source-map',
entry: paths.src,
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ['babel-loader', 'eslint-loader']
}
]
},
output: {
path: __dirname + paths.dest,
filename: 'widgets.js'
},
resolve: {
extensions: ['*', '.js', '.jsx']
}
};
};
and then for example in my index.js i do a simple console log...
import 'react-app-polyfill/ie11';
import 'react-app-polyfill/stable';
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
initReact = () => {
function createRootElement() {
const el = document.createElement('div');
el.id = 'root';
document.body.appendChild(el);
return el;
}
const root = document.getElementById('root') || createRootElement();
ReactDOM.render(<App />, root);
console.log('test');
};
if (typeof onReactReady === 'function') onReactReady();
The problem I am having is that in my browser console, this should obviously map to index.js:16 using inline-source-map. Instead its mapping to MobileFilterComponent.js:15
Any thoughts on why this could be happening?
Interestingly enough when I use eval-source-map it maps correctly, but with an altered file name. This makes looking up a file from ctrl+p in sources a pain as you may not know how the file is named.
**note I tagged this with AEM, as this is for an AEM project. I am wondering if maybe when AEM builds clientlib.js if some how the source maps are getting corrupted.

React-Router subroutes not displaying

It seems that when webpack builds the file the output can only see the maincard div and none of the contents therein. I'm not sure what's missing as when this is run as npm react-scripts start it works fine. I'm not sure what i'm missing from webpack for this to render correctly. I'm trying to load this into an S3 bucket so it has to be packed with the webpack.
import React from 'react';
import { connect } from 'react-redux';
import { Route, withRouter } from 'react-router-dom';
import { fetchUserList } from "../actions/UserActions";
import { fetchSkillList } from "../actions/SkillActions";
import WelcomeCard from "./WelcomeCard";
import UserSearchCard from "./UserSearchCard";
import AddUserCard from './AddUserCard';
import '../styles/MainCard.css';
class MainCard extends React.Component {
componentDidMount() {
this.props.fetchUserList();
this.props.fetchSkillList();
}
render() {
return (
<div className="main_card">
<Route exact path='/' component={WelcomeCard}/>
<Route path='/list' component={UserSearchCard}/>
<Route path='/new' component={AddUserCard}/>
</div>
);
}
}
const mapDispatchToProps = dispatch => {
return {
fetchUserList: () => dispatch(fetchUserList()),
fetchSkillList: () => dispatch(fetchSkillList())
}
};
export default withRouter( connect(undefined, mapDispatchToProps)(MainCard) );
Webpack Config:
let path = require('path');
let webpack = require('webpack');
const publicPath = '/dist/build/';
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
//Content
entry: './src/index.js',
mode: 'development',
// A SourceMap without column-mappings ignoring loaded Source Maps.
devtool: 'cheap-module-source-map',
plugins: [
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('development')
}
}),
//simplifies creation of HTML files to serve your webpack bundles. This is especially useful for webpack bundles that include a hash in the filename which changes every compilation. You can either let the plugin generate an HTML file for you, supply your own template using lodash templates or use your own loader.
new HtmlWebpackPlugin({
title: 'Talent Identification Manager'
}),
//Auto replacement of page when i save some file, even css
new webpack.HotModuleReplacementPlugin(),
new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css"
})
],
output: {
path: path.join(__dirname, publicPath),
filename: 'main.bundle-0.0.1.js',
publicPath: "/",
sourceMapFilename: 'main.map',
},
devServer: {
port: 3000,
host: 'localhost',
//Be possible go back pressing the "back" button at chrome
historyApiFallback: true,
noInfo: false,
stats: 'minimal',
publicPath: publicPath,
contentBase: path.join(__dirname, publicPath),
//hotmodulereplacementeplugin
hot: true
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules(?!\/webpack-dev-server)/,
loader: 'babel-loader',
query: {
presets: ['react', 'es2015', 'stage-2'],
plugins: ['syntax-decorators']
}
},
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader'
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
}
]
}
}
React Router doesn't know that you want to treat /talentidbucket as the base of your site, so you have explicitly tell it so by passing the base path as the basename prop of the BrowserRouter component in production.
class App extends React.Component {
render() {
return (
<BrowserRouter basename="/talentidbucket"> {/* ... */} </BrowserRouter>
);
}
}

How to use React.js with AdonisJs

How can I use React.js in the front-end of my AdonisJs project?
I've tried to install react with npm install react I thought this will works correctly. I made a file app.js with this code:
var React = require('react');
var ReactDOM = require('react-dom');
export default class Index extends Component {
render() {
return (< h1 > hello world! < /h1>)
}
}
ReactDOM.render( < Index / > , document.getElementById('example'))
But this isn't working at all, I don't know what to do more I have searched about how to use React in Adonis but I didn't find anything interesting.
I strongly suggest you to use WebPack for this task.
create a webpack.config.js file in your root directory:
maybe your code need some changes but this is the idea:
const webpack = require('webpack');
var CopyWebpackPlugin = require('copy-webpack-plugin');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var path = require('path');
var pkgBower = require('./package.json');
module.exports = {
target: "web",
devtool: "source-map",
node: {
fs: "empty"
},
entry: {
'app': path.join(__dirname, 'react-app', 'Index.jsx')
},
resolve: {
modules: [__dirname, 'node_modules', 'bower_components'],
extensions: ['*','.js','.jsx', '.es6.js']
},
output: {
path: path.join(__dirname, 'public', 'src'),
filename: '[name].js'
},
resolveLoader: {
moduleExtensions: ["-loader"]
},
module: {
loaders: [
{
test: /jquery\.flot\.resize\.js$/,
loader: 'imports?this=>window'
},
{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
loader: 'babel-loader',
query: {
presets: ['es2015', 'react', 'stage-0'],
compact: false
}
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
})
},
{
test: /\.woff|\.woff2|\.svg|.eot|\.ttf/,
loader: 'url?prefix=font/&limit=10000'
},
{
test: /\.(png|jpg|gif)$/,
loader: 'url?limit=10000'
},
{
test: /\.scss$/,
loader: 'style!css!sass?outputStyle=expanded'
}
]
},
plugins: [
new ExtractTextPlugin("styles.css"),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
}),
new CopyWebpackPlugin([{
from: 'img',
to: 'img',
context: path.join(__dirname, 'react-app')
}, {
from: 'server',
to: 'server',
context: path.join(__dirname, 'react-app')
}, {
from: 'fonts',
to: 'fonts',
context: path.join(__dirname, 'react-app')
}]),
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery'
}),
new webpack.optimize.DedupePlugin(),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin({
compress: { warnings: false },
mangle: true,
sourcemap: false,
beautify: false,
dead_code: true
}),
new webpack.ContextReplacementPlugin(/\.\/locale$/, 'empty-module', false, /js$/)
]
};
Then put your app in your root directory, in a folder react-app/ and your components can go inside that folder:
For example your file: [Index.jsx]
import React from 'react';
import ReactDOM from 'react-dom';
class Index extends Component {
render() {
return (< h1 > hello world! < /h1>)
}
}
ReactDOM.render( < Index / > , document.getElementById('example'));
you don't need to export this Index component in this case, but in case you need to just use export default ComponentName at the end of your component file.
The next step is in your routes file (I'm using AdonisJS 4) but is very similar for the version 3.x
Route.any("*", ({ view, response }) => (
view.render('index')
))
Then your index (.njk, or .edge) file (under resources/views) should look something like this:
<html>
<head>
<link rel="stylesheet" href="/src/styles.css">
<script type="text/javascript" src="/src/app.js"></script>
</head>
<body>
<div id="example"></div>
</body>
</html>
--
You need to install some npm/ packages with npm or yarn,
and remember to run in another terminal window or tab,
webpack -d --watch --progress
Regards.
This works. You are missing React.Component.
var React = require('react');
var ReactDOM = require('react-dom');
export default class Index extends React.Component {
render() {
return (< h1 > hello world! < /h1>)
}
}
ReactDOM.render( < Index / > , document.getElementById('example'))
Alternatively you can use import React, {Component} from 'react'; if you want to use your code structure.
For decoupled use, just build your React app and copy the build to Adonis public folder.

Issue with Webpack using React

Sorry if this is a duplicate question. I can't seem to solve this or find an answer. I have a basic Webpack setup i'm working with in conjunction with React and Django. Basically I'm getting compilation error's when using webpack.
These two webpack files aren't loading properly, both below, and neither is this App module (I think it's the provider component from redux).
I think it may be something to do with a driver - or something very simple that I've missed. I would really appreciate the help as I've been trying to fix this for a long time now haha!
Thanks!!!
webpack.config.local.config.js
var path = require("path")
var webpack = require('webpack')
var BundleTracker = require('webpack-bundle-tracker')
var ip = 'localhost'
var config = require('./webpack.base.config.js')
config.devtool = "#eval-source-map"
config.entry = {
App1: [
'webpack-dev-server/client?http://' + ip + ':3000',
'webpack/hot/only-dev-server',
'./reactjs/App1',
],
}
config.output.publicPath = 'http://' + ip + ':3000' + '/assets/bundles/'
config.plugins = config.plugins.concat([
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
new BundleTracker({filename: './webpack-stats-local.json'}),
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('development'),
'BASE_API_URL': JSON.stringify('https://'+ ip +':3000/api/v1/'),
}}),
])
config.module.loaders.push(
{ test: /\.js?$/, exclude: /node_modules/, loaders: ['react-hot', 'babel'] }
)
module.exports = config
webpack.base.config.js
var path = require("path")
var webpack = require('webpack')
module.exports = {
context: __dirname,
entry: {
// Add as many entry points as you have container-react-components here
App1: './reactjs/App1',
vendors: ['react']
},
output: {
path: path.resolve('./djreact/static/bundles/local/'),
filename: "[name]-[hash].js"
},
externals: [
], // add all vendor libs
plugins: [
new webpack.optimize.CommonsChunkPlugin('vendors', 'vendors.js'),
], // add all common plugins here
module: {
loaders: [
// js
{
test: /\.js$/,
exclude: /node_modules/,
loaders: ['babel'],
presets: ['es2015', 'react'],
},
// PNG
{
test : /\.(png|jpg|svg)$/,
include : path.join(__dirname, 'img'),
loader : 'url-loader?limit=30000&name=images/[name].[ext]'
},
{
test: /\.(ttf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/,
loader: 'file-loader'
},
// CSS
{
test: /\.scss$/,
include: path.join(__dirname, 'client'),
loader: 'style-loader!css-loader!sass-loader'
}
] // add all common loaders here
},
resolve: {
modulesDirectories: ['node_modules', 'bower_components'],
extensions: ['', '.js', '.jsx']
},
}
The App that is having some errors
App1.js
import React from "react"
import { render } from "react-dom"
import {
createStore,
compose,
applyMiddleware,
combineReducers,
} from "redux"
import { Router, Route, hashHistory, IndexRoute } from 'react-router'
import { Provider } from "react-redux"
import thunk from "redux-thunk"
import * as reducers from "./reducers"
import App1Container from "./containers/App1Container"
let finalCreateStore = compose(
applyMiddleware(thunk),
window.devToolsExtension ? window.devToolsExtension() : f => f
)(createStore)
let reducer = combineReducers(reducers)
let store = finalCreateStore(reducer)
class App1 extends React.Component {
render() {
return (
<Provider store={store}>
<Router history = {hashHistory}>
<Route path="/" component={Layout}>
<IndexRoute component = {App1Container}/>
</Route>
</Router>
<App1Container />
</Provider>
)
}
}
render(<App1/>, document.getElementById('App1'))
So here are the errors.
From webpack.local.config.js
From webpack.base.config.js
webpack.base.config.js => jsx syntax error, I think that is wrong babel settings
Can you share your .babelrc?
Usually, this file is as follows.
{
"presets": ["es2015","react"]
}

Categories