Take a moment to look again at the front end build tools, webPack (latest version 5).

Each study notes, completelyThere is noAny reference.

What problem does WebPack solve?

Webpack is a front-end static resource (module) building tool, static module packager.

Webpack is a front-end resource loading/packaging tool written by NodeJS. Nodejs provides powerful file processing and IO capabilities, so webPack itself only supports js and JSON files. For other files, it needs to be converted into commonJS files by Loader. Webpack can parse to.

Packaging principle: analyze each dependent resource from the entry file, identify the module dependencies layer by layer (Commonjs, AMD or ES6 import, WebPack will analyze them to obtain the code dependencies); What WebPack does is analyze code, transform code, compile code, and output code; The result is packaged code

Core Key: 5 steps:

  • entry: the entry
  • outputExports:
  • loader:wpWhich non-JS files can be processed (WP can only understand JS itself)
  • plugin: Perform a larger range of tasks, package compression, variable env, etc
  • mode: Mode production or development.

Installation and command line use

Installation: Yarn add webpack webpack-cli.

Command line packaging: node_modules/.bin/ webpack. / SRC /index.js -o. /development/ –mode=development

Encapsulate a simple build script: wp.sh:

if [[ $1x == "dev"x ]]; then echo "=====development====" node_modules/.bin/webpack ./src/index.js -o ./development/ --mode=development --color elif [ $1x == "pro"x ]; then echo "=====production====" node_modules/.bin/webpack ./src/index.js -o ./production/ --mode=production --color else  echo "========error=======" fiCopy the code

Package. json entry package:

"scripts": {
      "dev": "cross-env NODE_ENV=development webpack --config ./pack/config1.js"."serve": "cross-env NODE_ENV=development && webpack serve --config ./pack/config1.js"."dll": "rm -rf ./dllOut &&cross-env NODE_ENV=production && webpack --config ./pack/dll.js"."analyse": "webpack-bundle-analyzer --port 9000 buildOut/stats.json"."build": "cross-env NODE_ENV=production webpack --config ./pack/config1.js"
  },
Copy the code
  • cross-env makes it so you can have a single command without worrying about setting or using the environment variable properly for the platform

Ps: rm -rf can also be achieved by adding clean:true to output.

Core concept analysis:

Webpack packages the development environment configuration primarily to get the code running. Consider the following: package style resources, HTML resources, image resources, other resources *, devServe.

Front knowledge:

  • What are AMD, CommonJS, UMD?
  • # commonjs and commonjs2

1: mode:

module.exports = {
  mode: 'production'.// The default is production
};
Copy the code

2:entry:

If not, the default is main.

entry: {

  // Use multiple file types for each entry
  // Production is two files, which will be imported into the HTML separately, and inject two file dependencies
  // dev will form a chunk and output only a bundle.
  home: ['./home.js'.'./home.scss'].// Form a chunk and output a bundle file.
  add: './src/add.js'
}
Copy the code

3: output

output: {
  // File name (specify name + directory)
  filename: 'js/[name].js'.// Output file directory (public directory for future output of all resources)
  path: resolve(__dirname, 'build'),
  
   // Clear the package directory
   clean: true./ / all resources into public path prefix -- > 'imgs/a. pg' - > '/ imgs/a. pg'
  publicPath: '/'.chunkFilename: 'js/[name]_chunk.js'.// Specify the name of the non-entry chunk
  library: '[name]'.// The name of the variable exposed outward after the entire library is packaged
  libraryTarget: 'window' // Which variable name to add browser: window
  // libraryTarget: 'global' // node: global
  // libraryTarget: 'commonjs' // module exports
},
Copy the code

5: resolve

The main function is to configure how modules are resolved,

