1. devServer

I don’t know if you noticed that one of the tedious steps of debugging in the last few videos is that every time you test package, you need to re-execute the NPM run bundle command, and then manually open the index.html file in the dist directory to see the effect. Can we do this automatically when the source code changes in the SRC directory?

1.1 Use the –watch parameter

First, we can add the –watch argument to the webpack command:

// package.json
"scipts":{
    "watch":"webpack --watch"
}
Copy the code

He listens for changes to the packaged source code and repackages it as soon as it changes. To update the files under the dist directory.

That’s the first solution. Won’t help us up the server, can’t do Ajax debugging, have to manually refresh the browser.

1.2 webpackDevServer

The above method can only do automatic packaging, but if you want to automatically open files and simulate some of the server’s features, it is not enough to use the devServer tool, which is a webpacked local server that helps us listen for source code changes and automatically refresh the browser.

Based on using

First you need to install:

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

Then configure:

// webpack.config.js devServer:{contentBase:'./dist' // server root}Copy the code

Then add a command to the package.json file:

"start":"webpack-dev-server"
Copy the code

Then execute the start command, log prompt us in the local port 8080 started a service, can access, and at this time we change the source code, it will help us automatically refresh the browser, so it can improve the development efficiency.

Now we can see that there is no dist directory. DevServer still packs SRC, but it does not pack SRC in the dist directory, it packs SRC in memory, so it will be faster. Don’t worry.

At the same time, this server form compared to the previous direct open local index.html has another advantage is that you can send Ajax requests, because the request must be on a server to HTTP protocol, and the local open is the file protocol, certainly not! And opened the server is issued from the local port 8080, generally there is no problem —- most front-end framework is used in this way.

Other configuration

  • Open: This configuration allows you to automatically open the browser and display the interface after executing a command.
  • Proxy: Front-end frameworks sometimes configure this parameter to perform interface proxy for cross-domain requests
devServer:{
    ...
    proxy:{
        '/api':'http://localhost:3000'
    }
}
Copy the code

If the user accesses the API port of 8080, the port will be forwarded to port 3000.

  • Port: indicates the port for devServer startup

1.3 Implement a similar service yourself

Here we write a simple service based on Node to simulate the above functions of DevServer.

First we add a new command and the corresponding JS file:

"server":"node server.js"
Copy the code

Now we need to complete the server.js to help us create such a devServer-like server

Set up the environment

First you need to install Express or KOA to help you set up the server quickly, and you also need to listen for changes in webPack packaging, so you also need middleware:

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

We then add a publicPath to the Output field of the WebPack configuration file so that all fields referenced by the package will have a/root path:

output:{
    publicPath:'/',
    ...
}
Copy the code

Write server. Js

