Webpack 5: why MiniCssExtractPlugin.loader doesn't let HMR work? - webpack-dev-server

Can anyone explain me why MiniCssExtractPlugin.loader doesn't let HMR work and how can I fix it? I created the following webpack.config.js file:
const path = require ('path')
const HTMLWebpackPlugin = require ('html-webpack-plugin')
const MiniCssExtractPlugin = require ('mini-css-extract-plugin')
const cssLoaders = extra => {
const loaders = [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '',
}
},
'css-loader'
]
if (extra)
{
loaders.push(extra)
}
return loaders
}
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'app')
},
devServer: {
port: 8000,
hot: true
},
plugins:[
new HTMLWebpackPlugin({
template: './src/index.html'
}),
new MiniCssExtractPlugin({filename: '[name].[contenthash].css'})
],
module: {
rules: [
{
test: /\.css$/,
use: cssLoaders()
}
]
}
}
And after saving new styles, I get the following messages in the browser console:
[Info] [WDS] App updated. Recompiling... (x2)
[Info] [WDS] App hot update...
[Log] [HMR] Checking for updates on the server...
[Log] [HMR] Updated modules:
[Log] [HMR] - ./src/styles/style.css
[Log] [HMR] App is up to date.
[Log] [HMR] Reload all css
But in fact, in order to see the changes, I have to reload the page. If I change line
use: cssLoaders()
to
use: ['style-loader','css-loader']
HMR really begins working. I read on many forums that adding
target: 'web'
helps with this but in my case it also doesn't resolve this problem.

To avoid this it is necessary to make name of the compiled file without hash or contenthash

in development mode,you should remove contenthash in MiniCssExtractPlugin。
Please refer to webpack docs

Related

Import line getting error in Firefox

I have a React project that uses OverlayLoader library. Although code runs just fine on Chrome, it gets "TypeError: can't convert null to object" in firefox. After taking some time tracking down the error, I found that it comes from import line where I import OverlayLoader library
import OverlayLoader from 'react-overlay-loading/lib/OverlayLoader';
There's also "Source map error: request failed with status 404". But that shouldn't matter though. Why this error only occurs in Firefox?
EDIT : This is content of webpack.config.js
var dotenv = require('dotenv').config({path: __dirname + 'path'});
var webpack = require('webpack');
module.exports = {
entry: ["./js/app.jsx", "./css/custom.scss", "./css/main.scss"],
output: {
path: "public/js",
publicPath: "/js",
filename: "bundle.js"
},
module: {
loaders: [
{
test: /\.jsx?|\.js$/,
exclude: /(node_modules|bower_components|neal-react)/,
loader: "babel-loader",
},
{
test: /\.scss$/,
loader: "style!css!sass"
}
]
},
resolve: {
alias: {
querystring: 'querystring-browser'
}
},
plugins: [
new webpack.DefinePlugin({
"process.env": dotenv.parsed
})
]
};
Two things you can check:
Do you have a libraryTarget in your webpack config? If you, could you try and remove that?
Are you using externals in your webpack configuration? If so, the package will not be bundles and the browser might not have access to it.
Hope it helps.
EDIT:
Seems like it's a source-map issue. I thought that it might be in your configuration but it isn't. Usually a source-map error is because the browser can't find the source-map I think this is an issue you can report with the repo. It's not your configuration.

HMR only updates sometimes

