How does Webpack work?

The main contents include:

  • Packaged file
  • File dependencies
  • Overall thinking sorting
  • The code analysis
  • Module actuator
  • The source code
  • Project directory structure

Packaged file

  • index.js
  • a.js
  • b.js
  • c.js

File index. Js

import a from './a.js';
var temp = a
console.log("index.js + " ,temp);

Copy the code

File a. s.

import {b} from './b.js';
export default `a.js + ${b}`;
Copy the code

File b.j s

import {c} from './js/c.js';
export let b = `b.js +  ${c}`;
Copy the code

File SAN Antonio s

export const c = " c.js ";

Copy the code

File dependencies

Index introduces a, A introduces B, and B introduces C. Print data in index.js (ndex + a + B + C data)

Overall thinking sorting

Input a JS file, analyze its internal dependencies, find n dependent JS files, convert the N files into N functions according to the specified rules, and package the output into a JS file. (n-> 1) merge N Js files into one. This is an important feature of WebPack

The code analysis

Three functions

CreateAsset function STR -> {}

  • By passing the file path “./es6ToEs5/index.js” and reading the contents of the file through readFileSync,
  • Parse the file contents into a syntax tree using Babylon,
  • Traverse the syntax tree with the ImportDelaration hook function to pull out./a.js from the import a from ‘./a.js’ statement and store it in a dependent collection array.
  • Through the Babel. TransformFromAstSync traverse the js file syntax tree, to convert es6 es5, and returns a string
  • In this method, the external variable ID (the file ID starts at 0) is incremented, and the file ID is incremented by one each time this function is called. Finally, (you can use this ID to see how many files we are processing)
  • The output as a object function includes id, filename, dependencies, the code is as follows:
  {
    id: 0.filename: './es6ToEs5/index.js'.dependencies: [ './a.js'].code: '"use strict"; \n' +
     '\n' +
      'var _a = _interopRequireDefault(require("./a.js")); \n' +
      '\n' +
      'function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }\n' +
      '\n' +
      'var temp = _a["default"]; \n' +
      'console.log(" I am the data printed inside the index.js file + the contents of the file A.js: /br", temp); '
  }
Copy the code

CreateGraph function STR -> {}

  • First, the input is a file path string
  • Call the createAsset method to read the contents of the file and convert it to an object
  • Create a new array (for breadth traversal) to hold file objects
  • Iterate through the array of file objects and add a property to hold the data for the child dependencies
  • We iterate over the dependencies array of the file objects in the list
  • CreateAsset is called to get the file object that depends on the file
  • Add attribute mapping to the dependent subfile object, such as mapping: {‘./a.js’: 1}
  • Add the child dependencies to the array one by one, iterate the breadth, iterate the file objects of A. js, B. js, and c.js until there are no dependencies. (Use breadth traversal, loop and push to the loop target at the same time)
  • So far all dependencies (file objects) have been pushed into an array
  • Output array [file object, file object, file object…]

The bundle function [] = > STR

  • Loop through an array of file objects and store the code from each module in the function scope
  • Loop concatenation functions are concatenated according to 0:[function(){},mapping] or whatever they specify

Concatenate the function string of each file module

Zero:function (require, module, exports){
        "use strict";
        var _a = _interopRequireDefault(require("./a.js"));
        function _interopRequireDefault(obj) { 
            return obj && obj.__esModule ? obj : { "default": obj }; }
            var temp = _a["default"];
            console.log("index.js + ", temp);
        },
       {"./a.js":1},
    ]
Copy the code
  • Continue to concatenate, concatenate the simulated module actuators

The module executor and its require method STR -> executable script

(function(modules){
    // create the require function, which takes a module ID (the module ids are the numbers 0,1,2... , each ID corresponds to a function (a file module).
    function require(id){
      const [fn, mapping] = modules[id];
      function localRequire(relativePath){
        // Find the module id in the mapping according to the module path, recursively call require method, execute all modules
        return require(mapping[relativePath]);
      }
      const module = {exports: {}};// Execute the code for each module.
      fn(localRequire,module.module.exports);
      return module.exports;
    }
    // Execute the entry file,
    
    require(0);
  })({${modules}})
Copy the code
  • The module executor entry parameter, which is the entire JS string (including all the files that the entry file depends on) concatenated according to the specified rule, returns the entire packaged script that can be executed.
  • {“./a.js”:1}} {“./a.js”:1}
  • The require function takes a number, which corresponds to a module function.
  • The localRequire function returns each module function (file)
  • Fn (localRequire, the module, the module exports) corresponding to the function of each module function (the require of the module, exports) {… } this function.
  • The _interopRequireDefault function is executed in fn and returns an object. This object is the code for each file module

conclusion

  • File contents are read and converted to objects including ID,filename, dependency array,code
  • Breadth traverses an array of dependent file objects to obtain an array of all dependent file objects
  • Iterating through the resulting array of file objects produces a concatenated string of all dependent files as per the module executor’s rule 0:[function(){code}]
  • Automatically invoke all dependent modules in turn, starting with a file ID call to the entry file (require(0)) through the module executor (which receives the file string packed above).
  • We get the file dependencies through the AST Import hook.
  • For each file we also do, convert to ast, get the dependencies, add the required attributes, es6 to ES5, code, and then return a file object that we can use easily
  • Webpack is powerful, as is Babel, and AST is an important tool.

Project directory structure

The source code

Welcome your advice, exchange and study, and help to click star Github

————————————— next time decompose ————————————————

Commonjs and import: