modular

The reasons causing

  • A large number of module members contaminate the global scope
  • There is no private space, and members within a module can be accessed and modified by members outside the module
  • A large number of modules may cause naming conflicts
  • Unable to manage dependencies between modules
  • It is also difficult to identify the module members belong to during maintenance

commonJS

The CommonJS specification is the module specification followed in Node.js. Convention: A file is a module, and each module has its own scope. Exports via module.exports, imports via require.

CommonJS loads modules synchronously because the Node.js execution mechanism loads modules at startup and uses them at execution. However, it does not apply to browsers. If browsers use synchronous loading, a large number of synchronous mode requests will be triggered, resulting in low application running efficiency.

AMD

AMD defines each module through the define() function. If you need to export members from the current module, you can return them. The require() function is used to automatically load modules. Modules can be loaded asynchronously.

Require. js is a library based on AMD specifications. The main implementation principle is that when a module needs to be loaded, script tags will be automatically created internally to request and execute the code responding to the module.

// ADM defines A module define(['A', 'B'], function(moduleA, moduleB) {return moduleC}) function(moduleC) { moduleC.init })Copy the code

CMD

CMD is similar to CommonJS specification, specific implementation of Sea. Js, back require.js compatible. Synchronously load modules.

define(function(require, Exports,module) {var A = require('moduleA') // exports or module.exports = module function () { return B } })Copy the code

ES Module

Individual modules can be imported on demand and asynchronous import is supported. Use import to import and export and export default to export.

    import A form B
    import { default as A} form B

    export default A


    import {a,b,c} from C
    import * as D from C

    export {a,b,c}
Copy the code

Call import() as a function, passing it as an argument to the module’s path. It returns a promise, so it can be loaded asynchronously.

    import('/modules/myModule.mjs')
      .then((module) => {
        // Do something with the module.
      });
Copy the code

Webpack core features

Webpack wants to realize the modularization of the whole front-end project, and the various resources in the project (including CSS files, images, etc.) should belong to the module that needs to be managed. In other words, Webpack is not only a JavaScript module packaging tool, but also a module packaging tool for the entire front-end project (front-end engineering). That is, we can use Webpack to manage any type of resource file in a front-end project.

In daily development our packaging solution or idea is:

  • Compatible with user browsers
  • The ability to pack scattered modules together to avoid frequent network requests from the browser
  • Supports different types of front-end resource modules

Tips

  1. Webpack.config. js is a JS file that runs in the Node.js environment, so we need to write the code as CommonJS. The use of the module. The export.
  2. This can be added to the header when using VS Code during developmentimport { Configuration } from 'webpack' Used to prompt only webPack configuration item Settings
  3. VS Code folds Code

In this example, simple packaging generates bundle.js. Bunde.js is a self-executing function that loads an array of modules and defines utility methods such as webpack.require for loading other modules.

Loader

By default, only JS module code is handled in Webpack, and all files are treated as JS code during packaging by default. The core of Webpack to load different types of resource modules is Loader.

CSS

Css-loader: CSS-loader only loads CSS modules into JS code, but does not use this module.

Style-loader: Adds all style modules loaded in CSS-loader to the page by creating style tags.

Therefore, the configuration process must be carried out in sequence from back to front and from right to left.

How to write a loader

The process of Webpack loading resource files is similar to a working pipeline. You can use multiple Loaders in turn, but the end result of the pipeline must be a standard JS code string.

  1. Each Loader is an independent module that imports the file content to be processed and outputs the processed content.
  2. The loader that processes the last of each type of file returns a string of JS code at the end of the loader.
  3. Find an appropriate loader and proceed with our results later.

Plugins Plugins

The purpose of the Webpack plug-in mechanism is to enhance Webpack’s ability to automate the build of projects.

Common application scenarios of plug-ins

  • Implement automatic cleanup of the dist directory before packaging (last packaging result)clean-webpack-plugin
  • Automatic generation of application required HTML files;html-webpack-plugin
  • Inject potentially variable parts of the code, such as API addresses, depending on the environment;
  • Copy resource files that you do not need to participate in packaging to the output directory.copy-webpack-plugin
  • Compress the output of Webpack after it is packaged; Extract CSS in a separate file:mini-css-extract-pluginCompressed style files:optimize-css-assets-webpack-pluginBuilt-in JS compression plug-in:terser-webpack-plugin
  • Automatically publish packaged results to the server for automatic deployment;ssh2-sftp-client
  • Analysis of packaged volume:webpack-bundle-analyzerModule code cache:hard-source-webpack-pluginParallel compression: ‘terser-webpack-plugin

How to write a Plugin

Webpack’s plug-in mechanism is the most common hook mechanism we use in software development.

The hook mechanism is also particularly easy to understand, somewhat similar to events on the Web. There are many links in Webpack, and in order to facilitate the extension of plug-ins, Webpack almost buried a hook in each link. This allows us to easily extend the capabilities of Webpack by mounting different tasks on these different nodes as we develop the plug-in.

Webpack hooks

The core of the plugin, then, is to determine when a task should be executed and to which hook it should be mounted.

Tips

  1. NPX can call modules installed in the project. It checks whether the command exists in the node_modules/. Bin directory and the environment variable $PATH.
  2. NPM can be usedprocess.env.npm_config_xxxTo get the command line parameter XXX variable that is currently executedThe config of NPM(You can also use yargs to get command-line arguments.)

Webpack core steps

  • The Loader processes the loading of special types of resources, such as loading styles and images.

  • The Plugin enables various automated build tasks, such as automatic compression and automatic publishing.

    Once Webpack starts, it finds a specified file in the project (usually a JS file) as the entry point, based on our configuration. Then follow the code in the entry file, according to the statements such as import (ES Modules) or require (CommonJS) in the code, parse and infer the resource module that the file depends on, and then parse the dependency of each resource module separately, and repeat. Finally, a dependency tree is formed between all files used in the whole project.

    Once the dependency tree is in place, Webpack traverses (recursively) the dependency tree, finds the resource file for each node, gives it to the corresponding Loader to load the module according to the Loader configuration in the configuration option, and finally puts the loaded result into bundle.js. To achieve the packaging of the entire project.

Webpack CLI starts the packaging process

  • Find the entry file to get command line arguments: In the webpack-cli entry file bin/cli.js, cli parameters are parsed by yargs module. The cli parameters are the parameters passed in from the command line when we run the webpack command, for example –mode=production;
  • Merge default and configuration parameters: the bin/utils/convert-argv.js module is called to convert the resulting command line parameters into configuration option objects for Webpack. When convert-argv.js is working, it first sets default values for the command line arguments that are passed, and then determines whether a specific configuration file path is specified in the command line arguments. If so, the specified configuration file is loaded, and if not, it needs to find the configuration file according to the default configuration file loading rules. After the configuration file is found, the configuration in the configuration file is combined with the configuration in the CLI parameters. If the configuration file is duplicated, the CLI parameters are used first to obtain a complete configuration option.
  • Start loading the Webpack core module, passing in configuration options, and create the Compiler object, which is the core object of the Entire Webpack process and is responsible for building the entire project.

The Webpack starts building

  • Immediately after the Compiler object has been created, the code here begins to determine whether monitor mode is enabled in the configuration options
    • The watch method of the Compiler object is called if it is in monitor mode to start the build in monitor mode, but this is not our main thread of concern.
    • Instead of monitoring mode, call the Compiler object’s Run method and start building the entire application.
  • The run method triggers the beforeRun and run hooks and, crucially, calls the compile method of the current object to actually compile the project
  • Compile creates a Compilation object, which literally means “Compilation.” In fact, you can think of it as a context object during a build that contains all the resources and information from that build.
  • After creating the Compilation object, a hook called make is triggered to enter the make phase, which is at the heart of the build process.

Make phase

The goal of the main body in the make stage is to find the entry module according to the entry configuration, recurse all dependencies in turn, form a dependency tree, and then hand each recursed module to a different Loader for processing.

Webpack’s plug-in system is based on the official Tapable library implementation, we want to know where to register an event, we must know how to register the event. Tapable can be registered as follows:

So, we should be able to find the location of the event registration by simply searching the make.tap in the source code with the development tools.

  1. The SingleEntryPlugin (single-entry packaging) calls the addEntry method of the Compilation object to start parsing the entry;
  2. The addEntry method calls the _addModuleChain method to add the entry module to the module dependency list;
  3. Modules are then built through the buildModule method of the Compilation object.
  4. The buildModule method performs specific loaders to handle special resource loads;
  5. After build, generate AST syntax tree of module code from acorn library.
  6. Analyze the syntax tree to see if the module has any dependencies, and if so, continue to loop to build each dependency.
  7. All dependencies are resolved and the build phase is over.
  8. Finally, the bundle.js that needs to be exported is merged and written to the dist directory.

Webpack development configuration tips

Dev Server is locally developed

The following conditions must be met:

  1. Run using Http services, closer to production
  2. After modifying the code, WebPack completes the build automatically and the browser displays the latest results in a timely manner
  3. Source Map is provided to locate problems more conveniently and quickly

webpack-dev-server

When we run the webpack-dev-server command, it starts an HTTP server internally, provides static file services for the packaged results, and automatically packages our application with WebPack, then listens for changes to the source code, and immediately repackages the files as soon as they change.

To speed things up, webpack-dev-server does not write the packing results to disk, but stores them temporarily in memory, from which the internal HTTP server reads the files. This reduces unnecessary disk reads and writes and greatly improves the overall build efficiency.

devtool

Module hot Replacement Mechanism (HMR)

This means that we can replace a module in the application in real time while the application is running without changing the running state of the application.

It’s not out of the box, you need to add some extra code. vue.js HMR

Tree-shaking

Tree-shaking is implemented using two optimization features of Webpack:

  • UsedExports – Export only the external members in the package result.
  • Take out – compress packing results.
module.exports = {
  / /... Other Configuration Items
  optimization: {
  
    // The module exports only used members
    usedExports: true.// Compress the output
    minimize: true.// Merge each module into a function if possible
    concatenateModules: true,}}Copy the code

Code Splitting

Webpack implements subcontracting:

  • Configure multiple packaging entrances according to different services, output multiple packaging results, and extract common modulessplitChunks
  • Load Modules on demand in combination with the Dynamic Imports feature of ES Modules.

Tips

  • Simple to use when configuring with multiple filesObject.assginIf the combined configuration requirements cannot be met, you can installwebpack-merge
  • Define Plugin Configures global variables

Good article recommendation

Didi Webpack series

Webpack5 + Ts practice

Webpack knowledge points collection

Webpack compilation process