Opening or some of my broken words!

We have just written the basic configuration of webpack loading CSS, loading images, and some basic configurations. So this time we’ll pick up where we left off last week, and we’ll keep doing it! I used to write projects with vue scaffolding and wondered why it would automatically update my page every time I saved it. Why does it automatically open the browser for me every time I start a project? As MY mind was full of business requirements, I forgot all of these things, and the literacy process discovered that the classic Webpack interview question — Hot Update (HMR for Short) — was about this. Alas, young don’t know Webpack. This construction part will be the same as the previous basic part. I will first throw out the problems I don’t understand and post all the problems I have encountered during the project according to my usual way of writing projects, and then post detailed codes. If there are any big shots passing by, please stay! Please grant instruction! Please guidance! Code integrity Connection Directions 👉 github.com/xiaoshanweb…

This thesis mainly covers three parts

I. Load the vue and React files in webpack

In the basics article, we covered some basic configurations. But how to configure vue, React in Webpack?

1: babel

Before implementing the vue/React file, we must first understand the Babel plugin. Babel is a backconversion of non-ECMAScript 2015 languages into compatible javascript. Convert our Vue syntax, JSX to JS, arrow functions to function, const to var, and so on.

NPM install@babel /plugin-transform-arrow-functions -d plugin-transform-block-scoping -d install @babel/plugin-transform-block-scoping -d Convert const to varCopy the code

One thing to note is that Babel is a standalone tool that is not configured with build tools like WebPack. If there is a lot of content to convert, it is impossible to install plug-ins one by one, so Babel has a concept preset, we can just provide a preset to Webpack, and WebPack will load the plugin according to our preset and pass it to Babel. Our common default is env React TypeScript

npm install @babel/preset-env
npm install --save-dev @babel/core
Copy the code
2: Loads the React file
npm i --save-dev react react-dom
npm install @babel/preset-react -D
Copy the code

Add a root tag to the index. HTML file and a babel.config. js file to the root directory

Create a new babel.config.js file and write the plug-in we need to load. If you don’t want to create a new file, you can also configure it under WebPack to load the plug-in

module.exports = {
  presets: [["@babel/preset-env"],
    ["@babel/preset-react"]],}Copy the code

Configure babel-loader in webpack.config.js rules

{
    test: /\.jsx? $/i,
    exclude: /node_modeuls/,
    use: {
      loader: 'babel-loader'.// options: {
      // presets: [
      // ["@babel/preset-env", {
      // // targets: ["chrome 88"]
      // // enmodules: true
      / /}]
      / /]
      // // plugins: [
      // // "@babel/plugin-transform-arrow-functions",
      // // "@babel/plugin-transform-block-scoping"
      / / / /]
      // }}}Copy the code

Create a new reactfile.jsx file

import React, { Component } from 'react';

export default class ReactApp extends Component {
 constructor(props) {
   super(props);

   this.state = {
     message: "Hello React"}}render() {
   return (
     <div>{this.state.message}</div>)}}Copy the code

index.js

import React from 'react'
import ReactApp from './reactFile.jsx'
import ReactDOM from 'react-dom';

ReactDOM.render(<ReactApp />.document.getElementById("root"));
Copy the code

index.html

  <meta charset="UTF-8" />
  <meta name="viewport" content="Width = device - width, initial - scale = 1.0" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  <title>
    <%= htmlWebpackPlugin.options.title %>
  </title>
</head>

<body>
  <div id="root"></div>
</body>

</html>
Copy the code

rendering

3: Loads the Vue file
npm i --save-dev vue vue-loder vue-templete-compiler
Copy the code

Vue file loading is relatively simple, first set up and mount the Vue file,

<template>
 <div class="vue">I'm a Vue file</div>
</template>
<style scoped>
.vue {
 color: red;
 font-size: 20px;
}
</style>
Copy the code
import './index.less'
import Icon from './img.jpeg'
import printMe from './print'

import Vue from 'vue'
import VueApp from './App.vue'

import React from 'react'
import ReactApp from './reactFile.jsx'
import ReactDOM from 'react-dom';