Does anyone actually have HMR up and running smoothly? Mine is hot swapping sometimes only. How is that possible? I will edit a line of text and it will swap. Then I will go edit the same text and it will not see it. I'm using webpack 1.14. I've spent way too much time on this searching every example online and redoing and configuring my webpack.config. This thing is tough without some real documentation on exactly how to set it up with a webpack-dev-server that works everytime. With all of the unanswered questions on stackOverflow and the webpack GitHub issues section, you'd think nobody really understands it except for the creators and a few gurus.
I have a webpack config that looks like this:
var config = {
entry: [
'webpack-dev-server/client?http://localhost:8080',
// bundle the client for webpack-dev-server
// and connect to the provided endpoint
'webpack/hot/only-dev-server',
// bundle the client for hot reloading
// only- means to only hot reload for successful updates
DEV + "/index.jsx"],
output: {
path: OUTPUT,
filename: "app.js",
publicPath: '/',
},
devtool: 'inline-source-map',
devServer: {
hot: true,
// enable HMR on the server
contentBase: OUTPUT,
// match the output path
publicPath: '/'
// match the output `publicPath`
},
plugins: [
new ExtractTextPlugin('styles.css'),
new webpack.NamedModulesPlugin(),
/* new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production')
}
}),
new webpack.optimize.UglifyJsPlugin()*/
],
module: {
loaders: [
{
test: /\.jsx?$/,
include: DEV,
loaders: ["react-hot", "babel-loader"],
},
{
test: /\.css$/,
loader: 'style-loader'
}, {
test: /\.css$/,
loader: 'css-loader',
query: {
modules: true,
localIdentName: '[name]__[local]___[hash:base64:5]'
}
}
],
}
};
module.exports = config;
My file structure is:
-> EZTube
-> dev
->TabComponent
->other source code files
->index.jsx
-> output
->app.js
->index.html
->styles.css
-> webpack.config.js
-> package.json
My index.jsx looks like:
import React from "react";
import ReactDOM from "react-dom";
import TabComponent from './TabComponent/TabComponent.jsx';
import { AppContainer } from 'react-hot-loader';
ReactDOM.render(
<TabComponent />,
document.querySelector("#container")
);
if (module.hot) {
module.hot.accept('./TabComponent/TabComponent.jsx', () => {
const NewApp = require('./TabComponent/TabComponent.jsx').default
ReactDOM.render(NewApp)
});
}
The weird thing is sometimes hot swap happens when I make a change. Other times not at all. Just wondering if there was some wise internet sage out there who would understand why that is happening with the current set up.
I was having the same intermittent HMR problem, though I'm using
webpack-dev-middleware
webpack-hot-middleware
As HMR was working sometimes, I suspected the diffs were not always getting detected.
I'm running this on Windows, so I tried adding this configuration
watch: true,
watchOptions: {
aggregateTimeout: 300,
poll: 1000, //seems to stablise HMR file change detection
ignored: /node_modules/
},
https://webpack.js.org/configuration/watch/
My HMR is more consistently detected now.

How to resolve webpackwarning 'Cannot find update. Need to do a full reload'?

I am running my reactjs app with webpack and gulp, this is a fragement of my gulpfile:
gulp.task("webpack-dev-server", function(callback) {
// modify some webpack config options
var myConfig = Object.create(webpackConfig);
myConfig.devtool = "eval";
myConfig.debug = true;
// Start a webpack-dev-server
new WebpackDevServer(webpack(myConfig), {
//publicPath: "/" + myConfig.output.publicPath,
inline: 'true',
stats: {
colors: true
},
hot:true,
}).listen(9090, "localhost", function(err) {
if (err) throw new gutil.PluginError("webpack-dev-server", err);
gutil.log("[webpack-dev-server]", "http://localhost:9090/webpack-dev-server/index.html");
});
});
This is my webpack.config.js:
module.exports = {
entry: ["./app/app.js",
'webpack/hot/only-dev-server', // "only" prevents reload on syntax errors
],
output: {
path: path.resolve(__dirname, "dist"),
publicPath: "/dist/js",
filename: "http://localhost:9090/dist/js/myapp.js",
sourceMapFilename: "myapp.map"
},
devtool: '#source-map',
plugins: [
new webpack.HotModuleReplacementPlugin()
],
module: {
loaders: [
{
loader: 'babel',
exclude: /node_modules/
}]
},
devServer: {
inline: true
}
}
When the page reloads chrome devtools show the following error:
bootstrap 04b58fb…:25 GET http://localhost:9090/dist/04b58fb8512c7a3f39f8.hot-update.json 404 (Not Found)hotDownloadManifest # bootstrap 04b58fb…:25hotCheck # bootstrap 04b58fb…:244check # only-dev-server.js:12(anonymous function) # only-dev-server.js:70
only-dev-server.js:27 [HMR] Cannot find update. Need to do a full reload!
only-dev-server.js:28 [HMR] (Probably because of restarting the webpack-dev-server)
How can I fix this so I can reload the page?
Have you tried that:
if (module.hot)
module.hot.accept();
The webpack does not update any modules itself, you have to accept it.
https://webpack.github.io/docs/hot-module-replacement-with-webpack.html#what-is-needed-to-use-it

