Preface:

Can go to mineGithub/blogRead on and if you can help, go to star😊

You may have noticed that references to JS in HTML files are written manually, so if we change the output path or package the compiled file name, we have to change the references in HTML files manually. How do we do that, like in create-React-app where once you modify something in a file, the page will refresh itself? Let’s implement them step by step. Of course, this section does more than just accomplish these two points.

Automatically compile HTML and import JS files

Public index.html should be automatically compiled into the dist directory, and all JS references added automatically. You can use the HTML-webpack-plugin to handle this optimization.

The installationHtmlWebpackPlugin

Execute the following code on the console:

npm install --save-dev html-webpack-plugin
Copy the code

Configure the plugins property in webpack.prod.config.js

const merge = require('webpack-merge');
const common = require('./webpack.common.config.js');

const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = merge(common, {
  mode: 'production'.plugins: [
    new HtmlWebpackPlugin({
      filename: 'index.html'.// Why not '.. /public/index.html'
      // If the template is in the same directory as the template, start at the root
      template: 'public/index.html'.inject: 'body'.minify: {
        removeComments: true.collapseWhitespace: true,},})]});Copy the code
  • Filename: indicates the name of the packed HTML file
  • template: use our own defined HTML as a template, otherwise we have to package the HTML file to write
  • Inject: Inject JS file at the bottom of body. If head, inject JS in head
  • minify: Compressed HTML files, more configurationAm I
    • RemoveComments: Removes comments
    • CollapseWhitespace: collapses the space

Click on the official README for more configurations

Remove manually imported script tags from index.html


      
<html lang="en">
<head>
  <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>Configure webPack4 + React scaffolding from zero</title>
</head>
<body>
  <div id="root"></div>
</body>
</html>
Copy the code

Now let’s try packaging, see if there’s an extra HTML file in dist, and import script automatically. Open it in your browser and see if it outputs the content correctly!

Change the undetermined name of the packaged JS file

This operation is to prevent business brought on by a browser cache code updates, and the problem that the page didn’t change, you think about it, if the client request while on a js file name is the same, then it probably is not a new packet, and directly use the cached files before, of course, it related to caching strategies.

So how do we assign an indefinite name to the exported file? Very simply, [hash] or [chunkhash] modify webpkk.prod.config.js:

const merge = require('webpack-merge');
const common = require('./webpack.common.config.js');

const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = merge(common, {
  mode: 'production'.output: {
    filename: 'js/[name].[chunkhash:8].bundle.js',},plugins: [
    new HtmlWebpackPlugin({
      filename: 'index.html'.template: 'public/index.html'.inject: 'body'.minify: {
        removeComments: true.collapseWhitespace: true,},})]});Copy the code

Where, name is the module name, which has been configured in Entry. Resetting here will replace the previous setting in Common. Chunkhash is the hash of file content, and Webpack uses MD5 to hash files by default. 8 is the length of the hash. If not, WebPack sets the default value to 20.

Now you repackage and look at the name of the generated JS file ~

Clean up the dist directory before packing and compiling

After the above modification, because the js file name is different, if you pack it later, you will leave the JS file that was packaged before and after. We just want the latest packaged and compiled file, so we need to clear the dist directory first and then regenerate it.

Install the clean – webpack – the plugin

npm install --save-dev clean-webpack-plugin
Copy the code

This plugin is not included in the official documentation, you can check out its configuration documentation at Github

Use the clean – webpack – the plugin

Modify webpck. Prod. Config. Js:

const merge = require('webpack-merge');
const common = require('./webpack.common.config.js');

const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = merge(common, {
  mode: 'production'.output: {
    filename: 'js/[name].[chunkhash:8].bundle.js',},plugins: [
    new HtmlWebpackPlugin({
      filename: 'index.html'.template: 'public/index.html'.inject: 'body'.minify: {
        removeComments: true.collapseWhitespace: true,}}),new CleanWebpackPlugin()
  ]
});
Copy the code

Const CleanWebpackPlugin = require(‘ cleanwebpack-plugin ‘); And you need to pass in the parameter new below, the dist file path. Const {CleanWebpackPlugin} = require(‘ cleanwebpack-plugin ‘); And you don’t have to write path arguments anymore

Now execute to see if there is only one JS file! ~

The code segment

Let’s take a look at the console when we were packing and compiling earlier:



react
react-dom

Modify webpack.common.config.js to add an entry:

  entry: {
    index: './src/index.js'.framework: ['react'.'react-dom'],},Copy the code

Repackage and find that react and react-dom are compiled to framework.js, but our index.bundle.js is still 129KB. This is because we haven’t pulled out the common code in index.js yet.

Webpackage 3 uses the CommonsChunkPlugin plugin to remove common modules. In webpack4, the CommonsChunkPlugin is officially deprecated and instead is configured with optimization.splitchunks for greater convenience.

Add code to webpack.prod.config.js:

module.exports = {
  / /...
  optimization: {
    splitChunks: {
      chunks: 'all'.minSize: 30000.maxSize: 0.minChunks: 1.cacheGroups: {
        framework: {
          test: "framework".name: "framework".enforce: true
        },
        vendors: {
          priority: - 10.test: /node_modules/.name: "vendor".enforce: true,},}}},/ /...
};
Copy the code

The cacheGroups object, which defines modules that need to be pulled off, has the test attribute as a key value, which can be a string, regular expression, or function. If a string is defined, the entry module name will be matched, and the module containing it will be removed from the other modules. Name is the name of the extracted framework module, which is the same as the name of the entry file module, so that the extracted framework module overwrites the extracted framework module, even though they are both called framework. Vendors is a cache group, and its test set to /node_modules/ means that only modules imported from the node_modules folder are filtered, so all third-party modules are split out.

Repackaging, we find that the index.bundle.js file is only 1.69 KB in size


import React from 'react';

function App() {
  return (
    <div className="App">
      <h1>I am changed</h1>
    </div>
  );
}

export default App;
Copy the code

Once again, you will notice that the hash value of index.bundle.js (not cached) has changed, but the hash value of freamework.bundle.js (cached) has not changed.

Compressed JS files

We need to compress the js files generated by packaging as much as possible in order to reduce the file size and load them faster by users. We need a plugin: uglifyjs-webpack-plugin to do the job

Install uglifyjs webpack — the plugin

Execute the following code on the console:

npm install uglifyjs-webpack-plugin --save-dev
Copy the code

Introduction of uglifyjs webpack — the plugin

Add the following code to webpack.prod.config.js:

const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
Copy the code

Optimization specifies the minimizer parameter

minimizer: [
  new UglifyJsPlugin(),
	/ /...].Copy the code

The optimization parameter should now look like this:

  optimization: {
    minimizer: [new UglifyJsPlugin()],
    splitChunks: {
      chunks: 'all'.minSize: 30000.maxSize: 0.minChunks: 1.cacheGroups: {
        framework: {
          priority: 100.test: "framework".name: "framework".enforce: true
        },
        vendors: {
          priority: - 10.test: /node_modules/.name: "vendor".enforce: true,},}}},Copy the code

Our index.bundle.js has been reduced by 0.1KB, although this gap will grow as the business code increases.

Autocompile package

Every time we change the code, we have to go through this NPM run build to see the results, which greatly reduces the development efficiency. It’s unbearable! Webpack gives us a devServer development environment that supports hot updates and is quite comfortable.

Webpack – dev – server installation

Execute the following code on the console:

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

Add code towebpack.dev.config.js :

Are you forgetting the configuration file you created earlier? It doesn’t matter, there is no code anyway, it is specifically used to configure our development environment

const path = require('path');
const merge = require('webpack-merge');
const common = require('./webpack.common.config.js');

const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = merge(common, {
  mode: 'development'.output: {
    filename: 'js/[name].[hash:8].bundle.js',},devServer: {
    contentBase: path.resolve(__dirname, '.. /dist'),
    open: true.port: 9000.compress: true.hot: true
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: 'public/index.html'.inject: 'body'.hash: false
    }),
    new webpack.HotModuleReplacementPlugin()
  ]
});
Copy the code

HotModuleReplacementPlugin is webpack hot update plug-in, setting devServer. Hot is true, and introduced in the plugins HotModuleReplacementPlugin plug-in. Also note that we have hot enabled, so the export cannot use chunkhash and needs to be hash instead.

Modify our package.json

As in the previous build, we did this by configuring package.json. Now we also add the following code to simulate:

  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack --config ./config/webpack.prod.config.js",
+ "start": "webpack-dev-server --inline --config ./config/webpack.dev.config.js"
  },
Copy the code

Next, execute from the console

npm run start
Copy the code

Is a webpage with port 9000 automatically opened, which is the content of the page we wrote, which is one-to-one corresponding to our configuration? Now you can modify the code in app.js, and then go back to the page to see if it has changed, so we can integrate webpack-dev-server successfully.

We’ll configure csS-related properties in the next section. Come on!