欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

webpack4打包后的代码分析

程序员文章站 2022-05-30 17:44:06
...

此文分析时使用的依赖包版本号如下:

"devDependencies": {
  "html-webpack-plugin": "4.5.0",
  "webpack": "4.44.2",
  "webpack-cli": "3.3.12"
}

webpack配置文件如下:

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  devtool: 'none',
  mode: 'development',
  entry: './src/index.js',
  output: {
    filename: 'built.js',
    path: path.resolve('dist')
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ]
}

模块代码如下:

// index.js
const title = require('./title.js')
import name, { age } from './name'
const oBtn = document.getElementById('btn')

oBtn.addEventListener('click', function () {
  import(/*webpackChunkName: "btn"*/'./btn.js').then(btn => {
    console.log(btn)
  })
})

console.log('index.js内容执行了')
console.log(`${name}: ${age}`)
console.log(title)

// title.js
module.exports = 'webpack analyze'

// btn.js
module.exports = '按钮被点击了'

// name.js
export const age = 18
export default 'yhzzy'

html代码如下

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>webpack</title>
</head>

<body>
  <button id="btn">点击加载</button>
</body>

</html>

首先我们先来看看打包出来后的代码样子,我人为的去除了里面一些注释符号:
built.js

(function(modules) { // webpackBootstrap
	// install a JSONP callback for chunk loading
	function webpackJsonpCallback(data) {
		var chunkIds = data[0];
		var moreModules = data[1];
		// add "moreModules" to the modules object,
		// then flag all "chunkIds" as loaded and fire callback
		var moduleId, chunkId, i = 0, resolves = [];
		for(;i < chunkIds.length; i++) {
			chunkId = chunkIds[i];
			if(Object.prototype.hasOwnProperty.call(installedChunks, chunkId) && installedChunks[chunkId]) {
				resolves.push(installedChunks[chunkId][0]);
			}
			installedChunks[chunkId] = 0;
		}
		for(moduleId in moreModules) {
			if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
				modules[moduleId] = moreModules[moduleId];
			}
		}
		if(parentJsonpFunction) parentJsonpFunction(data);

		while(resolves.length) {
			resolves.shift()();
		}

	};

	// The module cache
	var installedModules = {};

	// object to store loaded and loading chunks
	// undefined = chunk not loaded, null = chunk preloaded/prefetched
	// Promise = chunk loading, 0 = chunk loaded
	var installedChunks = {
		"main": 0
	};

	// script path function
	function jsonpScriptSrc(chunkId) {
		return __webpack_require__.p + "" + chunkId + ".built.js"
	}

	// 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;
	}

	// This file contains only the entry chunk.
	// The chunk loading function for additional chunks
	__webpack_require__.e = function requireEnsure(chunkId) {
		var promises = [];

		// JSONP chunk loading for javascript

		var installedChunkData = installedChunks[chunkId];
		if(installedChunkData !== 0) { // 0 means "already installed".

			// a Promise means "currently loading".
			if(installedChunkData) {
				promises.push(installedChunkData[2]);
			} else {
				// setup Promise in chunk cache
				var promise = new Promise(function(resolve, reject) {
					installedChunkData = installedChunks[chunkId] = [resolve, reject];
				});
				promises.push(installedChunkData[2] = promise);

				// start chunk loading
				var script = document.createElement('script');
				var onScriptComplete;

				script.charset = 'utf-8';
				script.timeout = 120;
				if (__webpack_require__.nc) {
					script.setAttribute("nonce", __webpack_require__.nc);
				}
				script.src = jsonpScriptSrc(chunkId);

				// create error before stack unwound to get useful stacktrace later
				var error = new Error();
				onScriptComplete = function (event) {
					// avoid mem leaks in IE.
					script.onerror = script.onload = null;
					clearTimeout(timeout);
					var chunk = installedChunks[chunkId];
					if(chunk !== 0) {
						if(chunk) {
							var errorType = event && (event.type === 'load' ? 'missing' : event.type);
							var realSrc = event && event.target && event.target.src;
							error.message = 'Loading chunk ' + chunkId + ' failed.\n(' + errorType + ': ' + realSrc + ')';
							error.name = 'ChunkLoadError';
							error.type = errorType;
							error.request = realSrc;
							chunk[1](error);
						}
						installedChunks[chunkId] = undefined;
					}
				};
				var timeout = setTimeout(function(){
					onScriptComplete({ type: 'timeout', target: script });
				}, 120000);
				script.onerror = script.onload = onScriptComplete;
				document.head.appendChild(script);
			}
		}
		return Promise.all(promises);
	};

	// 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 = "";

	// on error function for async loading
	__webpack_require__.oe = function(err) { console.error(err); throw err; };

	var jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] || [];
	var oldJsonpFunction = jsonpArray.push.bind(jsonpArray);
	jsonpArray.push = webpackJsonpCallback;
	jsonpArray = jsonpArray.slice();
	for(var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]);
	var parentJsonpFunction = oldJsonpFunction;

	// Load entry module and return exports
	return __webpack_require__(__webpack_require__.s = "./src/index.js");
})
({
  "./src/index.js":
    (function(module, __webpack_exports__, __webpack_require__) {
      "use strict";
      __webpack_require__.r(__webpack_exports__);
      /* harmony import */ var _name__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./name */ "./src/name.js");
      const title = __webpack_require__(/*! ./title.js */ "./src/title.js")
      const oBtn = document.getElementById('btn')
      oBtn.addEventListener('click', function () {
        __webpack_require__.e(/*! import() | btn */ "btn").then(__webpack_require__.t.bind(null, /*! ./btn.js */ "./src/btn.js", 7)).then(btn => {
          console.log(btn)
        })
      })
      console.log('index.js内容执行了')
      console.log(`${_name__WEBPACK_IMPORTED_MODULE_0__["default"]}: ${_name__WEBPACK_IMPORTED_MODULE_0__["age"]}`)
      console.log(title)
    }),

  "./src/name.js":
    (function(module, __webpack_exports__, __webpack_require__) {
      "use strict";
      __webpack_require__.r(__webpack_exports__);
      /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "age", function() { return age; });
      const age = 18
      /* harmony default export */ __webpack_exports__["default"] = ('yhzzy');
    }),

  "./src/title.js":
    (function(module, exports) {
      module.exports = 'webpack analyze'
    })
});

