快速Webpack學習記之《__webpack_require__》

Webpack學習記之《webpack_require

準備

爲了看到Webpack是怎麼把模塊進行加載和打包,這裏建立了兩個文件,分別是a.jsindex.jsindex.js調用了a.jsfuncAjavascript

/* src/a.js */
export function funcA() {
  console.log('in funcA');
}

/* src/index.js */
import { funcA } from './a';

export function funcB() {
  funcA();
  console.log('in funcB');
}
複製代碼

webpack處理結果分析

如下webpack打包出來的文件(我作了一些刪減和eval的轉換)。 接下來咱們一步一步看看模塊是怎麼加載的。前端

var WebpackTest =
(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;
	}
	// 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 });
	};
	// Object.prototype.hasOwnProperty.call
	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };

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

 "./src/a.js":
  (function(module, __webpack_exports__, __webpack_require__) {
    __webpack_require__.r(__webpack_exports__);
    __webpack_require__.d(__webpack_exports__, "funcA", function() { return funcA; });
    function funcA() {  console.log('in funcA');}
  }),

  "./src/index.js":
  (function(module, __webpack_exports__, __webpack_require__) {
    __webpack_require__.r(__webpack_exports__);
    __webpack_require__.d(__webpack_exports__, "funcB", function() { return funcB; });
    var _a__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/a.js");
    function funcB() {
      Object(_a__WEBPACK_IMPORTED_MODULE_0__["funcA"])();
      console.log('in funcB');
    }
  })
});
複製代碼

step 1

咱們看到整個當即執行函數的真正執行的地方。 ./src/index.js就是在webpack.config.js中定義的entry。java

return __webpack_require__(__webpack_require__.s = "./src/index.js");
複製代碼

step 2

接下來輪到咱們的主角__webpack_require__webpack

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;
}
複製代碼

__webpack_require__函數能夠類比CommonJS的require,都是加載模塊代碼。和NodeJS的設計很相似,都是先從緩存取用,不然加載模塊並放入緩存。web

__webpack_require__所在的閉包能訪問外層變量modules和緩存installedModules。這個很關鍵,由於modules是webpack打包後當即執行函數傳入的參數。modules是一個object,key是string類型,value是function類型。瀏覽器

step3

咱們開始加載模塊moduleId('./src/index.js'),執行模塊方法緩存

modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
複製代碼

這裏咱們看到了兩個函數,分別是__webpack_require__.r__webpack_require__.d閉包

__webpack_require__.r方法主要是標識該模塊爲es模塊。函數

__webpack_require__.d方法是提供Getter給導出的方法、變量。工具

"./src/index.js":
  (function(module, __webpack_exports__, __webpack_require__) {
    // 標識模塊爲es模塊
    __webpack_require__.r(__webpack_exports__);
    // 提供funcB的getter
    __webpack_require__.d(__webpack_exports__, "funcB", function() { return funcB; });
    // 加載module a
    var _a__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/a.js");
    function funcB() {
      //調用module a的funcA方法
      Object(_a__WEBPACK_IMPORTED_MODULE_0__["funcA"])();
      console.log('in funcB');
    }
  })
複製代碼

咱們對比看看未經webpack處理的代碼,就能明白上面的webpack處理後的代碼啦。

/* 如下是源代碼,未經webpack處理 */
/* src/index.js */
import { funcA } from './a';

export function funcB() {
  funcA();
  console.log('in funcB');
}
複製代碼

step 4

想在瀏覽器中使用funcB,只須要調用WebpackTest.funcB()便可。 下面爲對應的webpack配置

//webpack.config.js
output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist'),
    library: 'WebpackTest',
    libraryTarget: 'var',
}
複製代碼

結尾

webpack是前端平常使用的工具,也是有必要了解webpack打包處理出來的文件。

相關文章
相關標籤/搜索