function component() {
  var element = document.createElement('div')
  element.innerHTML = 'Hello Webpack'
  element.classList.add('color_red')

  var img = new Image(300.300)
  img.src = Icon
  element.appendChild(img)

  var btn = document.createElement('button')
  btn.innerHTML = 'Click me'
  btn.onclick = printMe
  element.appendChild(btn)
  console.log(111)
  console.log(222)
  console.log(333)
  return element
}

document.body.appendChild(component())

ReactDOM.render(<ReactApp />.document.getElementById("root"));

new Vue({
  render: h= > h(VueApp)
}).$mount('#app')
Copy the code

index.html

  <meta charset="UTF-8" />
  <meta name="viewport" content="Width = device - width, initial - scale = 1.0" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  <title>
    <%= htmlWebpackPlugin.options.title %>
  </title>
</head>

<body>
  <div id="app"></div>
  <div id="root"></div>
</body>

</html>
Copy the code

Secondly, in webpack.config.js, vue-loader will match all. Vue files, and VueLoaderPlugin will process all matched vue files. However, when downloading vue-loader, pay attention to the version of vue-loader should not be too high, download 15.x.x version can be. There are two ways to introduce VueLoaderPlugin: either require(‘vue-loader/lib/plugin’) directly or download vue-loder-plugin directly. In vue-loder-plugin it also references vue-loader/lib/plugin

// const VueLoaderPlugin = require('vue-loader/lib/plugin')
const VueLoaderPlugin = require('vue-loader-plugin')

 {
   test: /\.vue$/i,
   use: 'vue-loader'
 },
 
 new VueLoaderPlugin()
Copy the code

rendering

II. Automatic compilation

In the last article, we used the Build method to view every update to the code. What method does WebPack provide for automatic compilation?

1:watch
The watch can monitor the changes of files and provide local services through live-server plug-in (VS plug-in) to automatically refresh the page after every modification of files. Disadvantages: A: The efficiency is not very high, so we still need to manually build the Watch before starting it; B: It recompiles all diamante files and generates new files (such as file operations, files, etc.). C: Although file changes can be monitored, there is no automatic browser refresh functionCopy the code
//package.json
"watch": "webpack --watch"./ / or webpack. Config. Js
module.exports={
    watch:true. }Copy the code
2:webpack-dev-server

In development, we want to implement refresh loading capability even without live-server. Webpack-dev-server does not generate any new output files to Watch after compiling, it generates files in memory. It allows users to configure an address that we must use to debug and develop.

  npm install --save-dev-webpack-dev-server
Copy the code

One thing to note about scripting commands in package.json is that WHEN I look at webpack-dev-server, I see two startup options. The first way is to directly use the web-dev-server plug-in to start webpack. The second way is to make sure that the version of Webpack is compatible with Webpack-dev-server. The most troublesome thing is that the two ways can not coexist.

"Start ": "webpack-dev-server", required version of web-dev-server "start-other": "Webpack serve", required version of webpack and web-dev-server "webpack": "^5.48.0", "webpack-cli": "^4.5.0", "webpack-dev-server": "^ 3.11.2"Copy the code

Then configure devServer in webpack.config.js, which is still relatively common,

ContentBase: This property doesn’t touch much, but if there’s some extra static resource in index. HTML that’s stored in pubilc, and it’s introduced in index. HTML that the browser can’t actually import through this path, So you can specify by setting up the contentBase where we’re going to get this file from. The concepts of contentBase and publicPath were confusing when I first looked at them, and when publishing, if the backend was h5 and PC on the same server, publicPath would need to distinguish between where H5 was coming from and where THE PC was coming from. PublicPath is an important one, and we’ll talk more about it next.

devServer: {
   host: '127.0.0.1'.// Host address
   port: 8000./ / the port number
   open: true// Whether the browser is automatically opened after the project is successfully started
 },
Copy the code

After you modify the file, you will see that the browser automatically refreshes. The configuration of Webpack-dev-server is relatively simple. Most of the handling of webpack-dev-server is done by itself, but what if I need to configure the hot update process myself? What if I don’t want framework integration? I ran into this problem when I was writing SSR (server rendering), starting the project through Node without hot updates and having to configure it myself.

