阅读 488

webpack打包源码-打包后文件分析

打包后文件:

(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 = "./src/index.js");
})
/************************************************************************/
({

	"./src/index.js":
	(function(module, exports) {
        let aa = "导入的js文件";
        module.exports = "导入的js文件";
	})

});
复制代码

分析:

  • 打包后的文件就是一个自调用函数,这个函数接收一个对象作为参数
  • 这个对象称为键值对
  • 这个键名是当前被加载模块的文件名与某个目录的拼接
  • 键值是一个函数, 和node.js里的模块加载有些类似, 会将被加载的模块包裹于一个函数中
  • 这个函数在将来某个时间点会被调用, 同时会接收一定的参数, 利用这些参数就可以实现模块的加载操作
  • 针对于上述代码,就是将这个对象传递给自调用函数的形参modules

自调用函数中:

  • 定义installedModules对象用作缓存模块
  • __webpack_require__方法: webpack中定义的,核心作用就是返回模块的exports
  • 接收一个模块id作为参数,在调用的时候就传入模块id将对应的模块的内容的导出,返回
  • 挂载一些方法和属性
  • 首次调用了return __webpack_require__(__webpack_require__.s = "./src/index.js");
  • __webpack_require__.s = 用于缓存路径

对于单文件打包结果:

  • 首先生成一个自调用函数, 称为模块定义
  • 模块定义会传给modules参数, 自动向下执行,
  • 在缓存installedModules[moduleId]中查询, 如果有直接返回
  • 在某个时间点执行了webpack自定义的__webpack_require__方法
  • __webpack_require__方法中通过模块moduleId, 此时的模块id即模块定义的键:"./src/index.js",找到对应模块的执行方法modules[moduleId]
  • __webpack_require__方法中内部定义module对象, 用于存放和返回模块的导出成员, 此对象中有三个参数, 分别为i:moduleId---模块定义的键, l:false---是否被加载, exports:{}---模块导出的成员
  • 通过modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);, 找到moduleId所对应的函数值(这个函数值即模块定义的值)进行调用, 这里call方法的作用, 改变this的指向, 这里将module.exports对象作为参数传递给了modules[moduleId], 这里函数的this便指向module.exports对象, 此处的modules[moduleId]相当于
function(module, exports) {
  let aa = "导入的js文件";
  module.exports = "导入的js文件";
}
复制代码

在一个作用就是调用执行函数

  • 然后将模块的导出值存放在module.exports的对象中
  • 即拿到了模块的导出值

打包后的功能函数解读:

(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__)
  // 将模块定义保存一份,通过m属性挂载到自定义方法上
	__webpack_require__.m = modules;
	// expose the module cache
  // 保存缓存
	__webpack_require__.c = installedModules;
  // Object.prototype.hasOwnProperty.call
  // 用于判断当前被传入的对象obj身上是否有指定的属性
	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
	// define getter function for harmony exports
  // 如果当前exports不具备name属性则条件成立,那么给exports设置属性name,同时提供方法这个属性的访问器getter
	__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) {
    // typeof Symbol !== 'undefined'说明是ES6 即ESModule
		if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
			Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
		}
    // 如果条件不成立,也直接在exports上添加__esModule属性
		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) {
    /**
     * 1 调用t方法后,会拿到被加载模块中的内容 value
     * 2 对应value来说,可能会直接返回,也可能处理后返回
     */
		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;
	};
	
	// __webpack_public_path__
	__webpack_require__.p = "";
	// Load entry module and return exports
	return __webpack_require__(__webpack_require__.s = "./src/index.js");
})
/************************************************************************/
({

/***/ "./src/index.js":
/***/ (function(module, exports) {
        let aa = "导入的js文件";

        module.exports = "导入的js文件";
/***/ })

});
复制代码

具体功能函数解读下回分解....

文章分类
前端
文章标签