webpack-dev-server hot reload not working - javascript

My file structure is:
dist
css
style.css
index.html
js
bundle.js
src
css
style.css
index.html
js
main.js
node_modules
webpack.config.js
package.json
My webpack.config.js looks like:
module.exports = {
entry: './src/js/main.js',
output: {
path: __dirname,
filename: './dist/js/bundle.js'
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /(node_modules)/,
loader: 'babel',
query: {
presets: ['es2015']
}
},
{
test: /\.vue$/,
loader: 'vue'
}
]
}
};
I run:
webpack-dev-server --content-base dist --hot
And it builds and seems like it's working. localhost:8080 shows the expected result but hot-reload does just not work. When I change a file I can see in terminal that a rebuild is happening but nothing happens in the browser. Am I missing something in the config?

What worked for me is to write <script src="bundle.js"> and not <script src="dist/bundle.js"> in my index.html file.
// index.html
<script src="bundle.js"></script> // works
<script src="dist/bundle.js"></script> // doesn't work!
Keeping dist/bundle.js as the output file works perfectly fine if you just build it using webpack. But when using webpack-dev-server, the static file already in the file system continues to be served, and not the latest hot replacement. It seems webpack-dev-server gets confused when it sees dist/bundle.js in the html file and doesn't hot replace it, even though webpack.config.js is configured to that path.

When using webpack-dev-server, it builds all files internally and does not spit them out into your output path. Running webpack alone, without the dev server, does the actual compilation to disk. The dev server does everything in memory which speeds up re-compilation by a lot.
To fix your hot reload issue, set the content base to your source directory and enable inline-mode
Like so:
webpack-dev-server --content-base src --hot --inline

None of the options on this page worked for me. After changing the devServer section to:
devServer: {
port: 8080,
contentBase: ['./src', './public'], // both src and output dirs
inline: true,
hot: true
},
it worked.

For Webpack ^5.72.1
This worked for me,
devServer: {
port: 3000,
hot: false,
liveReload: true,
},
Note: liveReload will reload the whole application on file save but it will lose application state. Hot reloading preserves state. But liveReload seemed to fix the issue for me with css/html not loading on the browser after save, without having to refresh the browser.

--inline --hot wasn't an issue for me
If you are using redux can try this.
For some random reason redux-devtools was not allowing hot reload for me. Try removing it from root component and redux compose config.
Note: Use redux devtool browser extension with this config in your store configuration: window.devToolsExtension ? window.devToolsExtension() : f => f
Also, must read: https://medium.com/#rajaraodv/webpacks-hmr-react-hot-loader-the-missing-manual-232336dc0d96#.ejpsmve8f
Or try hot reload 3:
example: https://github.com/gaearon/redux-devtools/commit/64f58b7010a1b2a71ad16716eb37ac1031f93915

Webpack hot reloading stopped working for me as well. The solution for me was to delete the node_modules folder and fresh install all dependencies.
Just open the parent folder of node_modules in your terminal and run npm install

100% Working Solution
You have to just follow 3 steps and you will get your hot reloading as you expected
Include "publicPath" key in "Output" property of webpack config. "publicPath" should contain path to your bundle.js file so that dev-server will know if there is any change in your bundle.js file and it will reload your application.
Your config should look like this -
output: {
path: __dirname,
publicPath:"/dist/js/",
filename: './dist/js/bundle.js'
}
Add "devServer" option in config file -
devServer:{
contentBase:"/src/",
inline:true,
stats:"errors-only"
}
Please note that contentBase should point to the path where you put your index.html file which contain your script tag in your case it will be "/src/"
At last you have to make sure 'src' attribute of your 'script' tag in index.html points to bundle.js starting from "http://localhost:port" as follow -
<script src="http://localhost:portnumber + value in publicPath + bundle.js"></script>
in your case it will look like this -
<script src="http://localhost:8080/js/dist/bundle.js" type="text/javascript"></script>
And finally remember webpack-dev-server doesn't compile your js file or make build or watch on your js file it dose everything in memory to watch on your js file you have to run
webpack --watch
in seprate window

The only thing that works for me is apply the "hotOnly" inside the configuration of the "devServer" (on the "webpack.config.js"), like this:
devServer: {
hotOnly: true,
},
After reload the "Webpack Dev Server", the "Hot Reload" works, at least, after saving any change in CSS or JS files.

