Getting "Aborted because 0 is not accepted" and full page reload with react-hot-loader - javascript

I am trying to set up webpack hot reloading with react-hot-loader. It mostly seems to be working. I am using webpack in an existing rails app.
But it isn't hot-reloading. It is simply triggering a reload every time my react code is changed. The error messages I get are:
[HMR] Cannot apply update. Need to do a full reload! - dev-server.js:18
[HMR] Error: Aborted because 0 is not accepted - dev-server.js:19
at hotApply (http://localhost:8080/assets/webpack/bundle.js?body=1:380:31)
at hotUpdateDownloaded (http://localhost:8080/assets/webpack/bundle.js?body=1:293:13)
at hotAddUpdateChunk (http://localhost:8080/assets/webpack/bundle.js?body=1:273:13)
at webpackHotUpdateCallback (http://localhost:8080/assets/webpack/bundle.js?body=1:5:12)
at http://localhost:8080/assets/webpack0.bd89931b2fa8e2901794.hot-update.js:1:1
Navigated to http://lvh.me:3000/react_page
Here is my webpack.hot.config.js settings:
var path = require('path');
var webpack = require('webpack');
var config = module.exports = {
// Set 'context' for Rails Asset Pipeline
context: __dirname,
entry: {
App: [
'webpack-dev-server/client?http://localhost:8080/', // WebpackDevServer host and port
'webpack/hot/only-dev-server', // "only" prevents reload on syntax errors
'./app/frontend/javascripts/app.js' // Your appʼs entry point
],
vendor: ['jquery', 'react', 'react-dom', 'react-redux', 'redux','redux-thunk']
},
devtool: 'inline-source-map',
// Require the webpack and react-hot-loader plugins
plugins: [
//new webpack.HotModuleReplacementPlugin(),
new webpack.optimize.CommonsChunkPlugin(
{
name: 'vendor',
chunks: [''],
filename: 'vendor.js',
minChunks: Infinity
}),
new webpack.NoErrorsPlugin(),
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jquery': 'jquery'
})
],
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loaders: [
'react-hot',
'babel?presets[]=es2015&presets[]=react'
],
cacheDirectory: true
}
]
},
output: {
path: path.join(__dirname, 'app', 'assets', 'javascripts', 'webpack'), // Save to Rails Asset Pipeline
filename: 'bundle.js', // Will output App_wp_bundle.js
publicPath: 'http://localhost:8080/assets/webpack',
//publicPath: 'http://localhost:8080/assets/webpack' // Required for webpack-dev-server
},
resolve: {
extensions: ['', '.js', '.jsx'],
modulesDirectories: ['node_modules'],
},
};
And I run the code with
webpack-dev-server -d --config webpack.hot.config.js --hot --inline
The rails development environment serves the webpack files outside the application asset pipeline via the webpack-dev-server because of the following setting in my development.rb file.
config.action_controller.asset_host = Proc.new { |source|
if source =~ /webpack\/bundle\.js$/i
"http://localhost:8080"
end
}
I have been trying to get this working for hours. Any help would be appreciated.
Thanks guys!

Ok i was getting the same error, but after trying some things out i figured this out: My root component was a stateless functional component (pure function). I refactored it to a class component and BAM! the hot reloading is working again.
Before:
const App = (props) => (
<div>
<Header links={headerLinks} logoSrc={logoSrc} />
{props.children}
</div>
);
After:
class App extends React.Component {
render() {
return (
<div>
<Header links={headerLinks} logoSrc={logoSrc} />
{this.props.children}
</div>
);
}
}

As the answers provided above are still not working on my side with webpack 5,
Here is the working config from webpack
In webpack.config.js
devServer: {
.
.
.
hot: true,
}
In the webpack entrypoint index.js add
if (module.hot) {
module.hot.accept();
}
In package.json start script
"scripts": {
.
.
"start": "webpack serve --config /webpack.config.js"
},

I recently ran into this exact issue, the fix for me was removing this from the entries array: 'webpack-dev-server/client?http://localhost:9000/',.
As I was also running --hot as a command line argument, there were two instances of webpack-dev-server getting into a bad state.

I don't know if this will specifically help your issue, but I encountered this error recently as well - i fixed it by adding a .js extension to the module I was trying to set up with hmr - here was my code
if (module.hot) {
module.hot.accept('app/Routes', () => (
getRoutes = require('app/Routes')
))
}
I updated it to getRoutes = require('app/Routes.js') and the error disappeared, using webpack ^2.0.0-beta.
it also works if i add the JS extension as the first argument of hot accept like so:
if (module.hot) {
module.hot.accept('app/Routes.js', () => (
getRoutes = require('app/Routes')
))
}
so now it matches whats on the webpack HMR page