btn.built.js

(window["webpackJsonp"] = window["webpackJsonp"] || []).push([["btn"],{

"./src/btn.js":
  (function(module, exports) {
    module.exports = '按钮被点击了'
  })

}]);

下面我们就来分析一下这个源码。

代码结构

将打包后的代码折叠,不难发现,其实就是一个IIFE自执行函数,函数的参数则是被打包的具体模块代码的一个健值对形式

(function(modules) {
  // 处理逻辑代码
})
({
  "./src/index.js":
    (function(module, __webpack_exports__, __webpack_require__) {
      "use strict";
      __webpack_require__.r(__webpack_exports__);
      /* harmony import */ var _name__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./name */ "./src/name.js");
      const title = __webpack_require__(/*! ./title.js */ "./src/title.js")
      const oBtn = document.getElementById('btn')
      oBtn.addEventListener('click', function () {
        __webpack_require__.e(/*! import() | btn */ "btn").then(__webpack_require__.t.bind(null, /*! ./btn.js */ "./src/btn.js", 7)).then(btn => {
          console.log(btn)
        })
      })
      console.log('index.js内容执行了')
      console.log(`${_name__WEBPACK_IMPORTED_MODULE_0__["default"]}: ${_name__WEBPACK_IMPORTED_MODULE_0__["age"]}`)
      console.log(title)
    }),

  "./src/name.js":
    (function(module, __webpack_exports__, __webpack_require__) {
      "use strict";
      __webpack_require__.r(__webpack_exports__);
      /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "age", function() { return age; });
      const age = 18
      /* harmony default export */ __webpack_exports__["default"] = ('yhzzy');
    }),

  "./src/title.js":
    (function(module, exports) {
      module.exports = 'webpack analyze'
    })
})

其中每一个模块的值也是一个IIFE自执行函数,这个函数会接收三个参数

  • 第一个参数 module,为缓存的模块,用来操作CommonJS规范代码的module.exports导出
  • 第二个参数 exports或__webpack_exports__,为缓存的module的exports属性,为exports时用于CommonJS规范代码exports.xxx = yyy导出,而为__webpack_exports__时则是用于esModule规范的代码导出
  • 第三个参数 webpack_require,是用来导入模块依赖的一个函数