The following modules couldn't be hot updated: (Full reload needed)

I'm trying to setup hot module reloading in a react/typescript (with TSX) environment. I have used the react/redux real-world example as a model in getting things going, and this is what I have so far:
server.js
var webpack = require('webpack')
var webpackDevMiddleware = require('webpack-dev-middleware')
var webpackHotMiddleware = require('webpack-hot-middleware')
var config = require('./webpack.config')
var app = new (require('express'))()
var port = 3000
var compiler = webpack(config)
app.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: config.output.publicPath }))
app.use(webpackHotMiddleware(compiler))
app.use(function(req, res) {
res.sendFile(__dirname + '/index.html')
})
app.listen(port, function(error) {
if (error) {
console.error(error)
} else {
console.info("==> 🌎 Listening on port %s. Open up http://localhost:%s/ in your browser.", port, port)
}
})
webpack.config.js
var path = require('path')
var webpack = require('webpack')
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
devtool: 'cheap-module-eval-source-map',
entry: [
'webpack-hot-middleware/client',
path.resolve('./src/index.tsx'),
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js'
},
plugins: [
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({ template: './index.html' })
],
module: {
loaders: [
{ test: /\.tsx?$/, loader: 'ts-loader' }
]
},
resolve: {
extensions: ['', '.ts', '.tsx', '.js', '.json']
},
}
index.tsx
import * as React from 'react';
import { render } from 'react-dom';
import Root from './containers/root';
render(
<Root />,
document.getElementById('root')
);
containers/root.tsx
import * as React from 'react';
export default class Root extends React.Component<void, void> {
render(): JSX.Element {
return (
<p>boom pow</p>
);
}
}
Changing <p>boom pow</p> to <p>boom boom pow</p> in the root element kicks off this in the javascript console in the browser:
[HMR] bundle rebuilding
client.js?3ac5:126 [HMR] bundle rebuilt in 557ms
process-update.js?e13e:27 [HMR] Checking for updates on the server...
process-update.js?e13e:81 [HMR] The following modules couldn't be hot updated: (Full reload needed)
This is usually because the modules which have changed (and their parents) do not know how to hot reload themselves. See http://webpack.github.io/docs/hot-module-replacement-with-webpack.html for more details.
process-update.js?e13e:89 [HMR] - ./src/containers/root.tsx
process-update.js?e13e:89 [HMR] - ./src/index.tsx
I've stepped through these steps as best I can tell, but am still having no luck.
What am I missing?
The problem, as mentioned by commenters, was missing in my loader - I'm not sure if this had anything to do with it, but I also switched to using babel after typescript - and having typescript compile to ES6. New config below:
var path = require('path')
var webpack = require('webpack')
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
devtool: 'cheap-module-eval-source-map',
entry: [
'webpack-hot-middleware/client',
path.resolve('./src/index.ts'),
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js'
},
plugins: [
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({ template: path.resolve('./src/index.html') })
],
module: {
loaders: [
{ test: /\.tsx?$/,
loaders: [
'react-hot',
'babel?presets[]=es2015',
'ts-loader'
]
},
{ test: /\.json$/,
loader: 'json'
}
]
},
resolve: {
extensions: ['', '.ts', '.tsx', '.js', '.json']
},
}
if someone still struggles with this see the readme: https://github.com/webpack-contrib/webpack-hot-middleware/blob/master/README.md
This module is only concerned with the mechanisms to connect a browser client to a webpack server & receive updates. It will subscribe to changes from the server and execute those changes using webpack's HMR API. Actually making your application capable of using hot reloading to make seamless changes is out of scope, and usually handled by another library.
webpack-hot-middleware doesn't handle hot reload, you'd need to use react-hot-loader for example

