One, foreword
The previous article covered how to handle static resources. This article will go one step further and show you how to create a basic yet efficient development environment.
Keywords: HtmlWebpackPlugin, Source Map, Dev Server, Hot Module Replacement.
Plugins – Quick packing
If Loader is used to convert different resources, Plugin is used to help us manage the packaging process.
In the previous packaging process, there were actually two problems.
First, we are not allowed to delete the index. HTML in the output folder (DIST), and the packaged file is used as the HTML template.
Second, when we change the name of the output file, the packaged new file will coexist with the old file that was not renamed before.
In order to pack quickly, we need to solve these two problems.
a) HtmlWebpackPlugin
The solution to the first problem is to make index.html automatically generated. HtmlWebpackPlugin does this. It automatically generates an index.html file in the output directory after packaging.
Before installing the plug-in, you need to write an index.html file under SRC to use as a template for subsequent packaging.
src/index.html
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="Width = device - width, initial - scale = 1.0" />
<title>my webpack demo</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
Copy the code
Install plug-in:
npm install --save-dev html-webpack-plugin
Copy the code
webpack.config.js
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
// ...
plugins: [
new HtmlWebpackPlugin({
template: "./src/index.html".// Set your own template file here})]};Copy the code
b) CleanWebpackPlugin
The solution to the second problem is to clear the contents of the output directory before packaging, and then let it regenerate. The CleanWebpackPlugin plugin, while not official, is still recommended prior to 5.20.0.
Its Github address is github.com/johnagan/cl…
Install plug-in:
npm install --save-dev clean-webpack-plugin
Copy the code
webpack.config.js
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
// ...
plugins: [
new CleanWebpackPlugin(), // Clear the files in the input directory before packaging
new HtmlWebpackPlugin({
template: "./src/index.html".// Set your own template file here})]};Copy the code
c) output.clean
Webpack.js.org/configurati…
There is a more convenient way: in webPack 5.20.0+, the ability to clear the contents of the output directory is built in, simply by configuring a parameter in the Output option.
webpack.config.js
module.exports = {
/ /...
output: {
clean: true.// Clean the output directory before emit.}};Copy the code
Third, Devtool
Now try writing an incorrect syntax and package it.
consele.log(123)
Copy the code
Even with the wrong syntax, the package will still succeed, and when you open the wrapped index.html in your browser, an error will appear in the console.
When you click on index.js:79 on the right, it jumps to the wrong location.
But this location will be different from our normal logic and will direct you to the error location in the package file, not to the error location in your business code.
Obviously, what we as developers want to see is a place in the business code.
This is where the devtool option comes in. It maps to where the business code went wrong when the code went wrong.
The configuration is different in different environments.
1. Source Map in the development environment
webpack.config.js
module.exports = {
mode: 'development'.devtool: 'eval-cheap-module-source-map' // development
}
Copy the code
2. Source Map in the production environment
module.exports = {
mode: 'production'.devtool: 'nosources-source-map'.// production
}
Copy the code
Reference: webpack.js.org/configurati…
Four, DevServer
After handling static resources with Loaders and quick Plugins packaging, we were basically happy to package files.
At this point, there is a new problem, what problem? That is, we can’t see the results of the packaging until we run the code after it is packaged.
During development, we want automatic packaging so that we can see the changes as we write the code, rather than manual packaging every time.
Officials offer three ways:
- Webpack’s Watch Mode (listen for file changes, repackage, output directory can see the new package file.)
- Webpack-dev-server (enable local development server, default port 8080, compiled file in memory, not local.)
- Webpack-dev-middleware (middleware that uses Webpack as Node.js)
These are all good development tools, and in most cases, the second is just fine.
Note: these tools are for the benefit of the development environment only, please avoid such use in the production environment!!
1. Watch (Listening mode)
You can instruct webpack to “watch” all files within your dependency graph for changes. If one of these files is updated, the code will be recompiled so you don’t have to run the full build manually.
Set up the script in package.json.
package.json
{
"scripts": {
"watch": "webpack --watch".// Listen to package
"bundle": "webpack" // Plain packing}},Copy the code
Run NPM Run Watch in the terminal and you’ll see how WebPack compiles your code. It doesn’t go away after it’s packaged, and the script keeps watching for changes to your files. When you make changes to the file, it will automatically recompile the changed modules. (That is, if you change the contents of the document, it will automatically pack it for you.)
2. Webpack-dev-server (local development server)
The
webpack-dev-server
provides you with a rudimentary web server and the ability to use live reloading.
Installation:
npm install --save-dev webpack-dev-server
Copy the code
package.json
{
"scripts": {
"start": "webpack serve".// Start the local server
"watch": "webpack --watch".// Listen to package
"bundle": "webpack" // Plain packing}},Copy the code
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// ...
mode: 'development'.devtool: 'eval-cheap-module-source-map'.devServer: {
contentBase: path.join(__dirname, 'dist'), // Specify the path to the directory where the HTML page is accessed
open: true.// The page is automatically opened when the server is started
compress: true.// Enable gzip compression
port: 9000.// Customize the port number
publicPath: '/' // The default path for the server to access static resources with a higher priority than output.publicPath
},
// ...
}
Copy the code
Note:
- In a development environment, mode, Devtool, and devServer configurations are very important!
- Webpack-dev-server does not write any files to the output directory after compilation. Instead, it stores the packaged files in memory as if they were real files installed on the server root path. If you want to find packaged files on another path, you can change this setting by using the publicPath option in devServer.
3. Webpack-dev-middleware — this section can be skipped
webpack-dev-middleware
is a wrapper that will emit files processed by webpack to a server. This is used inwebpack-dev-server
internally, however it’s available as a separate package to allow more custom setups if desired.
Installation:
npm install --save-dev express webpack-dev-middleware
Copy the code
package.json
{
"scripts": {
"server": "node server.js".// Run the Node server
"start": "webpack serve".// Start the local server
"watch": "webpack --watch".// Listen to package
"bundle": "webpack" // Plain packing}},Copy the code
webpack.config.js
module.exports = {
// ...
output: {
// ...
publicPath: '/'}}Copy the code
Add a server.js file to the root directory
const express = require('express');
const webpack = require('webpack');
const webpackMiddleware = require('webpack-dev-middleware');
const config = require('./webpack.config')
const compiler = webpack(config); // Package the compiler
// Tell express to use the webpack-dev-middleware and use the webpack.config.js
// configuration file as a base.
const app = express();
app.use(webpackMiddleware(compiler, {
publicPath: config.output.publicPath,
}));
app.listen(3000.() = > {
console.log('Server listening on port 3000');
});
Copy the code
NPM run server is running on port 3000
Above, we have implemented automatic packaging.
Hot Module Replacement(HMR)
Run NPM run start, at this point, we try to modify the file, and then go back to the page, you will find that the terminal webpack helped us to recompile the code, and then it will automatically refresh, the refreshed page is reset, the previous operation on the page is missing, and we have to start again.
What we want is that when the file changes and is recompiled, the page doesn’t refresh entirely, just the part that responds to the change. This is where HMR, hot module replacement, comes in.
Note: HMR is equivalent to dev Server assist, again only for development environment, not production environment!!
1. HMR before
Now look at the situation before setting up HMR:
index.js
import './assets/styles/reset.css'
import './assets/styles/global.scss'
import { log } from './assets/js/log.js'
const root = document.getElementById('root');
// 1. Generate a button
const btn = document.createElement('button');
btn.textContent = 'Add Item';
btn.classList.add('btn');
root.appendChild(btn);
// 2. Add an event to the button and append the div element to root
btn.addEventListener('click'.() = > {
const item = document.createElement('div');
item.textContent = 'Item ' + (root.children.length);
item.classList.add('item');
root.appendChild(item);
});
log('hello'.'world! ');
Copy the code
./assets/styles/global.scss
// Custom variables
$color: #ff4200;
$fs: 14px;
$ls: 1.2;
// Customize mixins
@mixin size ($w.$h: $w) {
width: $w;
height: $h;
}
body {
font-size: $fs;
background-color: #eaeaea;
.btn {
@include size(100px.50px);
background-color: $color;
border: 1px solid # 000;
color: #fff;
text-align: center;
padding: 10px;
margin: 10px;
&:hover {
background-color: #ff4200; }}.item {
@include size(100px.50px);
background-color: #ff4200;
border: 1px solid # 000;
color: #fff;
text-align: center;
padding: 10px;
margin: 10px;
&:hover {
background-color: #ff4200; }}.item:nth-of-type(2n) {
background-color: blueviolet
}
}
Copy the code
./assets/js/log.js
const log = (. args) = > {
console.log(... args); }export { log };
Copy the code
Effect: When you click the Add Item button, an Item appears below it.
Now, change the style file so that the item created an even number of times is greenish-yellow.
global.scss
// ...
.item:nth-of-type(2n) {
// background-color: blueviolet;
background-color: yellowgreen;
}
Copy the code
Note that when we are done with the modification and press save, the page will refresh and the previous item will disappear. We need to click BTN again to generate item to see the effect of the modification.
After that, let’s change log.js,
const log = (. args) = > {
console.log(... args,1);
}
export { log };
Copy the code
As above, the page is refreshed globally after saving.
2. After the HMR
- After devServer configuration, add HOT and hotOnly, which means to enable HMR
- After the plugins are configured, add the HMR plug-in. (It’s built-in with WebPack, remember to introduce WebPack at the top)
webpack.config.js
const webpack = require('webpack');
module.exports = {
// ...
devServer: {
contentBase: path.join(__dirname, 'dist'), // Specify the path to the directory where the HTML page is accessed
// ...
hot: true.// Enable hot update
hotOnly: true.// Force hot update, no page refresh
},
plugins: [
// ...
new webpack.HotModuleReplacementPlugin()
],
}
Copy the code
After setting, run NPM run start again.
Repeat the style changes above and you will find that the page is not completely refreshed, but the style changes are already applied.
However, after trying to modify log.js, nothing has changed.
For js files, there are a few things you need to set up.
Add the following code to index.js:
if (module.hot) {
module.hot.accept('./assets/js/log.js'.(arr) = > {
log('hello'.'world! '); })}Copy the code
This means that if WebPack has hot update (that is, hot replacement) enabled, the first argument is the accepted file that was updated, and the second is the callback function that is triggered when the file is updated.
As above, we receive a change to log.js, and when it changes, log(‘hello’, ‘world! ‘).
At this point, re-execute NPM run start to see the effect.
summary
That’s all for this article.
- In order to output packaged files efficiently with template support, HtmlWebpackPlugin is needed;
- To quickly locate code errors, we need a source map;
- To better simulate real world development, we need devServer (WDS);
- To update the modified content locally in real time rather than globally, we need Hot Module Replacement (HMR)!