// Parse the rules of the module
resolve: {
  // Create aliases for 'import' or 'require' to make module introduction easier.
  // Configure the parsing module path alias: Advantages: abbreviated path when the directory hierarchy is complex; Disadvantages: Paths are not prompted
  alias: {
  The '@': path.join(__dirname, '.. '.'src')
   Utilities: path.resolve(__dirname, 'src/utilities/'),},// Configure to omit the file path suffix (not write the file suffix when importing)
  extensions: ['.js'.'.json'.'.jsx'.'.css'].// Tell the WebPack parsing module which directory to look for
  modules: [resolve(__dirname, '.. /.. /node_modules'), 'node_modules']}Copy the code

6: target

Since JavaScript can be written in both server-side and browser code, WebPack provides a variety of deployment targets,

module.exports = {
  target: 'node',
};
Copy the code

In the example above, the target is set to Node, and WebPack compiles the code in the node.js environment. (Use node.js require to load the chunk and not any built-in modules, such as FS or PATH)

Default usage: web, node, electron-main,electron-render

7: plugin

To list common plug-ins:

  • DefinePluginAllows for theCompile timeReplace variables in your code with other values or expressions. This is when you need to operate differently depending on the development mode versus the production mode.
new webpack.DefinePlugin({
   PRODUCTION: JSON.stringify(true),}),// Use in business
if(PRODUCTION){... }Copy the code
  • html-webpack-plugin: NPM address, This is awebpack plugin that simplifies creation of HTML files to serve your webpack bundles.
 new HtmlWebpackPlugin({
  title: "My App".filename: "index.html".template: "src/view/home.html".inject: body,
}),
Copy the code
  • mini-css-extract-pluginExtract: CSS
  • css-minimizer-webpack-plugin: CSS compression, which counts as a loader, for both comparisons.
const commmonCssLoader = [
  isDev ? "style-loader" : MiniCssExtractPlugin.loader,
  // Load the CSS file into the commonJS module, which contains the style string
  "css-loader",
  {
    // Add the browser prefix to the CSS using postCSS
    loader: "postcss-loader".options: {
      postcssOptions: {
        plugins: [
          // eslint-disable-next-line global-require
          require("autoprefixer"),
          // eslint-disable-next-line global-require
          require("postcss-preset-env")(),],},},},];Copy the code
  • DllPlugin and webpack DllReferencePlugin

  • Add-asset-html-webpack-plugin Add a JavaScript or CSS asset to the HTML generated by html-webpack-plugin.

 // Package a file to the build directory and automatically import the resource into the HTML
   new AddAssetHtmlWebpackPlugin({
    filepath: require.resolve(". /.. /.. /dllOut/jquery.js"),
    publicPath: ". /",}).Copy the code
  • eslint-webpack-plugin: This plugin uses eslintTo find and fix problems in your JavaScript code.

You also need to install eslint >= 7 from NPM, if You haven’t already:

yarn add eslint eslint-webpack-plugin --save-dev
Copy the code

Using the Airbnb standard, eslint-config-airbnb-base,This package provides Airbnb’s base JS .eslintrc (without React plugins) as an extensible shared config.

Our default export contains all of our ESLint rules, including ECMAScript 6+. It requires eslint and eslint-plugin-import.

yarn add eslint-plugin-import eslint-config-airbnb-base  --save-dev
Copy the code

Added esLint dependency fields in package.json: ESLint references the front-end project code flow to normalize common tools

"eslintConfig": {
    "env": {
      "browser": true."node": true
    },
    "ignorePatterns": [
      "dist"]."extends": "airbnb-base"."rules": {
      "quotes": "off"."node/no-unsupported-features/es-syntax": 0."node/no-extraneous-import": 0."node/no-unsupported-features/node-builtins": 0."node/no-extraneous-require": 0."node/no-deprecated-api": 0."node/no-missing-import": 0."node/no-unpublished-import": 0."node/no-missing-require": 0."node/no-unpublished-require": 0."no-unused-vars": "off"."func-names": [
        "error"."never"]."no-console": "off"}},Copy the code