Webpack hot module replacement lists updated React components in console but does not update them

After changing some text in my About component and saving the file, I can see the following logs in my console:
client.js?6a8d:123 [HMR] bundle rebuilding
client.js?6a8d:126 [HMR] bundle rebuilt in 3786ms
process-update.js:27 [HMR] Checking for updates on the server...
bootstrap 5e8b103…:45 XHR finished loading: GET "http://localhost:3001/dist/5e8b1032c40f91ebd6ce.hot-update.json".hotDownloadManifest # bootstrap 5e8b103…:45hotCheck # bootstrap 5e8b103…:264check # process-update.js:64module.exports # process-update.js:28processMessage # client.js?6a8d:139handleMessage # client.js?6a8d:65
index.js:81 [React Transform HMR] Patching Marketing
process-update.js:100 [HMR] Updated modules:
process-update.js:102 [HMR] - ./src/containers/Marketing/About.js
process-update.js:102 [HMR] - ./src/containers/Marketing/index.js
process-update.js:107 [HMR] App is up to date.
However, the DOM is not updated and the only way to get the updated text is to do a full browser refresh.
Any ideas on how to solve this? I am fairly sure this was setup correctly in the past and I'm not sure what I did which made it stop working. I can only recall adding code splitting in a few places recently but the about component is part of the main build.
Here's the content of ...-hot-update.json:
{"h":"c6abfe651b7516cb5169","c":[0]}
...-hot-update.js appears to contain the code of the modified component.
Here's my development webpack config:
require('babel-polyfill')
// Webpack config for development
var fs = require('fs')
var path = require('path')
var webpack = require('webpack')
var assetsPath = path.resolve(__dirname, '../static/dist')
var host = (process.env.HOST || 'localhost')
var port = (+process.env.PORT + 1) || 3001
// const { CommonsChunkPlugin } = webpack.optimize
// https://github.com/halt-hammerzeit/webpack-isomorphic-tools
var WebpackIsomorphicToolsPlugin = require('webpack-isomorphic-tools/plugin')
var webpackIsomorphicToolsPlugin = new WebpackIsomorphicToolsPlugin(require('./webpack-isomorphic-tools'))
var babelrc = fs.readFileSync('./.babelrc')
var babelrcObject = {}
try {
babelrcObject = JSON.parse(babelrc)
} catch (err) {
console.error('==> ERROR: Error parsing your .babelrc.')
console.error(err)
}
var babelrcObjectDevelopment = babelrcObject.env && babelrcObject.env.development || {}
// merge global and dev-only plugins
var combinedPlugins = babelrcObject.plugins || []
combinedPlugins = combinedPlugins.concat(babelrcObjectDevelopment.plugins)
var babelLoaderQuery = Object.assign({}, babelrcObjectDevelopment, babelrcObject, {plugins: combinedPlugins})
delete babelLoaderQuery.env
// Since we use .babelrc for client and server, and we don't want HMR enabled on the server, we have to add
// the babel plugin react-transform-hmr manually here.
// make sure react-transform is enabled
babelLoaderQuery.plugins = babelLoaderQuery.plugins || []
var reactTransform = null
for (var i = 0; i < babelLoaderQuery.plugins.length; ++i) {
var plugin = babelLoaderQuery.plugins[i]
if (Array.isArray(plugin) && plugin[0] === 'react-transform') {
reactTransform = plugin
}
}
if (!reactTransform) {
reactTransform = ['react-transform', {transforms: []}]
babelLoaderQuery.plugins.push(reactTransform)
}
if (!reactTransform[1] || !reactTransform[1].transforms) {
reactTransform[1] = Object.assign({}, reactTransform[1], {transforms: []})
}
// make sure react-transform-hmr is enabled
reactTransform[1].transforms.push({
transform: 'react-transform-hmr',
imports: ['react'],
locals: ['module']
})
module.exports = {
devtool: 'inline-source-map',
context: path.resolve(__dirname, '..'),
entry: {
'main': [
'webpack-hot-middleware/client?path=http://' + host + ':' + port + '/__webpack_hmr',
'bootstrap-sass!./src/styles/theme/bootstrap.config.js',
// 'font-awesome-webpack!./src/styles/theme/font-awesome.config.js',
'./src/client.js',
]
},
output: {
path: assetsPath,
filename: '[name]-[hash].js',
chunkFilename: '[name]-[chunkhash].js',
publicPath: 'http://' + host + ':' + port + '/dist/'
},
module: {
loaders: [
{ test: /\.jsx?$/, exclude: /node_modules/, loaders: ['babel?' + JSON.stringify(babelLoaderQuery)]},
{ test: /\.json$/, loader: 'json-loader' },
{ test: /\.less$/, loader: 'style!css?modules&importLoaders=2&sourceMap&localIdentName=[local]___[hash:base64:5]!autoprefixer?browsers=last 2 version!less?outputStyle=expanded&sourceMap' },
{
test: /\.scss$/,
loader: 'style!css?sourceMap&localIdentName=[local]___[hash:base64:5]!autoprefixer?browsers=last 2 version!sass?outputStyle=expanded&sourceMap'
},
{ test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/font-woff" },
{ test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/font-woff" },
{ test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/octet-stream" },
{ test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: "file" },
{ test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=image/svg+xml" },
{ test: webpackIsomorphicToolsPlugin.regular_expression('images'), loader: 'url-loader?limit=10240' }
]
},
progress: true,
resolve: {
modulesDirectories: [
'src',
'node_modules'
],
extensions: ['', '.json', '.js', '.jsx']
},
plugins: [
// hot reload
new webpack.HotModuleReplacementPlugin(),
new webpack.IgnorePlugin(/webpack-stats\.json$/),
// TODO: where should I put this in array?
new CommonsChunkPlugin({ name: 'common' }),
new webpack.DefinePlugin({
__CLIENT__: true,
__SERVER__: false,
__DEVELOPMENT__: true,
__DEVTOOLS__: true, // <-------- DISABLE redux-devtools HERE
'process.env.API_URL': JSON.stringify(process.env.API_URL),
'process.env.PUBLIC_URL': JSON.stringify(process.env.PUBLIC_URL),
'process.env.STRIPE_PUBLISHABLE_KEY': JSON.stringify(process.env.STRIPE_PUBLISHABLE_KEY),
'process.env.INTERCOM_APP_ID': JSON.stringify(process.env.INTERCOM_APP_ID),
'process.env.GOOGLE_ANALYTICS_CODE': JSON.stringify(process.env.GOOGLE_ANALYTICS_CODE),
'process.env.FEATURE_MONITORING': JSON.stringify(process.env.FEATURE_MONITORING),
}),
webpackIsomorphicToolsPlugin.development()
],
}
UPDATE: I just noticed that HMR is working properly for some components (my header and footer for example) but not for others (content of About page). Can't figure out yet what it is that makes some components fail to update.
I had the exact same fail type: everything "looks" like it hot reloads (correct files showing up in console, compile succeeding), but the DOM simply wasn't updating. Full refresh required to update.
Fix for me was: Do not mix Stateless and 'normal' React Components in a single file.
Multiple components styles in a single file failed with HMR.
In short, keep Stateless components:
export default const MyCom = () => <div>🍦</div>
Separate (files) from class based components:
export default class NextCom extends React.Component {
render () { return <div>👻</div> }
}
Putting those two examples into a single file produced the HMR-working-but-failing-to-update-DOM issue you seem to be having too.

Resources