I ran into a similar problem.
After 2 days of research and trying different things, I found out the simplest cause to my problem ever:
in webpack.config.js, I had a HRM dev server enabled. And I also had a HMR server run from command line. Thanks to hint from Tyler Kelley (see above), just by removing --hot from command line, it works OK now.
current webpack.config.js
devtool: "inline-source-map",
devServer: {
publicPath: '/dist/',
contentBase: path.join(__dirname, 'public'),
port: 9000,
hot: true
},
With this configuration, don't do this:
npx webpack-dev-server --hot --inline
Do this:
npx webpack-dev-server

For "webpack": "^5.74.0" and "webpack-dev-server": "^4.11.1".
I set devServer.static = ['./webpack-dev-server', './dist'], in webpack.config.js.
There is my config:
module.exports = {
devtool: 'inline-source-map',
devServer: {
open: true,
static: ['./webpack-dev-server', './dist']
},
entry: path.join(__dirname, 'src', 'index.ts'),
module: {
rules: [
{
test: /\.(ttf|png|svg|jpg|jpeg)$/i,
type: 'asset/resource',
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.ts$/,
loader: 'ts-loader',
options: {
configFile: path.join(__dirname, 'tsconfig.json')
}
}
]
},
mode: 'development',
output: {
filename: '[name][contenthash].js',
path: path.join(__dirname, 'dist'),
clean: true,
},
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, 'src', 'index.html'),
inject: 'body'
})
],
resolve: {
extensions: ['.js', '.ts']
}
}

Related

webpack-dev-server refuses to hot-reload html file

When using webpack-dev-server, when I make changes to the javascript file the changes are immediately reflected on the webpage.
However, when I make a change to the HTML file, the website does not reflect them. In order to see the new html page, I must first run webpack --mode production, and then, if I re-run webpack-dev-server --hot --mode development, I can see the new HTML changes.
This is quite annoying and I'd like my html changes to be hot-reloaded just like the javascript code. Is there a trick I'm missing? I've spent all day googling and playing with options. The only thing that has helped is to add
devServer:
...
devMiddleware: {
writeToDisk: true
},
to my webpack.config.js as per this answer. However, this has the following problem: My output dist/ folder gets clogged with .js files with checksum names every time a hot reload happens, which is also really annoying.
My project tree:
The full webpack.config.js:
const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require('path');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
entry: './src/index.ts',
watch: true,
module: {
rules: [
{
test: /\.ts?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
publicPath: '/dist/'
},
plugins: [
new HtmlWebpackPlugin({
title: "My app",
template: "./src/index.html",
/* This output directory is relative to the **OUTPUT** 'publicPath'!
So, if you were to write "./dist/index.html" below, it would output it in "./dist/dist/index.html"!
(You can verify this by running `npx webpack --watch` and looking what files it touches/generates.)
*/
filename: "index.html",
inject: "body"
})
],
devServer: {
// devMiddleware: { writeToDisk: true },
static: {
directory: path.join(__dirname, "dist"),
watch: true
},
compress: true,
webSocketServer: 'ws',
host: '0.0.0.0',
port: 10000,
/* Ensure I can access the server directly, without incurring the 'invalid host header' error */
allowedHosts: "all",
/* So that the webpack-dev-server reloads when I change the index.html file, even though it isn't explicitly listed anywhere. */
watchFiles: ['src/**/*'],
open: true,
hot: true,
},
};
Nevermind, I have found the issue:
Unfortunately Stackoverflow doesn't support line numbers, but if you look in the webpack.config.js code in my original question, you will find the following code:
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
publicPath: '/dist/'
},
That publicPath parameter appears to be what was causing the problem. Removing it made the hot-reload 'magic' autodetect that I've changed the HTML file, and re-deploy it.

How can Vue js load image from /dist/ folder when it does not exist?