处理逻辑代码分析

1.首先会定义一个对象用于缓存被加载的模块,将来在二次加载模块时,如果缓存中有则直接在缓存中取出,还会定一个用来标记模块是否加载的installedChunks

var installedModules = {}

// undefined没有加载,null预加载,Promise正在加载中,0已经加载
var installedChunks = {
  "main": 0
}

2.逻辑代码的核心,用来加载所有的依赖模块,接收一个模块Id参数,用来确定加载的模块

function __webpack_require__(moduleId) {
  // 检查该模块在缓存中是否存在,如果存在直接返回
  if (installedModules[moduleId]) {
    return installedModules[moduleId].exports
  }

  // 缓存中不存在则新建一个,并保存在缓存中
  var module = installedModules[moduleId] = {
    i: moduleId, // 模块Id
    l: false, // 模块是否已被加载
    exports: {} // 模块的导出内容
  }

  // 然后将新建的module的exports属性带入到全局参数modules中对应模块Id中执行代码,传入的三个参数就是上文中介绍的三个参数
  modules[moduleId].call(module.exports, module, module.exports, __webpack_require__)

  // 设置该模块为已加载
  module.l = true

  // 返回模块的导出
  return module.exports
}

3.我们先看源码执行时最后的返回,根据webpack配置的入口文件,对其进行加载

return __webpack_require__(__webpack_require__.s = "./src/index.js")

通过上文的分析,会新建一个i为"./src/index.js"的module保存到缓存模块中,并执行全局参数中"./src/index.js"内的代码

(function(module, __webpack_exports__, __webpack_require__) {
  "use strict";
  __webpack_require__.r(__webpack_exports__);
  /* harmony import */ var _name__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./name */ "./src/name.js");
  const title = __webpack_require__(/*! ./title.js */ "./src/title.js")
  const oBtn = document.getElementById('btn')
  oBtn.addEventListener('click', function () {
    __webpack_require__.e(/*! import() | btn */ "btn").then(__webpack_require__.t.bind(null, /*! ./btn.js */ "./src/btn.js", 7)).then(btn => {
      console.log(btn)
    })
  })
  console.log('index.js内容执行了')
  console.log(`${_name__WEBPACK_IMPORTED_MODULE_0__["default"]}: ${_name__WEBPACK_IMPORTED_MODULE_0__["age"]}`)
  console.log(title)
})

3.1 代码中首先执行了__webpack_require__.r(webpack_exports),webpack_require.r的作用是将一个exports标记为esModule模式的导出,因为源代码里使用了esModule的导入导出,所以要执行此操作

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

3.2 导入依赖模块"./src/name.js"

var _name__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./name */ "./src/name.js");

再次执行__webpack_require__,将"./src/name.js"存入缓存中并执行其中代码,因为此模块也是esModule规范,所以首先也会通过__webpack_require__.r来标记为esModule

(function(module, __webpack_exports__, __webpack_require__) {
  "use strict";
  __webpack_require__.r(__webpack_exports__);
  /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "age", function() { return age; });
  const age = 18
  /* harmony default export */ __webpack_exports__["default"] = ('yhzzy');
})

接下来执行__webpack_require__.d方法来向__webpack_exports__对象的身上添加指定的属性,同时给该属性提供一个getter用来获取此属性

__webpack_require__.d(__webpack_exports__, "age", function() { return age; });
__webpack_require__.d = function(exports, name, getter) {
  if(!__webpack_require__.o(exports, name)) {
    Object.defineProperty(exports, name, { enumerable: true, get: getter });
  }
};

其中用到的__webpack_require__.o方法用来判断对象的身上是否存在指定的属性

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

最后将age定义,以便将来获取,然后将默认导出挂载到__webpack_exports__

const age = 18
__webpack_exports__["default"] = ('yhzzy')

执行完上面的步骤后,"./src/name.js"中的__webpack_exports__被返回并将"./src/index.js"中的_name__WEBPACK_IMPORTED_MODULE_0__指向它

3.3 接下来回到"./src/index.js"的代码中,继续执行对依赖模块"./src/title.js"的导入,并执行"./src/title.js"中的代码

