为了看到Webpack是怎么把模块进行加载和打包,这里建立了两个文件,分别是a.js
和index.js
,index.js
调用了a.js
的funcA
。javascript
/* 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打包出来的文件(我作了一些删减和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');
}
})
});
复制代码
咱们看到整个当即执行函数的真正执行的地方。 ./src/index.js
就是在webpack.config.js中定义的entry。java
return __webpack_require__(__webpack_require__.s = "./src/index.js");
复制代码
接下来轮到咱们的主角__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类型。浏览器
咱们开始加载模块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');
}
复制代码
想在浏览器中使用funcB
,只须要调用WebpackTest.funcB()
便可。 下面为对应的webpack配置
//webpack.config.js
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
library: 'WebpackTest',
libraryTarget: 'var',
}
复制代码
webpack是前端平常使用的工具,也是有必要了解webpack打包处理出来的文件。