New ESLintPlugin({fix: true});

  • webpack-bundle-analyzerPackage analysis tool, above is the entry, inpluginAdd:
 new BundleAnalyzerPlugin({
    analyzerMode: "disabled".generateStatsFile: true.statsOptions: { source: false}}),Copy the code
  • webpack.ProvidePlugin: Automatically loads without modulesimportorrequireThey’re everywhere.
 // Load automatically without having to import modules or require them everywhere.
  new webpack.ProvidePlugin({
    $: 'jquery'.jQuery: 'jquery'._map: ['lodash'.'map'],}).Copy the code

8: devServe

The contentBase is packaged separately using dllPlugin. If you do not add the result path, localhost:5000 will not find the path after refreshing.

In addition, starting from WebPack 5, the command run in the script is WebPack Serve to start.

devServer: {
  // The directory where the code is run
 contentBase: [
    path.join(__dirname, ". /.. /.. /build"),
    path.join(__dirname, ". /.. /.. /dllOut"),,,// Monitor all files in the contentBase directory and reload them as soon as they change
  watchContentBase: true.watchOptions: {
    // Ignore the file
    ignored: /node_modules/
  },
  // Start gzip compression
  compress: true./ / the port number
  port: 5000./ / domain name
  host: 'localhost'.// Open the browser automatically
  open: true.// Enable the HMR function
  hot: true.// Do not display startup server logs
  clientLogLevel: 'none'.// Do not display anything except some basic information
  quiet: true.// If an error occurs, do not prompt in full screen
  overlay: false.// Server agent, --> solve development environment cross-domain problems
  proxy: {
    // Once devServer(5000) receives a request from/API/XXX, it forwards the request to server 3000
    '/api': {
      target: 'http://localhost:3000'.// When sending a request, rewrite the request path: / API/XXX --> / XXX (remove/API)
      pathRewrite: {
        '^/api': ' '}}}}Copy the code

9: loader

  • style-loader:Inject CSS into the DOM. Dynamically insert the style tag into the head tag to make the CSS code work.

  • Css-loader: loads the CSS file into JS as a CommonJS module, containing style strings. That is, dependencies in CSS, such as declarations that refer to external files such as @import and URL (), are handled using import and require methods.

Because this approach modularizes reference resources in CSS files, and Webpack only deals with JavaScript, this modularization facilitates compilation separation.

  • poster-loader

  • Yarn add sass-loader sass –save-dev, Loads a sass /SCSS file and compiles it to CSS

  • Babel-loader: Handles JS compatibility. You need to download the babel-Loader and @babel/core(this is the core code base file for Babel).

  1. Basic JS compatibility handling, using the plug-in @babel/preset-env, but the problem is: only the base syntax can be converted, such as promise advanced syntax can’t be converted.

  2. Full JS compatibility handling, using @babel/ Polyfill plugin, but the problem: only to solve part of the compatibility issues, but to introduce all the compatibility code, too large

  3. Do what you need to do for compatibility: load on demand, using core-JS.

Summary: Yarn add babel-loader@babel /preset- env@babel /core core-js needs to be installed.

  1. supportreactandjsxSyntax, Note:jsxGrammar isjsLanguage features. Therefore, you need to install a separate one:

yarn add react react-dom @babel/preset-react

 {
    test: /\.m? js$/,
    exclude: /node_modules/,
    include: [path.resolve(". /.. /.. /src")].use: {
      loader: "babel-loader".options: {
        cacheDirectory: true.// Babel package cache
        presets: [["@babel/preset-env",
            {
              useBuiltIns: "usage".// Load on demand
              corejs: {
                version: 3.// The version of Corejs must be specified
              },
               targets: { // Which version of the browser is compatible with
                chrome: '60'.firefox: '50'.ie: '9'.safari: '10'.edge: '17'}},]."@babel/preset-react".// Support JSX syntax],}}},Copy the code
  • vue-loader

For the vue3.x project:

 yarn add vue@next -S
 yarn add vue-loader@next
Copy the code

Lodaer configuration:

{
    test: /\.vue$/,
    use: [
      'vue-loader']},Copy the code

The also need to configure VueLoaderPlugin: it is to read the first compiler. The option. The module. The rule, then add the pitchloader, then put the vue – loade in order to in the end, is mainly in the treatment of the rule.

const { VueLoaderPlugin } = require('vue-loader/dist/index')...// Add the VueLoaderPlugin
  // is responsible for copying the other rules you have defined and applying them to the corresponding language block in the.vue file.
  // For example, if you have a rule that matches /\.js$/, then it applies to the 
  new VueLoaderPlugin(),
Copy the code
  • file-loaderurl-loader

file-loader : The file-loader resolves import/require() on a file into a url and emits the file into the output directory. You can specify where to copy and place resource files, and how to use version hash names for better caching.

In addition, this means that you can manage image files close to you and can use relative paths without worrying about urls at deployment time. With the correct configuration, WebPack will automatically rewrite the file path to the correct URL in the packaging output.

Url-loader allows you to conditionally convert files to inline Base-64 urls (when the file is less than a given threshold), which reduces the number of HTTP requests for small files. If the number of files exceeds the threshold, the files are automatically submitted to the file-Loader for processing.

import img from './image.png'; // By default, only JS and JSON file types are supported, and // require the file to be synchronized with fs.readFile. // By default, only JS and JSON files are supported. Const c = require("./static/c.png");Copy the code

If you use CommonJS to import images, you need to disable the default parameter, esModule: false.

   {
        test: /\.(png|jpg|gif)$/i,
        use: [
          {
            loader: "url-loader".options: {
              limit: 8192.// 8kb
              esModule: false.name(resourcePath, resourceQuery) {
                if (ENV === "development") {
                  return "[path][name].[ext]";
                }
                return "[contenthash].[ext]"; },},},],},Copy the code

Differences: This is the wP4 version, and here is the new WP5 implementation: Wp will now automatically select between Resource and inline by default: Files smaller than 8KB are considered to be of inline module type, otherwise they are considered to be of Resource module type.

Therefore, in WP5, files of resource types are not configured separately, and can be configured as follows:

{
    test: /\.(png|jpg|gif)$/i,
    type: "asset".generator: {
      filename: "img/[name].[hash:6][ext]",}},// How to package other resources such as fonts
 {
    test: /\.(ttf|eot|svg|woff|woff2)$/i,
    type: "asset".generator: {
      filename: "font/[name].[hash:6][ext]",}},Copy the code

Performance optimization

Development environment optimization

1: Hot Module replacement (HMR)

What it does: when a module changes, only one of the modules is repackaged and built (instead of all the modules), greatly speeding up the build process. In the development environment, just set hot :true in the devServer to automatically enable HMR (only available in development mode).

DevServer: {// enable the HMR function // When the webpack configuration is changed, the webpack service must be restarted for the new configuration to take effect. Hot: true}Copy the code

Hot-module replacement for each file:

  • Style files: You can use the HMR function because the styleloader used in the development environment implements hot module replacement internally by default.

  • Js file: HMR function cannot be used by default (if you modify a JS module, all JS modules will be refreshed), you need to add the code to support HMR function manually)

    // Bind if (module.hot) {// Once module.hot is true, the HMR function is enabled. Accept ('./print.js', function() {// the method will listen for changes to the print.js file. If the changes happen, only this module will be repackaged and built. Print (); // Print (); }); }Copy the code

    Note: the HMR function can only process js files that are not the entry JS files.

  • HTML file: The HMR function cannot be used by default. Generally, you do not need to use the HMR function for HTML because there is only one HTML file, so you do not need to optimize. Using HMR can cause problems: HTML files can no longer be hot-updated (not automatically packaged build)

Fix: modify the entry to import HTML files (so that HTML changes as a whole refresh)

entry: ['./src/js/index.js', './src/index.html']
Copy the code

2: devtools(source-map)

Source-map: a technique that provides a mapping of source code to post-build code (if something goes wrong with the post-build code, the mapping allows you to track the source code error.

  • Source-map external, error code accurate information and source code error location
  • Hidden -source-map external source code error cannot be traced, only to the error location and file
  • Cheap-source-map External error information and source code, only accurate to the line
  • Cheap-mod-source-map Specifies the exact location of external error codes and source code errors
  • The eval – source – within the map
  • Inlinep-source-map error code accurate information and source code error location

Development environment: Fast: eval > inline > cheap

Production environment: Consider whether source code should be hidden and whether debugging should be more friendly

  • Inlining makes the code bulky, so don’t do it in production
  • Hide source code
Nosource-source-map hides all source code. Hidden -source-map hides only source codeCopy the code

Eval-source-map (high integrity, fast inline)/eval-cheap-mode-souce-map (error message ignore column but contain other information, fast inline)

Production environment code optimization

Packing speed:

1: Enable the local persistent cache

Previous cache:

  • usecache-loadeR can write the compiled results to the hard disk cache,WebpackIf the file has not changed, it will be pulled directly from the cache.
  • And then there’s someloaderBuilt-in cache configuration, such asbabel-loader, you can set parameterscacheDirectoryUsing caching, write the result of each compilation to disk (default atnode_modules/.cache/babel-loaderDirectory)
  • terser-webpack-pluginOpen the cache

Webpack5 cache:

[webpack5 local caching scheme] (webpack.docschina.org/configurati…). This set of persistent cache, very convenient and fast. Jishuin.proginn.com/p/763bfbd3a…

 cache: {
    type: "filesystem".buildDependencies: {
      config: [__filename], // You can ignore it when you add it automatically on the CLI}},Copy the code

2: multi-process packaging

If the recommended thread-loader is used, place this loader before other loaders. Loaders placed after this loader are run in a separate worker pool. Process startup takes about 600ms, and process communication has overhead. (It’s expensive to start up, so don’t abuse it). Multiprocess packaging is only required if the work takes a long time. Therefore, this is not recommended if the project is not very large.

 {
    test: /\.m? js$/,
    exclude: /node_modules/,
    include: [path.resolve(". /.. /.. /src")].use: [{loader: "thread-loader".options: {
          workers: 2.// Two processes}, {},loader: "babel-loader",}]},Copy the code

3: externals:

The externals configuration option provides a way to “exclude dependencies from the output bundle.” Instead, the bundles that are created depend on those dependencies that exist in the consumer’s environment. Let some libraries be introduced via CDN without packaging

Instead of packaging imported packages into bundles, you retrieve external dependencies at runtime.

index.html:

< script SRC = "https://code.jquery.com/jquery-3.1.0.js" > < / script >Copy the code
  externals: {
   // The attribute name is 'jquery', indicating that the 'jquery' module in 'import $from 'jquery'' should be excluded.
    jquery: 'jQuery'.// If you want to externalize a class library that complies with CommonJS modularity rules,
    'fs-extra': 'commonjs fs-extra',},Copy the code

Note: A form such as {root, AMD, commonjs… } objects are only allowed for libraryTarget: ‘umd’ configurations. It is not allowed to be used with other Library Targets configuration values. This is the wrong way to write it,

Output :{libraryTarget: 'umd'} output:{libraryTarget: 'umd'}
lodash: {
  commonjs: "lodash".commonjs2: "lodash".amd: "lodash".root: "_".// Point to a global variable
},

// This should be:
lodash: "_"
Copy the code

Note: externals and DLL configuration conflict,

DLL: in line with the front-end modular requirements, webPack configuration is a little more complex, need to pre-package the required DLL resources, and configure the corresponding plugin during the build. With DLLS, these external dependencies generally do not need to be changed, and if they do, the project needs to be rebuilt.

External: Does not quite fit the modularity concept of the front end, the external libraries needed need to be accessible in the browser global environment. External library upgrades do not require a project rebuild if they are compatible with the previous API. Webpack configuration is slightly simpler, but it also requires that the required external libraries be packaged into the desired format and referenced at runtime

In contrast, DLLS should be more intelligent than External, mainly in terms of module references and packaging. Eg:

import AA from 'react/lib/createClass'

If the DLL method is used, it will not cause repackaging, it will refer to the DLL directly. If you use External, the react code is packaged in.

4: DLL

Mainly combined with the two plug-ins: DllPlugin and webpack DllReferencePlugin

The node_modules libraries are packaged together, but the output js file of many libraries is too large, and it usually doesn’t change: vue, react, jQuery. You don’t have to do it every time you pack, so these can be packaged together separately, instead of taking part in one pack at a time. The new DLL. Js

const { resolve } = require("path");
const webpack = require("webpack");
const path = require("path");
const { isDev } = require("./util/env");

module.exports = {
  entry: {
    [name] --> jquery
    // ['jquery '] --> the library to package is jquery
    jquery: ["jquery"],},output: {
    // The output is specified
    path: path.resolve(process.cwd(), "dllOut"), // Package it to the DLL directory
    filename: !isDev ? "[name].[contenthash:10].js" : "[name].js".// What is the name of the contents exposed in the packaged library

    // Store the global variable name of the dynamic link library, such as _dll_react for react
    // The _dll_ prefix is used to prevent global variable conflicts
    library: "_dll_[name]",},plugins: [
    // Generate a manifest.json -->
    // Provide the jquery mapping (tells WebPack that you don't need to package and expose content names after jquery)
    new webpack.DllPlugin({
      // The name of the global variable in the dynamic link library must be the same as that in output.library
      // The value of this field is the value of the name field in the manifest
      // For example, react. Manifest. Json has "name": "_dll_react"
      name: "_dll_[name]".// The name of the exposed content of the mapping library
      path: resolve(__dirname, ".. /dllOut/manifest.json"), // Output file path}),].mode: "production"};Copy the code

After packaging separately, add a reference to webpack.config.js:

// Tell WebPack which libraries will not be packaged and which names will have to be changed when used
  new webpack.DllReferencePlugin({
    manifest: path.resolve(process.cwd(), "dllOut/manifest.json"),}),Copy the code

After that, add-asset-html-webpack-plugin was used to dynamically add it into HTML to form a reference.

Code performance

1: the tree – shaking

Tree shaking is a term commonly used to describe the removal of dead-code from a JavaScript context. Prerequisites:

  • mode: production

  • Es Module introduces file analysis

  • Add sideEffects:[*./ CSS] to package.json.

This is the side effect of tree-shaking because we added the “sideEffects”: false in package.json, so all CSS references to import a.ss are invalid.

2: lazy load and preload or dynamic load

Lazy loading: Loading files only when they are needed (requires code splitting). However, if the resource is large, the load time will be long and there will be delay.

Prefetch (poor compatibility) : Loads in advance before use. This resource is loaded when all other resources are loaded and the browser is idle. It’s loaded when you use it, and it’s fast. So it’s better to add preloading to lazy loading.

img1.onclick = function () {
  
  // Specify the name of the packaged chunk, imhClick, and WP5 will automatically assign one
  import(
    /* webpackChunkName: 'imhClick'*/ "./util"
  ).then(({ add }) = > {
    console.log(add(3000.5000));
  })
  .catch(() = > {
    console.log('Failed to load file ~');
  })


  / / preload
  import(
    /* webpackChunkName: 'imhClick',webpackPrefetch: true */ "./util"
  ).then(({ add }) = > {
    console.log(add(3000.5000));
  });
};
Copy the code

Let a chunk (eg: util.js) be packaged as a separate chunk.

Import dynamic import syntax: you can package a file separately (test file is not packaged in the same file as index, but separately).

However, this is rarely used in actual development. React and Vue both have their own methods to support this. Common routing switches, individual modules, etc., do this, and the resources do not occupy the startup packet resources.

  • React: Code Splitting and Lazy Loading
  • Vue: Dynamic Imports in Vue.js for better performance
  • Angular: Lazy Loading route configuration and AngularJS + webpack = lazyLoad

3: code splite

Reference:

4: PWD offline cache

Pwa: Offline accessibility technology (progressive web development applications) using ServiceWorker and Workbox technologies. The advantage is that it can be accessed offline, but the disadvantage is poor compatibility.

// Insert into plugins:
  new WorkboxWebpackPlugin.GenerateSW({
    2. Delete the old serviceWorker and generate a serviceWorker configuration file */
    clientsClaim: true.skipWaiting: true
  })
Copy the code

index.js

if ('serviceWorker' in navigator) { // Handle compatibility issues
window.addEventListener('load'.() = > {
navigator.serviceWorker
  .register('http://127.0.0.1:5500/buildOut/service-worker.js') // Registering serviceWorker must be on the server
  .then(() = > {
    console.log('SW registration succeeded ~');
  })
  .catch(() = > {
    console.log('sw registration failed ~');
  });
});
}
Copy the code

Develop loader and plugin

Loader custom development: Reference to implement a Loader replacement for sensitive words.

mkdir loader && cd loader && npm init -y && yarn add webpack weboack-cli 

touch index.js > console.log('this is fuck! ');

touch loader1.js  // vi 

// const loaderUtils = require('loader-utils'); // WP5 no longer requires this parameter
module.exports = function (source) {
  // const options = loaderUtils.getOptions(this);
  
  const options = this.getOptions();
  if (options.mode === "kindly") {
    let result = source.replace("fuck"."kiss");
    return result;
  } else {
    returnsource; }};// The pitch method on loader is not required
module.exports.pitch = function (arg) {
  console.log("=====loader1");
  // todo
};


touch loader.js  // vi


module.exports = function (source) {
  const options = this.getOptions();
  const result = source.replace('! ', options.endFlag);
  return result;
}
module.exports.pitch =  function(arg) { 
   console.log('=====loader2');
 }
Copy the code

Set the webpack.config.js configuration:

const path = require("path");

module.exports = {
  mode: "production".entry: {
    main: "./index.js",},output: {
    filename: "[name].js".path: path.resolve(__dirname, "dist"),},module: {
    rules: [{test: /\.js$/,
        use: [
          {
            loader: path.resolve(__dirname, "./loader1.js"),
            options: {
              mode: "kindly",}}, {loader: path.resolve(__dirname, "./loader2.js"),
            options: {
              endFlag: "?????",},},],},],},},};Copy the code

Finally, after executing the NPM run build, you can see in the dist directory :console.log(“this is kiss?? ); Loader is called from right to left, but the pitch method is executed from left to right.

The plugin development:

mkdir plugin && cd plugin && npm init -y && yarn add webpack weboack-cli 

touch myplugin.js  //vi

class myPlugin {

    constructor(doneCallback, failCallback) {
        this.doneCallback = doneCallback;
        this.failCallback = failCallback;
    }

    apply(compiler) {
        compiler.hooks.done.tap('myPlugin'.(stats) = > {
            this.doneCallback(stats);
        });
        compiler.hooks.failed.tap('myPlugin'.(err) = > {
            this.failCallback(err); }); }}module.exports = myPlugin;
Copy the code

Call this plugin:

plugins: [
    new myPlugin(
      () = > {
        console.log("Success");
      },
      (error) = > {
        console.log('failure',error); }),].Copy the code

Refer to the article

  • Differences between Hash, Chunkhash, and Contenthash in WebPack
  • Webpack5 has changed significantly
  • Juejin. Cn/post / 690973…
  • www.woc12138.com/article/45
  • Juejin. Cn/post / 690971…
  • Juejin. Cn/post / 690971…