const title = __webpack_require__(/*! ./title.js */ "./src/title.js")
(function(module, exports) {
  module.exports = 'webpack analyze'
})

__webpack_require__的具体执行不再赘述,最后会将"./src/title.js"模块的exports设置为’webpack analyze’,并返回,所以title也等于’webpack analyze’
这一步执行完了后,便会执行几个打印事件输出数据

console.log('index.js内容执行了') // index.js内容执行了

// 上文已经确定了_name__WEBPACK_IMPORTED_MODULE_0__的值,输出yhzzy: 18
console.log(`${_name__WEBPACK_IMPORTED_MODULE_0__["default"]}: ${_name__WEBPACK_IMPORTED_MODULE_0__["age"]}`)
console.log(title) // webpack analyze

3.4 接下来注册按钮及按钮的点击事件

const oBtn = document.getElementById('btn')
oBtn.addEventListener('click', function () {
  __webpack_require__.e(/*! import() | btn */ "btn").then(__webpack_require__.t.bind(null, /*! ./btn.js */ "./src/btn.js", 7)).then(btn => {
    console.log(btn)
  })
})

当点击按钮时,会执行__webpack_require__.e动态导入"./src/btn.js"模块,最后返回一个Promise
先看几个其中用到的函数

// 配置中的publicPath,默认为空
__webpack_require__.p = "";

// 组装script标签的src值
function jsonpScriptSrc(chunkId) {
  return __webpack_require__.p + "" + chunkId + ".built.js"
}

再来看__webpack_require__.e

__webpack_require__.e = function requireEnsure(chunkId) {
  var promises = [];
  
  // 从最开始定义的installedChunks中拿chunkId(此时为btn)的的值,为0则直接返回,第一次加载结果为undefined
  var installedChunkData = installedChunks[chunkId];
  if(installedChunkData !== 0) { // 0 means "already installed".

    // 判断installedChunkData的值是否为Promise正在加载中
    if(installedChunkData) {
      promises.push(installedChunkData[2]);
    } else {
      // 创建一个Promise,并在其内部将installedChunks[chunkId](installedChunks[‘btn’])和installedChunkData的值设置为一个包含resolve, reject的数组
      var promise = new Promise(function(resolve, reject) {
        installedChunkData = installedChunks[chunkId] = [resolve, reject];
      });
      // 把installedChunkData[2]的值设置为promise本身,并保存到promises数组*将来调用
      promises.push(installedChunkData[2] = promise);

      // 组装script标签,并添加到index.html中调用
      var script = document.createElement('script');
      var onScriptComplete;

      script.charset = 'utf-8';
      script.timeout = 120;
      if (__webpack_require__.nc) {
        script.setAttribute("nonce", __webpack_require__.nc);
      }
      script.src = jsonpScriptSrc(chunkId);

      // create error before stack unwound to get useful stacktrace later
      var error = new Error();
      onScriptComplete = function (event) {
        // avoid mem leaks in IE.
        script.onerror = script.onload = null;
        clearTimeout(timeout);
        var chunk = installedChunks[chunkId];
        if(chunk !== 0) {
          if(chunk) {
            var errorType = event && (event.type === 'load' ? 'missing' : event.type);
            var realSrc = event && event.target && event.target.src;
            error.message = 'Loading chunk ' + chunkId + ' failed.\n(' + errorType + ': ' + realSrc + ')';
            error.name = 'ChunkLoadError';
            error.type = errorType;
            error.request = realSrc;
            chunk[1](error);
          }
          installedChunks[chunkId] = undefined;
        }
      };
      var timeout = setTimeout(function(){
        onScriptComplete({ type: 'timeout', target: script });
      }, 120000);
      script.onerror = script.onload = onScriptComplete;
      // 将script添加在html并执行,此例中执行了btn.built.js中的代码
      document.head.appendChild(script);
    }
  }
  return Promise.all(promises);
};

btn.built.js执行

(window["webpackJsonp"] = window["webpackJsonp"] || []).push([["btn"],{

"./src/btn.js":
  (function(module, exports) {
    module.exports = '按钮被点击了'
  })

}]);

其中window[“webpackJsonp”]方法在打包的入口文件中注册了

