The working principle of

The basic concept

  • Entry: Entry, the first step that Webpack performs the build starts with Entry.
  • Module: module, everything in Webpack is a module, a module corresponds to a file. Webpack will recursively find all dependent modules from the configured Entry.
  • Chunk: A chunk of code. A chunk is a combination of multiple modules and is used for code merging and splitting.
  • Loader: Module converter, used to convert the original contents of the module into new contents as required.
  • PluginPlugins that broadcast events at specific times in the Webpack build process. Plugins can listen for these events and do something at specific times.

Generalization process

Initialization parameters — > Start compilation — > Determine entry — > Compile module — > Complete module compilation — > Output resource — > Output complete

  1. Initialization parameters: Read and merge parameters from the configuration file (default webpack.config.js) and shell statements to get the final parameters
  2. Compile: Initialize the parameters from the previous stepCompilerObject to load all configured plug-insPlugin, which starts the compilation by executing the object’s run method
  3. Determine the entry: according to the configurationentryFind all the entry files
  4. Compile module: calls all configured modules from the entry fileLoaderCompile the module, find out which modules the module depends on, and repeat this step until all entry dependent files have been processed
  5. Complete the compilation of modules: After the fourth step, you have the final content of each module after it has been translated and the dependencies between them
  6. Output resources: assemblies of multiple modules based on the dependencies between the entry and moduleschunkEach chunk is converted into a separate file and added to the output list. This is the last chance to modify the output
  7. Output completion: after determining the output content, determine the output path and file name according to the configuration (webpack.config.js && shell), and then change the content of the fileWrite to the file system(fs)

To summarize, the Webpack build process can be divided into three phases:

  1. Initialization: Start the build, read and merge configuration parameters, load Plugin, and instantiate Compiler.
  2. Compile: From the Entry, the corresponding Loader is called for each Module to translate the contents of the file, and then find the Module that the Module depends on, and compile the process recursively.
  3. Output: Combine the compiled modules into chunks, convert the chunks into files, and output to the file system.

bundle.js

Bundle. js is actually an immediate execution function. The reason bundle.js can run directly in the browser is that the output file defines a load function that can be executed in the browser via the __webpack_require__ function to simulate the require statement in Node.js. In addition, Webpack has been optimized for caching, so that a loaded module will not be executed a second time, and the execution result will be cached in memory. When a module is accessed a second time, it will directly read the cached return value from memory.

(function(modules){
    // Simulate the require statement
    function __webpack_require__(){}
    // Execute the 0th module in the array of all modules (main.js)
    __webpack_require_[0([]})/* Hold an array of all modules */])
Copy the code

Performance optimization

Reduce Webpack packaging time

  1. Optimize the Loader: optimize Loader’s file search range (exclude node_modules) and cache Babel compiled files (Loader: ‘Babel? CacheDirectory = true ‘). For Loaders, the most important factor affecting packaging efficiency is Babel. becauseBabel converts the code into a string to generate the AST, which is then transformed into new code.The larger the project, the more code it converts, the less efficient it becomes.
  2. HappyPack: can convert the synchronized execution of the Loader to parallel.
module: {
  loaders: [{test: /\.js$/.include: [resolve('src')].exclude: /node_modules/.// The content after the id corresponds to the following
      loader: 'happypack/loader? id=happybabel'}},plugins: [
  new HappyPack({
    id: 'happybabel'.loaders: ['babel-loader? cacheDirectory'].// Start four threads
    threads: 4})]Copy the code
  1. DllPlugin: Specific libraries can be pre-packaged and then introduced. Greatly reduces the number of times you have to package a library. You only need to repackage a library when it is up to date.
// In a separate file
// webpack.dll.conf.js
const path = require('path')
const webpack = require('webpack')
module.exports = {
  entry: {
    // Libraries that want to be packaged uniformly
    vendor: ['react']},output: {
    path: path.join(__dirname, 'dist'),
    filename: '[name].dll.js'.library: '[name]-[hash]'
  },
  plugins: [
    new webpack.DllPlugin({
      // Name must be the same as output.library
      name: '[name]-[hash]'.// This property needs to be consistent with the DllReferencePlugin
      context: __dirname,
      path: path.join(__dirname, 'dist'.'[name]-manifest.json')]}})// Use the DllReferencePlugin to import the dependent files into the project
// webpack.conf.js
module.exports = {
  / /... Omit other configurations
  plugins: [
    new webpack.DllReferencePlugin({
      context: __dirname,
      // Manifest is the json file that was packaged before
      manifest: require('./dist/vendor-manifest.json'),}})]Copy the code
  1. Code compression: used in Webpack3webpack-parallel-uglify-pluginTo run in parallelUglifyJS(single thread), webPack4 willmodeSet toproductionBy default, compression is enabled.

Reduce the size of Webpack files

  1. According to the need to load: Each routing page is individually packaged as a file,loadashThis functionality can also be used by large libraries.
  2. Scope Hoisting: analyzes dependencies between modules and merges packaged modules into a function whenever possible. To enable this function in Webpack4, you only need to enable itoptimization.concatenateModules.
// test.js
export const a = 1
// index.js
import { a } from './test.js'
Copy the code

After packaging the above two files, the generated code looks like this:

[
  /* 0 */
  function (module, exports, require) {
    / /...
  },
  / * 1 * /
  function (module, exports, require) {
    / /...}]Copy the code

If you use Scope Hositing, you will generate code similar to this:

[
  /* 0 */
  function (module, exports, require) {
    / /...}]Copy the code
  1. Tree Shaking: You can delete unreferenced code from a project. This function is enabled by default in the Webpack4 production environment.
// test.js
export const a = 1
export const b = 2
// index.js
import { a } from './test.js'
Copy the code

The variable b in the test file is not packaged into the file if it is not used in the project.