2022-webpack5 practical tutorial

foreword

Hand-to-hand teach you how to pack, let you feel webpack in the hands-on practice process.
Before you start, you can briefly understand the concept of webpack
Each summary has a corresponding branch, which is convenient for everyone to learn
webpack version: 5.58.1

getting Started

Create a new directory and initialize npm
npm init
Next install the webpack and webpack-cli packages
npm i -D webpack webpack-cli

default allocation

Create a new folder src, create a new main.js in it, and write a little test code
console.log("webpack")
Add new commands to scripts in package.json

"scripts": {
  "build": "webpack ./src/main.js"
},

Execute the packaging command npm run build
At this point, if a dist folder is generated and contains main.js inside, it means that the package has been successful
This example is just the default configuration of webpack itself. Next, we will implement a richer custom configuration.

custom configuration

Create a new build folder and create a new webpack.config.js in it

const path = require('path');

module.exports = {
  mode:'development', // development mode
  entry: path.resolve(__dirname,'../src/main.js'), // entry file
  output: {
      filename: 'output.js', // Packaged file name
      path: path.resolve(__dirname,'../dist') // packaged directory
  }
}

Change packaging command

{
  // ...
  "scripts": {
    "build": "webpack --config build/webpack.config.js"
  },
}

Then execute npm run build, you will get the following results

where main.js is the legacy we packaged for the first time.
js has been packaged, the next thing we have to do is to introduce js into the html file

add js to html file

We need html-webpack-plugin to do this for us
npm i -D html-webpack-plugin
Create a new folder public at the same level as build, and create a new index.html in it
The configuration is as follows

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

module.exports = {
  mode:'development', // development mode
  entry: path.resolve(__dirname,'../src/main.js'), // entry file
  output: {
      filename: '[name].[hash:8].js', // [name] refers to the name of the entry attribute, the default is main
      path: path.resolve(__dirname,'../dist') // packaged directory
  },
  plugins:[
    new HtmlWebpackPlugin({
      // Select an html as a template, the same html will be generated in the dist directory, and then the packaged js will be injected into the html file
      template: path.resolve(__dirname,'../public/index.html') 
    })
  ]
}

After the packaging is successful, check whether the index.html file in the dist directory refers to the packaged js

How to inject multiple files into html

  1. Multiple entry files, injected into the same html file

In this case, we just need to add the entry, and the html-webpack-plugin plugin will automatically inject all packaged js into html

module.exports = {
  // ...
  entry: {
    main: path.resolve(__dirname,'../src/main.js'),
    share: path.resolve(__dirname,'../src/share.js')
  }
}
  1. Multiple entry files, injected into different html files according to different requirements

We can fix this by generating multiple instances of html-webpack-plugin

module.exports = {
 // ...
  plugins:[
    new HtmlWebpackPlugin({
      // Select an html as a template, the same html will be generated in the dist directory, and then the packaged js will be injected into the html file
      template: path.resolve(__dirname,'../public/index.html'),
      filename: 'index.html',
      chunks: ['main'] // Configure which files will be injected into the html file. [] means no js will be injected. If there is no such attribute, all js will be injected by default.
    }),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname,'../public/share.html'),
      filename: 'share.html',
      chunks: ['share']
    })
  ] 
}

Empty the dist directory before packaging

I believe you have also discovered that there are more and more files in the dist directory. Let's solve this problem.
We need clean-webpack-plugin to do this for us
npm i -D clean-webpack-plugin

// The rest of the configuration is the same as above
const { CleanWebpackPlugin } = require('clean-webpack-plugin')

module.exports = {
   plugins:[
    // ...
    new CleanWebpackPlugin()
  ] 
}

As reminded by friends, webpack5 has a new way to clear the dist directory, and the clean field is added to the output, which is now added below

module.exports = {
  // ...
  output: {
      filename: '[name].[hash:8].js', // [name] refers to the name of the entry attribute, the default is main
      path: path.resolve(__dirname,'../dist'), // packaged directory
      clean: true
  },
}

Inject css into html as style tag

Our entry file is js, so we introduce our css file in entry js

// main.js
import "../static/css/base.css"
import "../static/css/color.scss"
import "../static/css/fontsize.less"

console.log("webpack")

We need some loader s to parse our css files
npm i -D style-loader css-loader
If you use less to build styles, you need to install
npm i -D less less-loader
If you use scss to build styles, you need to install
npm i -D node-sass sass-loader
The configuration file is as follows