Const express = require('express') const webpack = require('webpack') const app = express( app.listen(3000,() => { console.log('server is running) })Copy the code

Let’s write some webpack logic, using some apis for WebPack and webpackDevMiddleware:

const express = require('express') const webpack = require('webpack') const webpackDevMiddleware = require('webpack-dev-middleware') const config = require('./webpack.config.js'); Const complier = webpack(config); // Use Webpack with config to compile code at any time. Const app = express() returns a compiler const app = express() // Create a server instance // Use complier // middleware to help listen for changes to the packaged source code // Whenever the file is changed, complier will run again, Corresponding packaging output content is publicPath app. Use (webpackDevMiddleware (complier), {publicPath: config. The output. PublicPath}) / / listener port app.listen(3000,() => { console.log('server is running) })Copy the code

Now if you rerun the complier compiler, it will repackage the code

Then we change the source code and see that the console outputs the packaging information.

But here the browser has to be manually refreshed, and it takes a lot of configuration to be exactly the same as devServer. Here will not continue to expand, interested in their own online search learning materials.

You can also use Webpack in Node, and can implement a lot of custom WebPack extension services

2. Hot Module Replacement – Updates the Hot Module

Here’s a problem: devServer refreshes the browser when you make changes to the style of the source code, but all the changes you made to the HTML (such as adding an element to the page append) are gone and you have to do it all over again.

Here you can use HMR to modify the CSS and directly update the page style, no need to refresh.

2.1 use HMR

CSS

devServer:{ ... Hot :true, // Open HMR hotOnly:true // Even if HMR doesn't work, I don't want the browser to refresh automatically, I won't do anything else}Copy the code

Now that the devServer configuration is complete, we also need to introduce a plug-in for WebPack:

// webpack.config.js
const webpack = require('webpack')
...

plugins:[
    ...
    new webpack.hotModuleRepalcemnetPlugin()
]
Copy the code

After the above configuration, the HMR function is enabled. We need to restart devServer for the configuration file to take effect.

We found that the CSS has been modified, it will not affect the interface, only replace the CSS content, not change the CONTENT rendered by JS! , greatly convenient style debugging.

JS

The same problem with CSS applies to JS files: every time a JS file is modified, an HTTP request is sent to request 8080 to refresh, and the state of the other JS files is not saved.

We hope that data changes in individual modules will not affect the contents of other modules, so we can use HMR to achieve this.

Here we turn on the previous HMR configuration, and we need some extra code to make it work:

//index.js ... counter() number() if(module.hot){ module.hot.accpet('./number',() => { document.body.removeChild(document.getElementById('number')) number(); }) // If the number file has changed, the following function is executed:Copy the code

2.2 Precautions

This JS HMR can not be updated directly like CSS, CSS actually needs to write similar logic, but csS-loader has already handled it for you.

In vue and other frameworks, we haven’t written JS HMR code like the one above, because vue-Loader also has these processes built in. React uses the Babel Process to implement HMR.

Note, however, that if you want to hot update some files, such as data files, the default processing logic may not include, you need to manually write code like the above, there is no way to use loader or Bable Process.

Those who are interested can also continue to learn the underlying principles of HMR online

3. Babel

How do we combine Babel and Webpack to handle our ES6 syntax

3.1 Introduction of Problems

First we’ll create a new index.js file that uses some ES6 syntax:

const arr = [
    new Promise(() => {}),
    new Promise(() => {})
];

arr.map(item=>{
    console.log(item)
})
Copy the code

The index file above includes the ES6 syntax, we tried to use Webpack package:

npx webpack
Copy the code

There is no devServer package here, because the packaged file is not generated in the directory, but stored in memory, so you can’t see it. Just pack it in Webpack

Let’s take a look at the content generated by the package, importing almost exactly what’s in index.

To see if the previous code works, let’s open Chrome (devServer).

This is because newer versions of Chrome implement the ES6 syntax itself, but if we use older versions of Chrome or Internet Explorer we may get an error. The final reason is that the application is not compatible.

We hope that when Webpack is packaged it will convert ES6 to ES5 syntax so that all browsers can run.

3.2 Introduction and use of Babel

Babel is a popular JS compiler that can convert ES6 syntax to ES5 syntax.

To use Babel with Webpack, see the webpack tutorial on Babel’s website.

We need to install a babel-loader and the core library @babel/core to complete the JS code -> AST -> ES5 code process

npm install --save-dev babel-loader @babel/core
Copy the code

Add a rule to config rules as described above:

rules:[{
    test:/\.js$/,
    exclude:/node_modules/,
    loader:"babel-loader"
}]
Copy the code

Exclude indicates that if your js file is in Node-moudles, you will not use babel-loader, because this is a third party code, and it will almost always be escaped.

Then you need to install @babel/ Preset to turn on ES5 conversion:

npm install @babel/preset-env --save-dev
Copy the code

This is because babel-loader is a bridge between Webpack and Babel, and doesn’t translate ES6 to ES5, it needs another module, and this is preset-env.

rules:[{
    test:/\.js$/,
    exclude:/node_modules/,
    loader:"babel-loader",
    options:{
        presets:["@babel/preset-env"]
    }
}]
Copy the code

Then, we will open a package and look at the main.js file and see that the arrow function becomes a normal function and the let becomes a var.

In addition, you can configure target to specify which browsers need to be escaped, and Babel will only be used for conversion if the configured browser version is lower than the version you specified. This is usually available because the older browser version is compatible with ES6.

rules:[{ test:/\.js$/, exclude:/node_modules/, loader:"babel-loader", Options: {presets: [[" @ Babel/preset - env ", {the targets: {edge: "17", chrome: "67", firefox: "60", safari: "11.1"}}]]}}]Copy the code

3.3 the Babel/polyfill

But is it enough just to do this conversion? Not enough, for example, the array map method doesn’t exist in older browsers, so this is not only a syntactic conversion for preset-env, but also a way to add missing variables or functions to the code. Here you need to use babel-polyfill:

npm install --save @babel/polyfill
Copy the code

Be careful not to add -dev here, because this is also needed when the code runs.

All we need to do is import where polyfill is required, and here we place this import at the top of the business code index.js

// index.js

import "@babel/polyfill";

const arr = [];

arr.map(...)
Copy the code

We don’t want Babel to include all the compatible syntax. For example, we just want Babel to polyfill the map method, otherwise the package will be too big

Here we need to write a configuration to webpack.config.js, and make changes to the presets field in webpack.config.js, and add a configuration:

rules:[{
    test:/\.js$/,
    exclude:/node_modules/,
    loader:"babel-loader",
    options:{
        presets:[["@babel/preset-env",{useBuiltIns:'usage'}]]
    }
}]
Copy the code

When I polyfill, I don’t add all of them, I add them according to what I need, and then I make a bag:

Note: This is not recommended if you are developing a library or a third party module, because polyfill is compatible with global substitution, and using this method will pollute the global environment.

Babel/plugin – transform – 3.4 runtime

Packaging libraries requires a different configuration:

Here we need to install two modules, according to the instructions on the official website. Then you need to add a plugin to the WebPack configuration parameters:

rules:[{
    test:/\.js$/,
    exclude:/node_modules/,
    loader:"babel-loader",
    options:{
        "plugins":[["@babel/plugin-transform-runtime",{
            "corejs":2,
            "helpers":true,
            "regenerator":true,
            "useEsModules":false
        }]]
    }
}]
Copy the code

Corejs2: corejs2: corejs2: corejs2: corejs2: corejs2: corejs2: corejs2

npm install --save @babel/runtime-corejs2
Copy the code

And then you’re done. If you are writing business code, refer to 3.3 to use Polyfill.

If you are writing a class library, do the same to avoid polluting the global environment.

3.5 Troubleshooting the Problem that there are too many Options

For online business, there may be a lot of options. In this case, we can write a separate. Babelrc file in the root directory and copy the configuration items into it:

// .babelrc
{
    "plugins":[["@babel/plugin...."]]
}
Copy the code

3.6 Configuring React Code Packaging

React has a JSX syntax that webPack can’t recognize without special processing. Babel has a tool to parse JSX syntax for React.

npm install --save-dev @babel/preset-react
Copy the code

Add @babel/preset- React to the presets field.

{
    presets:[
        [
            "@babel/preset-env",{
                targets:{
                    chrome:'67',
                },
                useBuiltIns:'usage'
            }
        ],
        "@babel/preset-react"
    ]
}
Copy the code

The react code is converted from ES6 to ES5, and then from right to left. Restart Devserver