All those who suffer: don’t forget slash before public path:
publicPath:’/assets/scripts/‘ not publicPath:’assets/scripts/’
Three days lost because of 1 forward slash in the path string

Try this:
In your package.json file, delete the line that contains "test" "echo \"Error: no test specified\" && exit 1" under the scripts object, and replace it with:
...
"scripts": {
"start": "webpack-dev-server --hot"
},
...
Then to restart your project, just use npm start.
This worked for me when I ran into this problem.
Edit: Can you share your package.json file?
Try adding this to webpack.config.js as well
devServer: {
inline: true,
port: 3000,
hot: true
},

Check your console logs if it has below error then add cors to your webpack dev server file
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin react hot reload
Ideally add below entry in you dev server js
headers: { "Access-Control-Allow-Origin": "*" },

I increased the max number of file changes that can be watched and it worked for me. I guess the issue for me was too many files.
echo fs.inotify.max_user_watches=1999999 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
source

You can try adding this to your config:
module.exports = {
...
devServer: {
contentBase: './dist/', // Since your index.html is in the "dist" dir
open: true, // Automatically open the browser
hot: true, // Automatically refresh the page whenever bundle.js changes
// (You will have to refresh manually if other files change)
},
...
};
And then running (no options):
webpack-dev-server

With the above settings, while using webpack-dev-server for static page building I add bundle js or whatever js file configured as output to the html page. This way I get refresh on my static page after any changes.

For webpack version 5, the module.loaders is now module.rules. And for the presets change query to options.

Make sure in development mode you are not using a plugin that extract css into files, example MiniCssExtractPlugin. It messes the things up.

Related

How to make webpack-dev-server serve my index.html

I'm trying to get an extremely simple bare-bones TypeScript project setup with Webpack and I'm having an incredibly hard time for some reason.
I followed this guide and everything is working. When I simply run webpack my files will bundle and compile and be outputted into the dist directory. From there I can host them on a local server and it all works fine.
However, I want to avoid having to manually bundle and compile my code every single time I make a change, and I'd like for this to be done automatically each time I save my files. As far as I can tell this is a common use for Webpack and so I'm not sure why I'm having such an incredibly hard time finding any good information on it.
I decided to use the webpack dev server to accomplish this, so I read this tutorial and for the life of me I can't find anybody who explains how to get it to also server my index.html? When I run webpack serve --mode=development all goes well, and when I navigate to the localhost port that I server to I get a 404 error.
One of the "tips" on the previously linked page reads
If you're having trouble, navigating to the /webpack-dev-server route will show where files are served. For example, http://localhost:9000/webpack-dev-server.
When I navigate to localhost:1234/webpack-dev-server it tells me that it's only serving a single file: bundle.js Clearly a JavaScript file alone is not going to work, and I need it to also serve the index.html file that's in my dist directory.
Now, my knowledge here is very limited as this is my first time working with Webpack, but here's all the detail I can give and hopefully it's not accidentally totally unrelated:
Whenever my dev server reloads itself (whenever it's booted up or if a watched file changes while it's running) it only updates the bundle.js file that it's serving. It doesn't update the bundle.js file stored in my dist directory on my hard drive. How can I make it update both?
And also, how do I make the server also serve my index.html file instead of only the bundle.js? Where is it even getting that bundle.js from? Is it compiling all of my code from scratch to create that js file or is it taking that out of the dist directory?
And additionally, am I going about this totally in the wrong way? Where should my index.html even go? I put my TypeScript files into a src directory and they're converted to .js files and moved into my dist directory... Should I also put my index.html inside src or does it belong in dist or somewhere else entirely? When I put index.html in src it doesn't get copied over into dist, it just ignores it completely. If my index.html file doesn't belong in src it must belong in dist, but if it belongs in dist then how can I expect the dev server to find it and serve it along with the other TypeScript files in src? Why can't the dev server just serve everything in dist and automatically compile everything from src into dist? I must be misunderstanding the flow of it all, but I have no idea where to look for an explanation and I've been at this for several hours now.
Just a general explanation of how it all works would be very helpful as well, as I can't find a single article or forum post anywhere that details all the spaghetti going on with Webpack. I've been avoiding bundlers and all this NPM mess for as long as I can because I constantly run into issues like this, but I finally decided to jump in and just push through all the mess and I'm already regretting it. If someone could just point me (and other people having similar problems) to some good resources for learning about all the automagic going on that would be hugely appreciated. The Webpack documentation and guides are very much worthless to a newbie.
My Webpack config file:
const path = require("path");
module.exports = {
entry: "./src/index.ts",
module: {
rules: [
{
test: /\.tsx?$/,
use: "ts-loader",
exclude: /node_modules/,
}
]
},
resolve: {
extensions: [".tsx", ".ts", ".js"]
},
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "dist")
},
devServer: {
compress: false,
static: false,
client: {
logging: "warn",
overlay: {
errors: true,
warnings: false
},
progress: true
},
port: 1234, host: "0.0.0.0"
}
};
Is your entry set in webpack? So that it is included?
entry: {
main: 'path/to/index.ts'
},
You could also try adding to your index.ts file
require('file-loader?name=[name].[ext]!../index.html');
Or
require("./src/index.html");
// Then In your webpack config file add a loader
loaders : { { test: /\.html/, loader: 'file?name=[name].[ext]' } }
Otherwise you could always copy this file over with webpack copy plugin
{
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html'
})
]
}
will need to run npm install --save-dev html-webpack-plugin to install it. As well as move your index.html file into your src folder
Please visit localhost:1234/bundle (Where bundle.js is your bundled file) the magichHTML route, which will load the HTML file with the bundled script.

