Webpack catalog

  1. The core configuration of webpack5
  2. Webpack5 modularity principle
  3. Webpackage 5 with Babel/ESlint/ browser compatibility
  4. Webpack5 performance optimization
  5. Webpack5 Loader and Plugin implementation
  6. Webpack5 core source code analysis

Installation depends on Webpack webpack-CLI

The webpack-cli installation package is not required. For example, it is not used in vue-CLI or react-CLI. Node_modules /. For example, run the webpack command to configure the configuration file. The configuration commands and configuration file parameters in the command require webpack-CLI, and webpack-CLI depends on Webpack. We can also introduce Webpack directly into the file, such as calling the webpack function and passing in parameters such as configuration commands and configuration files, without relying on webpack-CLI.

When the webpack command is executed, the webpack.config.js configuration file in the current directory is executed by default, if not, the./ SRC /index.js entry configuration file is executed. For example, run webpack –entry./ SRC /main.js –output-path./build to specify the packing entry and packing exit

--entry string[] An entry file for an application, for example./src/main.js
--config, -c string[] Provide a path to the WebPack configuration file, for example./webpack.config.js
--config-name string[] The configuration name to use
--name string Configuration name, used when loading multiple configurations
--color boolean Enable console colors
--merge, -m boolean Merge two configuration files using webpack-merge, for example-c ./webpack.config.js -c ./webpack.test.config.js
--env string[] Passed to the configured environment variable when it is a function

Specific other command parameters can refer to the official documentation webpack.docschina.org/api/cli/#fl…

The core configuration

mode

Provides the mode configuration option to tell WebPack to use the built-in optimizations for the corresponding mode. There are three values’ none ‘|’ development ‘|’ production ‘, the default for ‘production’. The corresponding description is as follows.

options describe
development willDefinePlugin 中 process.env.NODE_ENVIs set todevelopment. Enable valid names for modules and chunks.
production willDefinePlugin 中 process.env.NODE_ENVIs set toproduction. Enable deterministic obfuscation names for modules and chunks,FlagDependencyUsagePlugin.FlagIncludedChunksPlugin.ModuleConcatenationPlugin.NoEmitOnErrorsPlugin 和 TerserPlugin 。
none Do not use any default optimization options

Different modes will have different default configurations. Currently, there is no display of default configurations on the official website. You can only check webpack default Options (source code).

module.exports = {
  mode: 'production'  // Production environment
  // mode: 'development' // development environment
  // mode: 'node' // No configuration
}
Copy the code

entry

Entry is a configuration entry for compilation and packaging. You can enter strings, objects, and arrays

  • The input parameter is a string
module.exports = {
  entry: './src/main.js'
}
Copy the code
  • The input parameter is an object
module.exports = {
  entry: {
    main: './src/main.js'.index: './src/index.js'}}Copy the code

output

Output is the file that finally packages the output

Set the main parameters as follows

  • filenameOutput file name
  • pathPackage the output file directory
  • cleanThe package directory will be deleted before packaging

Note: Configuring output.path requires an absolute path, so you can import node’s path library to obtain the absolute path of the current package output file directory.

const path = require('path')
const resolve = (src) = > {  
  return path.resolve(__dirname, src)
}
module.exports = {  
  entry: './src/main.js'.output: {    
    filename: 'bundle.js'.path: resolve('build'),    
    clean: true}}Copy the code

devtool

This option controls whether and how the Source map is generated. What is the source map? In our production environment, when an error is reported, it is difficult to locate the specific location of the error, because the code in the production environment has been uglified and compressed by some Babel, Loader and compression tools, so it is particularly difficult to debug. Even in the development environment, The code is compiled and there are many inconsistencies with the source code. The source map maps compiled code to the source file. The source map maps compiled code to the source file. The source map file is generated from the source file. We can use webpack configuration to generate the Source map file, and then add a comment at the end of the compiled code pointing to the source-Map file. //# sourceMappingURL=bundle.js.map The browser will look for the Soure Map file based on our comments and restore the source code from the source Map file for us to debug.

Reading soure map in our browser is enabled by default. In Chrome, it is enabled as shown below

Devtool = source-map = devtool = source-map