So I'm trying to learn Vue.js + webpack and initated a project by following these steps:
f:www\> npm install -g vue-cli
f:www\> vue init webpack-simple my-project
f:www\> cd my-project
f:www\> npm install
f:www\> npm run dev
The default page runs on http://localhost:8080/.
Now, in webpack.config.jsfile I have the following lines:
entry: './src/index.js',
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/dist/',
filename: 'main.js'
},
and in the index.html we find the following line <script src="/dist/main.js"></script>
At this point I thought Webpack was a bit like Gulp in that it compiles src files and puts them in the /dist/ folder.
But Webpack never creates the /dist/ folder.
How can the Vue logo be loaded from <img src="/dist/logo.png?82b9c7a5a3f405032b1db71a25f67021"> when /dist/ folder does not exist?
Why is main.js not created?
webpack.config.js (short version)
var path = require('path');
var webpack = require('webpack');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/dist/',
filename: 'main.js'
},
module: {
rules: [
{
test: /\.css$/,
use: [
'vue-style-loader',
'css-loader'
],
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
}
}
]
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
},
extensions: ['*', '.js', '.vue', '.json']
},
devServer: {
historyApiFallback: true,
noInfo: true,
overlay: true
},
performance: {
hints: false
},
devtool: '#eval-source-map'
};
if (process.env.NODE_ENV === 'production') {
module.exports.devtool = '#source-map';
// http://vue-loader.vuejs.org/en/workflow/production.html
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true
})
])
}
So after some more googling, I found this turorial that explains the entire webpack-simple setup.
Here is the section regarding the /dist/ folder:
npm run build
Right now we are simply using npm run dev to work with and test out an
installation of the Vue Cli tool. This is great
for testing in the local environment, but what about if you actually
want to publish your application to the web? In this case you will
instead run npm run build. This will build your application for
production and you’ll see a new /dist/ folder which contains the
finished bundle.
So during development, the files are placed in a chached / temp location (not sure where)

Webpack - browser refresh on a file change which isn't module

