Note source: Hook Education – big front end employment Training camp

Content: Notes, thoughts and experiences in the process of learning

Webpack packaging tools

The problem

  • The ES Module has an environment compatibility problem. Procedure
  • Too many module files and too many network requests
  • All front-end resources need to be modular, not just JS

Solution:

  • Transpose the new standard JS file to ES5 code
  • Package all js files into one file
  • Package not only JS files but also other files, CSS, HTML files, etc

The module packaging tool webpack is used as an example

The WebPack core features meet these requirements

  • Module packaging tool: Package the pieces of module code together
  • Module loader: Module code conversion
  • Code split: Package according to code requirements
  • Support resource module: Support file import by resource mode

Packaging tools address front-end modularity as a whole, not just js modularity as mentioned above

Webpack to fit

  1. Create three files using ES Moudle mode. Here you can use serve to see the effect

    <body>
      <! -- Import js file, set to mudule mode -->
      <script type="module" src="./src/index.js"></script>
    </body>
    Copy the code
    // index.js
    
    // Import modules
    import h1 from './code.js'
    // Use the module
    const h = h1()
    document.body.append(h)
    Copy the code
    // code.js
    
    // Export the module
    export default() = > {const h1 = document.createElement('h1')
      h1.innerText = '123'
      h1.onclick = function () {
        console.log('123')}return h1
    }
    Copy the code
  2. Create a new project with YARN: YARN init –yes

  3. Install two dependencies using YARN: yarn webpack webpack-cli –dev

  4. View the installed version using YARN: YARN Webpack –version

  5. Perform Webpack packing with YARN: YARN Webpack

  6. By default, it will be packaged in the dist directory. Just change the DRC property of HTMNL and delete type=”module” because Webpack has converted the file to ES5

You can use NPM scripts to set up automation instructions

Webpack configuration file

After Webpack4, the configuration can be 0. By default, index under SRC is used as the entry for packing. If you want to customize some configurations, you need to add one in the root directorywebpack.config.jsFile, in the file configuration

// webpack.config.js


// Introduce the path module, and use its methods later
const path = require('path')
// The webpack configuration file needs to be exported
module.exports = {
  // Set the js entry file. The default is the index.js file below SRC
  entry: './src/one.js'.// Set output correlation
  output: {
    // The name of the output file, main.js by default
    filename: 'output.js'.// Set the output path. Only absolute path can be set, so use path to set the path
    path: path.join(__dirname, 'output')}}Copy the code

Webpack working mode

Can be understood as a default configuration for different environments, there are currently three modes:

  • production: Online mode, default packaging mode, compact code volume is minimal, but not easy to read
  • development: Development mode, fast, will add some useful comments information
  • none: Raw mode, just packaging, no other processing

writing

  • Yarn webpack –mode Mode name interrupts operation

  • Written in the configuration file, this is no need to set the mode in the command

    module.exports = {
      mode: 'development'
    };
    Copy the code

Webpack packaging principles

Webpack packs all the modules we need to introduce into one file, and then uses some code within WebPack to keep those modules dependent

Resource loading module

Webpack only packages JS files by default, and other files cannot be packaged without special action

If you want to process other files that need to be processed using the loader, you need to install dependencies

The two dependencies to be installed to parse CSS files are style-loader and CSS-loader plug-ins

NPM install --save-dev style-loader css-loader yarn add --dev css-loader style-loaderCopy the code
// webpack.config.js

// Config file
module.exports = {
  module: {  
    // Configure other loaders
    rules: [{ // Configure the CSS packaging
      // test: is a regular expression that indicates that the file to be matched should end in CSS
      test: /\.css$/i.// use: the loader to be used. Here we use csS-loader to pack the CSS, and use style-loader to insert the packed CSS into the page in the form of style tags
      use: ['style-loader'.'css-loader'],},],}};// Note: the loader is loaded from back to front !!!!!!!!!!
// use: ['style-loader', 'css-loader'] indicates that css-loader is used before style-loader
Copy the code

Loader is the core feature of webpack. Different Loaders are used to load different types of resources

Importing a Resource Module

In general, we still use the JS file as the entry point for packaging, and we import the CSS files we need in the entry file to use packaging

// Import file


// Import modules
import h1 from './code.js'
// The CSS module is introduced here, since it is run directly, it does not need to be named
import './main.css'
// Use the module
const h = h1()
document.body.append(h)

// Then set the webPack configuration file entry file
Copy the code