module.exports = {
  / /...
  mode: 'development'.devtool: 'source-map'
  / /...
}
Copy the code

After repackaging, we added a bundle.js.map file to the bundle output file in addition to bundle.js

Looking at the bundle.js file, we can see that the sourceMappingURL annotation at the end of the file points to the bundle.js.map file

Then we can be sure that the bundle.js.map file is the source map file we want. What does the source map file look like

{
  "version": 3."file": "js/bundle.js"."mappings": "yBAIAA,QAAQC,IAAIC,KACZF,QAAQC,ICJCE,GDKTH,QAAQC,ICDCE,G"."sources": [
    "webpack://lyj-test-library/./src/main.js"."webpack://lyj-test-library/./src/js/priceFormat.js"]."sourcesContent": [
    "// import { createComponent } from './js/component'\n// createComponent()\n\nimport { add, minus } from './js/priceFormat'\nconsole.log(abc)\nconsole.log(add(2, 3))\nconsole.log(minus(5, 3))\n"."const add = (a, b) => {\n return a + b\n}\n\nconst minus = (a, b) => {\n return a - b\n}\n\nexport {\n add,\n minus\n}"]."names": [
    "console"."log"."abc"."a"]."sourceRoot": ""
}
Copy the code

Describe each of these properties

  • version: Current version in use, and the latest third edition
  • sourcesSource-map and packaged code converted from which files (the most original files)
  • names: Variable and attribute names before conversion (empty array if development mode is used, so there is no need to keep the name before conversion
  • mappings: source-map Specifies information, such as location, used to map to the source file, a set of Base64 VLQ encoding, unavailable
  • file: packaged file (browser loaded file)
  • sourceContent: Specific code information before conversion (corresponding to sources)
  • sourceRoot: All sources relative to the root directory

Currently webpack5 for dealing with the source map provides us with the 26 kinds of options, we can check the website webpack.docschina.org/configurati… The official website compares and compares the speed and slowness of each source map option, so let’s take a look at some of the main options used in our development test release.

First, there are three configurations that do not have a Source map

  • (none)The devtool property defaults to production and does not generate a source map
  • evalAs the development default, it does not generate a Source map, but it adds a comment to eval at the end of the eval. The browser will generate directories for us when we debug
  • false: No Source map file is produced, and no source Map-related content is generated

The options for generating a Source map are described below

source-map

//# sourceMappingURL=bundle.js.map (sourceMappingURL=bundle.js.map) {//# sourceMappingURL=bundle.js.map} And opening the error in the browser can locate the line of source code where the error was reported, and the column where the error started is specified for us.

eval-source-map

//# sourceURL=[module]\n//# sourceMappingURL=data:application/json; charset=utf-8; Base64.

The same configuration can also locate the specific row and column locations of the source code reporting the error

inline-source-map

//# sourceMappingURL=data:application/json; //# sourceMappingURL=data:application/json; charset=utf-8; Base64.

You can also locate the row and column locations of the source code in the browser

cheap-soure-map

//# sourceMappingURL=bundle.js.map annotation points to the.map file. The difference is that there is no column mapping. Because in real development we can probably analyze the problem when we get to a certain line.

However, there is a problem with this option. When we use loader to process source code, the source map error location is not handled so well. For example, we use babel-loader to process our code

When we repositioned the error location, we found that the error location did not match the source code

Hence the cheap-module-source-map configuration.

cheap-module-source-map

This option differs from cheap-source-map in that it works better for Soucre maps using the Loader. Let’s still use babel-loader. After repackaging, you can see that the error location now matches the source code exactly.

hidden-source-map

//# sourceMappingURL=bundle.js.map is removed at the bottom of the bundle.js file, so the source map file cannot be referenced. If you add the above comment manually under bundle.js, it will work again.

nosources-source-map

This option generates the Source map, which also adds url annotations to the bundle. Js file, but unlike source-Map, the bundle.js.map file lacks the sourceContent attribute

Therefore, only error messages can be generated, not source files.

In fact webpack gives us so many source map options that can be combined as follows

  • inline-|hidden-|eval: Selects one of three values
  • nosources: optional value
  • cheap: Optional value and can be followedmoduleThe value of the

Model rules [inline – | hidden – | eval -] [nosources -] [being – [module -]] source – the map.

So how do we use it optimally in different environments

  • The development phase: Recommended usesource-maporcheap-module-source-map
    • This value is used by vUE and React respectively to obtain debugging information for rapid development
  • Testing phase: Recommended usesource-maporcheap-module-source-map
    • During the test phase we also want to see the correct error in the browser
  • Release phase: false, default (no write)\

context

The current working directory of the Node.js process is used by default, but it is recommended to pass in a value in the configuration. This makes your configuration independent of CWD(current working Directory).

devServer

NPM install webpack-dev-server -d, a dependency package, is required to start a local server. Then we can enable the local server by using the webpack serve script. Webpack will give us a new port to open

"scripts": {
  "serve": "webpack serve --open"  // The open argument automatically opens the default browser
}
Copy the code

This will open a http://localhost:8085 page in the browser, and we can open the browser console to see the webpack-dev-server launch print-out, and not the build directory, but in memory. So how does this install package implement start local service. We can look at the source code

It actually uses the Express library to listen on a port to open a local server. Can express start a local service without using webpack-dev-server itself? NPM install webpack-dev-middleware express-d and create sever. Js

// server.js
const WebpackDevMiddleware = require('webpack-dev-middleware')
const Webpack = require('webpack')
const express = require('express')
const app = express()

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

const middleware = WebpackDevMiddleware(compile)

app.use(middleware)

app.listen(8888.() = > {
  console.log('Port 8888 started')})Copy the code

Start the file with Node and execute node server.js after startup

You can see that it works and the browser page works, but normally we don’t customize to start the service unless we need to output some custom content during the startup process.

HMR

So when we modify the file and we refresh the entire page, so the entire memory has to be reinitialized, is there a technology that allows us to update the modified part without refreshing the browser? There is HMR, HMR whole Hot Module Replace, Module hot replacement is the process of replacing, adding, and removing modules while the application is running without having to refresh the entire page.

Since the official prompt starts with Webpack-dev-server V4, HMR is enabled by default. It will be automatically applied webpack HotModuleReplacementPlugin, it is necessary to enable the HMR. So when hot is set to true or via the CLI –hot, you don’t need to add the plugin to your webpack.config.js.

{
  devServer: {
    hot: true}}Copy the code

But we still refresh the entire page after modifying the file, because we still need to configure something, we need to add the following configuration under the import file.

if(module.hot) {
  module.hot.accept('./js/priceFormat'.() = > {
    console.log('priceFormat updated ')})}Copy the code

When we modify the priceFormat file, the browser does not refresh

You can see that the browser control shows that HMR is successful. If we get an error while writing, normally the page will refresh after we modify it. If we want to keep the error message, we just need to configure hot: ‘only’.

Use hotOnly: true in Webpack, Webpack 5 has abandoned this property to use hot: ‘only’

{
  devServer: {
    hot: 'only'}}Copy the code

When we reset the error code, we can see that the browser does not refresh and keeps the error message.

Now let’s look at the IMPLEMENTATION of HMR for the mainstream framework

Vue HMR support

When loading vUE file, we use vue-loader, in fact vue-loader has helped us to implement HMR, we can try, we write a VUE component

When we change the value of MSG in the vue file from ‘hello vue2’ to ‘hello vue3’

You can see that the browser did not refresh and printed ‘hello vue3’, indicating that the HMR effect worked.

React HMR support

NPM install @pmmmwh/react-refresh-webpack-plugin react-refresh- D

// webpack.config.js
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin')
{
  / /...
  plugins: [
    / /...
    new ReactRefreshWebpackPlugin()
  ]
}
Copy the code
// babel.config.json
{
  "presets": [
    / /...]."plugins": [["react-refresh/babel"]]}Copy the code

Let’s write another React component and recompile it

Now we change the value of MSG from 123 to 456

You can see that the browser has not been refreshed and that values in the browser console and page have been reassigned and rendered.

Realize the principle of

So far the HRM implementation has been successfully configured, so let’s now look at the underlying IMPLEMENTATION of HRM. First, webpack-dev-server creates two services:

Static resource services (Express) and Socket services (net.socket)

  • Express Server is responsible for serving static resources directly (packaged resources are directly requested and parsed by browsers)
  • Socket service (net. The Socket)
  • Json (manifest file) and.js (Update chunk) files are generated when the server detects that the corresponding module has changed.
  • These two files can be actively sent directly to the client (browser) via a long connection
  • The browser takes the two new files, loads them through the HMR Runtime mechanism, and updates them for the modified modules

We can understand this by looking at the following schematic diagram

PublicPath (configurable in webpack4, deprecated in webpack5)

Since we are using the Webpack5 version, we can only configure it in the Output property, which specifies the previous path of the js/ CSS resource referenced in the browser. Webpack-dev-server will also default to the publicPath baseline, which is used to determine which directory to enable the service to access the webPack output files.

output: {
    path: resolve('build'),
    filename: 'js/bundle.js'.clean: true.publicPath: '/file'
}
Copy the code

Now restart the service

Localhost :8085 / index.html/’/’/’/’/’/’/’/’/’/’/’/’/’ /

The compiled index.html file can now be found under localhost:8085/file, with /fie in front of the js path. Output. publicPath specifies the import path of static resources such as JS/CSS and the path that services can access. In Webpack4, we usually configure output.publicPath and devServer.publicPath the same. In version 5, it merged these two attributes into output.publicPath.

host

The default value is 0.0.0.0. For hosts on the same network segment, the IP address is accessible. If the value is set to 127.0.0.1 or localhost, the IP address is inaccessible.

Localhost 0.0.0.0

  • Localhost: is essentially a domain name that is normally resolved to 127.0.0.1
  • 127.0.0.1: Loop Back Address, which means the packet sent by our host is directly received by ourselves

Here we set it to localhost or 127.0.01, which we can only access locally

If set to 0.0.0.0, we can access iPv4 addresses on the same network segment

port

That is, set the listening port, which is 8080 by default

open

The default value is false. If the browser is set to true, it will be opened

compress

Whether to enable Gzip Compression for static files. The default is false

When setting True is turned on, and the browser cache is cleared for reloading

You can see that bundle.js is much smaller than it used to be, and you can see that the response header has a GIZP flag indicating that the resource has been compressed by GIZP.

proxy

This configuration is often used to set the proxy server to solve cross-domain problems. For example, if we want to access the interface under http://locahost:3000 at http://localhost:8080, there are cross-domain problems due to different ports, so we can configure this property to solve the problem. The basic attributes are described as follows

  • target: indicates the destination address to be proxied to, such as/API /userhttp://localhost:3000/api/user
  • pathRewrite: By default, our/API is also written to the URL. If you want to delete it, you can rewrite the path using pathRewrite, such as ‘^/ API ‘: ”.
  • secure: Does not accept HTTPS forwarding by default. You can set this parameter to false if you want to support HTTPS forwarding
  • changeOriginThe default is to be proxied to localhost: 3000. If we want it to still point to the proxied address, we can set it to true
proxy: {  // To resolve cross-domain, set up proxy server
  '/api': {
    target: 'http://localhost:3000'.changeOrigin: true.// Update the host address of the server that is requested by the proxy. If the host address of the server is localhost:8080, the server that is requested by the proxy is 3000. Configure this property so that the host in the header after the proxy remains 8080
    pathRewrite: {
      '^/api': ' '
    },
    secure: false  // Can be forwarded to HTTPS server}}Copy the code

historyApiFallback

This attribute is a very common attribute in the development, its main function is to solve the SPA page after the route jump, when the page refresh, return 404 error, set true will return index.html and search from the current directory

{
  historyApiFallback: true.// historyApiFallback: {// Can also object, custom
    // rewrites: [
    // { from: '/^/$/', to: '/index.html'}
    // ]
  // }
}
Copy the code

resolve

How should this property be resolved to configure the reference module

  • extensions: If the referenced file name does not have a suffix, the file name extension is automatically added
  • mainFiles: When configuring a file directory, the system searches for index files in the directory by default
  • alias: Sets the path alias

The configuration is as follows:

resolve: {
  extensions: ['.js'.'.json'.'.wasm'.'.vue'.'.jsx'].// Automatically add the suffix name
  mainFiles: ['index'].// When a file is in a directory, the index file in the directory will be found
  alias: {  // Set the path alias
    The '@': resolve('src'),
    'pages': resolve('src/pages')}}Copy the code

module

Module handles different types of modules in a project

Set the main parameters as follows

rules

The rules attribute corresponds to an array, which contains different types of rules. A Rule is an object in which multiple attributes can be set:

  • Test: Used to match resources, usually set to a regular expression

  • Use: indicates an array of values

    • UseEntry is an object, and you can set a number of other attributes using the attributes of the object:

      • loader: Must have a loader property with a string value;
      • options: An optional attribute whose value is a string or object that is passed into the loader.
      • query: Currently options are used instead of \
    • Pass string (for example :use:[‘style-loader’]) is the abbreviation of loader attribute (for example :use:[{loader: ‘style-loader’}]).

  • Loader: rule-use: short for [{loader}].

Rules Modules of different types correspond to different Loaders, and these Loaders provide corresponding conversion rules for these modules. The following describes several common Loaders

1. Process style type files

For example, if CSS files are imported into js files and csS-loader is required to load the CSS, install NPM install CSs-loader-d

module.exports = {  
  / /...
  module: {
    rules: [{test: /.css$/.// Match the CSS file with the re
        use: [
          {
            loader: 'css-loader'}]// Use: [' csS-loader ']
        // if there is only one loader, it can be written as loader: 'css-loader'
        // But the first is recommended because all abbreviations are converted to the first}}}]Copy the code

After using csS-loader to process and parse CSS files, it will not insert the parsed CSS into the page. Therefore, we need another loader, style-loader, which stores the parsed CSS into the style file. npm install style-loader -D

Use the style – loader

module.exports = {  
  / /...
  module: {
    rules: [{test: /.css$/.// Match the CSS file with the re
        use: [
          {
            loader: 'style-loader'
          }
          {
            loader: 'css-loader'}]}}Copy the code

Note: If multiple Loaders are configured, the loader will process them sequentially. For example, style-loader is placed in front of CSS-loader because the CSS file needs to be processed first, and then the CSS is parsed in the style tag.

In a real project we might use the preprocessors of less, Sass, or stylus to write CSS styles. For example, if we write a less file, we need to use less-loader to load less and install less and less-loader: NPM install less less-loader -d. The configuration is as follows

Less-loader is required to parse less files, and less-Loader relies on less to convert them to CSS

module.exports = {  
  / /...
  module: {
    rules: [
      / /...
      {
        test: /.less$/.// Match less files with regex
        use: [
          { loader: 'style-loader' },
          { loader: 'css-loader' },
          { loader: 'less-loader' }
          // After less-loader parses less files, it converts them to CSS files. Therefore, csS-loader and style-loader need to continue processing CSS files}]}}Copy the code

2. Process resource type files

Before Webpack5, when we were dealing with some resource files, such as image files, we used a file-loader, which can import file resources through import/require, into the output folder. Install file-loader. NPM install file-loader -d and configure file-loader

{
  test: /.png|jpe? g|bmp|svg/i,  
  use: [    
    {      
      loader: 'file-loader'}}]Copy the code

After rebuilding, the resources will be placed in the output directory

So, if we want to configure the output of a project name according to a custom rule, it would be handled by a placeholder. Webpack gives us a lot of PlaceHolders, so let’s show you a few major ones.

  • [ext]: Extension of the processing file
  • [name]: Specifies the name of the processing file
  • [hash]: The contents of the file, processed using MD4’s hash function, to generate a 128-bit hash value (32 hexadecimal)
  • [contentHash]: The result of file-loader is consistent with that of [hash]
  • [hash:<length>]The default hash length is 32 characters, which is too long
  • [path]: path of the file relative to the WebPack configuration file;

For example, we can refer to vue-clie to handle the configuration of resource class files

{  
  test: /.png|jpe? g|bmp|svg/i,  
  use: [    
    {      
      loader: 'file-loader'.options: {        
        name: 'img/[name].[hash:8].[ext]'.// outputPath: 'img' // You can use img/ to create a folder for storing resources or use outputPath to define a folder}}}]Copy the code

After repacking

In addition to file-loader for resource files, we can also use url-loader. It differs from file-loader in that url-loader can convert smaller files into base64 urls. Install NPM install url-loader -d and configure it.

{  
  test: /.png|jpe? g|bmp|svg/i,  
  use: [    
    {      
      loader: 'url-loader'.options: {        
        name: 'img/[name].[hash:8].[ext]'}}}]Copy the code

After repacking

You can see that none of the resources are in the output folder because the current resources are converted to base64 and stored in bundle.js. However, in the actual development, I will keep large pictures as reserved resources and transfer small pictures to Base64, because small pictures can be requested together with the page after converting base64, reducing unnecessary request process. If large pictures are changed to Base64, the request speed of the page will be affected. So we can use the limit attribute in urL-loader to configure it

{  
  test: /.png|jpe? g|bmp|svg/i,  
  use: [    
    {      
      loader: 'url-loader'.options: {        
        name: 'img/[name].[hash:8].[ext]'.limit: 100 * 1024  // Images that do not exceed 100KB will be converted to Base64}}}]Copy the code

After repackaging, you can see that image A has been converted to Base64, while image B is still exported to the packaging directory.

After entering Webpack5, we no longer need to use file-loader or url-loader to process resource files. We can use the asset Module type provided by Webpack5 to replace the loader used above.

There are four types of resource modules

  • asset/resourceSend a separate file and export the URL previously by usingfile-loaderimplementation
  • asset/inlineExport the data URI of a resource, previously by usingurl-loaderimplementation
  • asset/sourceExport resource source code previously by usingraw-loaderimplementation
  • assetThe automatic choice between exporting a data URI and sending a single file was previously achieved by using urL-loader and configuring the resource volume limit

The configuration is as follows:

{  
  test: /.png|jpe? g|bmp|svg/i.// type: 'asset/resource', // similar to file-loader
  // type: 'asset/inline', // similar to url-loader
  type: 'asset'.// Similar to url-loader + limit limit
  generator: {
    filename: 'img/[name].[hash:8][ext]'  // Note that [ext] is included.
  },
  parser: {
    dataUrlCondition: {
      maxSize: 100 * 1024  // Images that do not exceed 100KB will be converted to Base64}}}Copy the code

We can also in the output. AssetModuleFilename configuration resource repository paths, such as the output. The assetModuleFilename: ‘img/[name].[hash:8][ext]’, but it is recommended to keep the path configuration in the respective Loader.

For other resources such as fonts, we can use asset/resource

{  
  test: /.(ttf|eot|woff2?) $/i,
  type: 'asset/resource'.generator: {
    filename: 'font/[name].[hash:6][ext]'  // Note that [ext] is included.}}Copy the code

3. Process vUE files

NPM install vue-loader -d NPM install vue-loader -d NPM install vue The vue-template-compiler package vue2 relies on for template template compilation is no longer needed, but replaced with @vue/compile-sfc, which is automatically installed when vue3 is installed. The WebPack configuration is as follows.

const { VueLoaderPlugin } = require('vue-loader')
module.exports = {
  / /...
  module: {
    rules: [
      / /...
      {
        test: /.vue$/,
        use: 'vue-loader'}},plugins: [
    new VueLoaderPlugin()
  ]
}
Copy the code

The relevant VUE codes are as follows

plugins

The Plugins option is used to customize the WebPack build process in a variety of ways, and several commonly used plugins are described below

Webpack comes with plug-ins

  • DefinePluginAllows you to create configured global constants at compile time

Third-party plug-ins

  • CleanWebpackPluginCleaning up the build directory
  • HtmlWebpackPluginPackage HTML
  • CopyWebpackPluginCopy the file
  • MiniCssExtractPluginRemove the CSS file

Here is a brief introduction to plug-in configuration

CleanWebpackPlugin

Install NPM install clean-webpack-plugin -d before build

const { CleanWebpackPlugin } = require('clean-webpack-plugin')
/ /...
{  
  plugins: [
    new CleanWebpackPlugin()
  ]
}
Copy the code

HtmlWebpackPlugin

NPM install html-webpack-plugin -d

const HtmlWebpackPlugin = require('html-webpack-plugin')
/ /...
{  
  plugins: [
    / /...
    new HtmlWebpackPlugin({
      title: 'test the title'}})]Copy the code

After repackaging, an index.html file is created in the build directory and bundle.js is automatically added

The index. HTML is actually built by ejS template in HTMl-webpack-plugin. When we do not have a custom template, the plug-in will have a default template default_index.ejs to create, which can be seen from the source of the plug-in

In a real project, however, we would use a custom template to create index.html. For example, we would create a public folder under the project to create an index.html file.

Contains some inside the < % = % > syntax for ejs filling template, htmlWebpackPlugin. Options. The title is the htmlWebpackPlugin plug-in into the ginseng, therefore we use to introduce custom configurations

const HtmlWebpackPlugin = require('html-webpack-plugin')
/ /...
{  
  plugins: [
    / /...
    new HtmlWebpackPlugin({
      title: 'test the title'.template: './public/index.html'.inject: true.// Set the injection location of packaged resources
      cache: true.// Set to true, new files will only be generated if the files are changed (the default is also true)
      minify: {}})]}Copy the code

DefinePlugin

This plug-in is built into WebPack and creates configured global constants at compile time, such as the BASE_URL global variable used in our custom template because I can configure it for this variable

const { DefinePlugin } = require('webpack')
/ /...
{  
  plugins: [
    / /...
    new DefinePlugin({
      BASE_URL: "'/'"}})]Copy the code

To use string values, you must enclose quotation marks around the string because the data inside the quotation marks is fetched.

CopyWebpackPlugin

The plugin is used to copy files from one folder to another, for example if we include the favicon.ico file in the public folder, we will copy it to the build directory. Install NPM install copy-webpack-plugin -d

  • The matching rules for replication are inpatternsSet in the
  • from: Sets the source from which to start replication
  • to: The location to copy to, which can be omitted, will be copied to the packaged directory by default
  • globOptions: Sets some additional options for writing files that need to be ignored
    • .DS_Store: a file automatically generated in the MAC directory
    • index.html: There is no need to copy because we have already passedHtmlWebpackPluginThe index.html generation is complete
const CopyWebpackPlugin = require('copy-webpack-plugin')
/ /...
{  
  plugins: [
    / /...
    new CopyWebpackPlugin({
      patterns: [  / / match
        {
          from: './public'.// Copy directories or files to the build directory by default
            globOptions: {  // Copy the configuration
            ignore: [  // Files to ignore
              '**/index.html'.// Add ** to indicate from directory
              '**/.DS_Store']}},],})]}Copy the code

MiniCssExtractPlugin

NPM install mini-CSs-extract-plugin -d to extract CSS files separately

plugins: [
  new MiniCssExtractPlugin({
    filename: 'css/[name].[contenthash:6].css'.chunkFilename: 'css/chunk.[name].[contenthash:6].css'})]Copy the code

What we need in the heart of the loader style – loader in the generate environment changed to use MiniCssExtractPlugin. Loader

use: [
  isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
  {
    loader: 'css-loader'.options: { importLoaders: 1}}'postcss-loader'
]
Copy the code

After the configuration, repackage and you can see that the CSS file is separate

optimization

Properties used to configure code optimization, let’s look at some of the more common ones

  • minimizer: for compression tools, you can add one or more customizedTerserPluginThe instance
  • splitChunks: Common Chunk Strategy. Can be inSplitChunksPluginView the options available to configure its behavior.
  • chunkIds: tells Webpack which algorithm to use when selecting a module ID. willoptimization.chunkIdsSet tofalseWebpack is told that no built-in algorithms will be used
    • natural: Uses ids in numeric order
    • named: Default value under development, id of a readable name
    • deterministic: deterministic, short numeric ID that does not change between compilations
      • This value is not available in webpack4
      • If you use Natural at that time, you will have problems when some compilations change
      • During development, we recommend itnamed
      • We recommend it for packagingdeterministic
  • runtimeChunk: Runtime code refers to the parsing, loading, and module information related code in the runtime environment. For example, we import file main.js and introduce a tool library utils.js. The code loading of utils.js via import is done by Runtime, which is good for the browser cache, if we change the utils.js library, but our main.js and Runtime remain the same
    • true/multiple: Package a Runtime file for each entry
    • single: Package a Runtime file
    • objectThe: name attribute determines the name of runtimeChunk

Environmental separation

In practice, we will split webpack.config.js, i.e. development environment and production environment. We will create a new config folder with three new files: webpack.common.js, webpack.dev.js, Webpack. Pro. Js. We will extract the common configuration from webpack.mon.js, the development configuration from webpack.dev.js, and the production configuration from webpack.pro.js.

We can now configure the packaging commands for each environment in package.json

"scripts": {
  "serve": "webpack serve --config ./config/webpack.common.js --env development"."build": "webpack --config ./config/webpack.common.js --env production"
}
Copy the code

Module. exports = {}} {env = {}} {env = {}} {env = {}}} {env = {}}} {env = {}} We can now use a function that returns a configuration object containing the arguments carried after –env.

We now see that module.exports in webpack.common.js receives a function that prints the following message when we execute the development environment command

As you can see, the returned parameter object contains the development key and its value is true, so we can use the parameter to determine whether it is a production or development environment. Below is the reference code for pulling away

// webpack.common.js
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { VueLoaderPlugin } = require('vue-loader')
const { DefinePlugin } = require('webpack')
const resolve = require('./path')

const { merge: webpackMerge } = require('webpack-merge')
const devConfig = require('./webpack.dev')
const proConfig = require('./webpack.pro')

const commonConfig = {
  context: resolve(' '),
  entry: './src/main.js'.output: {
    path: resolve('build'),
    filename: 'js/bundle.js'.clean: true.// publicPath: '/file'
  },
  resolve: {
    extensions: ['.js'.'.json'.'.wasm'.'.vue'.'.jsx'].// Automatically add the suffix name
    mainFiles: ['index'].// When a file is in a directory, the index file in the directory will be found
    alias: {  // Set the path alias
      The '@': resolve('src'),
      'pages': resolve('src/pages')}},module: {
    rules: [{test: /.css$/i,
        use: [
          'style-loader',
          {
            loader: 'css-loader'.options: {
              importLoaders: 1  // Importing CSS from CSS does not start with postCSs-loader but with CSS-loader conversion, so this configuration ensures that loader conversion starts one layer up}},'postcss-loader'] {},test: /.less$/,
        use: [
          'style-loader'.'css-loader'.'postcss-loader'.'less-loader'] {},test: /.png|jpe? g|bmp|svg/i,
        type: 'asset'.generator: {
          filename: 'img/[name].[hash:8][ext]'
        },
        parser: {
          dataUrlCondition: {
            maxSize: 100 * 1024}}}, {test: /.(j|t)sx? $/,
        exclude: /node_modules/,
        use: [
          'babel-loader',]}, {test: /.vue$/,
        use: 'vue-loader'}},plugins: [
    new HtmlWebpackPlugin({
      title: 'test the title'.template: './public/index.html'
    }),
    new DefinePlugin({
      BASE_URL: "'/'"
    }),
    new VueLoaderPlugin()
  ]
}

module.exports = (env) = > {
  console.log(env)
  process.env.NODE_ENV = env.production ? 'production' : 'development'
  const mergeConfig = env.production ? proConfig : devConfig
  return webpackMerge(commonConfig, mergeConfig)
}
Copy the code
// webpack.dev.js
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin')

module.exports = {
  mode: 'development'.devtool: 'cheap-module-source-map'.devServer: {
    hot: 'only'.host: '0.0.0.0'.compress: true.proxy: {  // To resolve cross-domain, set up proxy server
      '/lyj': {
        target: 'http://localhost:3000'.changeOrigin: true.// Update the host address of the server that is requested by the proxy. If the host address of the server is localhost:8080, the server that is requested by the proxy is 3000. Configure this property so that the host in the header after the proxy remains 8080
        pathRewrite: {  // Rewrite the path
          '^/lyj': ' '
        },
        secure: false  // Can be forwarded to HTTPS server}},historyApiFallback: true
  },
  plugins: [
    new ReactRefreshWebpackPlugin()
  ]
}
Copy the code
// webpack.pro.js
const TerserPlugin = require('terser-webpack-plugin')  // Zip js code plugin webpack5 comes with it

module.exports = {
  mode: 'production'.optimization: {
    minimizer: [
      new TerserPlugin({
        extractComments: false.// Delete the packaged license. TXT file}}})]Copy the code