Setting up webpack/HMR for Shopify development

I am trying to setup webpack's dev server and HMR to work with Shopify theme development. When running the server and opening the local IP, I get this error from Shopify's DNS provider, CloudFlare.
How can I properly setup webpack to inject hot changes (css/JS) to my proxied Shopify store (the mystore.myshopify.com url)?
My webpack config as follows:
const path = require("path");
const BrowserSyncPlugin = require('browser-sync-webpack-plugin');
module.exports = {
mode: "development",
devServer: {
contentBase: false,
hot: true,
https: true,
proxy: {
"**": {
target: "http://mystore.myshopify.com",
secure: false
}
},
},
entry: "./src/scripts/index.js",
output: {
filename: "./app.js",
path: path.resolve(__dirname, "dist")
},
plugins: [
],
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
// Creates `style` nodes from JS strings
'style-loader',
//postcss here (autoprefixer, babel etc)
// Translates CSS into CommonJS
'css-loader',
// Compiles Sass to CSS
'sass-loader',
],
},
],
},
};
My proposed solution for hot reloading with webpack and shopify.
In your package.json you will want the following scripts
A webpack build script that watches for changes. I have also added a progress parameter so I can see when it updates. This will be watching your /src folder for changes.
"webpack:build": "cross-env NODE_ENV=development webpack --watch --progress",
A shopify theme serve script that uploads the theme files from a /dist folder that is the output of a webpack build.
"shopify:serve": "cd dist && shopify theme serve"
You can link these two scripts together into one using the following.
"deploy:serve": "run-p -sr webpack:build shopify:serve"
So what happens is the webpack build script listens for changes in your /src code. When a change is main it re-builds the output to the /dist folder that shopify theme serve is listening on. When that updates, shopify uploads the changes.
Voila.
Here is the repo for this implementation if you want to play around - https://github.com/Sambuxc/9119-shopify-theme/
As of writing this, my dev versions are:
Node 18.7.0
Npm 8.15.0
Shopify Cli 2.21.0
Good luck and I hope this helps future developers.
Please reach out to me with any further questions if you get stuck.

Webpack: How to compile, write on disk and serve static content (js/css) using webpack-dev-server