I want to refresh page when I change (save) ./src/*.js files in my code editor.
The problem is I'm not importing this files in my entry point (with import in index.js) but I'm joining them with a plugin so code is in browser's global scope rather then in module.
Basically I want to split longer JavaScript code into smaller files, I don't want to have modules.
I've tried many configurations and closest to my needs is that below, except that it doesn't refresh browser, (it recompiles).
How can I achieve recompile and refresh on JavaScript which should be in globalscope of the browser (or all code in one module)?
webpack.config.js:
const path = require('path');
const MergeIntoSingleFilePlugin = require('webpack-merge-and-include-globally');
const FileWatcherPlugin = require("file-watcher-webpack-plugin");
module.exports = {
context: __dirname,
entry: { bundle: './src/index.js' },
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
}]
},
plugins: [
new MergeIntoSingleFilePlugin({
files: {
"app.js": [
path.resolve(__dirname, './src/setup.js'),
path.resolve(__dirname, './src/buttons.js'),
path.resolve(__dirname, './src/circle.js'),
path.resolve(__dirname, './src/wall.js')
]
}
}),
new FileWatcherPlugin({
root: __dirname,
files: ['*.js']
})
],
devServer: {
contentBase: './dist',
watchOptions: {
aggregateTimeout: 300,
poll: 1000
},
hot: true,
inline: true,
// publicPath: "./src",
watchOptions: {
ignored: './node_modules/'
}
}
};
npm start:
webpack-dev-server --open --inline --hot --watch --progress
and the setup.js, buttons.js etc are regular JS script files, not exported classes.
Any ideas appreciated!

Webpack: Taking a long time to build

I have an issue with webpack build times in my react application. Everything builds fine but it takes a long time.
Even I change just the JavaScript files the CSS rebuilds?
Also the CSS compilation is taking a longer than I think it should be (correct me if I am wrong)?
I am running a Core i7 with 16gb of Ram and the build is taking about a minute which is becoming very annoying during development when it's a one line change and you have to wait near enough a minute before you can see your changes in the browser?
Is this the wrong approach?
const CleanObsoleteChunks = require('webpack-clean-obsolete-chunks');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const DashboardPlugin = require('webpack-dashboard/plugin');
const path = require('path');
const webpack = require('webpack');
const BUILD_DIR = path.resolve(__dirname, '../dist');
const APP_DIR = path.resolve(__dirname, 'src/');
const config = {
devtool: 'source-map',
entry: {
"ehcp-coordinator": [
APP_DIR + '/index.js'
]
},
output: {
path: `${BUILD_DIR}/js/`,
filename: '[name].js',
chunkFilename: '[name]-chunk.js',
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['es2015', 'es2017', 'react', 'stage-0'],
plugins: ['transform-runtime', 'transform-decorators-legacy', 'transform-class-properties', 'syntax-dynamic-import',
["import", {"libraryName": "antd", "style": false}]]
}
}
}, {
test: /\.less$/,
use: ExtractTextPlugin.extract({
use: [{
loader: "css-loader"
}, {
loader: "less-loader"
}]
})
}
]
},
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': "'development'"
}),
new webpack.optimize.UglifyJsPlugin({
'sourceMap': 'source-map'
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
filename: '[name].js',
minChunks(module, count) {
var context = module.context;
return context && context.indexOf('node_modules') >= 0;
}
}),
new ExtractTextPlugin("../css/[name].css")
],
resolve: {
modules: [
path.resolve('./'),
path.resolve('./node_modules'),
],
extensions: ['.js', '.json']
}
};
module.exports = config;
As discussed in the comments, here are the most obvious changes you could make to speed up your build:
UglifyJsPlugin and ExtractTextPlugin are very heavy in terms of their impact on your compilation time, while not actually presenting many tangible benefits in development. Check process.env.NODE_ENV in your config script, and enable/disable them depending on whether you're doing a production build or not.
In place of ExtractTextPlugin, you can use style-loader in development to inject CSS into the head of the HTML page. This can cause a brief flash of unstyled content (FOUC) when the page loads, but is much quicker to build.
If you're not already, use webpack-dev-server rather than just running Webpack in watch mode - using the dev server compiles the files in memory instead of saving them to disk, which further decreases the compile times in development.
This does mean you'll have to manually run a build when you want to have the files written to disk, but you'll need to do that to switch to your production config anyway.
Not sure if this has any impact on performance, but the resolve section of your config doesn't meaningfully differ from the defaults, and you should be able to remove it without causing any issues.
In my case I updated devtool property to false.
Article on Medium: https://medium.com/#gagan_goku/hot-reloading-a-react-app-with-ssr-eb216b5464f1
Had to solve the same problem for my React app (HELO) with SSR. Things get complicated with SSR, but thankfully webpack gets a lot faster if you specify --mode=development, because it does it in memory.
webpack-dev-server did not work for me because I need the client.js bundle for the SSR client to work properly. Here's my setup:
webpack.config.js:
const path = require('path');
module.exports = {
entry: {
client: './src/client.js', // client side companion for SSR
// bundle: './src/bundle.js', // Pure client side app
},
output: {
path: path.resolve(__dirname, 'assets'),
filename: "[name].js"
},
module: {
rules: [
{
test: /\.js$/,
include: path.resolve(__dirname, 'src'),
loader: "babel-loader",
options: {
presets: [
'#babel/preset-env',
{'plugins': ['#babel/plugin-proposal-class-properties']},
],
}
}
]
},
watchOptions: {
aggregateTimeout: 1000,
poll: 500,
ignored: /node_modules/,
}
};
package.json:
"scripts": {
// IMP: --mode=development
"run-dev-ssr": "webpack --config webpack.config.js --watch --mode=development & babel src -d dist --watch & browser-refresh dist/server.js"
}
.browser-refresh-ignore:
node_modules/
static/
.cache/
.*
*.marko.js
*.dust.js
*.coffee.js
.git/
# Add these files to ignore, since webpack is storing the compiled output to assets/ folder
src/
dist/
Build times without mode:
Hash: 81eff31301e7cb74bffd
Version: webpack 4.29.5
Time: 4017ms
Built at: 05/10/2019 9:44:10 AM
Hash: 64e10f26caf6fe15068e
Version: webpack 4.29.5
Time: 2548ms
Time: 5680ms
Time: 11343ms
Build times with mode:
Hash: 27eb1aabe54a8b995d67
Version: webpack 4.29.5
Time: 4410ms
Time: 262ms
Time: 234ms
Time: 162ms

Webpack dev server not auto-reloading

So I've setup webpack and webpack-dev-server, but webpack-dev-server does not auto-reload. If i modify a file and save it there is no change in the browser until I manually refresh.
Here is my webpack config and my script file that runs webpack-dev-server. Does anyone see anything that could be preventing auto-reload from working?
I put these together by reading through multiple tutorials, the docs, and by reading through the react-create-app generated files.
config/webpack.config.dev.js
'use strict';
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const autoprefixer = require('autoprefixer');
const webpack = require('webpack');
const extractSass = new ExtractTextPlugin('style.css');
module.exports = {
entry : './src/index.jsx',
eslint: {configFile: './src/.eslintrc.json'},
module: {
loaders: [
{
exclude: /node_modules/,
include: ['src'],
loader: 'babel',
test : /(\.js|\.jsx)$/
},
{
exclude: /node_modules/,
include: ['src']
loader : extractSass.extract([ 'css', 'postcss', 'sass' ]),
test : /\.scss$/
}
],
preLoaders: [
{
exclude: /node_modules/,
loader : 'eslint',
query : {presets: [ 'react', 'latest' ]},
test : /(\.js|\.jsx)$/
}
]
},
output: {
filename : 'bundle.js',
path : 'dist',
publicPath: '/'
},
plugins: [
extractSass,
new HtmlWebpackPlugin({
inject : true,
template: paths.appHtml
}),
new webpack.HotModuleReplacementPlugin({multistep: true})
],
postcss: () => [
autoprefixer({
browsers: [
'>1%',
'last 4 versions',
'Firefox ESR',
'not ie < 9'
]
})
]
};
scripts/dev.js
run with $ yarn run dev
'use strict';
const WebpackDevServer = require('webpack-dev-server');
const config = require('../config/webpack.config.dev.js');
const webpack = require('webpack');
const compiler = webpack(config);
const server = new WebpackDevServer(compiler, {
clientLogLevel : 'warn',
compress : true,
contentBase : 'public',
filename : config.output.filename,
historyApiFallback: true,
hot : true,
inline : true,
lazy : false,
noInfo : true,
publicPath : '/',
quiet : true,
stats : 'errors-only',
watchOptions : {
aggregateTimeout: 300,
poll : 1000
}
});
server.listen(8080, 'localhost', () => {
console.log('Listening on port 8080');
});
According to the webpack dev server documentation you should add this entry point to the webpack configuration to support automatic refresh.
config.entry.unshift("webpack-dev-server/client?http://localhost:8080/");
jontem pointed out in his answer that my config was missing a webpack-dev-server client.
Here's the steps I took to apply his solution and also setup HMR.
config/webpack.config.dev.js
module.config = {
// ...
entry: [
// converted entry to an array
// to allow me to unshift the client later
path.resolve(__dirname, '../src/index.jsx')
],
// ...
module: {
loaders: {
// ...
{
// Use style loader instead of ExtractTextPlugin
// To allow for style injection / hot reloading css
exclude: /node_modules/,
loaders: [ 'style', 'css', 'postcss', 'sass' ],
test : /\.scss$/
},
// ...
}
}
}
scripts/dev.js
'use strict';
const WebpackDevServer = require('webpack-dev-server');
const config = require('../config/webpack.config.dev.js');
const webpack = require('webpack');
// unshift `webpack-dev-server` client
// and hot dev-server
config.entry.unshift('webpack-dev-server/client?/', 'webpack/hot/dev-server');
const compiler = webpack(config);
// ...
I had the same issue and the following configuration enabled static and the in-memory bundle auto-reloading. The key is to enable devServer.watchContentBase.
config/webpack.config.dev.js
...
module.exports = {
...
devServer: {
contentBase: ...,
publicPath: ...,
watchContentBase: true
},
...
}
package.json
{
...
"scripts": {
"develop": "webpack-dev-server --open --mode development --config config/webpack.config.dev.js",
...
}
...
}
Please add the following in your webpack config and try.
devServer: {
hot: true,
inline: true,
host: "localhost",
port: 8082,
watchOptions: {
poll: true
}
}
note: I was using webpack version ^3.11.0
I had a similar problem, fixed it by adding
watchOptions: {
poll: true
}
When I first installed the webpack starter, everything worked flawlessly, after a week of changes to webpack.config.js, it stopped working. I tinkered with various recommendations, the one that worked was watchOptions: {poll:true }
FYI I am webpack 4 with "webpack": "4.29.6", "webpack-cli": "^3.3.0", "webpack-dev-server": "3.3.1"
devServer: {
port: 3000,
contentBase: './',
watchOptions: {
poll: true
}
}
Also
if you use extract-loader, auto reload will not work
Hot Module Replacement feature
devServer: {
// ,,,
contentBase: '/your/path'
watchContentBase: true
hot: true,
},
prevents refresh your static files in web page, unless you press F5 button in browser
This third party webpack dev server documentation has the answer that I needed:
https://wohugb.gitbooks.io/webpack/content/dev_tools/webpack-dev-server.html
The relevant section reproduced below:
There is no inline: true flag in the webpack-dev-server configuration, because the webpack-dev-server module has no access to the webpack configuration. Instead the user have to add the webpack-dev-server client entry point to the webpack configuration.
To do this just add webpack-dev-server/client?http://: to (all) entry point(s). I. e. with the above configuration:
var config = require("./webpack.config.js");
config.entry.app.unshift("webpack-dev-server/client?http://localhost:8080");
var compiler = webpack(config);
var server = new webpackDevServer(compiler, {...});
server.listen(8080);
I also had the same issue and after adding this code line my problem solved. Now auto reloading worked
devServer : {
contentBase : './',
watchOptions : {
poll: true
}
}
For anyone experiencing this with Webpack v5, you need to set target to web in your config, like so:
module.exports = {
entry: "...",
target: "web",
.....
}

Categories

Resources