I'm currently learning how to use Webpack. I'm following the SurviveJS Webpack 5 book/tutorial that uses webpack-plugin-serve as the dev server, but I can't get the Live Reload functionality to work in my browser.
I see a lot of questions on this topic where the users are running webpack-dev-server, and those answers don't solve my problem.
SETUP:
ENVIRONMENT:
Windows 11 OS
VS Code v1.84.2
Node v18.18.0
Google Chrome (up to date, version 119.0.6045.160)
FILE STRUCTURE:
webpack-demo/
| + dist/
| | - index.html
| | - main.js
| + node_modules/
| + public/
| | - bundle.js
| | - index.html
| + src/
| | - component.js
| | - index.js
| package-lock.json
| package.json
| webpack.config.js
PROBLEM
EXPECTED BEHAVIOR:
In my terminal, execute
npm run startwhich runs the app in development mode.Open the app in Chrome at
127.0.0.1:8080, to see the webpage read "Hello World".In VS Code, open the
src/component.jsfile which is whereindex.jsgets the "Hello World" string.Change the string in
src/component.jsto something like "Hello World from Webpack" and save the file.Webpack detects a change in code and updates the
public/bundle.jsfile.liveReloadrefreshes the browser,public/index.htmlruns the updated JavaScript code, and the browser automatically updates to display "Hello World from Webpack".
ACTUAL BEHAVIOR:
Steps 5 & 6 do not happen as anticipated.
Step 5 - Webpack successfully detects a change in code, as the terminal shows that files are bundled immediately after
component.js's saved changes.Instead of
public/bundle.jsbeing updated, newdist/[hash]-main-wps-hmr.jsanddist/main-[hash]-wps-hrm.jsonfiles are created with hashed names.This behavior really confuses me. I know that "HMR" stands for Hot Module Replacement, but I don't know why these files are being generated instead of my bundled JavaScript file getting updated.
The
dist/[hash]-main-wps-hmr.jslooks just likedist/main.jsexcept it DOES have the text string updated.The JSON files are all the same single line of code:
{"c":["main"],"r":[],"m":[]}
See the terminal message below for additional detail.
Step 6 - The browser does not automatically refresh to display the changed text.
- A manual refresh will show the changed text.
Terminal Message:
> [email protected] start
> wp --mode development
⬡ webpack: Watching Files
⬡ wps: Server Listening on: http://[::]:8080
// WHEN component.js IS UPDATED AND SAVED:
⬡ webpack: assets by path *.js 76.2 KiB
asset main.js 74.7 KiB [emitted] (name: main)
asset 4bd00c0-main-wps-hmr.js 1.52 KiB [emitted] [hmr] (name: main)
asset index.html 190 bytes [emitted]
asset main-4bd00c0-wps-hmr.json 28 bytes [emitted] [hmr]
Entrypoint main 76.2 KiB = main.js 74.7 KiB 4bd00c0-main-wps-hmr.js 1.52 KiB
runtime modules 27 KiB 11 modules
cacheable modules 25.4 KiB
modules by path ./node_modules/webpack-plugin-serve/lib/client/ 24.2 KiB
modules by path ./node_modules/webpack-plugin-serve/lib/client/*.js 8.43 KiB
./node_modules/webpack-plugin-serve/lib/client/client.js 3.37 KiB [built]
./node_modules/webpack-plugin-serve/lib/client/log.js 756 bytes [built]
+ 2 modules
modules by path ./node_modules/webpack-plugin-serve/lib/client/overlays/*.js 15.7 KiB
./node_modules/webpack-plugin-serve/lib/client/overlays/progress-minimal.js 2.41 KiB [built]
./node_modules/webpack-plugin-serve/lib/client/overlays/progress.js 3.88 KiB [built]
+ 2 modules
modules by path ./src/*.js 224 bytes
./src/index.js 79 bytes [built]
./src/component.js 145 bytes [built] [code generated]
./node_modules/webpack-plugin-serve/client.js 1.05 KiB [built]
0 (webpack 5.89.0) compiled successfully in 49 ms
CODE
src/index.js:
import component from "./component";
document.body.appendChild(component());
src/component.js:
export default (text = "Hello world!") => {
const element = document.createElement("div");
element.innerHTML = text;
return element;
};
package.json:
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "wp --mode production",
"start": "wp --mode development",
"watch": "nodemon --watch \"./webpack.*.*\" --exec \"npm start\""
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"mini-html-webpack-plugin": "^3.1.3",
"nodemon": "^3.0.1",
"serve": "^14.2.1",
"webpack": "^5.89.0",
"webpack-nano": "^1.1.1",
"webpack-plugin-serve": "^1.6.0"
}
}
webpack.config.js:
(Does not specify an output property, that has not been covered yet in this stage of the tutorial so it should be using the default value).
const { mode } = require("webpack-nano/argv");
const {
MiniHtmlWebpackPlugin,
} = require("mini-html-webpack-plugin");
const { WebpackPluginServe } = require("webpack-plugin-serve");
module.exports = {
watch: mode === "development",
entry: ["./src", "webpack-plugin-serve/client"],
mode,
plugins: [
new MiniHtmlWebpackPlugin({ context: { title: "Demo" } }),
new WebpackPluginServe({
port: parseInt(process.env.PORT, 10) || 8080,
static: "./dist",
liveReload: true,
waitForBuild: true,
}),
],
};
I also tried the following config file based on the webpack-plugin-serve documentation which produces the same unexpected behavior (new hashed files inside dist/, no live reload).
const { mode } = require("webpack-nano/argv");
const {
MiniHtmlWebpackPlugin,
} = require("mini-html-webpack-plugin");
// BELOW LINE CHANGED:
const { WebpackPluginServe: Serve } = require("webpack-plugin-serve");
module.exports = {
watch: mode === "development",
entry: ["webpack-plugin-serve/client", "./src"],
mode,
plugins: [
new MiniHtmlWebpackPlugin({ context: { title: "Demo" } }),
// BELOW LINE CHANGED:
new Serve({
port: parseInt(process.env.PORT, 10) || 8080,
static: "./dist",
liveReload: true,
waitForBuild: true,
}),
],
};