Webpack eyes JS driver more front-end applications

  • Logical and reasonable, JS resource files need to cooperate
  • Ensure that resource files are necessary and not missing when going online

File resource loader

To load files, use the file-loader:

yarn add --dev file-loader

// Import file


// Import file, here is an image
import img from './1.png'
// Insert the page with an image
const m = new Image()
m.src = img
document.body.append(m)
Copy the code
// Config file
output: {
    // The name of the output file, main.js by default
    filename: 'output.js'.// Set the output path. Only absolute path can be set, so use path to set the path
    path: path.join(__dirname, 'output'),
    // Set the loading path here, otherwise there may be errors, set the loading path to the output path can be !!!!!!!
    publicPath: 'output/'
  },
module: {
    rules: [{ / / using the file - loader
      // Set file matching
      test: /\.png$/.// Use the loader
      use: 'file-loader'}}]Copy the code

Be sure to set the loading path, otherwise it is very likely to error, pay attention to the path after the /, for example:publicPath: 'output/', / will be spliced with the back to form a path

URL loader

Files are represented as data urls, which in theory can represent any type of file

Data urls represent files: protocol: media type encoding, file content

For example: data: [< mediatype >] [; base64], < data >

This way of representing files already contains the content of files, so there is no need to apply for HTTP requests. If you encounter files that cannot be represented by text, such as pictures and fonts, you can use Base64 to represent the content

Webpack supports this approach, which is implemented using the URL-loader

