webpack2是如何对实现es6-modules的(表现形式)

webpack2是如何对实现es6-modules的(表现形式)

webpack是如何实现module的呢?
我们从最后的文件分析
我们先创建两个文件

a.js

 let a = 1
 const b = 2
 export function log(val) {
  console.log(val)
}
export default{
  a:a,
  b:b
}


app.js

import tt from './a'
import {log} from './a'
console.log(tt.b)
log(tt.b)

然后在webpack中设置app.js为入口,打包一下...

webpack 会根据入口文件的依赖读入所有依赖的js,最后生成一个文件(默认配置),在文件中具体的看下面


ps:最后打包好都是在一个文件中,这里先拿出其中一部分分析

先看a.js在打包文件中是什么样子

function(module, __webpack_exports__, __webpack_require__) {

  "use strict";
  /* harmony export (immutable) */ __webpack_exports__["b"] = log;
  let a = 1
  const b = 2
  function log(val) {
    console.log(val)
  }
  /* harmony default export */ __webpack_exports__["a"] = {
    a:a,
    b:b
  };
}

可以看到webpack首先将整个文件包裹了起来,添加了三个变量,然后将export的属性都绑定到了__webpack_exports__


再看app.js

function(module, __webpack_exports__, __webpack_require__) {

  "use strict";
  Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
  /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__a__ = __webpack_require__(0);


  console.log(__WEBPACK_IMPORTED_MODULE_0__a__["a" /* default */].b)
  __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__a__["b" /* log */])(__WEBPACK_IMPORTED_MODULE_0__a__["a" /* default */].b)


  /***/ }

对比原app.js

import tt from './a'
import {log} from './a'
console.log(tt.b)
log(tt.b)

__webpack_require__(0)就是返回模块export的模块

可以看到,import 在这里就是创了一个含有导入模块export的对象,在下面调用模块时,去这个对象中调用.


下面来看__webpack_require__

(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: {}
  };

  // 执行了导入的module,把export的值都放到module.exports中
  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;

// identity function for calling harmony imports with the correct context
__webpack_require__.i = function(value) { return value; };

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

// 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 = 1);
})
  /************************************************************************/([
  /* 0 */  /***/ (function(module, __webpack_exports__, __webpack_require__) {

  "use strict";
  /* harmony export (immutable) */ __webpack_exports__["b"] = log;
  let a = 1
  const b = 2
  function log(val) {
    console.log(val)
  }
  /* harmony default export */ __webpack_exports__["a"] = {
    a:a,
    b:b
  };


  /***/ }),
  /* 1 */  /***/ (function(module, __webpack_exports__, __webpack_require__) {

  "use strict";
  Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
  /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__a__ = __webpack_require__(0);


  console.log(__WEBPACK_IMPORTED_MODULE_0__a__["a" /* default */].b)
  __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__a__["b" /* log */])(__WEBPACK_IMPORTED_MODULE_0__a__["a" /* default */].b)


  /***/ })
]);

这里用了一个立即执行函数,把所有的模块做为一个数组传了进去,在初始化之后,调用了入口模块return __webpack_require__(__webpack_require__.s = 1); 1就是入口模块所在的数组index,然后在调用入口模块时,递归的加载入口模块调用的模块,比如: 在入口模块中

 /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__a__ = __webpack_require__(0);

这就会去加载其他的模块,将其他模块中的export变量导入到入口模块中,供给模块内部使用.

总结

es6 module是静态的依赖,所以在运行前进行代码转换,这里的实现是将所有导出项作为一个对象的属性,在入口文件执行时,去递归的加载模块

发表评论

电子邮件地址不会被公开。 必填项已用*标注