New bee store open source warehouse (connotation Vue 2.x and Vue 3.x H5 mall open source code, with server API interface) : github.com/newbee-ltd

Vue 3.x + Vant 3.x + vue-router 4.x high copy wechat bookable open source address (with server API interface) : github.com/Nick930826/…

React + Vite 2.0 + Zarm React + Vite 2.0 + Zarm

digression

If you want to destroy a man, let him decorate it.

Hi, I’m Nick Chen, missing persons. I started renovating my home in June and couldn’t find time to write. Recently, the decoration is nearly finished, and the company is not very busy with the project, so I took some time to write an article and make a small contribution to the community.

The main purpose of this article is to talk about why Webpack exists and how the code works when packaged.

The preparatory work

With our eyes closed, we’ll write the simplest initialization procedure for a Webpack project.

Create a new folder and initialize the project with NPM init -y, as follows:

Install two more familiar Webpack plug-ins, as shown below:

yarn add webpack webpack-cli -D
Copy the code

Create a new webpack configuration file webpack.config.js in the root directory and add the following content:

const path = require('path');

module.exports = {
  mode: 'development'.// Development mode
  entry: './src/index.js'.// Import file
  output: {
    filename: '[name].js'.// Output file name, default is main.js
    path: path.join(__dirname, 'dist') // Output the address of the file after packaging}}Copy the code

Finally, create a SRC folder under the root directory, and create two files in the folder: index.js and tool.js.

// index.js
import MoonFestival from './tool';
MoonFestival();
Copy the code
// tool.js
export default() = > {document.body.innerHTML = 'Happy Chuseok 🎑'
};
Copy the code

Modify package.json as follows:

"scripts": {
  "build": "webpack --config webpack.config.js"
},
Copy the code

Finally, run NPM run build hard and you will find a dist folder in the root directory, as shown below:

You can try creating a new index.html file and importing main.js as follows:

<! DOCTYPEhtml>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
  <title>Webb parker</title>
</head>
<body>
  <script src="./dist/main.js"></script>
</body>
</html>
Copy the code

Open it in a browser, as shown below:

The purpose of the above steps is to package a copy of the built code in webpack, and let’s look at how a wave of built code runs in the browser.

Introduce pre-package scripts

Try importing the script from the SRC directory before packaging and modifying index.html as follows:

<! DOCTYPEhtml>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
  <title>Webb parker</title>
</head>
<body>
  <script src="./src/index.js"></script>
</body>
</html>
Copy the code

By default, use Google browser to open, here we recommend a VSCode plug-in Live Server, its function is to directly start a Web service.

Select the index. HTML file and click the “Go Live” button in the lower right corner of VSCode to start a http://127.0.0.1:5000 service by default, as shown below:

Error: the browser does not support ES Module import, export and other keywords by default. But there is a trick to getting ES Module support. We add a type=” Module “attribute to the script tag of index. HTML to refresh the browser again, as shown below:

This property allows browsers to support modular development in the ES Module specification, but let’s look at the browser support for this property:

The support wasn’t great, so a series of build project tools were spawned: Grant, gulp, FIS3, rollup, Parcel, Webapck, and more, leading to Webpack.

Webpack stem what

In view of the above, you want to develop your code in ES Module format, and you want your code to run reliably in all major browsers. There is only one way, write code in ES Module format and go live in a modular format that is compatible with all major browsers through a packaging tool.

Webpack does this for us, using the Babel tool to convert ES6 code into ES5 code, with the goal of making it more compatible with major browsers. Webpack uses Node operations to convert code into code strings, break the code into modules through tags, and execute the code strings through eval.

The text is weak enough to understand how packaged works in multiple browsers, so let’s take a look at what /dist/main.js is all about.

Thin body

The above code, packaged, output main.js is about 96 lines long. After we comment out some of the code, it looks something like this:

(() = > {
  "use strict";
  var __webpack_modules__ = ({
    "./src/index.js": ((__unused_webpack_module, __webpack_exports__, __webpack_require__) = > {
      eval("__webpack_require__.r(__webpack_exports__); \n/* harmony import */ var _tool_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./tool.js */ \"./src/tool.js\"); \n\n(0,_tool_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(); \n\n//# sourceURL=webpack://weibopaike/./src/index.js?");
    }),
    "./src/tool.js": ((__unused_webpack_module, __webpack_exports__, __webpack_require__) = > {
      eval("__webpack_require__.r(__webpack_exports__); \n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ }); \n/* Harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (() => {\n document.body.innerhtml = 'Happy Mid-Autumn Festival 🎑'\n}); \n\n//# sourceURL=webpack://weibopaike/./src/tool.js?"); })});var __webpack_module_cache__ = {};
  function __webpack_require__(moduleId) {
    var cachedModule = __webpack_module_cache__[moduleId];
    if(cachedModule ! = =undefined) {
      return cachedModule.exports;
    }
    var module = __webpack_module_cache__[moduleId] = {
      exports: {}}; __webpack_modules__[moduleId](module.module.exports, __webpack_require__);
      return module.exports;
    }

  (() = > {
    __webpack_require__.d = (exports, definition) = > {
      for(var key in definition) {
        if(__webpack_require__.o(definition, key) && ! __webpack_require__.o(exports, key)) {
          Object.defineProperty(exports, key, { enumerable: true.get: definition[key] }); }}}; }) (); (() = > {
    __webpack_require__.o = (obj, prop) = > (Object.prototype.hasOwnProperty.call(obj, prop))
  })();

  (() = > {
    __webpack_require__.r = (exports) = > {
      if(typeof Symbol! = ='undefined' && Symbol.toStringTag) {
        Object.defineProperty(exports.Symbol.toStringTag, { value: 'Module' });
      }
      Object.defineProperty(exports.'__esModule', { value: true}); }; }) ();var __webpack_exports__ = __webpack_require__("./src/index.js"); }) ();Copy the code

At first glance, my god, what is this? It’s just a little bit more complicated, just to scare you, but let’s break it down.

Thin body again

0, __unused_webpack_module is not used, it is a bit of an eyesy, first remove.

1. Change __webpack_require__ to require, which can be interpreted as Webpack’s internal custom require method for importing modules.

2. Clear __webpack_module_cache__, which can be interpreted as a module cache object, and store the module in __webpack_module_cache__ when the module is first loaded. There is no need to re-execute the __webpack_modules__ method on the next call.

3. __webpack_require__.r can also be temporarily cleaned up to add an __esModule attribute of true to __webpack_exports__, indicating that it is an ES Module. This is mainly to handle mixing ES Module and CommonJS.

4. Replace _tool_js__WEBPACK_IMPORTED_MODULE_0__ with tool for easy comprehension.

After a second liposuction, we came up with a scrawny basic code:

(() = > {
  "use strict";
  var __webpack_modules__ = ({
    "./src/index.js": (( __webpack_exports__, require) = > {
      eval("var tool = require( \"./src/tool.js\"); \n\n(0,tool[\"default\"])();");
    }),
    "./src/tool.js": (( __webpack_exports__, require) = > {
      eval("require.d(__webpack_exports__, {\n\"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n }); \nconst __WEBPACK_DEFAULT_EXPORT__ = (() => {\n document.body.innerhtml = 'Happy Mid-Autumn Festival 🎑'\n}); \n\n"); })});function require(moduleId) {
    var module = {
      exports: {}}; __webpack_modules__[moduleId](module.exports, require);
    return module.exports;
  }

  (() = > {
    require.d = (exports, definition) = > {
      for(var key in definition) {
        if(require.o(definition, key) && !require.o(exports, key)) {
          Object.defineProperty(exports, key, { enumerable: true.get: definition[key] }); }}}; }) (); (() = > {
    require.o = (obj, prop) = > (Object.prototype.hasOwnProperty.call(obj, prop))
  })();

  var __webpack_exports__ = require("./src/index.js"); }) ();Copy the code

The require.d method is used to define export variables for __webpack_exports__. For example, in the code above, eval in./ SRC /tool.js looks like this:

require.d(__webpack_exports__, {
	"default": () = > (__WEBPACK_DEFAULT_EXPORT__)
});
const __WEBPACK_DEFAULT_EXPORT__ = (() = > {
  document.body.innerHTML = 'Happy Chuseok 🎑'
});
Copy the code

It is equivalent to __webpack_exports__[“default”] = __WEBPACK_DEFAULT_EXPORT__. So let’s also “hack” require.d… The final code is as follows:

(() = > {
  "use strict";
  var __webpack_modules__ = ({
    "./src/index.js": (( __webpack_exports__, require) = > {
      eval("var tool = require( \"./src/tool.js\"); \n\n(0,tool[\"default\"])();");
    }),
    "./src/tool.js": (( __webpack_exports__, require) = > {
      eval("Const __WEBPACK_DEFAULT_EXPORT__ = (() => {\n document.body.innerhtml = 'Happy Mid-Autumn Festival 🎑'\n}); \n\n__webpack_exports__[\"default\"] = __WEBPACK_DEFAULT_EXPORT__"); })});function require(moduleId) {
    var module = {
      exports: {}}; __webpack_modules__[moduleId](module.exports, require);
    return module.exports;
  }

  var __webpack_exports__ = require("./src/index.js"); }) ();Copy the code

Now let’s take a hard look at these 21 lines of code.

Line by line analysis

First of all, the whole code block is an IIFE, which is an immediate function. The reason for putting the packaged code block into an immediate function is to avoid contaminating global variables.

webpack_modules

All of our module code is stored in this object with the file name key code string as the value. / SRC /index.js looks like this:

var tool = require("./src/tool.js");

(0,tool["default") ();Copy the code

The eval code in./ SRC /tool.js looks like this:

const __WEBPACK_DEFAULT_EXPORT__ = (() = > {
  document.body.innerHTML = 'Happy Chuseok 🎑'
});

__webpack_exports__["default"] = __WEBPACK_DEFAULT_EXPORT__;
Copy the code

Note that the above code is all strings and must be passedwebpack_modules(‘./ SRC /index.js’)(XXX, XXX).

require

This method is a module-importing mechanism generated within Webpack that emulates CommonJS and takes a moduleId argument, which is the module’s file path, such as./ SRC /index.js and./ SRC /tool.js.

An object is defined internally:

var module = {
  exports: {}};Copy the code

Assign some of the eval code string above to the exports object, such as:

__webpack_exports__["default"] = __WEBPACK_DEFAULT_EXPORT__;
Copy the code

Finally return out, e.g.

var tool = require("./src/tool.js");
Copy the code

Module. Exports (0,tool[“default”])(); Execute document.body.innerHTML = ‘Happy Mid-Autumn Festival 🎑’.

The entrance

The logical entry to our code for all of the above business is./ SRC /index.js, so at the end of the immediately executed function, the entry is executed:

var __webpack_exports__ = require("./src/index.js");
Copy the code

The entire Webpack file is executed recursively through the require method, cascading all modules together.

Let’s execute the scrawny code above, as follows:

I got it again.

Run through the code line by line

We make a breakpoint at the very top of the./dist/main.js code as follows:

(() = > {
	debugger;
  "use strict"; . }) ()Copy the code

Take a look at how this code is executed inside the browser:

conclusion

In order to facilitate the analysis of the execution mechanism, the code only involves the introduction of one module. In normal development, there will be a large number of modules introduced and complex dependencies, which involves deeper knowledge. There will be a very sound module classification mechanism inside Webpack. And some deep cache optimization mechanism, which requires students to further study. At least once you understand the principles above, you won’t have to ask webPack-related questions. From the development of modularity to the packaging mechanism of Webpack.