module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"] // Parsing from right to left
      },
      {
        test: /\.scss$/,
        use: ["style-loader", "css-loader", "sass-loader"] // In addition, you need to install node-sass(sass also works)
      },
      {
        test:/\.less$/,
        use:['style-loader','css-loader','less-loader'] // In addition, you need to install the less module
      }
    ]
  }
}

After packaging, open the html file in the browser, and you can see the css we injected

add browser prefix to css

In order to adapt to more browser styles we need to prefix css
We need postcss-loader and autoprefixer to do this for us

Refer to the webpack video explanation: into learning

There are two ways to introduce autoprefixer

  1. Introduction of postcss.config.js (recommended)

Create postcss.config.js in the **project root directory**, the configuration is as follows

module.exports = {
  plugins: [
    require('autoprefixer')
  ]
}

Then import it directly in webpack.config.js

module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader", "postcss-loader"] // Parsing from right to left
      },
      {
        test: /\.scss$/,
        use: ["style-loader", "css-loader", "postcss-loader", "sass-loader"] // In addition, you need to install node-sass(sass also works)
      },
      {
        test:/\.less$/,
        use:['style-loader','css-loader', "postcss-loader", 'less-loader'] // In addition, you need to install the less module
      }
    ]
  } 
}
  1. Configure directly in webpack.config.js
moudule.exports = {
 // ...
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader", {
          loader: "postcss-loader",
          options: {
            postcssOptions: {
              plugins: [
                ['autoprefixer']
              ]
            }
          }
        }] // Parsing from right to left
      },
      {
        test: /\.scss$/,
        use: ["style-loader", "css-loader", {
          loader: "postcss-loader",
          options: {
            postcssOptions: {
              plugins: [
                ['autoprefixer']
              ]
            }
          }
        }, "sass-loader"] // In addition, you need to install node-sass(sass also works)
      },
      {
        test:/\.less$/,
        use:['style-loader','css-loader', {
          loader: "postcss-loader",
          options: {
            postcssOptions: {
              plugins: [
                ['autoprefixer']
              ]
            }
          }
        }, 'less-loader'] // In addition, you need to install the less module
      }
    ]
  } 
}

After completing the above configuration, we found that css was not successfully prefixed. Here we have to do another step, that is to configure package.json, and add the following configuration to package.json

{
 // ...
"browserslist": [
    "defaults",
    "not ie < 11",
    "last 2 versions",
    "> 1%",
    "iOS 7",
    "last 3 iOS versions"
  ]
}

External links import css files

Above, we load our styles through the style tag, but if there are too many css files, it will be very confusing.
We need mini-css-extract-plugin to help us implement
npm i -D mini-css-extract-plugin

// The rest of the configuration remains the same
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
  // ...
  plugins: [
    // ...
    new MiniCssExtractPlugin({
      filename: "[name].[hash].css",
    })
  ],
    module: {
    rules: [
      {
        test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, "css-loader", "postcss-loader"] // Parsing from right to left
      },
      {
        test: /\.scss$/,
        use: [MiniCssExtractPlugin.loader, "css-loader", {
          loader: "postcss-loader",
          options: {
            postcssOptions: {
              plugins: [
                ['autoprefixer']
              ]
            }
          }
        }, "sass-loader"] // In addition, you need to install node-sass(sass also works)
      },
      {
        test:/\.less$/,
        use:[MiniCssExtractPlugin.loader,'css-loader', "postcss-loader", 'less-loader'] // In addition, you need to install the less module
      }
    ]
  }
}

However, in this way, all css will be merged into one css file. If you want to split it, you can only use other methods. I see that others use extract-text-webpack-plugin on the Internet, but when I go to the npm official website to see Time.

So I won't discuss splitting css here.

image processing

Image processing in css and js only needs to add the following configuration

module.exports = {
    // ...
  module: {
    rules: [
        // ...
      {
        test: /\.(jpe?g|png|gif)$/i,
        type: "asset",
        generator: {
          filename: 'static/[name].[hash].[ext]'
        }
      },
    ]
  }
}

If you need to process pictures in html, you need to use html-loader
npm i -D html-loader
The configuration is as follows

module.exports = {
    // ...
  module: {
    rules: [
        // ...
      {
        test: /\.html$/i,
        loader: "html-loader"
      },
    ]
  }
}

If you need to configure more resource files, please refer to the resource module

escape js file