3: webpack-dev-middleware

Webpack-dev-middlewarek is a wrapper that can send files processed by WebPack to a Server. It is used internally by webpack-dev-server (yes, it is used internally by webpack-dev-server for hot updates). However, Webpack-dev-Middleware can also be used as a separate package, making it easier for users to customize it to their needs.

The example I saw on the official website, SO I just used it. Of course, if you are familiar with Node, you can build it using KOA. The official example is Express. Start by installing Express, Webpack-dev-Middleware

npm install --save-dev express webpack-dev-middleware
Copy the code

Then create a new server.js file. Let’s start with Express, Webpack, and Webpack-dev-middleware. Create an app and listen for port number 3000. Config takes all the configuration information and passes it to WebPack, which compiles all the configuration information. Once webpack is successfully compiled, a Compiler object is generated and passed to webpackDevMiddleware. WebpackDevMiddleware is the middleware that generates an Express after processing it

const webpackDevMiddleware = require('webpack-dev-middleware')
const webpack = require('webpack')
const express = require('express')

const app = express()
// Load the configuration information
const config = require('./webpack.config')
// Pass the configuration information to webpack compilation
const compiler = webpack(config)

// The compiled result is returned to webpackDevMiddleware, and subsequent requests for webpackDevMiddleware() are returned to the middleware for processing
app.use(webpackDevMiddleware(compiler))

app.listen(4000.() = > {
  console.log("Service already started on port 3000 ~");
});

Copy the code

The project structure is as follows

Ok, when we’re done with the code, let’s test it. Open the terminal and type nodeserver.js. When the console displays output, it means that the operation is successful. Next, type http://127.0.0.1:4000 in the browser

4: HMR (HotModuleReplacement)

HMR– Hot replacement/hot update. Professionally speaking, this means that you can add, remove, or replace modules while the program is running without having to refresh the entire page. By default, webpack-dev-server already supports HMR, so we just need to turn it on.

devServer: {
    // contentBase: './dist',
    host: '127.0.0.1'.port: 8000.open: true.hot: true / / open HMR
  },
Copy the code

When the browser shows these, the connection is successful.

The three hot update methods are actually refreshing the entire page. If I want to refresh only the page I have changed after each change, I can control whether the current page should be updated by adding updates to each page using the module.hot.accept method. However, large projects don’t allow us to configure this at all. In VUE, React, how do we work with hot updates? Vue-loader currently supports hot update, so we don’t need to configure it. React officially provides React-Refresh.

npm install -D @pmmmwh/react-refresh-webpack-plugin react-refresh
Copy the code

Modify the webpack.config.js and babel.config.js files


const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin')

plugins: [new ReactRefreshWebpackPlugin()
]
Copy the code
module.exports = {
  presets: [["@babel/preset-env"],
    ["@babel/preset-react"]],plugins: [['react-refresh/babel']]}Copy the code
HMR principle

Look at the following picture (wang Hongyuan teacher’s picture moved, if there is something wrong, immediately delete! . We can see that the browser communicates with webpack-dev-server through sockets. The source code is packaged in Webpack and compiled into memory, and the browser requests resources from the server via HTTP requests. But HTTP requests are short links that require the browser to initiate a request before the server responds.

We need to achieve a state where the server still pushes data or resources to the browser without the browser making a request, but short links are not possible to achieve this requirement.

Socket can solve this problem. It is the bridge between the server and the browser. When we start devServer, socket establishes a webSocket long connection between the server and the browser. When a file is modified and saved, Webpack will package the modified file into a compiled JSON and JS file and inform the browser through socket. The browser responds to the message and refreshes the corresponding file.

Bug highlights

2021-08-06

The first bug is one that I can’t explain at my current intelligence level. The webpack-dev-server version does not match the webpack-CLI version

“Webpack – cli” : “^ 4.7.2”, “webpack – dev – server” : “^ 3.11.2”

Updated version

“Webpack – cli” : “^ 3.3.12”, “webpack – dev – server” : “^ 3.11.2”