From the perspective of easy understanding nodejs javascript in import and export module specification commonjs

foreword (preface)

Recently read "nodejs develop real" geeks time, there are examples where a nodejs in commonjs module specification, examples can be concluded that if module.exports as the export, then the priority is the highest.

I'm very curious, and its operating mechanism is what?

OF in a small boot Finally, the nodejs codes by webpack packaged into js code, and at an angle js as a window.

Therefore, this article, I want to do is to put the packaged js code for dismantling and analyzed one by one, in order to understand the mode of operation is probably behind it.

example (case)

First of all, we give the code nodejs case of:

/commonjs/lib.js:

exports.hello = 'world'

module.exports = function minus (a, b) {
  return a - b
}

exports.add = function (a, b) {
  return a + b
}

/commonjs/index.js:

var lib = require('./lib.js')

console.log(lib)

Our output by node commonjs / index.js, terminal minus this function.

Then we execute the script: webpack --devtool none --mode = development --target node commonjs / index.js

It will generate a dist folder in our root directory, and generates a file in which main.js:

main.js:

/******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};
/******/
/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
/******/
/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId]) {
/******/ 			return installedModules[moduleId].exports;
/******/ 		}
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			i: moduleId,
/******/ 			l: false,
/******/ 			exports: {}
/******/ 		};
/******/
/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ 		// Flag the module as loaded
/******/ 		module.l = true;
/******/
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}
/******/
/******/
/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules;
/******/
/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules;
/******/
/******/ 	// define getter function for harmony exports
/******/ 	__webpack_require__.d = function(exports, name, getter) {
/******/ 		if(!__webpack_require__.o(exports, name)) {
/******/ 			Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ 		}
/******/ 	};
/******/
/******/ 	// define __esModule on exports
/******/ 	__webpack_require__.r = function(exports) {
/******/ 		if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ 			Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ 		}
/******/ 		Object.defineProperty(exports, '__esModule', { value: true });
/******/ 	};
/******/
/******/ 	// create a fake namespace object
/******/ 	// mode & 1: value is a module id, require it
/******/ 	// mode & 2: merge all properties of value into the ns
/******/ 	// mode & 4: return value when already ns object
/******/ 	// mode & 8|1: behave like require
/******/ 	__webpack_require__.t = function(value, mode) {
/******/ 		if(mode & 1) value = __webpack_require__(value);
/******/ 		if(mode & 8) return value;
/******/ 		if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ 		var ns = Object.create(null);
/******/ 		__webpack_require__.r(ns);
/******/ 		Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ 		if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ 		return ns;
/******/ 	};
/******/
/******/ 	// getDefaultExport function for compatibility with non-harmony modules
/******/ 	__webpack_require__.n = function(module) {
/******/ 		var getter = module && module.__esModule ?
/******/ 			function getDefault() { return module['default']; } :
/******/ 			function getModuleExports() { return module; };
/******/ 		__webpack_require__.d(getter, 'a', getter);
/******/ 		return getter;
/******/ 	};
/******/
/******/ 	// Object.prototype.hasOwnProperty.call
/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "";
/******/
/******/
/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(__webpack_require__.s = "./commonjs/index.js");
/******/ })
/************************************************************************/
/******/ ({

/***/ "./commonjs/index.js":
/*!***************************!*\
  !*** ./commonjs/index.js ***!
  \***************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {

var lib = __webpack_require__(/*! ./lib.js */ "./commonjs/lib.js")

console.log(lib)



/***/ }),

/***/ "./commonjs/lib.js":
/*!*************************!*\
  !*** ./commonjs/lib.js ***!
  \*************************/
/*! no static exports found */
/***/ (function(module, exports) {

exports.hello = 'world'

module.exports = function minus (a, b) {
  return a - b
}

exports.add = function (a, b) {
  return a + b
}


/***/ })

/******/ });

Thus a total of 124 lines of code (comments and blank lines a lot, should be less than 100 lines of code, or only five hundred sixty-seven eighty lines), it does not take a long time to finish, but we have to understand it.

module split (split module)

The whole adaptive code an anonymous function, we first code into two parts: the function body , the parameters .

parameter

We first start with the parameters of logic in the main body of the function, the parameters relative to the relatively simple:

{
  "./commonjs/index.js": (function (module, exports, __webpack_require__) {
      var lib = __webpack_require__("./commonjs/lib.js")
      console.log(lib)
  }),
  "./commonjs/lib.js": (function (module, exports) {
      exports.hello = 'world'
      module.exports = function minus(a, b) {
          return a - b
      }
      exports.add = function (a, b) {
          return a + b
      }
  })
}

I will get rid of the parameters in the extra comment that the above code. It is an object, the object has two functions types of properties, it is easy to see that we can before we packed two script files --commonjs / index.js and commonjs / lib.js, representatives of the two functions the parameter structure is basically the same as the first two parameters and the module exports, index.js because of the introduction in lib.js, so we need to require an extra parameter (the code for __webpack_require__), that is, before we followed two functions in vivo exactly the same script in the script file.

Function body

var a = function (modules) { // webpackBootstrap
  // The module cache
  var installedModules = {};

  // The require function
  function __webpack_require__(moduleId) {

      // Check if module is in cache
      if (installedModules[moduleId]) {
          return installedModules[moduleId].exports;
      }
      // Create a new module (and put it into the cache)
      var module = installedModules[moduleId] = {
          i: moduleId,
          l: false,
          exports: {}
      };

      // Execute the module function
      modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);

      // Flag the module as loaded
      module.l = true;

      // Return the exports of the module
      return module.exports;
  }


  // expose the modules object (__webpack_modules__)
  __webpack_require__.m = modules;

  // expose the module cache
  __webpack_require__.c = installedModules;

  // define getter function for harmony exports
  __webpack_require__.d = function (exports, name, getter) {
      if (!__webpack_require__.o(exports, name)) {
          Object.defineProperty(exports, name, {
              enumerable: true,
              get: getter
          });
      }
  };

  // define __esModule on exports
  __webpack_require__.r = function (exports) {
      if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
          Object.defineProperty(exports, Symbol.toStringTag, {
              value: 'Module'
          });
      }
      Object.defineProperty(exports, '__esModule', {
          value: true
      });
  };

  // create a fake namespace object
  // mode & 1: value is a module id, require it
  // mode & 2: merge all properties of value into the ns
  // mode & 4: return value when already ns object
  // mode & 8|1: behave like require
  __webpack_require__.t = function (value, mode) {
      if (mode & 1) value = __webpack_require__(value);
      if (mode & 8) return value;
      if ((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
      var ns = Object.create(null);
      __webpack_require__.r(ns);
      Object.defineProperty(ns, 'default', {
          enumerable: true,
          value: value
      });
      if (mode & 2 && typeof value != 'string')
          for (var key in value) __webpack_require__.d(ns, key, function (key) {
              return value[key];
          }.bind(null, key));
      return ns;
  };

  // getDefaultExport function for compatibility with non-harmony modules
  __webpack_require__.n = function (module) {
      var getter = module && module.__esModule ?
          function getDefault() {
              return module['default'];
          } :
          function getModuleExports() {
              return module;
          };
      __webpack_require__.d(getter, 'a', getter);
      return getter;
  };

  // Object.prototype.hasOwnProperty.call
  __webpack_require__.o = function (object, property) {
      return Object.prototype.hasOwnProperty.call(object, property);
  };

  // __webpack_public_path__
  __webpack_require__.p = "";


  // Load entry module and return exports
  return __webpack_require__(__webpack_require__.s = "./commonjs/index.js");
}

This one, we can be divided into three overall logic: __webpack_require__ function , __webpack_require__ function additional properties , return of function .

1 .__ webpack_require__ function

We focus on these few lines of code:

  • This is a data structure of a module:
// Create a new module (and put it into the cache)
var module = installedModules[moduleId] = {
    i: moduleId,
    l: false,
    exports: {}
};

  • In conjunction with the start of the anonymous function parameter structure - (module, exports, require), exports are a subset of the object module, if given a new object to module.exports, exports have been abandoned, so from here, we know why If we use module.exports, then module.export will exports covered.
// Execute the module function
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
  • This one, we are concerned is the final return, output is module.exports, this is actually the code in the preceding two paragraphs, we can expect to.
// Flag the module as loaded
module.l = true;

// Return the exports of the module
return module.exports;

We then went to see.

return 2. Functions

In fact, the whole execution of code only the last big that a return, it only calls __webpack_require__, so we just look at this one on the line.

It passed a path string, just the anonymous function parameter index.js script functions corresponding attribute name, according to a statement __webpack_require__ function first creates a module object, and then execute the following statement:

var lib = __webpack_require__("./commonjs/lib.js")
console.log(lib)

Wherein __webpack_require __ ( "./ commonjs / lib.js") is also an object to create a module, and operated by the script to lib.js module, and then returned to module.exports lib code above.

Here, import and export operation mechanism modules we've got a little clearer outline, in such a way, for the introduction of export between modules, basically meet our needs.

Additional function 3 .__ webpack_require__ property

This part of the code and this demo is actually nothing to do, but the mentality for a closer look, or read a bit.

These two are a property with exposed modules (anonymous function passed in the Senate, I am here let's call him good for the module queue) and installedModules (this is the beginning of code declares a variable data cache module is used, mainly by a Flag data module and moduleId derived composition)

// expose the modules object (__webpack_modules__)
__webpack_require__.m = modules; 

// expose the module cache
__webpack_require__.c = installedModules;

The following function is a utility function for a property of an object to add getter.

// define getter function for harmony exports
  __webpack_require__.d = function (exports, name, getter) {
      if (!__webpack_require__.o(exports, name)) {
          Object.defineProperty(exports, name, {
              enumerable: true,
              get: getter
          });
      }
  };

EsModule used to set the following sentence indicated in the export target, in particular how to use, since this demo not used, is not clear. (Probably thinking that should be in the direction of the script using this method will be used when EsModule of export, due to the time that this article is no longer continue verified)

// define __esModule on exports
  __webpack_require__.r = function (exports) {
      if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
          Object.defineProperty(exports, Symbol.toStringTag, {
              value: 'Module'
          });
      }
      Object.defineProperty(exports, '__esModule', {
          value: true
      });
  };

The following sentence is declared a personal guess export module data structure EsModule based.

  // create a fake namespace object(声明一个假的命名空间对象)
  // mode & 1: value is a module id, require it
  // mode & 2: merge all properties of value into the ns
  // mode & 4: return value when already ns object
  // mode & 8|1: behave like require
  __webpack_require__.t = function (value, mode) {
      if (mode & 1) value = __webpack_require__(value);
      if (mode & 8) return value;
      if ((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
      var ns = Object.create(null);
      __webpack_require__.r(ns);
      Object.defineProperty(ns, 'default', {
          enumerable: true,
          value: value // module.exports
      });
      if (mode & 2 && typeof value != 'string')
          for (var key in value) __webpack_require__.d(ns, key, function (key) {
              return value[key];
          }.bind(null, key));
      return ns;
  };

Since the phrase and see the module .__ esModule return module [ 'default'], can generally be determined according to the type of module specifications, select a different data acquisition method derivation module, wherein for acquiring EsModule getDefault about the export default derived data.

// getDefaultExport function for compatibility with non-harmony modules
  __webpack_require__.n = function (module) {
      var getter = module && module.__esModule ?
          function getDefault() {
              return module['default'];
          } :
          function getModuleExports() {
              return module;
          };
      __webpack_require__.d(getter, 'a', getter);
      return getter;
  };

Determine whether an object contains an attribute.

// Object.prototype.hasOwnProperty.call
  __webpack_require__.o = function (object, property) {
      return Object.prototype.hasOwnProperty.call(object, property);
};

This is a path, specifically the public path represents what is not clear.

// __webpack_public_path__
  __webpack_require__.p = "";

legend

Here Insert Picture Description
Finally, I made a chart based on personal understanding. Based on the above analysis, if the above model, we can imagine, nodejs when dealing with perhaps the first to have a script to acquire a collection of modules ModuleSet (This module is based on the entry script began to set, the set of all associated modules ), I indicated with Input map, then Input passed to the script again this ModuleSet a script script, we assume that it is a function, the function began to expand from the entry point by methods require.

last (final)
Thank you finish reading this article, your reading is my motivation to continue moving forward.

For the above, what new ideas or find something wrong, I hope you can point out.

Finally, attach the individual often visit social platforms:
know almost: https://www.zhihu.com/people/bi-an-yao-91/activities
CSDN: https://blog.csdn.net/YaoDeBiAn
GitHub: https://github.com/yaodebian

Personal current limited capacity, and there is no independent ability to build a community, if you have any questions or ideas to communicate with me, please contact me through one of these platforms, thank you! ! !

Published 80 original articles · won praise 91 · Views 150,000 +

Guess you like

Origin blog.csdn.net/YaoDeBiAn/article/details/104736252