In order to make our js code compatible with more environments we need to escape our js files
npm i -D babel-loader @babel/preset-env @babel/core core-js

module.expors = {
  // ...
  module: {
    rules: [
      // ...
      {
        test: /\.js$/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              [
                '@babel/preset-env',
                {
                  useBuiltIns: 'usage',
                  corejs: {
                    //version of core-js
                    version: 3
                  },
                  //Compatible browser required
                  targets: {
                    chrome: '60',
                    firefox: '60',
                    ie: '9',
                    safari: '10',
                    edge: '17'
                  }
                }
              ]
            ],
          }
        },
        exclude: /node_modules/
      }
    ]
  }
}

babel-loader is responsible for converting ES6/7/8 syntax to ES5 syntax
core-js is responsible for converting new APIs, such as promise s, Generator s, Set s, Maps, Proxy, etc.

Advanced

Build a Vue development environment

Vue file handling

Install the necessary dependencies first
npm i -D vue-loader vue-template-compiler vue-style-loader
npm i -S vue
vue-loader is used to parse .vue files
vue-template-compiler for compiling templates
vue-style-loader parsing styles

const vueLoaderPlugin = require('vue-loader/lib/plugin')
module.exports = {
  // ...
  module:{
    rules:[
      // This loader must be placed at the top
      {
        test:/\.vue$/,
        use:['vue-loader']
      }
      // ...
    ]
  },
  resolve:{
    // set path alias
    alias:{
      'vue$':'vue/dist/vue.runtime.esm.js',
      '@':path.resolve(__dirname,'../src')
    },
    // Try to resolve these suffix names in order.
    // If there are multiple files with the same name but different suffixes, webpack will parse the file with the suffix listed first in the array and skip the rest.
    extensions:['*','.js','.json','.vue']
  },
  plugins:[
    new vueLoaderPlugin()
  ]
}

Hot update configuration

We need to use webpack-dev-server to start a local service and configure hot updates
npm i -D webpack-dev-server
The configuration is as follows

const Webpack = require('webpack')
module.exports = {
  // ...
  devServer:{
    port:3000,
    hot:true
  },
  plugins:[
    new Webpack.HotModuleReplacementPlugin()
  ]
}

Configure packaging commands

"scripts": {
  // ...
  "dev": "webpack-dev-server --config build/webpack.config.js --open"
},

Add --open to automatically open the http://localhost:3000 page
Next, write a few lines of code to test, first modify our main.js

// main.js
import Vue from 'vue'
import App from './App.vue'

new Vue({
  render: h => h(App)
}).$mount('#app')

Create a new App.vue file

<template>
  <div>
    {{msg}}
  </div>
</template>

<script>
export default {  data() {    return {      msg: "webpack vue"
    }  }}
</script>

<style lang='scss' scoped>
div {  color: aquamarine;  display: flex;}
</style>

Modify the original index.html

<!DOCTYPE html>
<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>webpack</title>
</head>
<body>
  <div id="app"></div>
</body>
</html>

Finally execute npm run dev

Distinguish between development and production environments

There is a huge difference in build targets between development and production environments. In the development environment, we need: a powerful source map and a localhost server with live reloading (real-time reloading) or hot module replacement (hot module replacement) capabilities. The production environment goals have shifted to other areas, focusing on compressing bundle s, lighter source map s, resource optimization, etc., through these optimizations to improve load times. Because of the logical separation to follow, we generally recommend writing separate webpack configs for each environment.
We add two more files webpack.prod.js and webpack.dev.js based on the original webpack.config.js
Here we need to use webpack-merge to help us merge the code
npm i -D webpack-merge

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

module.exports = merge(common, {
  mode: 'development',
  devtool: 'inline-source-map',
  devServer:{
    port:3000,
    hot:true
  }
});
// webpack.prod.js
const { merge } = require('webpack-merge');
const common = require('./webpack.config.js');

module.exports = merge(common, {
  mode: 'production',
});

The original webpack.config.js also needs to be modified, we only need to delete the mode and devserver fields
Finally modify the scripts command in package.json

"scripts": {
    "build": "webpack --config build/webpack.prod.js",
    "dev": "webpack-dev-server --config build/webpack.dev.js --open"
  },

Run npm run dev in the development environment, package npm run build

at last

It's not easy to code words, if it helps you, then give it a like

Tags: Webpack

Posted by ibechane on Mon, 17 Oct 2022 16:56:42 +1030