I want to build my js/css code, write it on disk and serve it using webpack-dev-server in a single command. I don't want to set-up another server for production mode. How do we do it? Sharing my webpack.config.js file content below:
module.exports = {
watch: true,
entry: [
'./src/index.js'
],
output: {
path: __dirname +'/dist/',
publicPath: '/dist/',
filename: 'bundle.js'
},
module: {
loaders: [
{
exclude:/(node_modules)/,
loader: 'babel',
query: {
presets: ['es2015', 'react']
}
}
]
},
devServer: {
historyApiFallback: true,
contentBase: './'
}
};
Please find the start script used in package.json below:
"start": "webpack-dev-server --progress --colors"
I am running "npm run start". Please help.
New webpack-dev-server is released, and it supports writeToDisk option.
devServer: {
writeToDisk: true
}
With webpack-dev-server v4.0.0+, devMiddleware is used:
devServer: {
devMiddleware: {
writeToDisk: true
}
}
webpack-dev-server uses a "virtual" Express server in conjunction with Sock.js to emulate a server running on your machine. Regarding compilation, webpack-dev-server does recompile the bundle whenever it detects code changes. This recompilation is served from memory, however, as opposed to the project's build directory (or, in your case, the dist directory). From the docs:
Using this configuration, webpack-dev-server will serve the static files in your build folder. It’ll watch your source files, and recompile the bundle whenever they are changed.
Regarding writing to your disk, webpack-dev-server does not do this. This is partially addressed by what's been written above. Additionally, note the following, also from the Webpack docs:
This modified bundle is served from memory at the relative path specified in publicPath (see API). It will not be written to your configured output directory. Where a bundle already exists at the same URL path, the bundle in memory takes precedence (by default).
To write to your disk, use the ordinary webpack module. Of course, as your question hints at, manual recompilation after every change is tedious. To address that chore, include the watch flag. From the Terminal, you could execute the command:
$ webpack --watch
I prefer to delegate this to an NPM script, however. Note that the -w flag below is equivalent to writing --watch.
// NPM `scripts` field:
"watch": "webpack -w"
If you want to run webpack-dev-server while also having your changes get recompiled and written to your output directory, you can add an additional NPM script like so:
"scripts": {
"serve": "npm run watch && npm run start",
"start": "webpack-dev-server --progress --colors",
"watch": "webpack -w"
}
Then, in your Terminal, just execute $ npm run serve to accomplish this.
If you're interested in the added convenience of automatic reload, you can do so by defining the following within the plugins field of your Webpack config file:
new webpack.HotModuleReplacementPlugin()
Note: This will likely require additional configuration settings for Babel. If I were you, I would take out the query field from your babel loader and, instead, delegate your Babel configuration to an external .babelrc file. A good one to use that is compatible with hot reloading might look like this:
{
"presets": ["env", "es2015", "react"],
"plugins": ["react-hot-loader/babel"]
}
On a side note, I've created a boilerplate repo for easily starting out projects with my desired structure. The Webpack configuration may of interest to, specifically. In particular, it employs Webpack 2 and includes other build tools like Babel (for transpilation), ESLint (syntax checker) as well as support for CSS/Sass and a variety of other file formats.
You can change your start script definition to this:
"start": "webpack --watch & webpack-dev-server --inline --progress --colors".
This sends the webpack watch-and-rebuild process to the background so that you can also hot-reload your modified modules as you change them with webpack-dev-server.
EDIT:
Either of these plugins may do what you want:
https://github.com/gajus/write-file-webpack-plugin
https://github.com/FormidableLabs/webpack-disk-plugin
webpack-dev-server serve files from memory, you can replace webpack-dev-server with webpack-simple-serve, it use webpack's watch feature, write the compiled files to disk and use serve-handler to serve.

Webpack-dev-server doesn't build files on change

So I have the following webpack configuration :
import path from 'path';
module.exports = {
entry: {
index: './dev/index.js'
},
output: {
path: path.join(__dirname, 'dist'),
publicPath: './dist/',
filename: 'bundle.js',
chunkFilename: '[id].bundle.js'
},
module:{
loader:{
test: /\.js$/,
exclude:path.resolve(__dirname, "node_modules"),
loader: 'js'
}
}
};
The problem is that when I do webpack --watchthe file does build in the /dist/ folder at every change. Yet when I run the webpack-dev-server the files don't even build. Why is that?
Please help.
The reason you are not seeing files emitted into your dist folder is because webpack-dev-server uses an in-memory filesystem
This allows for extremely fast incremental builds when your code changes. This was an intentional design on our part. You can view the resulting code in your browser and never need to reference those files.
It is not recommended by us, for the sake of build performance, but you can look in to plugins like write-file-webpack-plugin if you need this feature.
'webpack' writes your bundle to disk, whereas 'webpack-dev-server' loads the bundle into memory. So when running the latter command you wont see a new 'bundle.js' file appear in your file system, even though you should see output to the console reporting the bundling and the start up of the dev server).
The output.publicPath config key determines the location of the in-memory bundle on the host dev server. So if you set the publicPath to 'dist' then the index.html served by the webpack dev server will need a script tag in order to reference the bundle.