function webpackJsonpCallback(data) {
 // webpackJsonpCallback逻辑
};

// 将webpackJsonp挂载到window全局对象上,并将值设置为[]
var jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] || [];

// 将数组原生push方法挂载到oldJsonpFunction
var oldJsonpFunction = jsonpArray.push.bind(jsonpArray);

// 修改window["webpackJsonp"]的push方法为webpackJsonpCallback
jsonpArray.push = webpackJsonpCallback;
// 拷贝一份jsonpArray
jsonpArray = jsonpArray.slice();
for(var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]);

// 将数组原生push方法赋给parentJsonpFunction
var parentJsonpFunction = oldJsonpFunction;

所以btn.built.js内的代码就相当于是

webpackJsonpCallback([["btn"], {
"./src/btn.js":
  (function(module, exports) {
    module.exports = '按钮被点击了'
  })
}])

function webpackJsonpCallback(data) {
  var chunkIds = data[0]; // ["btn"]

  // {
  //   "./src/btn.js":
  //     (function(module, exports) {
  //       module.exports = '按钮被点击了'
  //     })
  // }
  var moreModules = data[1]; 
  // add "moreModules" to the modules object,
  // then flag all "chunkIds" as loaded and fire callback
  var moduleId, chunkId, i = 0, resolves = [];
  for(;i < chunkIds.length; i++) {
    chunkId = chunkIds[i]; // btn
    
    // 判断installedChunks对象中是否存在btn,上文__webpack_require__.e执行时我们已经将btn添加了进去
    if(Object.prototype.hasOwnProperty.call(installedChunks, chunkId) && installedChunks[chunkId]) {

      // 将btn的resolve方法添加到resolves中
      resolves.push(installedChunks[chunkId][0]);
    }

    // 设置installedChunks中btn的状态为0已加载
    installedChunks[chunkId] = 0;
  }

  // 获取"./src/btn.js"内的代码
  for(moduleId in moreModules) {
    if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
      
      //将"./src/btn.js"模块添加到全局参数modules中
      modules[moduleId] = moreModules[moduleId];
    }
  }
  if(parentJsonpFunction) parentJsonpFunction(data);

  // 执行resolves中的resolve方法,将上文__webpack_require__.e内的Promise变为成功状态
  while(resolves.length) {
    resolves.shift()();
  }

};

回到__webpack_require__.e的最后一步执行return Promise.all(promises),此时由于已经在webpackJsonpCallback中resolve了,会返回一个Promise继续执行按钮点击中的then里面的函数,接下来我们回到按钮点击方法中,在then中会执行__webpack_require__.t

const oBtn = document.getElementById('btn')
oBtn.addEventListener('click', function () {
  __webpack_require__.e(/*! import() | btn */ "btn").then(__webpack_require__.t.bind(null, /*! ./btn.js */ "./src/btn.js", 7)).then(btn => {
    console.log(btn)
  })
})
// 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) {
  // 用传进来的mode数字与预设数字进行&预算,此例中7转为2进制为0111
  // 1的2进制为0001,满足条件,__webpack_require__("./src/btn.js")执行,返回值为“按钮被点击了”,此时value=“按钮被点击了”
  if(mode & 1) value = __webpack_require__(value);
  // 8的2进制为1000,不满足条件
  if(mode & 8) return value;
  // 4的2进制为0100,满足条件,但是value的类型为string,继续向下执行
  if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
  // 创建一个空对象null,并标记为esModule规范
  var ns = Object.create(null);
  __webpack_require__.r(ns);
  // 将ns的default属性设置为value
  Object.defineProperty(ns, 'default', { enumerable: true, value: value });
  // 2的2进制为0010满足,类型条件不满足
  if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
  // {default: "按钮被点击了", __esModule: true, Symbol(Symbol.toStringTag): "Module"}
  return ns;
};

之后如果点击按钮便会输出

{default: "按钮被点击了", __esModule: true, Symbol(Symbol.toStringTag): "Module"}

其余挂载到__webpack_require__上的方法介绍

// 保存modules数组
__webpack_require__.m = modules;

// 保存已安装的模块
__webpack_require__.c = installedModules;

// 用于设置具体的 getter
__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;
};
相关标签: javascript webpack