module: {
    rules: [{/ / use url - loader
      // A similar method to file
      test: /\.png$/.// If you just want to convert files to data-urls, use: 'url-loader' to convert files to data-urls unconditionally
      // use: 'url-loader'
      
      In practice, however, we may only need to convert smaller or some files. Base64 encoding is slower to convert large files, so it is better for small files
      // Configure the conversion condition
      use: {
        // Use url-loader again
        loader: 'url-loader'./ / configuration
        options: {
          // Convert files smaller than or equal to 10K
          limit: 10 * 1024  // 10KB, which is calculated in bytes}}}}]Copy the code

Note: When using url-loader, install file-loader (unless all urls are converted), because file-loader is called by default if the conversion conditions are not met

Work proposal

  • Use data-urls for small files to reduce requests
  • Store large files separately

Common loader types

  • Compile conversion classes to convert loaded resources into JS code, such as CSS-loader
  • File operations: Copy resources to output directories and export file access paths, such as file-loader
  • Code inspection class: verify the code, unify the code style, improve the quality

Webpack and ES2015

Webpack handles the export and import modules for packaging purposes, but not the rest of ES6 code

To handle the new ES6+ features, install babel-Loader: Babel relies on multiple plug-ins

nary add --dev babel-loader @babel/core @babel/preset-env

// Config file

module: {
  rules: [{ / / use the Babel - loader
    // Compile the js file
    test: /\.js$/.// Babel needs to be configured
    use: {
      / / use the loader
      loader: 'babel-loader'.options: {
        // Compile the library, which contains all the required functionality
        presets: ['@babel/preset-env']}}}}Copy the code

Webpack is just a packaged tool that the loader can compile and transform

How resources are loaded

  • Follow the ES Modules standard import declaration
  • Follow the CommonJS standard require function
  • Follow AMD standard define function and require function

Don’t mix unless you have to

Loaders also trigger resource loading when loading non-JS codes. For example, CSS/HTMl-loader also triggers resource loading when encountering SRC, URL, and @import (CSS imports CSS) instructions. When encountering resource loading, the loader also uses the corresponding loader

  • The @import directive and URL function in the style code
  • HTML code image tag SRC attribute

Summary: In Webpack, all resources that need to be referenced in the code and their possibilities will be found, handed to different loaders according to the configuration, and output to the package directory

Core operating Principles

Loader is the core of Webpack

Working principle:

  1. Locate the entry file according to the configuration
  2. Follow the entry file to find all resources that need to be loaded
  3. Assign these resources to different loaders according to the configuration file
  4. Finally, all the processed data is exported to the output directory, and everything that can be combined is written to a JS file
  5. These dependencies are inherited from the.js file to ensure that no errors occur during loading

Try to develop a loader

Loader is responsible for converting resource files from input to output

Multiple Loaders can be used for the same resource at a time, and the result of this loader can be sent to the next loader for processing

Webpack requires that the result returned by a loader must be a piece of JS code or the result returned by another loader

// Write a loader


// Install the markdown parsing plugin - marked
const marked = require('marked')

// The loader parser is an output, output content, here we take a parameter source as the parser input content
module.exports = source= > {
  console.log(source) // We can print it out

  // the return value requires that a piece of js code be output
  // return 'console.log(hello)'  

  // We can use marked to parse the input, which is converted to a piece of HTML code
  const html = marked(source)

  // We can print it here, using moudel.export and export default, both of which are supported by Webpack
  // But note that the HTML is a piece of HTML code, direct output may cause errors, we first convert it to JSON
  // return `moudel.export = ${JSON.stringify(html)}`
  // return `export default ${JSON.stringify(html)}`


  // You can also output HTML directly to the next loader for processing
  return html
}
Copy the code
// Config file

// add path
const path = require('path')
module.exports = {
  // Package mode
  mode: 'none'.// Import file file
  entry: './src/index.js'.// Output configuration
  output: {
    / / name
    filename: 'dist.js'./ / path
    path: path.join(__dirname, 'dist'),
    // Resource path
    publicPath: 'dist/'
  },
  // loaders
  module: {
    rules: [{
      // Parse the MD file
      test: /\.md$/.Use: './md-loader'
      // use: './md-loader'
      // If we write a loader that needs another loader handler name, we can write multiple loaders, pay attention to the sequence, execute the order from back to front
      use: ['html-loader'.'./md-loader']]}}}Copy the code

conclusion

  • Loader is a tool to convert data from input to output
  • Loader can be seen as a pipeline. We can use one loader to convert files or combine multiple loaders to convert files, such as CSS-loader to style-loader

Plugin mechanism – Plugin

Enhance WebPack automation capabilities

Plugin handles automation beyond resource loading

Such as deleting files before each package, compressing code, and so on

Common plug-in

Automatic cleanup of output directory plug-ins

Plug-in address: www.npmjs.com/package/cle…

Use clean-webpack-plugin => YARN add –dev clean-webpack-plugin

// Webpack configuration file

// add path
const path = require('path')

// Introduce the clean-webpack-plugin to deconstruct a constructor !!!!!!!
const {
  CleanWebpackPlugin
} = require('clean-webpack-plugin');


module.exports = {
  // Package mode
  mode: 'none'.// Import file file
  entry: './src/index.js'.// Output configuration
  output: {
    / / name
    filename: 'dist.js'./ / path
    path: path.join(__dirname, 'dist'),
    // Resource path
    publicPath: 'dist/'
  },
  // loaders
  module: {
    rules: [{
      // Parse the MD file
      test: /\.md$/.Use: './md-loader'
      // use: './md-loader'
      // If we write a loader that needs another loader handler name, we can write multiple loaders, pay attention to the sequence, execute the order from back to front
      use: ['html-loader'.'./md-loader']]}},// All plug-ins are placed here, which is an array !!!!!
  plugins: [
    // Add the plugin !!!!!
    new CleanWebpackPlugin()
  ]
}
Copy the code

Automatically generate HTML plug-ins

Let HTML files also participate in the WebPack build process

Address: document webpack.docschina.org/plugins/htm…

Use the html-webpack-plugin => yarn add –dev html-webpack-plugin

// add path
const path = require('path')
// Destruct a constructor by introducing the clean-webpack-plugin
const {
  CleanWebpackPlugin
} = require('clean-webpack-plugin');

// Install the HTML-generated template, which does not need to be deconstructed!!!!!!!!!!!!!!!!!!!!!!!
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  // Package mode
  mode: 'none'.// Import file file
  entry: './src/index.js'.// Output configuration
  output: {
    / / name
    filename: 'dist.js'./ / path
    path: path.join(__dirname, 'dist'),
    // Resource path
    publicPath: 'dist/'
  },
  // loaders
  module: {
    rules: [{
      // Parse the MD file
      test: /\.md$/.Use: './md-loader'
      // use: './md-loader'
      // If we write a loader that needs another loader handler name, we can write multiple loaders, pay attention to the sequence, execute the order from back to front
      use: ['html-loader'.'./md-loader']]}},// All the plugins should be placed here, which is an array
  plugins: [
    // Add a plug-in
    new CleanWebpackPlugin(),
    
    // Create a new instance. The parameters can be set to!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    new HtmlWebpackPlugin({
      // Set the title
      title: 'I am the title'.// Set the meta attribute
      meta: {
        viewport: 'width=device-width'
      },
      // If you want to substitute in some structure, you can use templates, because by default an empty HTML is generated
      template: './src/index.html'
    }),
    // If you want to generate multiple HTML files, you need to create multiple instances
    new HtmlWebpackPlugin({
      // Set the name, because the default name is index.html, if not renamed will conflict with the previous one
      filename: 'tow.html'}})]Copy the code
<! -- This is a template -->
<! DOCTYPEhtml>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
  <title>Document</title>
</head>

<body>
  <div class="box">
    <! Template strings can be used inside templates.
    <h1><%= htmlWebpackPlugin.options.title %></h1>
  </div>
</body>

</html>
Copy the code

Copy file plug-in

Some static files that do not participate in the construction can be directly copied to the output directory pole

Address: document webpack.docschina.org/plugins/cop…

Use copy-webpack-plugin => arn add –dev copy-webpack-plugin

// add path
const path = require('path')
// Destruct a constructor by introducing the clean-webpack-plugin
const {
  CleanWebpackPlugin
} = require('clean-webpack-plugin');
// Install the HTML-generated template, which does not need to be deconstructed
const HtmlWebpackPlugin = require('html-webpack-plugin');
/ / introduce copy plugin!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
const CopyPlugin = require("copy-webpack-plugin");
module.exports = {
  // Package mode
  mode: 'none'.// Import file file
  entry: './src/index.js'.// Output configuration
  output: {
    / / name
    filename: 'dist.js'./ / path
    path: path.join(__dirname, 'dist'),
    // Resource path
    publicPath: 'dist/'
  },
  // loaders
  module: {
    rules: [{
      // Parse the MD file
      test: /\.md$/.Use: './md-loader'
      // use: './md-loader'
      // If we write a loader that needs another loader handler name, we can write multiple loaders, pay attention to the sequence, execute the order from back to front
      use: ['html-loader'.'./md-loader']]}},// All the plugins should be placed here, which is an array
  plugins: [
    // Add a plug-in
    new CleanWebpackPlugin(),
    // Create a new instance. The parameters are configurable
    new HtmlWebpackPlugin({
      // Set the title
      title: 'I am the title'.// Set the meta attribute
      meta: {
        viewport: 'width=device-width'
      },
      // If you want to substitute in some structure, you can use templates, because by default an empty HTML is generated
      template: './src/index.html'
    }),
    // If you want to generate multiple HTML files, you need to create multiple instances


    // Use the copy plugin!!!!!!!!!!!!!!!!!!!!!!!!!
    new CopyPlugin({
      / / configuration
      patterns: [{
        SRC from the root directory
        from: "src".// Copy to SRC in the output path
        to: "src"},],},]}Copy the code

Try developing a plug-in

Webpack.docschina.org/api/compile…

Pulgin uses the hook mechanism

Plug-ins extend by mounting functions on hooks in the lifecycle

I understand this principle, the teacher is not very detailed, did not understand

Problems with the WebPack development experience

Ideal development environment:

  • Run as an HTTP server
  • Automatic compilation, automatic refresh
  • Provides source map support to quickly locate problems

Enhance the development experience

Automatic compilation

Use Webpack’s Watch working mode to listen for file changes and automatically repackage

Method implementation:yarn webpack --watch

Added when running the webpack command--watch, so that webPack does not exit immediately after it is packed, it goes into monitoring mode, and when the file changes, it is immediately repacked

Automatically refresh the browser

Use the browserSync tool

  • It is cumbersome to use both tools at the same time
  • Efficiency goes down, you have to keep writing and reading

webpack dev server

Webpack official development tools, provides a development server, integrated automatic compilation and automatic refresh browser functions

Install: yarn add –dev webpack-dev-server

Run yarn webpack-dev-server –open to automatically open the browser

Note:

  • Pay attention to webpack-CLI version, too high version may cause error, I practice when the version is 4X error, experimental feasible version is"Webpack - cli" : "^ 3.3.12"If your version has an error, try changing it to this version
  • This method does not package locally, but saves the packed results in memory and reads them from memory, thus reducing local read and write operations and making it more efficient
Access static resource files

In real development, we might not use copy-webpack-plugin all the time, because if we had too many files to copy, we would have to copy them every time, so we usually only use copy before we go live

So in WebPack Dev Server, we need to add the Settings parameters and package these files as well

Method to add the devServer configuration in the WebPack configuration file

devServer: {
  // Static resource to copy
    contentBase: 'path'
  },
Copy the code

Note: pay attention to the location of the HTML file when using it. It is best to place it in the SRC directory, so as to open it correctly. I put it in the root directory when I contact you

The proxy API

Root cause: Interface cross – domain problems during development

Solution: Webpack-dev-server supports configuring proxy services

Noun:

Endpoint – Access endpoint/entry point

devServer: {
    contentBase: './123'.// Add the proxy service
    proxy: {
      // Proxy address Settings
      '/api': {
        / / to the agent's url, for example http://localhost:8080/api/users = > https://api.github.com/api/users
        target: 'https://api.github.com'.// Rewrite the path. If you don't want the API to pass through, you can replace it with empty. The parameters in this path will be matched by the re
        pathRewrite: {
          '^api': ' '}},Localhost :8080 localhost:8080 localhost:8080 localhost:8080 localhost:8080 localhost:8080
      changeOrigin: true}},Copy the code

Source Map – Source code map

Webpack.docschina.org/configurati…

  • Current debugging and error reporting is based on converted running code
  • The Source Map file maps the relationship between the transformed code and source code
  • Mapping can be used to pinpoint the wrong error information in the source code

Source Map solves the problem of inconsistency between Source code and running code

Webpack configures the Source Map

Package the results to generate a source map file

// Webpack configuration file

// Create a source-map file while packing
devtool: 'source-map'
// This is the simplest way to generate a map file, but there are currently 12 different ways to generate a map file, all of which have different effects and speeds
Copy the code

Eval mode Source map

Eval is a function in JS that runs the code inside the function

Eval (optional code to run //sourceURL= path)

You can add comments (//sourceURL) inside the parameters to point to the file in which the code is running

Eval mode does not produce a map file. All packaged code is executed in an eval function, but this method can only locate files, not rows and columns, so it is the fastest to build

Differences between modes

Key words:

  • Eval – Executes module code using EVAL
  • Cheap – Whether row information is included. Columns are not included in this manner
  • Module – Gets the original unconverted source code

Such as:

**cheap-module-sval-source map **=> Unconverted, containing row information executed using eval

Choose the right model

Application development typically does not use multiple patterns

Teacher’s Personal choice:

  • In the development environment:cheap-module-sval-source map
    • You don’t write too much code per row, and you don’t need to locate columns
    • The code after the conversion may be quite different from the code before the conversion, so you need to know what went wrong before I converted
    • The first package is slow, but the repackage is relatively quick
  • Production environment (last packaged) : None – Not generated
    • Map will expose the source code to the production environment, and the code may be recovered
    • Debugging should be a development phase, not a production phase
  • To use map: nosource-source map
    • Location is indicated but source code is not exposed

Webpack auto-refresh issue

Problem: Webpack-dev-server completely refreshes the entire web page each time, and once the entire page is refreshed, the action state in the page is lost

Requirement: The code can be updated in time without the page being refreshed

HMR- Module hot update/replacement

The module content is replaced in real time during the application process without affecting the running status of the application. Only the modified module is replaced to the application

Open the HMR

Integrated in Webpack-dev-server

Opening method:

  • Method 1: Run the code directly with –hot
    • Run directly on the terminalyarn webpack-dev-server --hot
  • Method 2: Modify the configuration file
    • Added to configuration file devServerHot: true,
    • Webpack, introduced the configuration file, and then create * * webpack HotModuleReplacementPlugin * * instance ()
/ / introduce webpack
const webpack = require('webpack')

module.exports = {
  ......
  / / set webpack - dev - server
  devServer: {// Enable hot update
    hot:true
  }
  // Create instance!! Notice that this is written in plugins
  new webpack.HotModuleReplacementPlugin()
}
Copy the code

But when we run it, we find that the CSS file does enable hot update, but when we show the JS file, we find that the page is still refreshed

HMR doubt

MHR in WebPack is not “out of the box” like other plug-ins, requiring manual handling of module hot update replacement logic

CSS can implement hot update because the style-loader has already processed hot update, so there is no need to manually configure

CSS code is logically simple, regular, and easily replaceable, so it can be hot updated

Js code does not have any special rules, there may be many changes, so we can not find the code operation rules to achieve logical replacement

With framework development, every file is regular, so JS can be hot updated, and projects created through scaffolding already inherit the HMR schema internally

Summary: We need to handle hot replacement after js module update manually

HMR Apis

Handle JS hot updates manually

  • **module.hot.accept(' module path ', callback function)**

Webpack handles hot replacement of JS modules

Module.hot. accept(' module path ', callback function)

// Import modules
import html from './html.js'
// Import the CSS file
import '.. /css/index.css'
// Import images
import src from '.. /img/ Screenshot 2021-02-07 11.21.07.png'

// Use the HTML module. Generate structure to add to the page
const input = html()
document.body.append(input)
const img = new Image()

// Create an image and insert it into the page
img.src = src
document.body.append(img)


console.log('111')


// Create a variable to receive the current input tag and store it
let lastInput = input
// Configure hot update. The first argument is the address of the module's file, and the second argument is the callback function
module.hot.accept('./html.js'.() = > {
  // Inside the callback function is the code for what to do when the module is updated, i.e., if this is empty, the module update will not take effect
  const value = lastInput.value
  const newInput = document.createElement('input')
  newInput.value = value
  newInput.className = 'input'
  newInput.onclick = () = > {
    console.log('I am input2')}})Copy the code

Matters needing attention

  • Problem: If the HMR code is wrong, an error will be reported, but it will automatically refresh, and the error information will be lost, which is not easy to find

    • Solution: Use hotOnly: true instead of HOT. Once the system detects an error, it does not refresh the page so that the error message remains

    • // Webpack configuration file
      devServer: {
          hotOnly: true
      },
      Copy the code
  • Problem: HMR plug-ins report errors when plugins do not start HMR plug-ins

    • Solution: Check whether the module. Hot object is available before using MHRapi. If so, do not use it otherwise

    • // If module.hot exists, the HMR plugin is enabled
      if (module.hot) {
        .........
      }
      Copy the code
  • There is a lot of code in the code that has nothing to do with business functions that will affect the production environment

    • Solution: Packaging does not package the code in the middle of the if statement (in the case of MHR being turned off), nor does it package the code. The production environment is not affected

Production environment optimization

When the code is in production, the code we pack with WebPack may have some unnecessary code redundancy

There are many patterns available in Webpack, and we can create different configurations for different work environments

Configurations in different environments

  • Configuration files Export different configurations according to different environments (only applicable to small and medium-sized projects)
    • Execute when usedYarn webpack -- Env environment name (corresponding to configuration file)
  • One configuration file for each environment (recommended for large projects)
    • You can install the Webpack-Merge module to use as a configuration object mergeyarn add webpack-merge --dev
    • Since there is no default configuration file, you should enter it when you perform packagingyarn webpack --config webpack..... js, includingwebpack..... jsIs the name of the configuration file to use
// Option 1: output different configurations depending on the incoming file
// webpack.config.js configuration file

// Import modules
const path = require('path') // path
const webpack = require('webpack') // webpack
const { // Clear the output directory
  CleanWebpackPlugin
} = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin') / / HTML module
const CopyPlugin = require("copy-webpack-plugin") // Copy the file

// Determine the environment according to the parameters passed in to output different configurations
Module. exports supports adding a function with argument 1 representing the runtime environment (passed in at the command line) and argument 2 representing the passed argument (normally not needed).
module.exports = (env, argv) = > {
  // Create a template for the development environment
  const config = {
    // Package mode = None
    mode: 'none'.// Import file
    entry: './src/js/index.js'.// Output configuration
    output: {
      // Output the file name
      filename: 'index.js'.// Output directory
      path: path.join(__dirname, 'dist')},// The loader to use
    module: {
      rules: [{ / / CSS
          test: /\.css$/,
          use: ['style-loader'.'css-loader'] {},/ / pictures
          test: /\.png$/,
          use: {
            loader: 'url-loader'.options: {
              milit: 200 * 1024}}}, {// Switch js to ES5
          test: /\.js$/,
          use: {
            loader: 'babel-loader'.options: {
              presets: ['@babel/preset-env']}}}]},// Plug-in configuration
    plugins: [
      / / HTML plugin
      new HtmlWebpackPlugin({
        title: 'practice',}).// Hot update plugin
      new webpack.HotModuleReplacementPlugin()
    ],
    // webpack-dev-server
    devServer: {
      / / root directory
      contentBase: './dist'.// Enable hot update
      hot: true
    },
    / / open source - the map
    devtool: 'eval-cheap-module-source-map'
  }
  
  // Determine if the parameter passed is production. If production is passed, modify the template
  if (env === 'production') {
    // Set the packaging mode to production mode
    config.mode = 'production'
    / / disable the source - the map
    config.devtool = false
    // Set up plugins, add two plugins
    config.plugins = [
      // Here we use ES6 syntax to deconstruct the original config.plugins. config.plugins,new CleanWebpackPlugin(),
      new CopyPlugin({
        patterns: [{
          from: "./src/other".to: "other"}]]}})// Return the configuration, output the original template in development environment, output the processed template in production environment
  return config
}

// Yarn webpack will be packaged according to the default configuration file (no arguments are passed, so no if statements are entered)
// Run yarn webpack --env Production to package files in production mode
Copy the code
// Option 2: configure a different configuration file for each environment

// Import template configuration module, here directly import template js file
const common = require('./webpack.common.js')
// Introduce the webpack-merge plugin
const merge = require('webpack-merge')
const { // Clear the output directory plug-in
  CleanWebpackPlugin
} = require('clean-webpack-plugin')
const CopyPlugin = require("copy-webpack-plugin") // Copy file plug-in

// Merge configuration parameters using the webpack-merge plugin. This function merges the two objects directly
module.exports = merge(common, {
  // Package mode
  mode = 'production'.// Module use
  plugins: [
    new CleanWebpackPlugin(),
    new CopyPlugin({
      patterns: [{
        from: "./src/other".to: "other"}],})]})Copy the code

DefinePlugin – Inject global members

  • DefinePlugin is a class built into WebPack that can inject a member globally
  • The value of the injected member is replaced directly into the packaged code
// The Webpack module must be imported first
const webpack = require('webpack')



module.exports = merge(common, {
.........
  plugins: [
    // used in modules
    new webpack.DefinePlugin({
      // The js code snippet is used here, so a layer of quotes will be removed after parsing
      API_BASE_URL: '"https://api.baidu.com"'})]})Copy the code

Tree-shaking – Removes unreferenced code

Remove unused code from your code to reduce volume optimization code

It is the optimization result of a set of functions, not a plug-in or method, and is automatically enabled in production mode

// Webpack configuration file
module.exports = {
  .........
  // Configure tree-shaking
  optimization: {
    // Unreferenced code is not output. When enabled, the color of unreferenced code is lightened
    usedExporta: true.// Enable compressed code, which compresses packaged code and removes unapplied code
    minimize: true}}Copy the code

If you think of code as a big tree

  • UsedExporta is responsible for marking dead leaves (no code applied)
  • Take care to shake down the dead leaves.

ConcatenateModules – Merge module functions

The default packaging is to put each module in a separate function, if we have too many modules will result in too many functions

ConcatenateModules can combine all modules together and output them in a single function, reducing the size of code and increasing the operating efficiency. This method is also called scope reactive.

Usage: Add directly in Optimization aboveConcatenateModules: true,

The Tree – shaking and Babel

There is a lot of evidence that using babel-loader causes tree-shaking to fail

Tree-shaking must be implemented using the ES Module

The new babel-Loader now supports ES Moudel and does not cause tree-shaking to fail

If you are not sure if it is a new version, you can force Babel to be turned on

module: {
  rules: [{
    // Set in babel-loader
      test: /\.js$/,
      use: {
        loader: 'babel-loader'.options: {
          presets: [// Force no conversion to modules
            ['@babel/preset-env', {modules: flase}]
          ] 
        }
      }
    }
  ]
},
Copy the code

SideEffects – sideEffects

This is usually only used when developing NPM modules

Side effects: the module does anything other than export members when it executes. Unused modules are not packaged when the function is enabled

Usage:

  1. Optimization in the configuration file enables:SideEffects: true,
  2. Add the sideEffects field to package.json:"SideEffects" : "true"Tell the system that all of our code has no side effects

Matters needing attention

  • Problem: Make sure your code has no side effects, otherwise the system will assume that all code has no side effects, such as CSS modules adding methods to built-in objects will be ignored
  • The solution
    • Turn off side effect declarations in package.json
    • Tell the system which files have side effects, and the system packages the code that has side effectsSideEffects: [file path, file path......]

Webpack Code Splitting – Code Splitting

The problem

  • All the code is then packaged together and can become too bulky
  • Not every module is required after startup, and some code will only work for certain operations

Solution: Subcontract and load on demand

  • Multiple entry packing
  • Dynamic import

Multiple entry packing

Generally applicable to traditional multi-page applications, most commonly a page a packaged entry, common parts extracted separately

module.exports = {
  entry: {
    // Configure two entry files to pack multiple entries
    index: '. /... /... /.js'.index2: '. /... /... /.js',},output: {
    // The output filename ADAPTS to the dynamic addition of name, which accepts the names of both entries
    filename: '[name].bindle.js'.path: path.join(__dirname, 'dist')},plugins: [
    // When we package, we find that the HTML internally references all of the packaged JS code, we manually modify the chunks so that the file only references the required JS files
    new HtmlWebpackPlugin({
      title: 'practice'.template: './code3/src/index.js'.filename: 'index.html'.chunks: ['index']}),new HtmlWebpackPlugin({
      title: Practice '2'.template: './code3/src/index2.js'.filename: 'index2.html'.chunks: ['index2']]}})Copy the code

Extract common modules

Multi-entry packaging does not extract the common parts, and there will be much of the same module code

The solution is to separate the common modules and store them separately, so you don’t need to store a copy in every packaged file

// Webpack configuration file

module.export = {
  .......
  optimization: {
    solitChinks: {
  		// Package all public modules separately
      chunks:'all'}}}Copy the code

Dynamic import

Load on demand: Load a module when it is needed

Dynamic import modules will automatically package and subcontract all dynamically imported modules

Dynamic imports use the ES Moudel method

// We can use dynamically loaded modules in a judgment condition or for loop, so that the code is only loaded at use, not directly after startup
if (x === 1) {
  // Import the module and use the then method to use the imported module
  import('./src/tow.js').then(({
    //Rename the imported module to onedefault: one
  }) = > {
    / / to use one
    console.log(one)
  })
} else {
  import('./src/tow.js').then(({
    default: tow
  }) = > {
    console.log(tow)
  })
}
Copy the code

Magic annotation

Add a name to the packaged file

To use: add inline comments to dynamically imported parameters, for example:

// webpackChunkName Can prefix a packaged file
// Prefix this file with one
import(/*webpackChunkName:'one'*/'./src/tow.js').then(({
    //Rename the imported module to onedefault: one
  }) = > {
    / / to use one
    console.log(one)
  })


// After packaging, the name is one.config file set name.js
Copy the code

Note: If two dynamically imported inline comments are the same, they are packaged into a single file

MiniCssExtractPlugin – CSS extracts to a single file

The Chinese document: webpack.docschina.org/plugins/min…

Plug-ins needed:yarn add mini-css-extract-plugin --dev

Using this plugin eliminates the need to use style-loader because the plugin extracts CSS files into separate files that need to be imported using link

Will style – loader replace MiniCssExtractPlugin. Loader

// The plugin needs to be imported
{
  test: /\.css$/./ / used here MiniCssExtractPlugin. Loader replace style - loader
  use: [MiniCssExtractPlugin.loader , 'css-loader']},Copy the code

Suggestion: more than 150 KB to use CSS file MiniCssExtractPlugin. Loader, otherwise it may backfire

OptimizeCssAssetsWebpackPlugin – compressing CSS files

Install plug-in:

  • Compressed CSS plugin:yarn add optimize-css-assets-webpack-plugin --dev
  • Compressed JS plugins:yarn add --dev terser-webpack-plugin
    • If you add the previous plugin to Minimizer, the system will assume that you want to manually configure the plugin, which will invalidate webPack’s default compressed JS code, so we need to manually add it back

Documents:

  • optimize-css-assets-webpack-plugin
  • TerserWebpackPlugin

The YARN Add optimize- CSS-assets-webpack-plugin was not found, but the plugin was provided

Webpack.docschina.org/plugins/css…

Usage:

  • Create instance objects directly in plugins
  • Writing in the minimizer
// Add a plugin to the list

// Webpack configuration file
module.export = {
  
  // Method 1: Write in minimizer
  optimization: {
    minimizer: [
      new OptimizeCssAssetsWebpackPlugin(),
      // Packaging in production mode will result in js compression not working properly, because once we set minimizer, the system will assume that we are using custom js compression and will not use the default js compression, so we have to manually introduce another plugin to solve this problem
      new TerserWebpackPlugin()
    ]
  },
  
  // Method 2: Write it in plugins, there is no need to design other plugins, but this is not recommended by the authorities, so use method 1 instead
  plugins: [
    new OptimizeCssAssetsWebpackPlugin(),
  ]
}
Copy the code

Output file name Hash

You are advised to use hash for the file name in production mode

Usage: In the Webpack configuration file, you can use hash wherever you want to change the name, such as filename in outpot or filename in HTML plug-in

// It can be used anywhere in the configuration file where naming is involved
output: {
  filename: '[name]-[hash]-bundle.js'
}

new HtmlWebpackPlugin({
      filename: 'the index - [r]. [8] hash: HTML',})// [...hash:x], x can specify how many bits of the hash name to generate, for example, [contenthash:8] generates an 8-bit hash
Copy the code

There are three hash values:

  • Hash: whole directory level, each change of the file will change the entire file name
  • Chunkhash: path level (dependency), only the path file name is changed
  • Contenthash: Indicates the file level. Only the name of the modified file is changed

An 8-bit hash is recommended