Webpack-dev-server not bundling even after showing bundle valid message

I've set up a basic react application with webpack but I couldn't get the webpack-dev-server running properly.
I've installed webpack-dev-server globally and tried running the command sudo webpack-dev-server --hot as hot reloading was required.
The project seems to be working fine with just webpack cmd. It builds into my build folder and I can get it working via some server but it wont work with webpack-dev-server. From terminal its clear that the build process has completed with no error being thrown [webpack: bundle is now VALID.] and its in fact watching properly because on any change it does trigger the build process but it doesn't really gets built [it doesn't serve my bundle.js]. I tried changing the entire config and still couldn't get the issue resolved.
It would be much appreciated if someone can help.
Following is my webpack.config.js file.
var path = require('path');
module.exports = {
devtool: '#inline-source-map"',
watch: true,
colors: true,
progress: true,
module: {
loaders: [{
loader: "babel",
include: [
path.resolve(__dirname, "src"),
],
test: /\.jsx?$/,
query: {
plugins: ['transform-runtime'],
presets: ['es2015', 'react', 'stage-0'],
}
}, {
loader: 'style!css!sass',
include: path.join(__dirname, 'src'),
test: /\.scss$/
}]
},
plugins: [],
output: {
path: path.join(__dirname, 'build/js'),
publicPath: '/build/',
filename: '[name].js'
},
entry: {
bundle: [
'./src/index.js'
]
},
devServer: {
contentBase: "./",
inline: true,
port: 8080
},
};
I've got the issue resolved by myself. Silly as it sounds but the issue was with the publicPath under the output object. It should match the path property instead of just /build/, i.e.,
output: {
path: path.join(__dirname, 'build/js'),
publicPath: '/build/js', // instead of publicPath: '/build/'
filename: '[name].js'
},
In my case I had to check where the webpack is serving the file.
You can see it:
http://localhost:8080/webpack-dev-server
Then I could see my bundle.js path > http://localhost:8080/dist/bundle.js
After that I used that /dist/bundle.js in my index.html <script src="/dist/bundle.js"></script>
Now it refreshes any file changes.
webpack-dev-server serves your bundle.js from memory. It won't generate the file when you run it. So bundle.js is not present as a file in this scenario.
If you wan't to use bundle.js, for example to optimize it's size or test your production deployment, generate it with webpack using the webpack command and serve it in production mode.
By the way, started from Webpack v4 it is possible to write in-memory assets to disk:
devServer: {
contentBase: "./",
port: 8080,
writeToDisk: true
}
See doc.
The fix to this for me was:
devServer: {
devMiddleware: {
writeToDisk: true,
}
}
https://webpack.js.org/configuration/dev-server/#devserverwritetodisk-
Dev-server keeps the compiled file in memory, and I can't access it directly...
BUT! THE SOLUTION is that you have no need to access it, in development(even when you run your project on node server or localhost) use localhost:8080 to access your page, and that's where webpack-dev-server is serving your page and you can feel all advantages of using it(live reload!), BUT! it doesn't compile your bundle.js, SO! before production, you need to manually run webpack build command, and that's it! there is no way for dev-server to compile your bundle.js file! Good Luck!
Please refer to this - https://github.com/webpack/webpack-dev-server/issues/24
According to this, webpack dev server no longer writes to the disk. So, you wont be able to see the build file. Instead, it will be served from the memory. To get it working you have to set the proper path.
Example: in index.html loads the build file from '/dist/main.js' so in webpack config file set the output.publicPath to '/dist/'
In my case I was using VS Code and I had to restart it. I have noticed that vs code bugs up sometimes. The changes you make in configuration files (package.json, webpack.config.js etc.) do not take effect sometimes. So, in case you encounter a situation where something doesn't work even with the correct settings, just restart vs code.
I can't see any bug reports related to this. So that's strange. I'm thinking this bug is triggered if you change one of the configuration files some time later after you have already built the project multiple times.
If this is actually what's happening then it's a huge bug. I'll try switching to Visual Studio instead of Code and see if this still happens. If it does then it's probably an issue with webpack.

Categories